我想为.so
加载动态的自定义NaticityActivity
,但是在NativeActivity.onCreate()
调用classLoader.findLibrary("UE4");
时出现错误
这是NativeActivity.onCreate()
的聚会
BaseDexClassLoader classLoader = (BaseDexClassLoader) getClassLoader();
String path = classLoader.findLibrary(libname);
if (path == null) {
throw new IllegalArgumentException("Unable to find native library " + libname +
" using classloader: " + classLoader.toString());
}
byte[] nativeSavedState = savedInstanceState != null
? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null;
mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(),
getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()),
getAbsolutePath(getExternalFilesDir(null)),
Build.VERSION.SDK_INT, getAssets(), nativeSavedState,
classLoader, classLoader.getLdLibraryPath());
if (mNativeHandle == 0) {
throw new UnsatisfiedLinkError(
"Unable to load native library \"" + path + "\": " + getDlError());
}
super.onCreate(savedInstanceState);
//Hack classLoader nativeLibraryDirectories, add my .so file path
UnrealHelper.RequestPermission(this);
UnrealHelper.CopyFile(Environment.getExternalStorageDirectory().getPath() + "/libUE4.so", getFilesDir() + "/libUE4.so");
String TestA = System.mapLibraryName("gnustl_shared");
//libUE4.so
String fileName = System.mapLibraryName("UE4");
String TmpVal = "";
BaseDexClassLoader classLoader = (BaseDexClassLoader) getClassLoader();
try
{
Field pathListField = classLoader.getClass().getSuperclass().getDeclaredField("pathList");
pathListField.setAccessible(true);
Object pathListVal = pathListField.get(classLoader);
Field nativeLibPathField = pathListVal.getClass().getDeclaredField("nativeLibraryDirectories");
nativeLibPathField.setAccessible(true);
Object nativeLibPathVal = nativeLibPathField.get(pathListVal);
ArrayList nativeLibraryDirectories = (ArrayList)nativeLibPathVal;
//add my .so path to classLoader
nativeLibraryDirectories.add(getFilesDir());
//nativeLibPathField.set(pathListVal, nativeLibraryDirectories);
//pathListField.set(classLoader, pathListVal);
//ref: https://android.googlesource.com/platform/libcore-snapshot/+/ics-mr1/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
//ref: https://android.googlesource.com/platform/libcore-snapshot/+/ics-mr1/dalvik/src/main/java/dalvik/system/DexPathList.java
for (Object directory : nativeLibraryDirectories) {
File file = new File((File)directory, fileName);
if (file.exists() && file.isFile() && file.canRead()) {
//is valid
TmpVal = file.getPath();
}
}
}
catch(Exception Exp)
{
String ErrorMsg = Exp.toString();
System.out.print(ErrorMsg);
}
//test the path added, but got null
String path = classLoader.findLibrary("UE4");
答案 0 :(得分:0)
您必须将共享库打包到apk中,以便System.loadLibrary("your-lib-name")
可以找到它。请注意,System.loadLibrary
仅接受库名,而不接受完整路径。
对于System.load()
,我尝试了以下步骤,效果很好。您可以尝试您的项目,看看它如何进行。
第1步:
确保在manifest.xml中配置了对外部存储的应用权限,请参见下文:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
并确保您已授予这些权限。
第2步:
假设您下载的.so
文件位于外部SD卡的/Download/
,即/Download/libnative-lib.so
。下面的代码段会将libnative-lib.so
复制到/data/data/<your-app-id>/files/libnative-lib2.so
,并且此libnative-lib2.so
的加载将成功。
String path_sd_card = Environment.getExternalStorageDirectory().getAbsolutePath();
FileOutputStream outputStream;
FileInputStream inputStream;
// 1. This path works.
//System.load("/data/data/com.arophix.jniexample/files/libnative-lib.so");
String filesDir = getFilesDir().getAbsolutePath();
try {
inputStream = new FileInputStream(new File(path_sd_card + "/Download/libnative-lib.so"));
outputStream = new FileOutputStream(new File(filesDir + "/libnative-lib2.so"));//openFileOutput("libnative-lib2.so", Context.MODE_PRIVATE);
FileChannel inChannel = inputStream.getChannel();
FileChannel outChannel = outputStream.getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
inputStream.close();
outputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// This path works
System.load(filesDir + "/libnative-lib2.so");
注意:已在Android Emulator Nexus 6P API 23上验证。
答案 1 :(得分:0)
可以通过System.load()
以下代码成功加载了OpenCV库,并调用了SO库函数以获取版本号
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Copy "libopencv_java3.so" to App directory and return the full path of the SO file
String pathOpenCV = FileUtil.loadAssetFile(this, "libopencv_java3.so");
try {
System.load(pathOpenCV);
} catch (Exception e) {
android.util.Log.e("System.Load", e.toString());
}
//All version number returns correctly
int vMajor = Core.getVersionMajor_0();
int vMinor = Core.getVersionMinor_0();
int vRev = Core.getVersionRevision_0();
}
查看结果:
您可能需要检查您的应用权限。