我有两个应用程序A和B。应用程序A使用DexClassLoader
从应用程序B加载自定义视图类。这很好。
但是,如果应用程序B中的自定义视图通过java.lang.System.loadLibrary
和dalvik.system.PathClassLoader
加载与apk B捆绑的私有本机库。然后我得到
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.app-b-xxx==/base.apk"],nativeLibraryDirectories=[/system/lib, /vendor/lib]]] couldn't find "my_native_lib.so"
如果我自己启动应用程序B,它就可以很好地加载私有的本地库。
是否支持此功能?我知道DexClassLoader
只加载类,但这些加载的类是否可以调用它们自己绑定的本地库?
你真的不应该像那样直接加载类,你可能会因此与谷歌发生冲突。我认为这违反了Play Store的TOS。这也不安全——如果安装了其他同名应用程序冒充你,你只允许他们的代码以你的用户身份运行,这是一个巨大的安全问题。
但让我们忽略这一点。以下是它不起作用的原因-你的应用程序没有库。当您通过loadLibrary加载时,它会在应用程序的本地特定路径中查找.so文件"您的应用程序";在这种情况下,是运行的应用程序,而不是代码来源的应用程序。所以它找错地方了。如果你在两个应用程序中都包含.so文件,它可能会起作用。但你显然需要知道实现细节才能让它发挥作用,你不能用它来加载任何随机的类库。
如果您愿意使用一点反射,DexClassLoader
包含一个名为pathList
的私有字段,然后该字段包含一个称为addNativePath(Collection<String>)
的方法。
要获取App B的本机库目录,您可以通过包管理器加载它。
// assumes currently in an activity
val nativeLibraryPath = packageManager.getPackageInfo("com.package.name", 0).applicationInfo.nativeLibraryDir
val clClass = classLoader.javaClass
val plField = clClass.superclass.getDeclaredField("pathList")
plField.isAccessible = true
val plInst = plField.get(classLoader)
val plClass = plClass.javaClass
val anpMethod = plClass.getDeclaredMethod("addNativePath", Collection::class.java)
anpMethod.invoke(
plInst,
listOf(nativeLibraryPath)
)
请记住,由于这使用了隐藏的API方法,这可能会在某些较新版本的Android中停止工作。(我写的代码主要在Android 11上测试(
如果您使用System.loadLibrary
加载本机库(根据提供的错误,情况似乎并非如此(,那么只使用具有从应用程序B到本机库的绝对路径的System.load
就可以工作,而无需摆弄类加载器。