mirror of
https://github.com/joel16/SDL2.git
synced 2024-12-11 13:05:27 +00:00
331 lines
14 KiB
Plaintext
331 lines
14 KiB
Plaintext
================================================================================
|
|
Simple DirectMedia Layer for Android
|
|
================================================================================
|
|
|
|
Requirements:
|
|
|
|
Android SDK
|
|
http://developer.android.com/sdk/index.html
|
|
|
|
Android NDK r4 or later
|
|
http://developer.android.com/sdk/ndk/index.html
|
|
|
|
|
|
================================================================================
|
|
How the port works
|
|
================================================================================
|
|
|
|
- Android applications are Java-based, optionally with parts written in C
|
|
- As SDL apps are C-based, we use a small Java shim that uses JNI to talk to
|
|
the SDL library
|
|
- This means that your application C code must be placed inside an android
|
|
Java project, along with some C support code that communicates with Java
|
|
- This eventually produces a standard Android .apk package
|
|
|
|
The Android Java code implements an "activity" and can be found in:
|
|
android-project/src/org/libsdl/app/SDLActivity.java
|
|
|
|
The Java code loads your game code, the SDL shared library, and
|
|
dispatches to native functions implemented in the SDL library:
|
|
src/SDL_android.cpp
|
|
|
|
Your project must include some glue code that starts your main() routine:
|
|
src/main/android/SDL_android_main.cpp
|
|
|
|
|
|
================================================================================
|
|
Building an app
|
|
================================================================================
|
|
|
|
Instructions:
|
|
1. Copy the android-project directory wherever you want to keep your projects and rename it to the name of your project.
|
|
2. Move or symlink this SDL directory into the <project>/jni directory
|
|
3. Edit <project>/jni/src/Android.mk to include your source files
|
|
4. Run 'ndk-build' (a script provided by the NDK). This compiles the C source
|
|
|
|
If you want to use the Eclipse IDE, skip to the Eclipse section below.
|
|
|
|
5. Edit <project>/local.properties to point to the Android SDK directory
|
|
6. Run 'ant debug' in android/project. This compiles the .java and eventually
|
|
creates a .apk with the native code embedded
|
|
7. 'ant debug install' will push the apk to the device or emulator (if connected)
|
|
|
|
Here's an explanation of the files in the Android project, so you can customize them:
|
|
|
|
android-project/
|
|
AndroidManifest.xml - package manifest, customize this for your app
|
|
build.properties - empty
|
|
build.xml - build description file, used by ant
|
|
default.properties - holds the ABI for the application, currently android-5 which corresponds to the Android 2.0 system image
|
|
local.properties - holds the SDK path, you should change this to the path to your SDK
|
|
jni/ - directory holding native code
|
|
jni/Android.mk - Android makefile that includes all subdirectories
|
|
jni/SDL/ - directory holding the SDL library files
|
|
jni/SDL/Android.mk - Android makefile for creating the SDL shared library
|
|
jni/src/ - directory holding your C/C++ source
|
|
jni/src/Android.mk - Android makefile that you should customize to include your source code and any library references
|
|
res/ - directory holding resources for your application
|
|
res/drawable-* - directories holding icons for different phone hardware
|
|
res/layout/main.xml - place holder for the main screen layout, overridden by the SDL video output
|
|
res/values/strings.xml - strings used in your application, including the application name shown on the phone.
|
|
src/org/libsdl/app/SDLActivity.java - the Java class handling the initialization and binding to SDL. Be very careful changing this, as the SDL library relies on this implementation.
|
|
|
|
|
|
================================================================================
|
|
Customizing your application name
|
|
================================================================================
|
|
|
|
To customize your application name, edit AndroidManifest.xml and replace
|
|
"org.libsdl.app" with an identifier for your product package.
|
|
|
|
Then create a Java class extending SDLActivity and place it in a directory
|
|
under src matching your package, e.g.
|
|
src/com/gamemaker/game/MyGame.java
|
|
|
|
Here's an example of a minimal class file:
|
|
--- MyGame.java --------------------------
|
|
package com.gamemaker.game;
|
|
|
|
import org.libsdl.app.SDLActivity;
|
|
import android.os.*;
|
|
|
|
/*
|
|
* A sample wrapper class that just calls SDLActivity
|
|
*/
|
|
|
|
public class MyGame extends SDLActivity {
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
}
|
|
|
|
protected void onDestroy() {
|
|
super.onDestroy();
|
|
}
|
|
}
|
|
------------------------------------------
|
|
|
|
Then replace "SDLActivity" in AndroidManifest.xml with the name of your
|
|
class, .e.g. "MyGame"
|
|
|
|
================================================================================
|
|
Customizing your application icon
|
|
================================================================================
|
|
|
|
Conceptually changing your icon is just replacing the icon.png files in the
|
|
drawable directories under the res directory.
|
|
|
|
The easiest way to create a set of icons for your project is to remove all
|
|
the existing icon.png files, and then use the Eclipse IDE to create a dummy
|
|
project. During the process of doing this Eclipse will prompt you to create
|
|
an icon. Then just copy the drawable directories it creates over to your
|
|
res directory.
|
|
|
|
You may need to change the name of your icon in AndroidManifest.xml to match
|
|
the filename used by Eclipse.
|
|
|
|
================================================================================
|
|
Loading assets
|
|
================================================================================
|
|
|
|
Any files you put in the "assets" directory of your android-project directory
|
|
will get bundled into the application package and you can load them using the
|
|
standard functions in SDL_rwops.h.
|
|
|
|
There are also a few Android specific functions that allow you to get other
|
|
useful paths for saving and loading data:
|
|
SDL_AndroidGetInternalStoragePath()
|
|
SDL_AndroidGetExternalStorageState()
|
|
SDL_AndroidGetExternalStoragePath()
|
|
|
|
See SDL_system.h for more details on these functions.
|
|
|
|
================================================================================
|
|
Pause / Resume behaviour
|
|
================================================================================
|
|
|
|
If SDL is compiled with SDL_ANDROID_BLOCK_ON_PAUSE defined, the event loop will
|
|
block itself when the app is paused (ie, when the user returns to the main
|
|
Android dashboard). Blocking is better in terms of battery use, and it allows your
|
|
app to spring back to life instantaneously after resume (versus polling for
|
|
a resume message).
|
|
Upon resume, SDL will attempt to restore the GL context automatically.
|
|
In modern devices (Android 3.0 and up) this will most likely succeed and your
|
|
app can continue to operate as it was.
|
|
However, there's a chance (on older hardware, or on systems under heavy load),
|
|
where the GL context can not be restored. In that case you have to listen for
|
|
a specific message, (which is not yet implemented!) and restore your textures
|
|
manually or quit the app (which is actually the kind of behaviour you'll see
|
|
under iOS, if the OS can not restore your GL context it will just kill your app)
|
|
|
|
================================================================================
|
|
Threads and the JAVA VM
|
|
================================================================================
|
|
|
|
For a quick tour on how Linux native threads interoperate with the JAVA VM, take
|
|
a look here: http://developer.android.com/guide/practices/jni.html
|
|
If you want to use threads in your SDL app, it's strongly recommended that you
|
|
do so by creating them using SDL functions. This way, the required attach/detach
|
|
handling is managed by SDL automagically. If you have threads created by other
|
|
means and they make calls to SDL functions, make sure that you call
|
|
Android_JNI_SetupThread before doing anything else otherwise SDL will attach
|
|
your thread automatically anyway (when you make an SDL call), but it'll never
|
|
detach it.
|
|
|
|
================================================================================
|
|
Using STL
|
|
================================================================================
|
|
|
|
You can use STL in your project by creating an Application.mk file in the jni
|
|
folder and adding the following line:
|
|
APP_STL := stlport_static
|
|
|
|
For more information check out CPLUSPLUS-SUPPORT.html in the NDK documentation.
|
|
|
|
================================================================================
|
|
Additional documentation
|
|
================================================================================
|
|
|
|
The documentation in the NDK docs directory is very helpful in understanding the build process and how to work with native code on the Android platform.
|
|
|
|
The best place to start is with docs/OVERVIEW.TXT
|
|
|
|
|
|
================================================================================
|
|
Using Eclipse
|
|
================================================================================
|
|
|
|
First make sure that you've installed Eclipse and the Android extensions as described here:
|
|
http://developer.android.com/sdk/eclipse-adt.html
|
|
|
|
Once you've copied the SDL android project and customized it, you can create an Eclipse project from it:
|
|
* File -> New -> Other
|
|
* Select the Android -> Android Project wizard and click Next
|
|
* Enter the name you'd like your project to have
|
|
* Select "Create project from existing source" and browse for your project directory
|
|
* Make sure the Build Target is set to Android 2.0
|
|
* Click Finish
|
|
|
|
|
|
================================================================================
|
|
Using the emulator
|
|
================================================================================
|
|
|
|
There are some good tips and tricks for getting the most out of the
|
|
emulator here: http://developer.android.com/tools/devices/emulator.html
|
|
|
|
Especially useful is the info on setting up OpenGL ES 2.0 emulation.
|
|
|
|
|
|
================================================================================
|
|
Troubleshooting
|
|
================================================================================
|
|
|
|
You can create and run an emulator from the Eclipse IDE:
|
|
* Window -> Android SDK and AVD Manager
|
|
|
|
You can see if adb can see any devices with the following command:
|
|
adb devices
|
|
|
|
You can see the output of log messages on the default device with:
|
|
adb logcat
|
|
|
|
You can push files to the device with:
|
|
adb push local_file remote_path_and_file
|
|
|
|
You can push files to the SD Card at /sdcard, for example:
|
|
adb push moose.dat /sdcard/moose.dat
|
|
|
|
You can see the files on the SD card with a shell command:
|
|
adb shell ls /sdcard/
|
|
|
|
You can start a command shell on the default device with:
|
|
adb shell
|
|
|
|
You can do a clean build with the following commands:
|
|
ndk-build clean
|
|
ndk-build
|
|
|
|
You can see the complete command line that ndk-build is using by passing V=1 on the command line:
|
|
ndk-build V=1
|
|
|
|
If your application crashes in native code, you can use addr2line to convert the addresses in the stack trace to lines in your code.
|
|
|
|
For example, if your crash looks like this:
|
|
I/DEBUG ( 31): signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 400085d0
|
|
I/DEBUG ( 31): r0 00000000 r1 00001000 r2 00000003 r3 400085d4
|
|
I/DEBUG ( 31): r4 400085d0 r5 40008000 r6 afd41504 r7 436c6a7c
|
|
I/DEBUG ( 31): r8 436c6b30 r9 435c6fb0 10 435c6f9c fp 4168d82c
|
|
I/DEBUG ( 31): ip 8346aff0 sp 436c6a60 lr afd1c8ff pc afd1c902 cpsr 60000030
|
|
I/DEBUG ( 31): #00 pc 0001c902 /system/lib/libc.so
|
|
I/DEBUG ( 31): #01 pc 0001ccf6 /system/lib/libc.so
|
|
I/DEBUG ( 31): #02 pc 000014bc /data/data/org.libsdl.app/lib/libmain.so
|
|
I/DEBUG ( 31): #03 pc 00001506 /data/data/org.libsdl.app/lib/libmain.so
|
|
|
|
You can see that there's a crash in the C library being called from the main code. I run addr2line with the debug version of my code:
|
|
arm-eabi-addr2line -C -f -e obj/local/armeabi/libmain.so
|
|
and then paste in the number after "pc" in the call stack, from the line that I care about:
|
|
000014bc
|
|
|
|
I get output from addr2line showing that it's in the quit function, in testspriteminimal.c, on line 23.
|
|
|
|
You can add logging to your code to help show what's happening:
|
|
|
|
#include <android/log.h>
|
|
|
|
__android_log_print(ANDROID_LOG_INFO, "foo", "Something happened! x = %d", x);
|
|
|
|
If you need to build without optimization turned on, you can create a file called "Application.mk" in the jni directory, with the following line in it:
|
|
APP_OPTIM := debug
|
|
|
|
|
|
================================================================================
|
|
Memory debugging
|
|
================================================================================
|
|
|
|
The best (and slowest) way to debug memory issues on Android is valgrind.
|
|
Valgrind has support for Android out of the box, just grab code using:
|
|
svn co svn://svn.valgrind.org/valgrind/trunk valgrind
|
|
... and follow the instructions in the file README.android to build it.
|
|
|
|
One thing I needed to do on Mac OS X was change the path to the toolchain,
|
|
and add ranlib to the environment variables:
|
|
export RANLIB=$NDKROOT/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-ranlib
|
|
|
|
Once valgrind is built, you can create a wrapper script to launch your
|
|
application with it, changing org.libsdl.app to your package identifier:
|
|
--- start_valgrind_app -------------------
|
|
#!/system/bin/sh
|
|
export TMPDIR=/data/data/org.libsdl.app
|
|
exec /data/local/Inst/bin/valgrind --log-file=/sdcard/valgrind.log --error-limit=no $*
|
|
------------------------------------------
|
|
|
|
Then push it to the device:
|
|
adb push start_valgrind_app /data/local
|
|
|
|
and make it executable:
|
|
adb shell chmod 755 /data/local/start_valgrind_app
|
|
|
|
and tell Android to use the script to launch your application:
|
|
adb shell setprop wrap.org.libsdl.app "logwrapper /data/local/start_valgrind_app"
|
|
|
|
If the setprop command says "could not set property", it's likely that
|
|
your package name is too long and you should make it shorter by changing
|
|
AndroidManifest.xml and the path to your class file in android-project/src
|
|
|
|
You can then launch your application normally and waaaaaaaiiittt for it.
|
|
You can monitor the startup process with the logcat command above, and
|
|
when it's done (or even while it's running) you can grab the valgrind
|
|
output file:
|
|
adb pull /sdcard/valgrind.log
|
|
|
|
When you're done instrumenting with valgrind, you can disable the wrapper:
|
|
adb shell setprop wrap.org.libsdl.app ""
|
|
|
|
|
|
================================================================================
|
|
Known issues
|
|
================================================================================
|
|
|
|
- SDL audio (although it's mostly written, just not working properly yet)
|
|
- TODO. I'm sure there's a bunch more stuff I haven't thought of
|