ABI 拆分在 NativeScript 2.3.0 中失败
ABI Split failed in NativeScript 2.3.0
我已经在普通组中寻求帮助,但大多数人也没有得到帮助。
我的简单应用程序有一个荒谬的 apk 大小的大问题。我使用@markosko nativescript 过滤器将应用程序从 17.2MB 减少到 14MB,即使 nativescript-snapshot
也无法帮助发布版本仍然是 17MB。
我尝试使用 nativescipt 文档中的 ABI 拆分示例,但我注意到它正在尝试拆分,但 glade 对所有 apk 使用相同的名称,所以我在 app.glade 中想到了这个
def tnsBuildMultipleApks=true;
android {
defaultConfig {
generatedDensities = []
applicationId = "com.maliyo.oneclick"
versionCode Integer.parseInt("" + "1" + "0")
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
if (Boolean.valueOf(tnsBuildMultipleApks)) {
splits {
abi {
enable true
reset()
include 'armeabi', 'armeabi-v7a', 'x86', 'mips'
universalApk true
}
}
}
}
def getDate() {
def date = new Date()
def formattedDate = date.format('yyyyMMdd')
return formattedDate
}
// map for the version code that gives each ABI a value
ext.versionCodes = [
'F0F1F2X86Debug':1, 'F0F1F2ArmeabiDebug':2, 'F0F1F2Armeabi-v7aDebug':3, 'F0F1F2MipsDebug':4,
'F0F1F2X86Release':1, 'F0F1F2ArmeabiRelease':2, 'F0F1F2Armeabi-v7aRelease':3, 'F0F1F2MipsRelease':4
]
// For each APK output variant, override versionCode with a combination of
// ABI APK value * 100 + defaultConfig.versionCode
android.applicationVariants.all { variant ->
// assign different version code for each output
variant.outputs.each { output ->
if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) {
println("******************************************************")
println(output);
println(output.getVariantOutputData().getFullName())
if (Boolean.valueOf(tnsBuildMultipleApks)) {
def file = output.outputFile
// version at the end of each built apk
//output.outputFile = new File(file.parent, file.name.replace(".apk", "-" + android.defaultConfig.versionName + "-" + getDate() + ".apk"))
output.outputFile = new File(file.parent, file.name.replace(".apk", "-" + output.getVariantOutputData().getFullName() + "-" + getDate() + ".apk"))
output.versionCodeOverride =
//(assd++) * 100
project.ext.versionCodes.get(output.getVariantOutputData().getFullName(), 0) * 100
+ android.defaultConfig.versionCode
}
}
}
}
/**/
好吧,它拆分了,但我认为因为我在输出中破解了文件名,adb 由于命名模式找不到将 apk 推送到设备或模拟器的方法,也许,只是说 apk not found
.
我尝试通过 USB 手动将适当的 apk 发送到设备,它的应用程序已成功安装,但在闪屏显示 metadata/treeNodeStream.dat could not be loaded
后崩溃
更新
@plamen-petkov 非常感谢您的贡献,我同意您的看法,当您一个接一个地构建并更改 abi 过滤器时,它工作正常。但是在我的 app.gradle 中,我成功地构建了多个 apk 并进行了测试,一切正常。
但就像 tns 仅将 appname-debug.apk
或 appname-release.apk
推送到 adb。我可以用 tnsBuildMultipleApks
关闭这个拆分,也许当我还在测试时,我可以关闭它并使用 tns run android
,当我想进行最终构建时,它会再次打开它,因为它与 tns build android --release ....
// Add your native dependencies here:
// Uncomment to add recyclerview-v7 dependency
//dependencies {
// compile 'com.android.support:recyclerview-v7:+'
//}
import groovy.json.JsonSlurper //used to parse package.json
def tnsBuildMultipleApks=true;
String content = new File("$projectDir/../../app/package.json").getText("UTF-8")
def jsonSlurper = new JsonSlurper()
def appPackageJson = jsonSlurper.parseText(content)
android {
defaultConfig {
generatedDensities = []
applicationId = appPackageJson.nativescript.id
versionCode = appPackageJson.version_code ?: 1
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
if (Boolean.valueOf(tnsBuildMultipleApks)) {
splits {
abi {
enable true
reset()
include 'x86', 'armeabi-v7a', 'arm64-v8a'
universalApk true
}
}
}
}
// map for the version code that gives each ABI a value
ext.versionCodes = [
'x86':1, 'armeabi-v7a':2, 'arm64-v8a':3
]
// For each APK output variant, override versionCode with a combination of
// ABI APK value * 100 + android.defaultConfig.versionCode
// getAbiFilter() not working for me so I extracted it from getFullname()
if (Boolean.valueOf(tnsBuildMultipleApks)) {
android.applicationVariants.all { variant ->
println(appPackageJson)
println(android.defaultConfig.versionCode)
println(android.defaultConfig.applicationId)
def name
def flavorNamesConcat = ""
variant.productFlavors.each() { flavor ->
flavorNamesConcat += flavor.name
}
flavorNamesConcat = flavorNamesConcat.toLowerCase()
println(flavorNamesConcat)
variant.outputs.each { output ->
if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) {
//You may look for this path in your console to see what the values are
println("******************************************************")
println(output); println(output.getVariantOutputData().getFullName())
def abiName = output.getVariantOutputData().getFullName().toLowerCase().replace(flavorNamesConcat, "").replace(project.ext.selectedBuildType, "")
println(abiName)
def file = output.outputFile
output.versionCodeOverride =
project.ext.versionCodes.get(abiName, 0) * 100
+ android.defaultConfig.versionCode
def apkDirectory = output.packageApplication.outputFile.parentFile
def apkNamePrefix = output.outputFile.name.replace(".apk", "-" + abiName)
if (output.zipAlign) {
name = apkNamePrefix + ".apk"
output.outputFile = new File(apkDirectory, name);
}
name = apkNamePrefix + "-unaligned.apk"
output.packageApplication.outputFile = new File(apkDirectory, name);
}
}
}
}
如果您一次使用 ABI 拆分,它们会很有用。这是一个例子:
android {
...
splits {
abi {
enable true
reset()
include 'armeabi-v7a'
}
}
...
}
生成的 .apk 文件将只包含 armeabi-v7a 设备所需的库,因为它是上面 ABI 拆分配置中提到的唯一架构。正如 documentation 中指出的那样,可用的 ABI 是 'arm64-v8a'、'armeabi-v7a'、'x86',因此您不能使用 'armeabi' 或 'mips' 架构.
此外,您不需要这一行:'universalApk true',因为它所做的是忽略拆分并制作一个包含所有提供的体系结构的 .apk 文件,而您想要的恰恰相反。
您还可以关注 this 问题的进展,因为它会进一步减小 .apk 的大小。
希望对您有所帮助!
这对我来说效果很好,生成 apks 和 tns run android
现在运行良好,谢谢。
// Add your native dependencies here:
// Uncomment to add recyclerview-v7 dependency
//dependencies {
// compile 'com.android.support:recyclerview-v7:+'
//}
import groovy.json.JsonSlurper //used to parse package.json
def tnsBuildMultipleApks=true;
String content = new File("$projectDir/../../app/package.json").getText("UTF-8")
def jsonSlurper = new JsonSlurper()
def appPackageJson = jsonSlurper.parseText(content)
android {
defaultConfig {
generatedDensities = []
applicationId = appPackageJson.nativescript.id
versionCode = appPackageJson.version_code ?: 1
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
if (Boolean.valueOf(tnsBuildMultipleApks)) {
splits {
abi {
enable true
reset()
include 'x86', 'armeabi-v7a', 'arm64-v8a'
universalApk true
}
}
}
}
// map for the version code that gives each ABI a value
ext.versionCodes = [
'x86':1, 'armeabi-v7a':2, 'arm64-v8a':3
]
// For each APK output variant, override versionCode with a combination of
// ABI APK value * 100 + android.defaultConfig.versionCode
// getAbiFilter() not working for me so I extracted it from getFullname()
if (Boolean.valueOf(tnsBuildMultipleApks)) {
android.applicationVariants.all { variant ->
println(appPackageJson)
println(android.defaultConfig.versionCode)
println(android.defaultConfig.applicationId)
def name
def flavorNamesConcat = ""
variant.productFlavors.each() { flavor ->
flavorNamesConcat += flavor.name
}
flavorNamesConcat = flavorNamesConcat.toLowerCase()
println(flavorNamesConcat)
variant.outputs.each { output ->
if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) {
//You may look for this path in your console to see what the values are
println("******************************************************")
println(output); println(output.getVariantOutputData().getFullName())
def abiName = output.getVariantOutputData().getFullName().toLowerCase().replace(flavorNamesConcat, "").replace(project.ext.selectedBuildType, "")
println(abiName)
def file = output.outputFile
def versionCode = project.ext.versionCodes.get(abiName, 0);
output.versionCodeOverride =
project.ext.versionCodes.get(abiName, 0) * 100
+ android.defaultConfig.versionCode
def apkDirectory = output.packageApplication.outputFile.parentFile
println(output.outputFile.name)
def apkNamePrefix = ""
if(versionCode){
apkNamePrefix = output.outputFile.name.replace(".apk", "-" + abiName)
}
else {
apkNamePrefix = output.outputFile.name.replace(".apk", "")
}
if (output.zipAlign) {
name = apkNamePrefix + ".apk"
output.outputFile = new File(apkDirectory, name);
}
name = apkNamePrefix + "-unaligned.apk"
output.packageApplication.outputFile = new File(apkDirectory, name);
}
}
}
}
我已经在普通组中寻求帮助,但大多数人也没有得到帮助。
我的简单应用程序有一个荒谬的 apk 大小的大问题。我使用@markosko nativescript 过滤器将应用程序从 17.2MB 减少到 14MB,即使 nativescript-snapshot
也无法帮助发布版本仍然是 17MB。
我尝试使用 nativescipt 文档中的 ABI 拆分示例,但我注意到它正在尝试拆分,但 glade 对所有 apk 使用相同的名称,所以我在 app.glade 中想到了这个
def tnsBuildMultipleApks=true;
android {
defaultConfig {
generatedDensities = []
applicationId = "com.maliyo.oneclick"
versionCode Integer.parseInt("" + "1" + "0")
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
if (Boolean.valueOf(tnsBuildMultipleApks)) {
splits {
abi {
enable true
reset()
include 'armeabi', 'armeabi-v7a', 'x86', 'mips'
universalApk true
}
}
}
}
def getDate() {
def date = new Date()
def formattedDate = date.format('yyyyMMdd')
return formattedDate
}
// map for the version code that gives each ABI a value
ext.versionCodes = [
'F0F1F2X86Debug':1, 'F0F1F2ArmeabiDebug':2, 'F0F1F2Armeabi-v7aDebug':3, 'F0F1F2MipsDebug':4,
'F0F1F2X86Release':1, 'F0F1F2ArmeabiRelease':2, 'F0F1F2Armeabi-v7aRelease':3, 'F0F1F2MipsRelease':4
]
// For each APK output variant, override versionCode with a combination of
// ABI APK value * 100 + defaultConfig.versionCode
android.applicationVariants.all { variant ->
// assign different version code for each output
variant.outputs.each { output ->
if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) {
println("******************************************************")
println(output);
println(output.getVariantOutputData().getFullName())
if (Boolean.valueOf(tnsBuildMultipleApks)) {
def file = output.outputFile
// version at the end of each built apk
//output.outputFile = new File(file.parent, file.name.replace(".apk", "-" + android.defaultConfig.versionName + "-" + getDate() + ".apk"))
output.outputFile = new File(file.parent, file.name.replace(".apk", "-" + output.getVariantOutputData().getFullName() + "-" + getDate() + ".apk"))
output.versionCodeOverride =
//(assd++) * 100
project.ext.versionCodes.get(output.getVariantOutputData().getFullName(), 0) * 100
+ android.defaultConfig.versionCode
}
}
}
}
/**/
好吧,它拆分了,但我认为因为我在输出中破解了文件名,adb 由于命名模式找不到将 apk 推送到设备或模拟器的方法,也许,只是说 apk not found
.
我尝试通过 USB 手动将适当的 apk 发送到设备,它的应用程序已成功安装,但在闪屏显示 metadata/treeNodeStream.dat could not be loaded
更新
@plamen-petkov 非常感谢您的贡献,我同意您的看法,当您一个接一个地构建并更改 abi 过滤器时,它工作正常。但是在我的 app.gradle 中,我成功地构建了多个 apk 并进行了测试,一切正常。
但就像 tns 仅将 appname-debug.apk
或 appname-release.apk
推送到 adb。我可以用 tnsBuildMultipleApks
关闭这个拆分,也许当我还在测试时,我可以关闭它并使用 tns run android
,当我想进行最终构建时,它会再次打开它,因为它与 tns build android --release ....
// Add your native dependencies here:
// Uncomment to add recyclerview-v7 dependency
//dependencies {
// compile 'com.android.support:recyclerview-v7:+'
//}
import groovy.json.JsonSlurper //used to parse package.json
def tnsBuildMultipleApks=true;
String content = new File("$projectDir/../../app/package.json").getText("UTF-8")
def jsonSlurper = new JsonSlurper()
def appPackageJson = jsonSlurper.parseText(content)
android {
defaultConfig {
generatedDensities = []
applicationId = appPackageJson.nativescript.id
versionCode = appPackageJson.version_code ?: 1
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
if (Boolean.valueOf(tnsBuildMultipleApks)) {
splits {
abi {
enable true
reset()
include 'x86', 'armeabi-v7a', 'arm64-v8a'
universalApk true
}
}
}
}
// map for the version code that gives each ABI a value
ext.versionCodes = [
'x86':1, 'armeabi-v7a':2, 'arm64-v8a':3
]
// For each APK output variant, override versionCode with a combination of
// ABI APK value * 100 + android.defaultConfig.versionCode
// getAbiFilter() not working for me so I extracted it from getFullname()
if (Boolean.valueOf(tnsBuildMultipleApks)) {
android.applicationVariants.all { variant ->
println(appPackageJson)
println(android.defaultConfig.versionCode)
println(android.defaultConfig.applicationId)
def name
def flavorNamesConcat = ""
variant.productFlavors.each() { flavor ->
flavorNamesConcat += flavor.name
}
flavorNamesConcat = flavorNamesConcat.toLowerCase()
println(flavorNamesConcat)
variant.outputs.each { output ->
if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) {
//You may look for this path in your console to see what the values are
println("******************************************************")
println(output); println(output.getVariantOutputData().getFullName())
def abiName = output.getVariantOutputData().getFullName().toLowerCase().replace(flavorNamesConcat, "").replace(project.ext.selectedBuildType, "")
println(abiName)
def file = output.outputFile
output.versionCodeOverride =
project.ext.versionCodes.get(abiName, 0) * 100
+ android.defaultConfig.versionCode
def apkDirectory = output.packageApplication.outputFile.parentFile
def apkNamePrefix = output.outputFile.name.replace(".apk", "-" + abiName)
if (output.zipAlign) {
name = apkNamePrefix + ".apk"
output.outputFile = new File(apkDirectory, name);
}
name = apkNamePrefix + "-unaligned.apk"
output.packageApplication.outputFile = new File(apkDirectory, name);
}
}
}
}
如果您一次使用 ABI 拆分,它们会很有用。这是一个例子:
android {
...
splits {
abi {
enable true
reset()
include 'armeabi-v7a'
}
}
...
}
生成的 .apk 文件将只包含 armeabi-v7a 设备所需的库,因为它是上面 ABI 拆分配置中提到的唯一架构。正如 documentation 中指出的那样,可用的 ABI 是 'arm64-v8a'、'armeabi-v7a'、'x86',因此您不能使用 'armeabi' 或 'mips' 架构.
此外,您不需要这一行:'universalApk true',因为它所做的是忽略拆分并制作一个包含所有提供的体系结构的 .apk 文件,而您想要的恰恰相反。
您还可以关注 this 问题的进展,因为它会进一步减小 .apk 的大小。
希望对您有所帮助!
这对我来说效果很好,生成 apks 和 tns run android
现在运行良好,谢谢。
// Add your native dependencies here:
// Uncomment to add recyclerview-v7 dependency
//dependencies {
// compile 'com.android.support:recyclerview-v7:+'
//}
import groovy.json.JsonSlurper //used to parse package.json
def tnsBuildMultipleApks=true;
String content = new File("$projectDir/../../app/package.json").getText("UTF-8")
def jsonSlurper = new JsonSlurper()
def appPackageJson = jsonSlurper.parseText(content)
android {
defaultConfig {
generatedDensities = []
applicationId = appPackageJson.nativescript.id
versionCode = appPackageJson.version_code ?: 1
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
if (Boolean.valueOf(tnsBuildMultipleApks)) {
splits {
abi {
enable true
reset()
include 'x86', 'armeabi-v7a', 'arm64-v8a'
universalApk true
}
}
}
}
// map for the version code that gives each ABI a value
ext.versionCodes = [
'x86':1, 'armeabi-v7a':2, 'arm64-v8a':3
]
// For each APK output variant, override versionCode with a combination of
// ABI APK value * 100 + android.defaultConfig.versionCode
// getAbiFilter() not working for me so I extracted it from getFullname()
if (Boolean.valueOf(tnsBuildMultipleApks)) {
android.applicationVariants.all { variant ->
println(appPackageJson)
println(android.defaultConfig.versionCode)
println(android.defaultConfig.applicationId)
def name
def flavorNamesConcat = ""
variant.productFlavors.each() { flavor ->
flavorNamesConcat += flavor.name
}
flavorNamesConcat = flavorNamesConcat.toLowerCase()
println(flavorNamesConcat)
variant.outputs.each { output ->
if (output.outputFile != null && output.outputFile.name.endsWith('.apk')) {
//You may look for this path in your console to see what the values are
println("******************************************************")
println(output); println(output.getVariantOutputData().getFullName())
def abiName = output.getVariantOutputData().getFullName().toLowerCase().replace(flavorNamesConcat, "").replace(project.ext.selectedBuildType, "")
println(abiName)
def file = output.outputFile
def versionCode = project.ext.versionCodes.get(abiName, 0);
output.versionCodeOverride =
project.ext.versionCodes.get(abiName, 0) * 100
+ android.defaultConfig.versionCode
def apkDirectory = output.packageApplication.outputFile.parentFile
println(output.outputFile.name)
def apkNamePrefix = ""
if(versionCode){
apkNamePrefix = output.outputFile.name.replace(".apk", "-" + abiName)
}
else {
apkNamePrefix = output.outputFile.name.replace(".apk", "")
}
if (output.zipAlign) {
name = apkNamePrefix + ".apk"
output.outputFile = new File(apkDirectory, name);
}
name = apkNamePrefix + "-unaligned.apk"
output.packageApplication.outputFile = new File(apkDirectory, name);
}
}
}
}