重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
如何为安卓应用提供64位原生的支持?
创新互联2013年开创至今,先为大庆等服务建站,大庆等地企业,进行企业商务咨询服务。为大庆企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。
必须承认,64位构建会让APK的体积变的更大,多了so库嘛
64位通常会使应用运行的更加的快,因为64位的指令集支持更高的代码运行效率,举个例子:能够使用两倍数量的寄存器,支持双精度的浮点的运算,这使得编译器可以做更加复杂的矢量化优化
使用App Bundle发布格式在GooglePlay,Apk包的体积也不会受到太大影响,GooglePlay会按照用户设备的架构仅推送所需的文件,即使提供了32位和64位的文件,根据用户设备的架构类型,只需下载最使用的一套文件
在GooglePaly上可以构架一个包含X86和X86-64的文件Bundle,而不用担心对目标ARM设备应用体积的影响
从 2019 年 8 月 1 日开始,您在 Google Play 上发布的应用必须支持 64 位架构。后续不知道国内的应用市场是否也要强制
64 位 CPU 能够为您的用户提供更快、更丰富的体验。添加 64 位的应用版本不仅可以提升性能、为未来创新创造条件,还能针对仅支持 64 位架构的设备做好准备。
1、使用以 Java 编程语言或 Kotlin 编写的代码(包括任何库或 SDK),那么就表示该应用已经支持 64 位设备
2、应用使用了任何原生代码,或者不确定自己的应用是否使用了这类代码,那么需要评估应用并相应采取措施。
是否使用了原生代码?
使用了任何 C/C++(原生)代码。
与任何第三方原生库关联。
通过使用原生库的第三方应用构建程序构建而成。
应用是否包含 64 位库?
要确定应用是否包含 64 位库,最简单的方法就是检查 APK 文件的结构,在编译时,APK 会与应用所需的所有原生库打包在一起。应用无需支持所有 64 位架构,但对于支持的每种原生 32 位架构,则应用都必须包含相应的 64 位架构。,说通俗一点就是成对的出现应当支持的架构
对于 ARM 架构,32 位库位于 armeabi-v7a 中。对应的 64 位库位于 arm64-v8a 中
对于 x86 架构, x86(32 位)和 x86_64(64 位)
分析APK,只有32的架构
image.png
分析APK,32位和64位的架构
image.png
如果使用 Android Studio 或Gradle 进行编译,如何为安卓应用提供64位原生的支持呢?
大多数 Android Studio 项目都使用 Gradle 作为底层编译系统,因此本部分适用于使用这两种工具进行编译的情况。针对原生代码进行编译很简单,只需将 arm64-v8a和/或 x86_64(取决于您要支持的架构)添加到应用的“build.gradle”文件中的 ndk.abiFilters 设置
在 build.gradle 加入ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
image.png
如果使用 CMake 进行编译?
可以通过将 arm64-v8a 传递到“-DANDROID_ABI”参数来编译 64 位 ABI
:: Command Line
cmake -DANDROID_ABI=arm64-v8a … or
cmake -DANDROID_ABI=x86_64 …
使用 ndk-build 进行编译?JNI
可以通过 APP_ABI 变量修改“app.mk”文件,从而编译 64 位 ABI:
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
打包需要使用cmake是AndroidSdk目录下的
${ANDROID_HOME}/cmake/3.6.4111459/bin/cmake
参数:
-H
-B
-DANDROID_NDK
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY
-DCMAKE_MAKE_PROGRAM
-DCMAKE_TOOLCHAIN_FILE
-DANDROID_ABI
-DCMAKE_BUILD_TYPE
-DANDROID_NATIVE_API_LEVEL 最低支持的Api版本
-DANDROID_TOOLCHAIN
-DCMAKE_GENERATOR
打包所有abi的脚本例子:
其实android ndk上的编译说到底也就是交叉编译,只要配置好交叉编译工具链,使用原有的makefile也是可以编译出在android运行的c、c++程序的。以android-ndk-r4-crystax的ndk版本为例:编译器路径 android-ndk-r4-crystax/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin名称前缀 arm-eabi-头文件目录 android-ndk-r4-crystax/build/platforms/android-3/arch-arm/usr/include库文件目录 android-ndk-r4-crystax/build/platforms/android-3/arch-arm/usr/lib你可以试一下上面的配置,如果编译链接都没有问题,可以adb push到android设备上运行看看,什么结果?有点崩溃,根本运行不起来,你也许想试试看android自带的ndk例子,确实是能够运行的,问题在哪儿呢?只是正确配置了编译器、头文件、库文件还不够,还需要配置编译、链接的参数,android例子中编译链接的参数是什么呢?你也许想深究一下android的makefile,可是不久你会发现那是更崩溃的事情,里面用了很多的make脚本函数。其实android的makefile是可以把执行的详细命令输出来的,只要make的时候加上V=1即可。可以看到确实带了很多参数编译参数:-fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -Wa,--noexecstack -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID 链接参数:-nostdlib -Bdynamic -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,--no-undefined -Wl,-z,noexecstack -L$(PLATFORM_LIBRARY_DIRECTORYS) crtbegin_static.o crtend_android.o 这其中链接参数中的-Wl,-dynamic-linker,/system/bin/linker、crtbegin_static.o、crtend_android.o是最关键的,android使用了自己的进程加载器,并且自定义了c运行时的启动结束。难怪先前编译的进程启动不了。