Users of NativeScript face conflicting goals when using architecture-dependant native code (*.so files).
During development they want to build their program very quickly to iterate very fast. They usually develop for x86 emulator (like Genymotion or Visual Studio) and arm-based testing devices.
When publishing to Google Play Store, they may need to split the archive to avoid the 100 MB file size limit currently imposed.
Additional obstacle is that 64-bit Android does not allow mixing 64-bit and 32-bit architecture-dependent native code. When a single dependency introduces a 64-bit .so file, all dependencies must be 64-bit as well. This can easily slip during development, when people usually use 32-bit devices and emulators.
We need to solve these problems in couple of places: The CLI, the Docs and the Gradle scripts
I propose this behavior:
publish command. It is also mandatory for build --release (but see bellow for comments). When building _without_ --release, it is not mandatory. [CLI]Apple has different requirements for publishing to App Store. I believe that build and publish commands can differ in this case. iOS specific functionality should be addressed in a dedicated issue.
Comments:
--arch mandatory for building in release mode, AppBuilder team will need to revise the BpcTooling to introduce it. Also, this may not be the optimal behavior for the user.Awesome, thanks for putting this into its own subject.
One item that you do need to make sure that is correct is the versioncode. See: https://androidbycode.wordpress.com/2015/06/30/android-ndk-version-code-scheme-for-publishing-apks-per-architecture/ covers the requirements on the versioncode much better than the official docs: http://developer.android.com/google/play/publishing/multiple-apks.html Basically each apk platform needs a apk prefix. Xyyy where X is the platform code; and yyy is my code.
Example:
If I set my version code to 105, then build a Arm-v8 then the version code ends up being:
In the fourth case:
"If a pluging is missing requested architecture, stop the build. This does not apply when only jars or aars are used [Android runtime]"
.aar files can contain .so files so we should take care of that too.
@Plamen5kov - updated the text, thank you!
:+1:
@teobugslayer some notes
The apk limit is 100MB currently.
We need to think support for all scenarios in http://developer.android.com/google/play/publishing/multiple-apks.html
Also if there is no 64bit libs in my app why the option is mandatory. A 32bit app will run fine on 64 bit devices.
I think we should package a single apk by default (and as per the guidance) and introduce complexity only when user wants it. And If he wants it allow all possible options. The tns build tools should not constrain the developer.
@blagoev, when we switch to using combined 32 and 64 bit {N} runtime, there always will be 64 bit code in the APK. We can either make the option mandatory (again, only for the "publish" command"), or default to something which we consider "safe", like, 32-bit only build, all build, or something else. Opinions?
@teobugslayer for the publish command only it is ok to have this to be mandatory. If there are no other 64bit libs in the project we can build against a 32bit only runtime. We just need to make sure the build fails if there is one plugin which does not have a 64bit library on 64 builds.
Please note the 64 bit version of the library seems to be coming along for the ride anyway; so now the APK files are 10 megs JUST for the runtimes. Can this be moved up in priority. This does make NS look horrible compared to other solutions. And the issue is WAY more import than silly things like than #1420 which has a critical rating .
:+1:
Hello. I was wondering if there is still no way to make tns build for a specific android architecture?
In an app we're currently working on we want to use libVLC through a plugin. But it really slows down our development process that we arent able to build for one architecture at a time.
If anyone knows of a manual fix to the build.gradle file it would be very much appreciated. Maybe something like abiFilters?
Hey @Plamen5kov,
Do you know such manual fix?
@enchev
I used to be able to do this in my plugin include.gradle file:
android {
productFlavors {
'nativescript-plugin-name' {
dimension 'nativescript-plugin-name'
// Setting below requires 'android.useDeprecatedNdk=true'
// in platforms/android/gradle.properties file.
ndk {
abiFilters 'armeabi-v7a'
}
...
But it doesn't seem like it's possible anymore in the latest version of Nativescript CLI.
Hi @dfg-nota
I don't believe the new version of cli can change the way include.gradle works. What you're doing should be working. Let me check it out and i'll get back to you.
Could you give me the version of CLI you're using?
@Plamen5kov I just checked my platforms/android/configurations folder after a build and it seems my plugin include.gradle file from above is turned into this:
android {
productFlavors {
"F0" {
dimension "nativescriptpluginname"
}
}
}
dependencies {
compile 'de.mrmaffen:vlc-android-sdk:1.9.8'
}
ndk abiFilters was removed. It seems the replaceProductFlavorInContent function in build.gradle strips it out.
Hi @dfg-nota,
I tested it out and you're right, you can open an issue in the android-runtime.
I am facing the same issue. Is there any work around available?
@Plamen5kov Any chance this will get in 3.0? It's a pain having to double my build time and run commands twice, compiling arm and x86 separately, especially at scale
Hi @vbresults you can use this PR, where abi split configuration is respected and once tns build android is ran there are two resulting apk files:
testapp-debug-x86.apk
testapp-debug-armeabi-v7a.apk
I can't tell if there will be functionality enabled in cli to help with the workflow for 3.0, but you would be able to edit the app.gradle file and it's changes will be respected.
Starting with android runtime v3.0.0 when abi split configuration is provided in the app/App_Resources/Android/app.gradle script, apks for all distinct architectures will be output, allowing the developer to publish smaller packages in the Google Play Store.
Please refer to the Publishing for Android article if you want to learn how to setup ABI splits.
Closing this as resolved.
@Plamen5kov @Pip3r4o The splits code sample/doc doesn't set a different versionCode for each ABI and therefore it can't be used to publish to the app stores.
Please update the docs, this is what I use (armv7 adds 2 to the base version code, x86 adds 4) at the bottom of my app.gradle:
ext.abiCodes = ['armeabi-v7a': 2, x86: 4]
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
def baseAbiVersionCode = project.ext.abiCodes.get(output.getFilter("ABI"))
if (baseAbiVersionCode != null) {
output.versionCodeOverride = baseAbiVersionCode + variant.versionCode
}
}
}
@vbresults Thanks for reporting that behavior. What you point out is indeed the case with the APKs, they don't have a distinct version code themselves. The respective code configuring the apks can be found here - https://github.com/NativeScript/android-runtime/blob/master/build-artifacts/project-template-gradle/build.gradle#L162 . Do you have a suggestion on general naming of apks configured with separate ABIs? The abiCodes list with the 2 and 4 versions appears non-standard.
Would you be willing to submit a PR?
@Pip3r4o The official guide (where I got 95% of my code) shows a convention but I personally don't want to be locked into their versionCode * 1000 formula. What to do here?
Most helpful comment
Please note the 64 bit version of the library seems to be coming along for the ride anyway; so now the APK files are 10 megs JUST for the runtimes. Can this be moved up in priority. This does make NS look horrible compared to other solutions. And the issue is WAY more import than silly things like than #1420 which has a critical rating .