Skip to content

Working for Android

Seth Archambault edited this page Jul 5, 2018 · 25 revisions

To build your raylib game for Android you need a set of Android tools. Those tools are basically the Android SDK and Android NDK, including Android Platform Tools and also Java Runtime.

Installing Android tools

Step 1. Install Java Runtime 8 (JRE), Android Studio (Android SDK, Android NDK) and Apache Ant tools:

Download and Install Java SE Runtime Environment 8

Download and Install on C: Android Studio. Use Android Studio's SDK Manager to install the latest Android Platform Tools and desired SDKs and NDK.

Download and decompress on C: Apache Ant

Step 2. Create the following environment variables:

Android Studio installs the NDK in a ndk-bundle folder inside the SDK folder location (where ever you installed it).

ANDROID_HOME = C:\android-sdk
ANDROID_SDK_TOOLS = C:\android-sdk\platform-tools
ANDROID_NDK = C:\android-sdk\ndk-bundle
ANT_HOME = C:\apache-ant

Compiling raylib source code

To compile raylib src it's required to install a custom ndk standalone toolchain. Build toolchain with this command:

python %ANDROID_NDK%\build\tools\make_standalone_toolchain.py --arch arm --api 16 --install-dir=C:\android_toolchain_arm_api16

After that, just navigate from command line to folder raylib/src/ and execute Makefile with:

mingw32-make PLATFORM=PLATFORM_ANDROID

Remember to setup ANDROID_NDK, ANDROID_TOOLCHAIN property properly in the Makefile!

ANDROID_NDK = C:/android-sdk/ndk-bundle
ANDROID_TOOLCHAIN = C:/android_toolchain_arm_api16

NOTE: libraylib.a will be generated in folder `raylib/release/android/armeabi-v7a/.

Compiling a raylib game for Android (using an example project template)

Step 1. To build an APK, navigate to folder raylib/template/simple_game/ and edit Makefile.Android. Replace these settings with yours where apropriate:

ANDROID_HOME = C:/android-sdk
ANDROID_NDK = $(ANDROID_HOME)/ndk-bundle
ANDROID_TOOLCHAIN = C:/android_toolchain_arm_api16
ANDROID_BUILD_TOOLS = $(ANDROID_HOME)/build-tools/26.0.3
ANDROID_PLATFORM_TOOLS = $(ANDROID_HOME)/platform-tools
JAVA_HOME = C:/PROGRA~1/Java/jdk1.8.0_152

Then build the apk with:

mingw32-make PLATFORM=PLATFORM_ANDROID

Step 2: To install the APK into connected device (previously intalled drivers and activated USB debug mode on device):

%ANDROID_SDK_TOOLS%\adb install -r simple_game.apk

Step 4: To view log output from device:

%ANDROID_SDK_TOOLS%\adb logcat -c
%ANDROID_SDK_TOOLS%\adb -d  logcat raylib:V *:S

Again, Notepad++ comes with an already prepared script to do that. Just open raylib/templates/simple_game/simple_game.c and run Notepad++ script raylib_compile_android_project_run_log.

If you have any doubt, just let me know.

Simple Process for Building for Android on MAC OSX

It's helpful to know step by step what each part of the process is doing. For this, let's create a simple bash script, where each line can be run manually and the results can be seen. This should be useful for understanding the process on Linux as well.

This is simple as in we're just using shell commands, no cmake, no builders of any kind.

Folder Setup

Note: project.c is copied from raylib/templates/simple_game/simple_game.c

/toolchain_arm_api22    put android_toolchain_arm_api22 here
/raylib                 put raylib here
/project1/lib
/project1/obj
/project1/src
/project1/dex
/project1/res/values/strings.xml
/project1/assets
/project1/project.c
/project1/AndroidManifest.xml

/res/values/strings.xml

Note: This is likely not necessary.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">My App</string>
</resources>

/src/com/seth/project/NativeLoader.java

Note: My project is named "project" and the namespace is named "seth"

package com.seth.project; 
public class NativeLoader extends android.app.NativeActivity { 
    static {
        System.loadLibrary("project"); // must match name of shared library (in this case libproject.so) 
    } 
} 

AndroidManifest.xml

Note: "package" is the unique name of your project, this will overwrite apps with the same name

<?xml version='1.0' encoding="utf-8" ?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package='com.seth.project' android:versionCode='0'
    android:versionName='0' >
    <application>
        <activity android:name="com.seth.project.NativeLoader"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:launchMode="singleTask"
            android:clearTaskOnLaunch="true">
        <meta-data android:name="android.app.lib_name" android:value="project"/>
            <intent-filter>
                <category android:name='android.intent.category.LAUNCHER'/>
                <action android:name='android.intent.action.MAIN'/>
            </intent-filter>
        </activity>
    </application>
</manifest>

Outline of the Process

cp              Copy libs from raylib to lib
gcc             Gen native_app_glue.o from raylib
ar rcs          Gen obj/libnative_app_glue.a from native_app_glue.o
gcc             Gen project.o from project.c
gcc             Gen lib/libproject.so from obj/project.o
aapt package    Gen R.java
javac           Gen classes from R.java and NativeLoader.java
dx              Gen classes.dex from objects
aapt package    Gen project.unsigned.apk
aapt add        Add shared library to project.unsigned.apk
keytool         Generate keystore
jarsigner       Gen project.signed.apk 
zipalign        Align project
adb install     Install project
adb logcat      view log

Install Standalone Toolchain

Install ndk-bundle using Android Studio. Install this in t

~/Library/Android/sdk/ndk-bundle/build/tools/make-standalone-toolchain.sh --arch=arm --platform=android-22 --install-dir=./toolchain_arm_api22

Install Raylib

Compile Raylib into ./raylib

~/.bash_profile

Add these files to path so you won't have a big headache later on

export ANDROID_SDK_ROOT="/Users/watchmyfeet/Library/Android/sdk"
export PATH="${ANDROID_SDK_ROOT}/build-tools/27.0.3/:$PATH"
export PATH="${ANDROID_SDK_ROOT}/tools:$PATH"
export PATH="${ANDROID_SDK_ROOT}/tools/bin:$PATH"
export PATH="${ANDROID_SDK_ROOT}/platform-tools:$PATH"

Initial Project Setup

Note: Keytool is in java folder on system

cd project1
mkdir lib/armeabi-v7a
cp ../raylib/release/libs/android/armeabi-v7a/libraylib.a lib/armeabi-v7a/libraylib.a
keytool -genkeypair -validity 1000 -dname "CN=seth,O=Android,C=ES" -keystore project.keystore -storepass 'whatever' -keypass 'mypass' -alias projectKey -keyalg RSA

Build Script

Note: Here's step by step commands which lead to the installation of your project!

../toolchain_arm_api22/bin/arm-linux-androideabi-gcc -c ../raylib/src/external/android/native_app_glue/android_native_app_glue.c -o obj/native_app_glue.o -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC -Wall -Wa,--noexecstack -Wformat -Werror=format-security -no-canonical-prefixes -DANDROID -DPLATFORM_ANDROID -D__ANDROID_API__=22

# Requires: folder setup
# Creates: obj/native_app_glue.o
# Note: This gcc uses other tools in the same toolchain folder structure, don't even thing about symlinking to it.

../toolchain_arm_api22/bin/arm-linux-androideabi-ar rcs obj/libnative_app_glue.a obj/native_app_glue.o

# Requires: obj/native_app_glue.o
# Creates: obj/libnative_app_glue.a

../toolchain_arm_api22/bin/arm-linux-androideabi-gcc -c project.c -o obj/project.o -I. -I../raylib/release/include -I../raylib/src/external/android/native_app_glue -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC -Wall -Wa,--noexecstack -Wformat -Werror=format-security -no-canonical-prefixes -DANDROID -DPLATFORM_ANDROID -D__ANDROID_API__=22 --sysroot=../toolchain_arm_api22/sysroot

# Requires: project.c
# Creates: obj/project.o

../toolchain_arm_api22/bin/arm-linux-androideabi-gcc -o lib/armeabi-v7a/libproject.so obj/project.o -shared -I. -I../raylib/release/include -I../raylib/src/external/android/native_app_glue -Wl,-soname,libproject.so -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -u ANativeActivity_onCreate -L. -Lobj -Llib/armeabi-v7a -lraylib -lnative_app_glue -llog -landroid -lEGL -lGLESv2 -lOpenSLES -latomic -lc -lm -ldl

# Requires: obj/project.o
# Creates: lib/armeabi-v7a/libproject.so

aapt package -f -m -S res -J src -M AndroidManifest.xml -I ${ANDROID_SDK_ROOT}/platforms/android-22/android.jar

# Requires: AndroidManifest.xml, res/
# Creates: src/com/seth/project/R.java

# javac -verbose -source 1.7 -target 1.7 -d obj -bootclasspath `/usr/libexec/java_home`/jre/lib/rt.jar -classpath ${ANDROID_SDK_ROOT}/platforms/android-22/android.jar:obj -sourcepath src src/com/seth/project/R.java src/com/seth/project/NativeLoader.java

# Requires: src/com/seth/project/R.java, src/com/seth/project/NativeLoader.java
# Creates: obj/com/seth/project/NativeLoader.class ... R&attr.class R$string.class R.class 

dx --verbose --dex --output=dex/classes.dex obj

# Requires: obj/com/seth/project/NativeLoader.class ... R&attr.class R$string.class R.class 
# Creates: dex/classes.dex

aapt package -f -M AndroidManifest.xml -S res -A assets -I ${ANDROID_SDK_ROOT}/platforms/android-22/android.jar -F project.unsigned.apk dex

# Creates: project.unsigned.apk
# Note: The "dex" at the end is the directory the classes.dex file is in! This folder can not contain the manifest file for whatever reason.

aapt add project.unsigned.apk lib/armeabi-v7a/libproject.so

# Does: Adds shared library to apk

jarsigner -keystore project.keystore -storepass whatever -keypass mypass -signedjar project.signed.apk project.unsigned.apk projectKey

# Does: Signs

zipalign -f 4 project.signed.apk project.apk

# Does: Aligns

adb install -r project.apk

# Does: install

Error: couldn't find libprojectlibrary.so

You'll get this if your shared library's name does not match across the build. In my case, I was referencing projectlibrary in the java file where it should have just been "project"

Error: INSTALL_FAILED_NO_MATCHING_ABIS

This one was tricky! Make sure the platform of the standalone toolchain you build matches the platform you are using on your system.

make-standalone-toolchain.sh --arch=arm --platform=android-22 --install-dir=./toolchain_arm_api22
${ANDROID_SDK_ROOT}/platforms/android-22

This command may also help.

adb shell getprop ro.product.cpu.abi

Error: INSTALL_FAILED_DEXOPT

This one was easier. The Apk generated must contain classes/classes.dex. If it doesn't, check aapt package -f -M to make sure you are including the folder dex is in at the end of it.

Dealing with Segmentation Faults - Using adb logcat

In the event of a segfault, don't despair! You can get the entire backtrace using adb logcat.

adb logcat "libc:*" "DEBUG:*" "*:S"

This gives you everything tagged with libc or DEBUG. "*:S" is there to Silence all other stuff.

Now, you may see a message that says "Suppressing debuggerd output because prctl(PR_GET_DUMPABLE)==0"

In that case you have to set this to 1.

In your c code, dd this include statement, and the prctl command somewhere early on in your main():

#include <sys/prctl.h>
...
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);

Here's a more robust logcat command:

adb logcat "threaded_app:*" "raylib:*" "libc:*" "DEBUG:*" "InputDispatcher:*" "JavaBinder:*" "WindowState:*" "Eve:*" "ViewRootImpl:*" "*:S"

Or be brave and try to find the important tags yourself:

adb logcat "*:*"
Clone this wiki locally