Android SO文件的兼容和适配

背景

项目中要用到FFmpeg相关的功能,所以要引用FFmpeg相关的so文件,编译ffmpeg源码库后发现ffmpeg.so文件大小超过10M,

这对于移动端应用是无法接受的,于是各种查资料、各种求助大神,终于压缩到了2.7M 左右(实际上还是很大) 。项目之前的so

已经兼容了 armeabiarmeabi-v7aarmeabi-v7ax86x86_64mipsmips64 7种CPU,所以为了保证兼容性,新加的

FFmpeg.so势必也需要提供7中类型的so包。再次陷入绝望……后来一些网友提到微信等lib下只有一种cpu目录。带着惊讶和好奇打开微信的apk文件,发现lib下竟然真的只有armeabi目录,瞬间感觉有希望了(感谢强大的网友)。


问题及解决方法


上表是google官网提供的ABI 和支持的指令集。不同的 CPU 支持不同的指令集。当我们需要支持尽可能多的不同CPU类型时,只需要将对应的so文件放置在不同的cpu类型目录下,APK安装运行的时候会根据自己需要而自己选取。毫无疑问,为每种cpu类型都提供对应的SO库可以达到更好的兼容适配不同cpu类型的效果。 但是这样却带来一个问题:当我们使用的so文件很大的时候,会导致APK文件较大,影响用户下载。
那我们是否可以只放置一些呢?只放置一些会有什么问题吗?
从目前移动端CPU市场的份额数据看,mips / mips64极少用于手机可以选择忽略, x86 架构(x86 / x86_64:)的手机都会包含由 Intel 提供的称为 Houdini 的指令集动态转码工具,实现对 arm.so 的兼容,再考虑 x86 1% 以下的市场占有率,x86 相关的两so 也可以选择忽略。剩下的ARM架构(armeabi、armeabi-v7a、arm64-v8a)几乎垄断,所以,除非你的用户很特殊,否则几乎可以不考虑单独编译带入X86、X86_64、mips、mips64架构SO文件。7个忽略了4个,已经算是不小的压缩了,这个时候如果apk包已经足够小了,那就OK了。可是我们的应用用到的so文件较大,忽略4个之后依然还很大,这个时候可以参考微信的做法。
1.只保留armeabi目录,将armeabi-v7a下so拷贝到armeabi并重命名。
2.构建方式指定需要类型的SO库,即只有armeabi
3.封装自定义实现loadLibrary方法,通过判断设备的CPU类型来决定使用armeabi-v7a的so还是armeabi的so
    public static final String ARM_V7A = "armeabi-v7a";
    public static final String ARM7_EXTRA_PATH = "_v7";

    /**
     * 根据cpu类型加载so文件,如果是armeabi-v7a类型,加载armeabi-v7a类型的so,其他cpu加载arm类型的cpu
     * @param soName
     */
    public static void loadLibrary(String soName) {
        TestLog.d(TAG, TestLog.isDebug() ? "loadLibrary:soName=" + soName : "");
        if (isABIArm7(getSupportABI())) {
            System.loadLibrary(soName + ARM7_EXTRA_PATH);
        } else {
            System.loadLibrary(soName);
        }
    }

    /**
     * 获取cpu类型
     * @return
     */
    public static String getSupportABI() {
        if (has5_0()) {
            String[] abis = Build.SUPPORTED_ABIS;
            if (abis != null && abis.length > 0) {
                return abis[0];
            }
        }
        return Build.CPU_ABI;
    }

    /**
     * 判断cpu是否是armeabi-v7a
     * @param abi
     * @return
     */
    public static boolean isABIArm7(String abi) {
        TestLog.d(TAG, TestLog.isDebug() ? "isABIArm7:abi=" + abi : "");
        if (abi != null && abi.contains(ARM_V7A)) {
            TestLog.d(TAG, TestLog.isDebug() ? "isABIArm7=true" : "");
            return true;
        }
        TestLog.d(TAG, TestLog.isDebug() ? "isABIArm7=false" : "");
        return false;
    }

4. 将程序中调用 System. loadLibrary的方法改为自定义的方法
如上,成功减小了应用包大小。如有错误欢迎随时指正和建议。

参考

猜你喜欢

转载自blog.csdn.net/tugele/article/details/78712813
今日推荐