Reputation: 177
I've built the Assimp library as a shared library. I've included it in my Android ndk project and it builds fine but when I load it I get the following error: Unable to load native library: My-Native-Activity.
(Perhaps I should add that my activity works fine when the library is not included and that I've checked the apk and on the device; the library is being added to the libs folder and installed on the device in /data/data/my-app/lib.)
I've done a lot of reading and it seems that the only way to solve this is to load them using System.loadLibrary before launching my native activity. I think I'd prefer load them dynamically using dlopen before taking that approach.
Am I correct in assuming that Android wont automatically load the shared libraries my native activity(i.e. my shared library) depends on?
I would build it as a static library but it was over 54Mb which wont work.
This is my Android.mk: I've tried adding -lassimp to LOCAL_LDLIBS. I'm not sure if that would be correct but it didn't make any difference.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := assimp
LOCAL_SRC_FILES := libassimp.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := native-activity
LOCAL_SRC_FILES := main.cpp
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv2
LOCAL_STATIC_LIBRARIES := android_native_app_glue
LOCAL_SHARED_LIBRARIES := assimp
LOCAL_CPPFLAGS += -march=armv7-a -mfloat-abi=softfp
LOCAL_CFLAGS := $(LOCAL_CPPFLAGS)
TARGET_ARCH_ABI := armeabi-v7a
LOCAL_C_INCLUDES += $(LOCAL_PATH)
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)
Upvotes: 16
Views: 22348
Reputation: 434
You want to start the NativeActivity with a java activity. This way you can load the shared libraries before NativeActivity.
AndroidManifest.xml:
<application android:label="@string/app_name" android:hasCode="true">
<activity android:name="DummyActivity"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="android.app.NativeActivity"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden">
<meta-data android:name="android.app.lib_name"
android:value="native-activity" />
</activity>
</application>
DummyActivity.java:
package com.example.native_activity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class DummyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
System.loadLibrary("some_shared_lib");
System.loadLibrary("native-activity");
super.onCreate(savedInstanceState);
Intent intent = new Intent(DummyActivity.this, android.app.NativeActivity.class);
DummyActivity.this.startActivity(intent);
}
}
Upvotes: 7
Reputation: 236
Subclassing android.app.NativeActivity is the simplest way to solve this problem.
package com.you;
public class MyNativeActivity extends android.app.NativeActivity {
static {
System.loadLibrary("assimp");
}
}
Then change your AndroidManifest.xml
. Replace android.app.NativeActivity
with MyNativeActivity
and remove the tag hasCode="false"
.
As a side note, Android does search for dependencies when loading a shared library. But the scope of the search is limited to /system/lib
.
Upvotes: 22
Reputation: 17012
Using System.loadLibrary
is the way to go.
Android won't automatically load dependent shared libraries for you. So you need to do something like this:
static {
System.loadLibrary("assimp"); // dependency .so first
System.loadLibrary("native-activity"); // dependent .so second
}
This code usually goes in the class which contains the native Java methods (i.e. methods defined with keyword native
, which map through to native code). Because this code is executed in a static
block it is executed when the Java classloader loads the class -- i.e. before any code in the class actually gets executed.
You shouldn't have to add any reference to assimp
to LOCAL_LDLIBS
because you're already referencing assimp
via the LOCAL_SHARED_LIBRARIES
declaration.
This question may be relevant.
Upvotes: 1
Reputation: 11
1: U could not use dlopen, since System.loadLibrary is the only method u load a native library from Java layer. 2: Ur library path looks not right, the location should be something like /data/data/urapp/lib/
U need to zip ur library to ur apk file, and while installing, android will unzip it and put it to /data/data/urapp/lib/ automatically.
Hope above information is useful for u.
Upvotes: 0