README.android
author Sam Lantinga <slouken@libsdl.org>
Sun, 04 Nov 2012 20:20:36 -0800
changeset 6652 bb2a33ed8688
parent 6650 d36232135316
child 6657 35de500cc918
permissions -rw-r--r--
Added link to the emulator info, which is extremeley useful for testing OpenGL ES 2.0
paul@4727
     1
================================================================================
paul@4726
     2
Simple DirectMedia Layer for Android
paul@4727
     3
================================================================================
paul@4725
     4
slouken@4965
     5
Requirements:
slouken@4965
     6
slouken@4965
     7
Android SDK
slouken@4965
     8
http://developer.android.com/sdk/index.html
slouken@4965
     9
slouken@4965
    10
Android NDK r4 or later
slouken@4965
    11
http://developer.android.com/sdk/ndk/index.html
paul@4725
    12
slouken@4967
    13
paul@4727
    14
================================================================================
paul@4727
    15
 How the port works
paul@4727
    16
================================================================================
paul@4727
    17
paul@4727
    18
- Android applications are Java-based, optionally with parts written in C
paul@4727
    19
- As SDL apps are C-based, we use a small Java shim that uses JNI to talk to 
paul@4727
    20
the SDL library
paul@4727
    21
- This means that your application C code must be placed inside an android 
paul@4727
    22
Java project, along with some C support code that communicates with Java
paul@4727
    23
- This eventually produces a standard Android .apk package
paul@4727
    24
slouken@4967
    25
The Android Java code implements an "activity" and can be found in:
slouken@4967
    26
android-project/src/org/libsdl/app/SDLActivity.java
slouken@4967
    27
slouken@4967
    28
The Java code loads your game code, the SDL shared library, and
slouken@4967
    29
dispatches to native functions implemented in the SDL library:
slouken@4967
    30
src/SDL_android.cpp
slouken@4967
    31
slouken@4967
    32
Your project must include some glue code that starts your main() routine:
slouken@4967
    33
src/main/android/SDL_android_main.cpp
slouken@4967
    34
paul@4727
    35
paul@4727
    36
================================================================================
paul@4727
    37
 Building an app
paul@4727
    38
================================================================================
paul@4727
    39
paul@4725
    40
Instructions:
slouken@4965
    41
1. Copy the android-project directory wherever you want to keep your projects and rename it to the name of your project.
slouken@6631
    42
2. Move or symlink this SDL directory into the <project>/jni directory
slouken@6631
    43
3. Edit <project>/jni/src/Android.mk to include your source files
slouken@6631
    44
4. Run 'ndk-build' (a script provided by the NDK). This compiles the C source
paul@4725
    45
slouken@4964
    46
If you want to use the Eclipse IDE, skip to the Eclipse section below.
paul@4725
    47
slouken@6631
    48
5. Edit <project>/local.properties to point to the Android SDK directory
slouken@6631
    49
6. Run 'ant debug' in android/project. This compiles the .java and eventually 
slouken@4964
    50
creates a .apk with the native code embedded
slouken@6650
    51
7. 'ant debug install' will push the apk to the device or emulator (if connected)
slouken@4964
    52
slouken@4965
    53
Here's an explanation of the files in the Android project, so you can customize them:
slouken@4965
    54
slouken@4965
    55
android-project/
slouken@4965
    56
	AndroidManifest.xml	- package manifest, do not modify
slouken@4965
    57
	build.properties	- empty
slouken@4965
    58
	build.xml		- build description file, used by ant
icculus@6387
    59
	default.properties	- holds the ABI for the application, currently android-5 which corresponds to the Android 2.0 system image
slouken@4965
    60
	local.properties	- holds the SDK path, you should change this to the path to your SDK
slouken@4967
    61
	jni/			- directory holding native code
slouken@4965
    62
	jni/Android.mk		- Android makefile that includes all subdirectories
slouken@4965
    63
	jni/SDL/		- directory holding the SDL library files
slouken@4965
    64
	jni/SDL/Android.mk	- Android makefile for creating the SDL shared library
slouken@4967
    65
	jni/src/		- directory holding your C/C++ source
slouken@4965
    66
	jni/src/Android.mk	- Android makefile that you should customize to include your source code and any library references
slouken@4965
    67
	res/			- directory holding resources for your application
slouken@4965
    68
	res/drawable-*		- directories holding icons for different phone hardware
slouken@4965
    69
	res/layout/main.xml	- place holder for the main screen layout, overridden by the SDL video output
slouken@4965
    70
	res/values/strings.xml	- strings used in your application, including the application name shown on the phone.
slouken@4965
    71
	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.
slouken@4965
    72
slouken@4965
    73
slouken@4965
    74
================================================================================
slouken@6631
    75
 Customizing your application name
slouken@6631
    76
================================================================================
slouken@6631
    77
slouken@6631
    78
To customize your application name, edit AndroidManifest.xml and replace
slouken@6631
    79
"org.libsdl.app" with an identifier for your product package.
slouken@6631
    80
slouken@6631
    81
Then create a Java class extending SDLActivity and place it in a directory
slouken@6631
    82
under src matching your package, e.g.
slouken@6631
    83
	src/com/gamemaker/game/MyGame.java
slouken@6631
    84
slouken@6631
    85
Here's an example of a minimal class file:
slouken@6631
    86
--- MyGame.java --------------------------
slouken@6631
    87
package com.gamemaker.game;
slouken@6631
    88
slouken@6631
    89
import org.libsdl.app.SDLActivity; 
slouken@6631
    90
import android.os.*; 
slouken@6631
    91
slouken@6631
    92
/* 
slouken@6631
    93
 * A sample wrapper class that just calls SDLActivity 
slouken@6631
    94
 */ 
slouken@6631
    95
slouken@6631
    96
public class MyGame extends SDLActivity { 
slouken@6631
    97
    protected void onCreate(Bundle savedInstanceState) { 
slouken@6631
    98
	super.onCreate(savedInstanceState); 
slouken@6631
    99
    } 
slouken@6631
   100
   
slouken@6631
   101
    protected void onDestroy() { 
slouken@6631
   102
	super.onDestroy(); 
slouken@6631
   103
    } 
slouken@6631
   104
}
slouken@6631
   105
------------------------------------------
slouken@6631
   106
slouken@6631
   107
Then replace "SDLActivity" in AndroidManifest.xml with the name of your
slouken@6631
   108
class, .e.g. "MyGame"
slouken@6631
   109
slouken@6631
   110
================================================================================
slouken@6631
   111
 Customizing your application icon
slouken@6631
   112
================================================================================
slouken@6631
   113
slouken@6631
   114
Conceptually changing your icon is just replacing the icon.png files in the
slouken@6631
   115
drawable directories under the res directory.
slouken@6631
   116
slouken@6631
   117
The easiest way to create a set of icons for your project is to remove all
slouken@6631
   118
the existing icon.png files, and then use the Eclipse IDE to create a dummy
slouken@6631
   119
project.  During the process of doing this Eclipse will prompt you to create
slouken@6631
   120
an icon. Then just copy the drawable directories it creates over to your
slouken@6631
   121
res directory.
slouken@6631
   122
slouken@6631
   123
You may need to change the name of your icon in AndroidManifest.xml to match
slouken@6631
   124
the filename used by Eclipse.
slouken@6631
   125
slouken@6631
   126
================================================================================
slouken@6646
   127
 Loading assets
slouken@6646
   128
================================================================================
slouken@6646
   129
slouken@6646
   130
Any files you put in the "assets" directory of your android-project directory
slouken@6646
   131
will get bundled into the application package and you can load them using the
slouken@6646
   132
standard functions in SDL_rwops.h.
slouken@6646
   133
slouken@6646
   134
There are also a few Android specific functions that allow you to get other
slouken@6646
   135
useful paths for saving and loading data:
slouken@6646
   136
SDL_AndroidGetInternalStoragePath()
slouken@6646
   137
SDL_AndroidGetExternalStorageState()
slouken@6646
   138
SDL_AndroidGetExternalStoragePath()
slouken@6646
   139
slouken@6646
   140
See SDL_system.h for more details on these functions.
slouken@6646
   141
slouken@6646
   142
================================================================================
gabomdq@6330
   143
 Pause / Resume behaviour
gabomdq@6330
   144
================================================================================
gabomdq@6330
   145
gabomdq@6330
   146
If SDL is compiled with SDL_ANDROID_BLOCK_ON_PAUSE defined, the event loop will
gabomdq@6330
   147
block itself when the app is paused (ie, when the user returns to the main
gabomdq@6330
   148
Android dashboard). Blocking is better in terms of battery use, and it allows your
gabomdq@6330
   149
app to spring back to life instantaneously after resume (versus polling for
gabomdq@6330
   150
a resume message).
gabomdq@6330
   151
Upon resume, SDL will attempt to restore the GL context automatically.
gabomdq@6330
   152
In modern devices (Android 3.0 and up) this will most likely succeed and your
gabomdq@6330
   153
app can continue to operate as it was.
gabomdq@6330
   154
However, there's a chance (on older hardware, or on systems under heavy load),
gabomdq@6330
   155
where the GL context can not be restored. In that case you have to listen for
gabomdq@6330
   156
a specific message, (which is not yet implemented!) and restore your textures
gabomdq@6330
   157
manually or quit the app (which is actually the kind of behaviour you'll see
gabomdq@6330
   158
under iOS, if the OS can not restore your GL context it will just kill your app)
gabomdq@6330
   159
gabomdq@6330
   160
================================================================================
gabomdq@6354
   161
 Threads and the JAVA VM
gabomdq@6354
   162
================================================================================
gabomdq@6354
   163
gabomdq@6354
   164
For a quick tour on how Linux native threads interoperate with the JAVA VM, take
gabomdq@6354
   165
a look here: http://developer.android.com/guide/practices/jni.html
gabomdq@6354
   166
If you want to use threads in your SDL app, it's strongly recommended that you
gabomdq@6354
   167
do so by creating them using SDL functions. This way, the required attach/detach
gabomdq@6354
   168
handling is managed by SDL automagically. If you have threads created by other
gabomdq@6354
   169
means and they make calls to SDL functions, make sure that you call
gabomdq@6354
   170
Android_JNI_SetupThread before doing anything else otherwise SDL will attach
gabomdq@6354
   171
your thread automatically anyway (when you make an SDL call), but it'll never
gabomdq@6354
   172
detach it.
gabomdq@6354
   173
gabomdq@6354
   174
================================================================================
slouken@6631
   175
 Using STL
slouken@6631
   176
================================================================================
slouken@6631
   177
slouken@6631
   178
You can use STL in your project by creating an Application.mk file in the jni
slouken@6631
   179
folder and adding the following line:
slouken@6631
   180
APP_STL := stlport_static
slouken@6631
   181
slouken@6631
   182
For more information check out CPLUSPLUS-SUPPORT.html in the NDK documentation.
slouken@6631
   183
slouken@6631
   184
================================================================================
slouken@4965
   185
 Additional documentation
slouken@4965
   186
================================================================================
slouken@4965
   187
slouken@4965
   188
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.
slouken@4965
   189
slouken@4965
   190
The best place to start is with docs/OVERVIEW.TXT
slouken@4965
   191
slouken@4964
   192
slouken@4964
   193
================================================================================
slouken@4964
   194
 Using Eclipse
slouken@4964
   195
================================================================================
slouken@4964
   196
slouken@4965
   197
First make sure that you've installed Eclipse and the Android extensions as described here:
slouken@4965
   198
	http://developer.android.com/sdk/eclipse-adt.html
slouken@4965
   199
slouken@4965
   200
Once you've copied the SDL android project and customized it, you can create an Eclipse project from it:
slouken@4965
   201
 * File -> New -> Other
slouken@4965
   202
 * Select the Android -> Android Project wizard and click Next
slouken@4965
   203
 * Enter the name you'd like your project to have
slouken@4965
   204
 * Select "Create project from existing source" and browse for your project directory
icculus@6387
   205
 * Make sure the Build Target is set to Android 2.0
slouken@4965
   206
 * Click Finish
slouken@4964
   207
slouken@4964
   208
slouken@4964
   209
================================================================================
slouken@6652
   210
 Using the emulator
slouken@4964
   211
================================================================================
slouken@4964
   212
slouken@6652
   213
There are some good tips and tricks for getting the most out of the
slouken@6652
   214
emulator here: http://developer.android.com/tools/devices/emulator.html
slouken@6652
   215
slouken@6652
   216
Especially useful is the info on setting up OpenGL ES 2.0 emulation.
slouken@4964
   217
slouken@4964
   218
slouken@4964
   219
================================================================================
slouken@4964
   220
 Troubleshooting
slouken@4964
   221
================================================================================
slouken@4964
   222
slouken@4965
   223
You can create and run an emulator from the Eclipse IDE:
slouken@4965
   224
 * Window -> Android SDK and AVD Manager
slouken@4965
   225
slouken@4965
   226
You can see if adb can see any devices with the following command:
slouken@4965
   227
	adb devices
slouken@4965
   228
slouken@4965
   229
You can see the output of log messages on the default device with:
slouken@4965
   230
	adb logcat
slouken@4965
   231
slouken@4965
   232
You can push files to the device with:
slouken@4965
   233
	adb push local_file remote_path_and_file
slouken@4965
   234
slouken@4965
   235
You can push files to the SD Card at /sdcard, for example:
slouken@4965
   236
	adb push moose.dat /sdcard/moose.dat
paul@4727
   237
slouken@4976
   238
You can see the files on the SD card with a shell command:
slouken@4976
   239
	adb shell ls /sdcard/
slouken@4976
   240
slouken@4976
   241
You can start a command shell on the default device with:
slouken@4976
   242
	adb shell
slouken@4976
   243
slouken@4975
   244
You can do a clean build with the following commands:
slouken@4975
   245
	ndk-build clean
slouken@4975
   246
	ndk-build
slouken@4975
   247
slouken@4973
   248
You can see the complete command line that ndk-build is using by passing V=1 on the command line:
slouken@4973
   249
	ndk-build V=1
slouken@4973
   250
slouken@4973
   251
If your application crashes in native code, you can use addr2line to convert the addresses in the stack trace to lines in your code.
slouken@4973
   252
slouken@4973
   253
For example, if your crash looks like this:
slouken@4973
   254
I/DEBUG   (   31): signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 400085d0
slouken@4973
   255
I/DEBUG   (   31):  r0 00000000  r1 00001000  r2 00000003  r3 400085d4
slouken@4973
   256
I/DEBUG   (   31):  r4 400085d0  r5 40008000  r6 afd41504  r7 436c6a7c
slouken@4973
   257
I/DEBUG   (   31):  r8 436c6b30  r9 435c6fb0  10 435c6f9c  fp 4168d82c
slouken@4973
   258
I/DEBUG   (   31):  ip 8346aff0  sp 436c6a60  lr afd1c8ff  pc afd1c902  cpsr 60000030
slouken@4973
   259
I/DEBUG   (   31):          #00  pc 0001c902  /system/lib/libc.so
slouken@4973
   260
I/DEBUG   (   31):          #01  pc 0001ccf6  /system/lib/libc.so
slouken@4973
   261
I/DEBUG   (   31):          #02  pc 000014bc  /data/data/org.libsdl.app/lib/libmain.so
slouken@4973
   262
I/DEBUG   (   31):          #03  pc 00001506  /data/data/org.libsdl.app/lib/libmain.so
slouken@4973
   263
slouken@4973
   264
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:
slouken@4973
   265
	arm-eabi-addr2line -C -f -e obj/local/armeabi/libmain.so
slouken@4973
   266
and then paste in the number after "pc" in the call stack, from the line that I care about:
slouken@4973
   267
000014bc
slouken@4973
   268
slouken@4973
   269
I get output from addr2line showing that it's in the quit function, in testspriteminimal.c, on line 23.
slouken@4973
   270
slouken@4973
   271
You can add logging to your code to help show what's happening:
slouken@4973
   272
slouken@4973
   273
#include <android/log.h>
slouken@4973
   274
slouken@4973
   275
	__android_log_print(ANDROID_LOG_INFO, "foo", "Something happened! x = %d", x);
slouken@4973
   276
slouken@4974
   277
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:
slouken@4974
   278
APP_OPTIM := debug
slouken@4974
   279
paul@4727
   280
paul@4727
   281
================================================================================
slouken@6650
   282
 Memory debugging
slouken@6650
   283
================================================================================
slouken@6650
   284
slouken@6650
   285
The best (and slowest) way to debug memory issues on Android is valgrind.
slouken@6650
   286
Valgrind has support for Android out of the box, just grab code using:
slouken@6650
   287
	svn co svn://svn.valgrind.org/valgrind/trunk valgrind
slouken@6650
   288
... and follow the instructions in the file README.android to build it.
slouken@6650
   289
slouken@6650
   290
One thing I needed to do on Mac OS X was change the path to the toolchain,
slouken@6650
   291
and add ranlib to the environment variables:
slouken@6650
   292
export RANLIB=$NDKROOT/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-ranlib
slouken@6650
   293
slouken@6650
   294
Once valgrind is built, you can create a wrapper script to launch your
slouken@6650
   295
application with it, changing org.libsdl.app to your package identifier:
slouken@6650
   296
--- start_valgrind_app -------------------
slouken@6650
   297
#!/system/bin/sh
slouken@6650
   298
export TMPDIR=/data/data/org.libsdl.app
slouken@6650
   299
exec /data/local/Inst/bin/valgrind --log-file=/sdcard/valgrind.log --error-limit=no $*
slouken@6650
   300
------------------------------------------
slouken@6650
   301
slouken@6650
   302
Then push it to the device:
slouken@6650
   303
	adb push start_valgrind_app /data/local
slouken@6650
   304
slouken@6650
   305
and make it executable:
slouken@6650
   306
	adb shell chmod 755 /data/local/start_valgrind_app
slouken@6650
   307
slouken@6650
   308
and tell Android to use the script to launch your application:
slouken@6650
   309
	adb shell setprop wrap.org.libsdl.app "logwrapper /data/local/start_valgrind_app"
slouken@6650
   310
slouken@6650
   311
If the setprop command says "could not set property", it's likely that
slouken@6650
   312
your package name is too long and you should make it shorter by changing
slouken@6650
   313
AndroidManifest.xml and the path to your class file in android-project/src
slouken@6650
   314
slouken@6650
   315
You can then launch your application normally and waaaaaaaiiittt for it.
slouken@6650
   316
You can monitor the startup process with the logcat command above, and
slouken@6650
   317
when it's done (or even while it's running) you can grab the valgrind
slouken@6650
   318
output file:
slouken@6650
   319
	adb pull /sdcard/valgrind.log
slouken@6650
   320
slouken@6650
   321
When you're done instrumenting with valgrind, you can disable the wrapper:
slouken@6650
   322
	adb shell setprop wrap.org.libsdl.app ""
slouken@6650
   323
slouken@6650
   324
slouken@6650
   325
================================================================================
paul@4727
   326
 Known issues
paul@4727
   327
================================================================================
paul@4727
   328
paul@4727
   329
- SDL audio (although it's mostly written, just not working properly yet)
paul@4727
   330
- TODO. I'm sure there's a bunch more stuff I haven't thought of