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)
system/vendor/lib.
On Android, it is possible to use the Mobile SDK native API from an NDK library instead of the Java API. To use the native API, you must call TasInitialize with two extra parameters: the JNI environment and the application context. Both are passed as parameters to each JNI native method.
Or: you could try putting your library into /res in the project and use System. load() instead of System. loadLibrary() to load it.
An Android library is structurally the same as an Android app module. It can include everything needed to build an app, including source code, resource files, and an Android manifest.
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
.
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);
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With