Android is the first free, open source, and fully customizable mobile platform. Android offers a full stack: an operating system, middleware, and key mobile applications. It also contains a rich set of APIs that allows third-party developers to develop great applications.製作 cygwin 環境下的 Cross tool chain 在完全開源前,很多開發人員在用 CodeSourcery 的 GNU Toolchains for ARM 。現在簡單了,下載到源碼後,在 prebuild 目錄下就有完整的 toolchain 用了。如果需要在其他系統內容下使用,可以去下載 android-toolchain-20081019.tar.bz2 源碼重新編譯。在 cygwin 下編譯時間,先檢查一下 gcc make Flex bison gettext-devel 等是否裝全(編譯過程中會用到 msgfmt 命令,cygwin 把它放到 gettext-devel 包裡了),然後按照其 readme.txt 裡的 linux 方式編譯就可以了。cgywin 下有時會出現檔案寫失敗的錯誤,用 chmod +w 修改即可解決。 在 <android source>/build/core/combo 目錄下的 linux-arm.mk 檔案對我們來說非常有協助,其中 C_INCLUDES 描述 C 語言的所有標頭檔位置,在 android source 裡找到這些目錄,並複製到新編譯好的 <toolchain>/arm-eabi/include 目錄下,動態庫在編譯過的 <android source>/out/target/product/generic/system/lib 目錄下,也可以從 Android SDK 的模擬器中 /system/lib 下找到這些檔案,並複製到 <toolchain>/arm-eabi/lib 目錄下。在 <android source>/build/core 下有 armelf.x armelf.xsc ,是以後編譯必須的串連指令碼。在 <android source>/out/target/product/generic/obj/lib 下的 crtbegin_static.o crtbegin_dynamic.o crtend_android.o 編譯時間還要根據自己情況選擇並串連到可執行檔中去,當然也可以在程式 main 函數後加如下函數代替。 void _start(int argc, char **argv) { exit( main(argc, argv) ); } First native C application on android 製作好了 toolchain ,就可以寫個 hello.c 測試一下了。代碼如下: #include <stdio.h> int main(int argc, char **argv) {printf("Hello World!/n"); return 0;} 編譯命令: $ arm-eabi-gcc -nostdlib -Bdynamic -Wl,-T,armelf.x -Wl,-dynamic-linker,/system/bin/linker / -include AndroidConfig.h -lc -o hello hello.c crtbegin_dynamic.o crtend_android.o $ adb push hello /data $ adb shell chmod 777 /data/hello $ adb shell /data/hello Hello World! $哈哈,Android 之旅開始了… Shared library for android
接下來測試 shared library ,編寫代碼 libhello.c : #include <stdio.h> int sayhello(char *name) {printf("Hello %s/n", name); return 0x12345;} 編寫代碼 hello2.c : extern int sayhello(char *name); int main(int argc, char **argv) {sayhello("World!"); return 0;} 編譯代碼及測試回合: $ arm-eabi-gcc -nostdlib -Wl,-T,armelf.xsc -Wl,-shared,-Bsymbolic -lc -o libhello.so libhello.c$ arm-eabi-gcc -nostdlib -Bdynamic -Wl,-T,armelf.x -Wl,-dynamic-linker,/system/bin/linker / -L./ -lc -lhello -o hello2 hello2.c crtbegin_dynamic.o crtend_android.o $ adb push libhello.so /data $ adb push hello2 /data $ adb shell chmod 777 /data/hello2 $ adb shell /data/hello2 Hello World! $ 呵呵,又邁進一步 ...The Java Native Interface (JNI) for Android 在 eclipse 裡建立一個 android 項目,新增加一個類 hello.java : package cn.oopsware.hello; public class hello {static {try {System.load("/data/lib/libhello_jni.so");} catch (Exception e) {} } public native int test1(); public native int test2(int[] name); } 修改主程式 onCreate 的代碼,用來調用顯示結果:
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); hello h = new hello(); TextView tv = new TextView(this); tv.setText( Integer.toHexString( h.test1() ) ); setContentView(tv);
} android 使用的 JNI 標頭檔在目錄 <android source>/dalvik/libnativehelper/include/nativehelper 下。也許是為了提高 android 映射庫函數的速度,android 另加了兩個函數,在載入和釋放庫時被VM調用,即:jint JNI_OnLoad(JavaVM* vm, void*) 和 void JNI_OnUnload(JavaVM* vm, void*) 。通過 JNIEnv 的 RegisterNatives 用法把一個 JNINativeMethod 數組註冊到 VM 。<android source>/dalvik/libcore/dalvik/src/main 加有個簡單的例子,可以協助理解 JNINativeMethod 中 signature 的寫法。共用庫代碼 libhello_jni.c :
#include "jni.h" static int test1(JNIEnv* env, jclass clazz) {return 0x654321;} static int test2(JNIEnv* env, jclass clazz, jarray a) {return 0x765432;}
#define gClassName "cn/oopsware/hello/hello"
static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "test1", "()I", test1 }, { "test2", "([I)I", test2 }, };
jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv *env; jclass cls; if ( (*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_4) ) return JNI_ERR; cls = (*env)->FindClass(env, gClassName); (*env)->RegisterNatives(env, cls, &gMethods[0], 2); return JNI_VERSION_1_4; }
void JNI_OnUnload(JavaVM* vm, void* reserved) { JNIEnv *env; jclass cls; if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_4)) return; cls = (*env)->FindClass(env, gClassName); (*env)->UnregisterNatives(env, cls); } 編譯並上傳到模擬器: $ arm-eabi-gcc -nostdlib -Wl,-T,armelf.xsc -Wl,-shared,-Bsymbolic / -lc -o libhello_jni.so hello_jni.c $ adb push libhello_jni.so data/bin/libhello_jni.so在 eclipse 裡運行 android 項目,即可看到正確結果。測試代碼及編譯好的測試.so 和 .apk,可下載下面的附件 jni_test.zip 。 |