標籤:
http://www.jianshu.com/p/f751be55d1fb
字數549 閱讀177 評論0 喜歡0
- 需求很簡單 ,就是載入指定檔案夾下的.so。
- 原因:android在程式啟動並執行狀態下 ,無法在 data/data/packageName/lib 下寫檔案,但可讀。
- 還有一個引申的問題:data/app-lib/packageName/ 下的.so 和 data/data/packageName/lib 的.so 是什麼關係?
1 . 擷取全域的classloader
PathClassLoader pathClassLoader = (PathClassLoader)context.getClassLoader();DexClassLoader myDexClassLoader = new DexClassLoader(str, context.getDir("dex", 0).getAbsolutePath(), str, context.getClassLoader().getParent());
2 . 擷取pathList
Object pathList = getPathList(pathClassLoader);
3 . 添加路徑
File[] file = new File[]{new File("/data/app-lib/pakageName-1"),new File("/data/app-lib/pakageName-2"),new File("/data/data/pakageName/files"),new File("/vendor/lib"),new File("/system/lib")} ;
4 . 擷取當前類的屬性
Object nativeLibraryDirectories=pathList.getClass().getDeclaredField("nativeLibraryDirectories");((Field)nativeLibraryDirectories).setAccessible(true);
5 . 設定新的路徑
((Field)nativeLibraryDirectories).set(pathList, file);
6 . 對classloader的操作,對應於BaseDexClassLoader:
public BaseDexClassLoader(String dexPath,File optimizedDirectory,String libraryPath,ClassLoader parent){ super(parent); this.pathList=new DexPathList(this,dexPath,libraryPath,optimizedDirectory);}
7 . dex,library路徑對應於DexPathList, 這部分和熱補丁密切相關,有興趣可以搜下hotfix ,很多開源項目。
privatefinalElement[]dexElements; //這部分就是dex分包的了,熱補丁,熱補丁,熱補丁privatefinalFile[]nativeLibraryDirectories;//這部分就是 libs 載入路徑了,預設有 /vendor/lib system/lib data/app-lib/packageName
最後給下代碼:
public static void initNativeDirectory(Application application) { if (hasDexClassLoader()) { try { createNewNativeDir(application); } catch (Exception e) { e.printStackTrace(); } } } private static void createNewNativeDir(Context context) throws Exception{ PathClassLoader pathClassLoader = (PathClassLoader) context.getClassLoader(); Object pathList = getPathList(pathClassLoader); //擷取當前類的屬性 Object nativeLibraryDirectories = pathList.getClass().getDeclaredField("nativeLibraryDirectories"); ((Field) nativeLibraryDirectories).setAccessible(true); //擷取 DEXPATHList中的屬性值 File[] files1 = (File[])((Field) nativeLibraryDirectories).get(pathList); Object filesss = Array.newInstance(File.class, files1.length + 1); //添加自訂.so路徑 Array.set(filesss, 0, new File(context.getFilesDir().getAbsolutePath())); //將系統自己的追加上 for(int i = 1;i<files1.length+1;i++){ Array.set(filesss,i,files1[i-1]); }// File[] filesss = new File[file.length+ files1.length];// filesss[0] = file[0];// for(int i = 1;i < files1.length+1;i++){// filesss[i] = files1[i];// } ((Field) nativeLibraryDirectories).set(pathList, filesss); } private static Object getPathList(Object obj) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { return getField(obj, Class.forName("dalvik.system.BaseDexClassLoader"), "pathList"); } private static Object getField(Object obj, Class cls, String str) throws NoSuchFieldException, IllegalAccessException { Field declaredField = cls.getDeclaredField(str); declaredField.setAccessible(true); return declaredField.get(obj); } /** * 僅對4.0以上做支援 * @return */ private static boolean hasDexClassLoader() { try { Class.forName("dalvik.system.BaseDexClassLoader"); return true; } catch (ClassNotFoundException var1) { return false; } }
參考連結
BaseDexClassLoader 實現
DexPathList 實現
- Java中System.loadLibrary() 的執行過程
android loadlibrary 更改libPath 路徑,指定路徑載入.so