背景
第一次開發(fā)Native項目觉增,需要在AndroidStudio(簡稱AS)上配置好NDK暴浦。
環(huán)境配置:AGP版本=3.4.2桩引,compileSdkVersion=28旋膳,targetVersion=26贩猎,NDK版本=22.0.7026061熊户,cmake.abiFilters="armeabi-v7a", "arm64-v8a"。
問題
- 在下載并配置好NDK后(下載:AS的SDK Tools)吭服,sync報錯NullPointerException嚷堡,但它其實是“NDK is missing a "platforms" directory.”引發(fā)的,只是這一句日志被標記為警告噪馏。
- 基于問題一麦到,在網(wǎng)上找了個解決方式(我信了它的邪??),在ndk目錄下新建一個“platforms”的文件夾就可以sync過了欠肾。但是接下來又編譯報錯“Error:ABIs [arm64-v8a] are not supported for platform. Supported ABIs are [armeabi-v7a, x86]”瓶颠。
解決過程
問題二的難點在于造成類似“ABIs [arm64-v8a] are not supported for platform”的原因有好幾種,我歸納總結為:
- NDK升級到17之后刺桃,不再支持armeabi架構粹淋。因此NDK升級是有可能造成類似 “ABIs [xxx] are not supported for platform”的錯誤;
- compileSdkVersion設置為19瑟慈,也會導致這個問題桃移,因為版本號為19的系統(tǒng)只能是32位的;
- 對自己和對NDK的不信任:對自己不信任是因為對編譯的東西還不夠熟悉葛碧,總覺得自己哪里配置出錯了借杰;對NDK不信任是覺得從官網(wǎng)下載的NDK為什么會出現(xiàn)“問題一”呢?是不是NDK下載錯了进泼,或者xxxxx的原因蔗衡。
解決方式
根據(jù)問題二報出的堆棧信息,進行斷點調(diào)試:
adb命令:./gradlew :[module]:installDebug -Dorg.gradle.debug=true --no-daemon 乳绕。(AGP7以上需要自己處理下Java11兼容問題)
關鍵斷點行:NdkHandler -> supports64Bits() (找不到這個類的同學在app的build.gradle下implementation一下AGP绞惦,例如 "com.android.tools.build:gradle:3.4.2")。
問題原因:編譯時Gradle會判斷這次編譯實際支持的abi洋措,當在build.gradle下配置的abi不屬于實際支持的abi時济蝉,就會報錯“ABIs [arm64-v8a] are not supported for platform...”。
實際支持的abi的判斷方式為:
判斷前提:gradle認為highestVersion>=20時,abi能夠支持到64位王滤,反之只能支持32位
//root 即配置NDK路徑
File platformDir = new File(root, "/platforms");
File[] platformSubDirs = platformDir.listFiles(File::isDirectory);
int highestVersion = 0;
assert platformSubDirs != null;
for (File platform : platformSubDirs) {
if (platform.getName().startsWith("android-")) {
try {
int version = Integer.parseInt(
platform.getName().substring("android-".length()));
//targetVersion即在build.gradle下配置的目標版本 此次為26
if (version > highestVersion && version < targetVersion) {
highestVersion = version;
}
} catch (NumberFormatException ignore) {
// Ignore unrecognized directories.
}
}
}
return highestVersion;
根據(jù)上面的代碼舉個例子:
targetVersion=26, “platforms”目錄下有三個文件夾“android-19”贺嫂、“android-25”、“android-31”時淑仆,經(jīng)過上面的程序后涝婉,會輸出highestVersion=25哥力。而根據(jù)前提蔗怠,25>=20,就認為arm64可用吩跋。
解決方式:在NDK目錄下新建了“platforms”文件夾寞射,并在“platforms”文件夾下新建了“android-19”、"android-21"锌钮、"android-31"三個文件夾桥温。
補充
應該有同學會疑問新建空文件夾會不會導致其它的問題產(chǎn)生?實際上并不會梁丘∏纸“/platforms/android-N”這個路徑實際上在SDK的目錄下就有,它的含義為第N個版本的android sdk文件氛谜。我猜想在這里Gradle只是想知道當前允許編譯哪幾個版本的apk掏觉,而哪個版本的sdk文件夾存在就認為能夠編譯對應版本的apk。如果只能編譯版本號20以下的apk值漫,那么就可以認為當前并不支持arm64澳腹。而判斷方式則是根據(jù)一個固定路徑下的文件名稱去判斷(無語...)。
為了進一步驗證上面的猜想杨何,我新建了一個基于AGP7.0的Cpp項目酱塔。這次不用新建“/platforms"文件夾也能編譯過去了,因為在AGP7.0上supports64Bits的判斷條件為 compileSdkVersion >= AndroidVersion.SUPPORTS_64_BIT (build.gradle下配置的compileSdkVersion)危虱。顯然Google也認為在AGP3.4.2上的supports64Bits判斷方式并不穩(wěn)妥羊娃。