Arcane Android Incantations (legacy OpenFL/Lime Android builds with Android API 26)

Posted on January 04, 2018

Table of Contents

Background

Google unwrapped a new app store policy this holiday season: https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html

In summary, in late 2018 new apps and updates to existing apps will need to target Android API version 26 or newer. In addition in 2019 64-bit native libraries will be mandatory.

I started developing Peasant Knight years ago so it uses HaxeFlixel/OpenFL/lime versions which are quite old and don’t run with newer Android APIs out of the box. It took me many frustrating hours to update from Android API 16 to 26, and I hope this write-up will save others from the same pain.

I haven’t tried compiling to other architectures yet (Lime compiles to 32-bit ARMv7 by default). That will remain an article for another day.


Lime logo by underscorediscovery. The Android robot is reproduced or modified from work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.



My setup

  • Haxe 3.2.0
  • HaxeFlixel 3.3.11
  • OpenFL 3.1.4
  • Lime 2.5.0
  • hxcpp 3.3.49
  • Those are very old versions of course but in my case they’re not worth updating

UPDATE

Here’s another working setup kindly contributed by a friend:

  • Haxe 4.3.3
  • HaxeFlixel 4.3.0 - latest as of January 2018
  • OpenFL 3.6.1
  • Lime 2.9.1
  • hxcpp 3.4.64

Lexicon

Most of the frustration stems from the fact that there’s no unified documentation for all the tools involved in a Lime Android build, and there’s quite a few. You just kind of get it after messing around and going through endless GitHub issues and forum posts. Hence the title. I won’t go into detail here but I’ll at least list all the Android-specific tools involved:

  • 32/64 bit: There’s overwhelming odds that your operating system supports 64-bit. Download only the 64-bit versions of everything. A mismatch could prevent the Android build process from executing correctly.
  • Java JDK/JRE: Java comes mainly in two flavors: the Java development kit which notably includes the Java compiler, and the Java runtime environment which is for end-users. The Android build process only requires the JDK.
  • Android SDK Manager: This is a now obsolete package which includes many tools (like Ant) that run during the build process. It’s also a download manager for Android tools and SDKs.
  • Android SDK Tools: Replaces the obsolete SDK Manager. They’re essentially equivalent, but old versions of Lime may or may not work with the new replacement.
  • Android NDK: Native Android toolkit for C/C++. Our C++ translated Haxe code is compiled and linked using this toolkit.
  • Ant: Invokes all the other tools during a build process. It’s like a very powerful batch file or shell script.
  • build-tools: A collection of tools used during the build process.
  • Target Android SDK/API/platform: Java libraries and more that are included in the build. The Android OS also treats applications differently depending on the API they are targeting.
  • Lime ndll libraries: A regular Lime installation provides pre-compiled lime dynamic libraries. These have been compiled using some specific Android NDK and API for a specific set of CPU architectures. Depending on the desired usage they may need to be re-compiled using a different NDK/API or for other CPU architectures.

The issue

I was able to compile with target-sdk 26, but I was getting the following error on launch: java.lang.UnsatisfiedLinkError: dlopen failed: library "/home/joshua/Development/Android/android-ndk-r8b/platforms/android-9/arch-arm/usr/lib/libc.so" not found.

You can find more info about it in this GitHub hxcpp issue and in this OpenFL forum post.

Cause

This happens because Android’s dynamic linker underwent a breaking change in API 23. Old OpenFL/Lime versions were compiled with Android NDK version r8b which is incompatible with this new dynamic linker.

Solution

Make sure to use Android NDK r9d or later, and re-compile the Lime libraries with that newer NDK. Be careful with using r14 or later, as header files and some other files have been moved and/or renamed.

Java

  • Remove all installed Java versions
  • Install Java JDK 1.8 64-bit (I used jdk1.8.0_151) 64-bit, AND DO NOT INSTALL THE JRE WHEN PROMPTED
  • Set the JAVA_HOME environment variable to your JDK installation directory
  • The Android build process is often confused about which Java version to use. This can cause it to use different Java versions at different steps and run into version conflicts down the line. Be safe.

Debugging Ant’s build.xml

If you want to see precisely which Java executables are used during the build process, or similar details, you can ask Ant to produce a log file. You would need to add the following line to the <Android SDK Manager>/tools/ant/build.xml file:

<record name="C:/Users/<Username>/Desktop/build.log" loglevel="debug" action="start" />

Android NDK

  • Download Android NDK version r9d 64-bit
  • Make sure Lime is pointed to its path

Android SDK Manager

  • Download Android SDK Manager version 22.0.5
  • Make sure Lime is pointed to its path

Hack

  • Download Android SDK Tools version 26.0.1
  • Using Android SDK Tools run sdkmanager platforms;android-26
  • Copy <Android SDK Tools path>/platforms/android-26 over to <Android SDK Manager path>/platforms
  • Using Android SDK Tools run sdkmanager build-tools;26.0.3
  • Copy <Android SDK Tools path>/build-tools/26.0.3 over to <Android SDK Manager path>/build-tools
  • This is necessary because Android SDK Manager is obsolete and incapable of downloading these packages but can still use them if we simply move them to the correct locations.

Re-compile Lime

  • Run openfl rebuild hxcpp android -clean
  • git clone Lime into <Haxe libs path>/lime (haxelib releases of Lime can’t be recompiled)
  • Checkout the tag containing your version of Lime (2.5.0 in my case)
  • Update the submodules
  • Rename your current Lime directory, and give its previous name to the cloned one
  • Run haxelib install format
  • Run lime rebuild android -Dlegacy
  • Run lime rebuild tools
  • The resulting Lime libraries will work with the new dynamic linker

Done!

  • Set <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="26" /> in your AndroidManifest.xml
  • Set <android target-sdk-version="26" /> in your Project.xml
  • Run lime build android -release and test