Android compatibility with 32-bit libraries on a 64-bit device, updated

Sometime ago I wrote the following post: Android compatibility with 32-bit libraries on a 64-bit device.

In that article, the proposed solution was to manually remove the library files that were causing the problem using exclude. See that article for the details on the reasons to do that.

There’s a better way using ABI Filters, though.

android {
    // ...
    buildTypes {
        // ...
        release {
            ndk {
                abiFilters "armeabi", "armeabi-v7a", "x86"
            }
        }
    }
}

With ABI Filters we specify the architectures that we want to keep, which is the opposite of what we were previously doing, which was manually removing the libraries we didn’t want to keep. So, what we’re doing is keeping 32-bit architectures, both for ARM and x86 (we’re excluding 64-bit libraries and MIPS).

Notice that nowadays I would also exclude “armeabi”, as all the nowadays devices use at least “armeabi-v7a”.

Finally, notice that by August 2019 all the apps using native libraries will have to provide both 32 and 64-bit versions, as Google states in the blog post “Improving app security and performance on Google Play for years to come“:

In August 2019, Play will require that new apps and app updates with native libraries provide 64-bit versions in addition to their 32-bit versions.

See also Reducing APK size by using ABI Filters and APK split by Igor Wojda for other uses of ABI Filters.

Kotlin interop: mixing Kotlin and Java ButterKnife-annotated activities

I’ve been working with Kotlin for a while, mainly for side-projects or toy-projects. Since last Google I/O 2017 announcement it has become clear that there are no more reasons or excuses to not use it in production.

One of the big selling points of Kotlin is that you can start small, by converting one class or two, or by creating new ones, while keeping all the remaining code in Java. So, interop between the two languages is almost 100% transparent. Almost.

Working to convert a small project step by step, I started to convert activities into Kotlin. Those activities use ButterKnife (I’m using current version, which is 8.7.0) to inject the views. So, after converting the first activity I stumbled upon a problem with the annotation processor: in Gradle script, you have to use either annotationProcessor or kapt, but not both at the same time. So, you have to choose:

  • using annotationProcessor only will not find Kotlin classes, and because of that injection will silently fail at runtime,
  • using kapt only will make compilation fail.

The final workaround I found was:

  • using kapt3 (by applying kotlin-kapt plugin to the Gradle script) and,
  • adding a @JvmField() annotation in addition to ButterKnife annotations so Kotlin compiler generates public fields instead of getters and setters.

By applying kapt3 we fix the compilation error involving “kotlin.jvm.internal.FunctionReference.(ILjava/lang/Object;)V” and by converting Kotlin fields to plain-old Java fields we allow ButterKnife compiler to find the fields to inject, as is unable to find Kotlin fields.

You can find the source code with different options in different branches (the one with the final solution is kotlin-workaround) in this GitHub project.

The project has two activities, one (MainActivity) that is written in Java and kept in this language, and the second one (NextActivity) that is converted to Kotlin. Notice that a simple suite of tests is available to check that both activities are being correctly injected, and that there is a TextView in both activities that has its text replaced by code to prove that the activity has been successfully injected.

Hope this tip is useful!