Android SO文件的兼容和适配

来源:互联网 发布:tensorflow教程 pdf 编辑:程序博客网 时间:2024/06/05 15:10

背景

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

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

已经兼容了 armeabi、armeabi-v7a、armeabi-v7a、x86、x86_64、mips、mips64 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的方法改为自定义的方法
如上,成功减小了应用包大小。如有错误欢迎随时指正和建议。

参考

1.Android SO文件的兼容和适配

2.Android官网ABI指导

3.为何 Twitter 区别于微信、淘宝,只使用了 armeabi-v7a?

原创粉丝点击