正常情况下我们都是通过System.loadLibrary()的方式来加载位于libs下的so。最近做的一个项目由于对于aar体积有严格的大小要求,所以将so做成了动态加载的策略
获取手机cpu架构的命令
adb shell getprop ro.product.cpu.abi
1.加载远程so
我们需要将so下载到本地进行加载,通过System.load()方法将本地so路径作为参数传入!
2. 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
@SuppressLint("UnsafeDynamicallyLoadedCode") public static void loadSoFile(Context context, String originFilePath) { File dir = context.getDir("libs", Context.MODE_PRIVATE); File file = new File(originFilePath); String toFilePath = dir.getAbsolutePath() + File.separator + file.getName(); copySdcardFile(originFilePath, toFilePath); System.load(toFilePath); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public static int copySdcardFile(String fromFile, String toFile) { try { FileInputStream fosfrom = new FileInputStream(fromFile); FileOutputStream fosto = new FileOutputStream(toFile); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while ((len = fosfrom.read(buffer)) != -1) { baos.write(buffer, 0, len); } fosto.write(baos.toByteArray()); baos.close(); fosto.close(); fosfrom.close(); return 0; } catch (Exception ex) { return -1; } }
|
一定要将so拷贝到app内部目录,否则无权限执行so
3. 平台适配问题
由于android平台存在多种类型的cpu架构,所以需要我们根据不同的cpu加载对应的so库,比如 x86,armabi等
代码获取当前设备的cpu
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public static String getFirstSupportedAbi() { String abi1 = ""; if (Build.VERSION.SDK_INT >= 21) { String[] abis = Build.SUPPORTED_ABIS; if (abis != null && abis.length > 0) { String abistr = ""; abi1 = abis[0]; for (String abi : abis) { abistr = abistr + abi + ","; } JdGame.print(abistr); } } else { if (!TextUtils.isEmpty(Build.CPU_ABI)) { abi1 = Build.CPU_ABI; } else if (!TextUtils.isEmpty(Build.CPU_ABI2)) { abi1 = Build.CPU_ABI2; } } return abi1; }
|
然后根据获取的 cpu值,去下载对应的 so 再进行加载