castle-engine package --target=android --package-format=android-app-bundle
Questions related to Android development.
Any Android >= 4.1 (platform android-16). Reasons:
Android 2.0 (platform android-5) is necessary, to have OpenGL ES 2.0
.
Android 2.3 (platform android-9) is necessary, to NativeActivity
and EGL
.
Android 4.1 (platform android-16) is necessary, because
New executables (with PIC) can run only on Android 4.1+ (according to http://wiki.freepascal.org/Android ).
New Android NDK just supports only >= 16.
In theory, you could workaround it, by explicitly compiling Android library without PIC support, and sticking to an ancient version of Android NDK. But this would give you an application that, in turn, doesn’t work on newer phones (since platform 23, PIC support is required).
Simple answer:
Follow https://castle-engine.io/manual_data_directory.php . This means:
When developing a game, put all your game data under the "data/" subdirectory.
Then load it using castle-data:/xxx
URLs, for example use LoadImage('castle-data:/gui/blabla.png')
to load an image stored under data/gui/blabla.png
.
The above approach makes your code 100% working on both Android and standalone platforms. Our build tool will automatically package the data/
subdirectory correctly.
Longer explanation about what happens under the hood:
In an Android application, you can read files on a normal filesystem, just like on any other Unix. Like file:///sdcard/my_texture.png
. However, it’s not a proper way to distribute your game read-only data. The game data should be placed as the "assets" inside the apk file, and opened using special Android functions. We support it seamlessly in the Castle Game Engine:
Our build tool automatically packs files inside the data/
subdirectory as Android "assets".
Our file-reading routines (the Download
function, and everything opening files/URLs built on top of it) support a special protocol castle-android-assets:/
to access Android assets. So you can open URL like castle-android-assets:/my_texture.png
.
Finally, the castle-data:/xxx
URL is resolved into castle-android-assets:/xxx
on Android by default (assuming you didn’t set ApplicationDataOverride
).
In effect, when you use the build tool and the castle-data:/xxx
on Android, you seamlessly read data from your APK "assets".
Simply use the global UserConfig
(in CastleConfig unit) to load/save your settings. See https://castle-engine.io/manual_user_prefs.php . The same mechanism works for saving preferences with standalone (desktop) applications.
Just like with standalone code, you have to explicitly call UserConfig.Load
and UserConfig.Save
when necessary. You will usually call UserConfig.Load
in your Application.OnInitialize
handler, to load user preferences at the beginning of your application. You will usually call UserConfig.Save
when user confirms the preferences change, or simply immediately — the exact moment depends on the game UI flow. Don’t wait too long before saving the user preferences — on Android, your application may be killed at any moment.
Traditionally, Android applications are distributed as APK (Android Package) files. This package format remains the default in CGE, as it can be easily installed on any Android device (so it is convenient for development purposes). Also, it is the required distribution format on most stores except the Google Play. For example you can upload APK to itch.io (see our platformer for Android on itch.io).
However, Google Play requires the new applications to be uploaded using a new AAB (Android App Bundle) format, not an APK. To generate the AAB file, just add the --package-format=android-app-bundle
to the build tool command-line, like this:
castle-engine package --target=android --package-format=android-app-bundle
Android App Bundle (AAB) is a collection of prebuilt resources targeted for different user devices (such as Android version, CPU architecture, Screen resolution). Play Store then automatically generates an APK based on user configuration. Note that it also means that AAB package cannot be directly installed on a mobile device/emulator and therefore for debugging and internal testing APK is still a necessary format.
The default remains to create APK. You can also request APK format explicitly using
castle-engine package --target=android --package-format=android-apk
or
castle-engine package --target=android --package-format=default
To create a "release" APK / AAB (one that you can distribute, e.g. through WWW or by uploading it to Google Play) you need to create your private key, and use it to sign your packages.
See Android signing documentation from Google for description how to create and manage your key store.
Note
|
For new applications uploaded to Google Play store, you can (actually, you have to) let the Google Play handle the final signing for you. This is even required in case of AAB, because Google Play needs to internally unpack your AAB and create APK from it. But you still need to sign the file you upload (whether APK or AAB) using the upload key, so the procedure described on this page still applies. |
Note
|
There is also a way to create a key store without using Android Studio or Play Store or interacting with Google, if you don’t want to follow Google instructions. You can do it using Java keytool. Call this on the command-line: keytool -genkey -v -keystore my_keystore_name.keystore -alias my_alias -keyalg RSA -keysize 2048 -validity 10000 and fill an interactive questionnaire to provide the passwords and certificate details. Be sure to save the generated keystore file and passwords secure. |
Once you have your keys, you need to tell our build tool to use them. You do this by creating AndroidSigningProperties.txt
file at the top of your project (along the CastleEngineManifest.xml
file). Add there these lines:
key.store=<path-to-your-keystore> key.alias=<key-alias-in-your-keystore> key.store.password=<my-password> key.alias.password=<my-password>
This will allow you to create release APK / AAB files (our build tool will automatically use it when making a "package" in "release" mode).
Use our CastleLog
unit (see log).
(The call to InitializeLog
will be done automatically, from CastleAutoGenerated
unit, so don’t worry about it.)
Use WritelnLog
or WritelnWarning
from your code.
On Android, these logs are send to the standard Android logging API ("logcat").
It is most comfortable to observe them by running your APK using castle-engine run --target=android
. It will automatically display the logs from your application.
Alternatively, you can use any other Android tool, e.g. command-line adb logcat
. It’s usually comfortable to filter by your program name, e.g. adb logcat | grep androiddemo
(although, in case of mysterious crashes at startup, take a look at the full log, not filtered; some important startup info may not be marked with application name).
Yes!
With latest versions of Android emulator it is possible to run OpenGL ES applications (see http://android-developers.blogspot.com/2012/04/faster-emulator-with-better-hardware.html , emulator can now handle apps using OpenGL ES 2.0 and hard floats).
Note
|
you will need to check "Use Host GPU" in emulator options. Otherwise the app will stop and in the log (Android logcat) you will see a message "Emulator without GPU emulation detected.". Also, make sure your device is created with sufficient space (on Internal storage or SD Card). |
Note
|
You can run emulator of the normal Android CPU (32-bit Arm or 64-bit Aarch64), running the "final" CGE application for the same CPU. But it is faster to use emulator/virtual machine of Android running 32-bit x86 or 64-bit x86_64 CPU and compile CGE applications for this CPU. To do this, compile your application like this: castle-engine package --os=android --cpu=x86_64 and transfer the resulting APK into the emulator/virtual machine. The Android SDK includes ready machines. You can also use virtual machines made from images on https://www.android-x86.org/ . |
You can compile a standalone program, for your normal OS, using OpenGLES instead of the traditional desktop OpenGL. This way you can test how your application looks like before actually compiling it for Android. The differences between desktop (OpenGL) and mobile (OpenGLES) are usually very small, due to the small number of things not yet implemented on OpenGLES.
Just define OpenGLES
symbol in src/castleconf.inc
inside the engine sources. Or add -dOpenGLES
to your fpc.cfg
file, or to the <compiler_options>
in your CastleEngineManifest.xml. Then recompile (the engine and your game).
Be sure to also install an OpenGL ES library (with EGL). Unlike normal OpenGL, it is not something automatically installed on your OS.
On Linux, you can install OpenGL ES + EGL by installing packages libgles2-mesa-dev and libegl1-mesa-dev (these are Debian names, other distros probably have something similar).
On Windows, you can install:
Angle. Official usage and download instructions are here, but it may be easiest to just copy libEGL.dll
and libGLESv2.dll
from your Google Chrome installation, like C:\Program Files (x86)\Google\Chrome\Application\64.0.3282.119
. Just copy these two DLL files to the directory of your game .exe.
Note that you will need to compile your application for the same architecture as Google Chrome, which is most probably 64-bit Windows, not 32-bit. So make sure to choose 64-bit Windows and CPU as target (e.g. in Lazarus project compilation options, or using CGE build tool like castle-engine compile --os=win64 --cpu=x86_64
).
Also this post has useful links: http://www.g-truc.net/post-0457.html .
If you use our build tool for compilation, the debug apk is already prepared such that you can debug it with "ndk-gdb". You must run ndk-gdb
within the output Android project, like this:
Create a debug Android package:
castle-engine package --target=android --mode=debug
Install the apk and run it using any way you like, for example by
castle-engine install --target=android castle-engine run --target=android
Run ndk-gdb by
cd <my-project-directory>/castle-engine-output/android/project/app/src/main/ ndk-gdb
Then debug, using ndk-gdb console just like a usual GDB.
You can set breakpoints (and the tab key will auto-complete symbols, including Pascal symbols (uppercased)). Below is a sample ndk-gdb session. As you can see, breakpoints on Pascal symbols work (like internal fpc_raiseexception, or function WindowRender defined in game.pas). Line numbers, printing values of variables, and everything else works fine as well :)
(gdb) break fpc_raiseexception Breakpoint 1 at 0xa1d29bdc (gdb) break WINDOWRENDER Breakpoint 2 at 0xa1d39e58: file game.pas, line 328. (gdb) continue Continuing. [Switching to Thread 4909.4926] Thread 10 "ine.androiddemo" hit Breakpoint 2, WINDOWRENDER (CONTAINER=0xb3992a60) at game.pas:328 328 begin (gdb) print YELLOW $1 = {1, 1, 0, 1} (gdb) delete breakpoints Delete all breakpoints? (y or n) y (gdb) continue Continuing.
It is probably possible to use Lazarus to even have a graphical debugger. TODO: if you have working instructions how to use ndk-gdb with Lazarus, please improve this wiki page!
Random hints:
Setting a breakpoint on fpc_raiseexception
is very useful — this way you can catch all FPC exceptions.
You can run ndk-gdb --launch
to set up breakpoints before the application launches. When ndk-gdb --launch
starts, you set up breakpoints in the GDB command-line, and when ready you execute continue
in GDB.
If you get an error around the [ .. readlink /system/bin/ps ..]
failing, a workaround is to edit <ndk>/python-packages/gdbrunner/init.py
and set ps_script = "ps"
.
Similar to the above instructions for ndk-gdb
, you should compile your application in the debug mode, and enter the directory of resulting Android project:
Create a debug Android package:
castle-engine package --target=android --mode=debug
Install the apk and run it using any way you like, for example by
castle-engine install --target=android castle-engine run --target=android
Run the live logs from your device, and filter them through ndk-stack
like this:
cd <my-project-directory>/castle-engine-output/android/project/app/src/main/ # if your applications runs using 32-bit Android CPU (Arm) adb logcat | ndk-stack -sym ./obj/local/armeabi-v7a # if your applications runs using 64-bit Android CPU (Aarch64) adb logcat | ndk-stack -sym ./obj/local/arm64-v8a
This assumes that the Android tools, including Android NDK tools, are available on your environment variable $PATH. See http://developer.android.com/ndk/guides/ndk-stack.html for more information about the ndk-stack
.
Now when the application crashes, you will see a nice backtrace, with a filename and line number indicating where the crash occured.
In short, don’t worry about it: WideString manager is automatically handled for you. This means that strings with international characters just work.
Note that WideString manager may not be installed when units "initialization" section is run. (This is a limitation of some Android versions.) But it will for sure be installed when Application.OnInitialize is called.
Background: Having a WideString manager is important if you use WideStrings (e.g. with standard FPC units to handle XML, like DOM) with non-ASCII characters (e.g. regional characters specific to some language). Our engine uses UTF-8 for displaying strings with TCastleFont, and VRML/X3D use UTF-8 encoding by default. So we need to be able to convert between WideStrings and AnsiStrings with UTF-8. This is what the "WideString manager" is for.
Our engine includes and correctly initializes manager from CastleAndroidCWString, which is a slightly modified version of FPC CWString for Android (to initialize with delay, required by some Android versions).
The compiler flag -CfVFPV3
is necessary to enable hardware floats, this way the engine works much faster. Our build tool automatically uses it when compiling your project. You should also have FPC standard units compiled with this option (following our Android wiki page).
Note
|
In theory it is possible to compile and use our engine without -CfVFPV3 (in which case make sure you use FPC standard units also compiled without -CfVFPV3 ), things will work, but they will be much slower. E.g. in Darkest Before the Dawn loading time drops from 6 (hard floats) to 36 (no hard floats) seconds, and frames per second during game drop from 40 (hard floats) to 10 (no hard floats).
|
Note that every unit has to be compiled with -CfVFPV3 (hard floats). It is especially important to remember it when compiling packages from Lazarus, since they also depend on standard Lazarus "fcllaz" package, which does not by default get compiled with -CfVFPV3.
It’s then easiest to just add
#ifdef ANDROID -CfVFPV3 #endif
to your fpc.cfg. This will automatically make everything compiled for Android (from Lazarus or from command-line) use -CfVFPV3. Otherwise, you will have to modify packages like "fcllaz" to add -CfVFPV3 to compilation options on Android.
You can put org.gradle.jvmargs=-Xmx2048M
in your ~/.gradle/gradle.properties
. (We don’t do it in every project, because it may unfortunately fail to work on some Windows machines, even when they have a lot of RAM…)
To improve this documentation just edit the source of this page in AsciiDoctor (simple wiki-like syntax) and create a pull request to Castle Game Engine WWW (cge-www) repository.
Copyright Michalis Kamburelis and Castle Game Engine Contributors.
This webpage is also open-source and we welcome pull requests to improve it.
We use cookies for analytics. See our privacy policy.