Java J类中加载so库并声明native方法,javac com/t/j.java编译并javah com/t/j导出com_t_j.h 的jni头文件在当前目录下,在工程主目录下创建文件夹,放入刚才的头文件并创建新文件(hkkk.c/cpp)实现相关方法,并编译出.so。
配置NDK,Java J类中加载so库并声明native方法,外部创建jni目录创建文件c/cpp文件们,android{defaultConfig{jndk{moduleName "so-name"}} productFlavors{arm{ndk{abiFilter "armeabi"}} //x86{ndk{abiFilter "x86"}取所需,默认自动编译所有平台()}}}, Andorid.mk(LOCAL_PAT :=$(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE :=so-name//模块名 LOCAL_SRC_FILES :=j.c//要编译的源文件 include $(BUILD_SHARED_LIBRARY)), Application.mk(APP_ABI :=armeabi//所需支持的平台), 默认编译jni下的源文件,android{sourceSets.main{jni.srcDirs 'src/main/jnilj'}}可改编译源
AS .so默认加载目录为jniLibs(可直接System.loadLibrary),也可在android{sourceSets.main{jniLibs.srcDir 'src/main/some'}}设置成其它的
安装apk的时候,解析apk,解压然后读取libs目录下的so文件,获取应用所支持的arch架构类型,本地释放解压到指定目录。64位(5.0系统后,通过ro.product.cpu.abilist属性值来判断,若含64即64位系统;5.0之前都是32位,可通过ro.product.cpu.abi值判断)系统会启动两个Zygote进程兼容32位应用(so)。启动应用时AMS.startProcessLocked()向Zygote进程发送一个消息,为应用创建相应虚拟机.再拼接so文件的全路径加载(DexClassLoader的nativeLib路径;System.load加载全局路径的so文件;System.loadLibrary)之。
Could not find libxxx.so:so文件的释放是系统会先遍历apk中所有so文件的全路径,然后在结合abiList的值来决定最终释放哪个目录中的so文件,若系统是arm64-v8a,而apk中的libs下也有arm64-v8a,就会把apk中的libs\arm64-v8a中的所有so文件释放解压到本地目录中,而不会在去释放armeabi/armeabi-v7a。所以使用so文件的时候,需要确定在每个架构类型目录中都要有相同的so文件(arm架构向下兼容)。
32-bit instead of 64-bit:64位的Zygote进程创建的虚拟机中加载了32位的so文件:一是我们把不同架构类型的so文件放错目录了,比如armeabi/armeabi-v7a的so文件放到了arm64-v8a中了;二是比如宿主工程中有arm64-v8a目录,系统的abiList中也有arm64-v8a类型,所以这时候应用的ApplicationInfo的abi就是arm64-v8a,但是插件中加载so却是armeabi/armeabi-v7a类型的。 类似:64-bit instead of 32-bit:32位的虚拟机中加载了64位的so文件问题导致
Shared library already opened:用不同的DexClassLoader实例多次加载了相同的so文件:用一DexClassLoader加载过so后,进程没被kill时so没有释放还在内存中,一个新的(比如用DexClassLoader类去加载插件,为了插件能够实时更新)DexClassLoader对象再去加载so。解决:如调用System.exit(0)杀进程;单例DexClassLoader。
//updating
HTML apk(编译/打包),dex
DexClassLoader(path、dexOutDir:保存解压出的dex文件、libPath:加载的时候需要用到的lib库,一般不用,一般包括/vendor/lib和/system/lib、parent:给DexClassLoader指定父加载器)可以加载任何路径apk/dex/jar;
PathClassLoader(默认path, libPath, parent:BootClassLoader)加载/data/app, /system/app/中的apk,,是已经安装到手机中的apk,解压释放dex到/data/dalvik-cache,然后在优化成odex
资源文件访问:A生命周期管理:class ProxyA{
AssetManager mAssetManager ; Resources mResources ; private DexClassLoader classLoader;
@override public AssetManager getAssets(){
return mAssetManager ==null? super.getAssets() : mAssetManager;
}
@override public Resources getResources (){
return mResources == null? super.getResources (): mResources ;
}
protected void loadResources(){
try{
AssetManager assetManager = AssetManager.class.newInstance();
Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
addAssetPath.invoke(assetManager, dexpath);
mAssetManager = assetManager;
}catch(Exception e){e.printStackTrace();}
Resources superRes = super.getResources();
superRes.getDisplayMetrics();
superRes.getConfiguration();
mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(),superRes.getConfiguration());
}
}
ClassLoader管理:
热更新:在运行时反射更改PathClassLoader.pathList.dexElements,构造自己的dex文件。所对应的dexElements数组的时候,就是通过构造一个DexClassLoader对象来加载dex文件,并且调用一次dexClassLoader.loadClass(dummyClassName);
dexClassLoader.pathList.dexElements中,就会包含我们的dex,通过把dexClassLoader.pathList.dexElements插入到系统默认的classLoader.pathList.dexElements列表前面,就可以让系统优先加载我们的dex中的类