1。前言事情是这样的,前几天收到GooglePlay的通知邮件,这才想起GooglePlay上有好几个app不支持64位CPU架构。早在今年1月,谷歌就发布通知称,从今年8月1日起,上架的应用除了32位版本外,还需要提供64位版本。眼看距离强制升级窗口只剩下两个月了,很多so支持第三方库的库,如果不提供64位版本,就需要同步督促合作伙伴更新。那么今天就来说说AndroidAPK升级到64位CPU架构的细节,看看你的应用是否需要支持64位CPU架构,如果需要,需要做什么?谷歌在2015年发布Android5.0时,增加了对64位处理器的支持。当时提出从8月19日开始的更新支持期,并在今年重申了这一强制性要求。只要你的应用有国际版,需要上架GooglePlay,就必须严格遵守这条规则。2.2那些APK需要支持64位?如果你有需要维护的国际化应用,今年8月1日之后,更新GooglePlay时,必须提供64位版本。那么这里所说的64位版本支持到底是什么呢?如果你的应用完全是用Java或Kotlin编写的,并且不包含任何原生(Native)支持,那么就意味着该应用已经支持64位。但是,如果应用程序中使用了任何原生(Native)支持(so库),则需要为这些so文件和不同的CPU架构提供不同版本的so支持。需要注意的是,有时候,在我们自己的代码中,我们并没有使用原生支持,而是包含在App中使用的一些第三方库中。这时候最保险的办法就是对最终打包生成的APK文件进行分析,判断是否需要提供64位架构支持。什么是CPU架构?什么是ABI?在Android中,虽然ARMCPU架构是主流,但目前至少支持几种CPU架构,ARM下的ARMv***RMv7/ARMv8,x86下的x86/x86_64,以及非常少见的MIPS-like架构。这里的每一种CPU类型都对应一个ABI(ApplicationBinaryInterface)。比如armeabi-v7a中的“armeabi”就是指该类型ARM的ABI,后面的“v7a”就是指ARMv7。通常我们可以简单的理解为:这三个概念是相通的,通常在技术讨论中,它们都在谈论一件事情。2.3为什么是强制性的?Google之所以有强制更新的要求,很大程度上是因为作为开发者,更新和完善ABI的动力不够。主要原因来自以下几个方面:1.APK体积增大。为不同的CPU架构提供相应的so库当然是最高效的方式。不过,这种做法最直接的影响是增加了APK文件。有时候完成这些so支持会导致整个APK体积增加几MB到几十MB。APK大小优化,很多公司都把它当成一个KPI指标,增加一个新特性,导致APK大小增加,很多情况下是不允许的,为此更改技术方案也是常有的事。从增长的角度来看,APK越小,用户下载的意愿越强,转化率越高。不过随着流量越来越便宜,iOS近期将蜂窝数据下载限制从150MB放宽至200MB,优化安装包大小的标准也可以适当放宽。2、具有一定的兼容性。在应用市场上,很多APP其实只支持armeabi或者armeabi-v7a,而市面上的设备并不只支持这两种CPU架构。但是这并不影响这些app在这些设备上的运行,这就是CPU架构的兼容性。不同的体系结构并不一定意味着它们不兼容。不同版本下,其实提供了两种ABI支持,即主ABI:和系统本身使用的nativecode一样,最好的方案。AuxiliaryABI:另一种支持的ABI方案,兼容方案。这种兼容策略这里不做讨论。最简单的是64位的arm64-v8a除了自身的CPU架构外,还兼容支持armeabi-v7a和armeabi;x86_64也兼容支持X86和armeabi。你看,虽然加入64位支持可以有效利用硬件的优势,提升性能,但大多数时候,使用兼容的解决方案是更简单的方法。3、之所以没有架构对应的so文件,比较尴尬。我们的App中实际上使用了两种类型的原生代码。一种是自己写的,源码在手,如果想提供相应的支持,可以通过修改配置重新编译来解决。另一个由第三方提供。此时,我们没有源代码,无法重新编译。只能和第三方沟通,看看能不能提供一个CPU架构对应的so库。这种情况是非常不可控的。例如,WebView的常见替代品,腾讯X5内核,本身不提供X86库。官方推荐使用armeabi或者armeabi-v7a。上面说了,ABI本身有一些兼容性规则,但是这样的兼容性规则是有条件的。例如:64位的arm64-v8a是向下兼容的,但是有一个前提,就是如果你的项目中有armeabi-v7a和arm64-v8a这两个目录,你需要保证这两个目录支持的so库文件一致。左边的例子,如果arm64-v8a手机使用b.so,会到arm64-v8a目录下搜索。当然,如果找不到b.so文件,会直接抛出异常,而不是去armeabi-v7a目录继续查找。如果需要提供多套ABI的支持,需要保证所有ABI目录下对应的so文件是一致的。在一些特殊情况下,我们无法提供对应平台的so库,比如腾讯X5内核的情况,就需要做一个trade-off。在没有GooglePlay强制性政策的情况下,出于各方的考虑,我们可能大部分时间会放弃对其他ABI的支持。不过现在强制??执行了,腾讯X5内核可能会升级,提供64位的so库。毕竟一面不能上架,一面是WebView内核。每个人都知道如何选择。3.支持64位架构3.1是否包含64位库?介绍了Android下CPU架构的一些细节,接下来我们就进入正题,如何升级和支持64位架构。从上一篇文章应该可以了解到,支持对应的ABIs体现在项目中,即有ABIs架构对应的目录,目录下有完整的so库支持。Google并不要求我们支持所有的64位架构,但是对于每一个已经支持的原生32位架构,必须包含相应的64位架构。例如:对于ARM架构,如果您有armeabi-v7a(32位),则需要arm64-v8a(64位)。对于x86架构,x86(32位)必须有x86_64(64位),这就需要我们有对应的目录,目录中包含对应的so文件。APK中提供了完整的ABI支持。运行后会选择对应的***支持加载使用。需要注意的是,有时我们将32位的so拷贝到64位,运行不会出现异常,但还是存在隐患。最好的办法就是根据不同的架构编译相应的so文件。原则上,我们的目标是确保应用程序能够在仅支持64位架构的环境中正常运行。3.2判断是否支持64位架构前面提到,我们的项目中可能引入了一些第三方库,导致在不清楚的情况下引入了一些意想不到的ABIs库。通常我们的做法是在Gradle中加入abiFilters过滤,以保证打包输出的APK中不会出现意外的ABIs目录等库。ndk{//设置支持的SO库架构abiFilters'armeabi-v7a'}然后我们分析最终打包输出的APK文件,这是最安全的方式。分析方法有两种:1.ASAPKAnalyzer在AndroidStudio中,从菜单中选择Build→AnalyzeAPK...选择要分析的APK文件,检查其lib目录,是否有预期的ABIs目录及完整性所以文件。2、使用zipinfo命令解析待分析的APK文件,然后使用zipinfo+grep命令输出其中包含的so文件。>zipinfo-1YOUR_APK_FILE.apk|grep\.so$lib/armeabi-v7a/libmain.solib/armeabi-v7a/libmono.solib/armeabi-v7a/libunity.solib/arm64-v8a/libmain.solib/arm64-v8a/libmono.solib/arm64-v8a/libunity.so还是看对应的目录so文件是否完整。3.3在64位设备上测试应用支持64位架构的目的是为了让我们可以利用CPU的特性来提升性能,但是稳定性仍然是我们的首要任务,所以升级之后,我们需要去测试。测试App,最简单的方法是使用adb命令安装应用,可以配合--abi参数使用,指明要在设备上安装哪些so库,这样我们安装的App就可以了设备将只包含我们的自定义库。#成功安装APK:>adbinstall--abiarmeabi-v7aYOUR_APK_FILE.apkSuccess#如果APK不包含64位so文件:>adbinstall--abiarm64-v8aYOUR_APK_FILE.apkadb:failedtoinstallYOUR_APK_FILE.apk:Failure[INSTALL_FAILED_NO_MATCHING_ABIS:13=failedtobraracties#如果你的设备(手机)不支持64位架构>adbinstall--abiarm64-v8aYOUR_APK_FILE.apkABIarm64-v8anosupportedonthisdevice去年推出的手机大部分都是64位架构的,随便找一个测试一下。3.4分包处理如果我们的应用只需要在中国分发,目前的策略不会影响我们,保持原样即可。但是如果有国际版的话,需要上架GooglePlay的一定要注意这个升级。在GooglePlay上上传APK可以根据CPU架构上传不同的APK,也就是我们可以先上传一个32位的APK,再上传一个64位的APK。此时需要使用Gradle的打包技巧,输出几个只包含对应平台的APK,以满足GooglePlay的要求,上传32位支持的APK和64位支持的APK,这样APK文件不能分开。至于增加很多。android{...splits{abi{enabletruereset()include'x86','x86_64','armeabi-v7a','arm64-v8a'//selectABIstobuildAPKsforuniversalApktrue//generateanadditionalAPKthatcontainsalltheABIs}}//mapfortheversioncodeproject.ext.versionCodes=['armeabi':1,'armeabi-v7a':2,'arm64-v8a':3,'mips':5,'mips64':6,'x86':8,'x86_64':9]android.applicationVariants.all{variant->//assigndifferentversioncodeforeachoutputvariant.outputs.each{output->output.versionCodeOverride=project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI),0)*1000000+android.defaultConfig.versionCode}}}这里使用了Gradle的splite配置。有兴趣的可以直接参考文档,就不多说了。4.总结时刻在这篇文章中,我们利用GooglePlay对64位架构的强制支持来解释Android下so库的一些兼容性问题。如果你在GooglePlay上有应用需要更新,别忘了提前准备好需要的so库。大多数原生支持的第三方库之前其实已经提供了对应的64位架构。我们只需要在最终日期前仔细添加so文件即可达到适配效果。更新完成后,别忘了测试。这篇文章在这里。如果您有任何更新的见解,欢迎在留言区讨论。
