轉自:http://blog.csdn.net/wangbin_jxust/article/details/37389383html
以前在進行cocos2dx開發時,已經詳細介紹瞭如何將win32的c++代碼移植到Android平臺,當再次回顧時,發現一些基礎的東西理解並非很完全,今天使用Android NDK提供的一個例子作一個簡單的移植。在進行該demo前,請確認你已經配置了Android開發環境和安裝了最新的Android NDK。java
建立一個Android項目 , 包名是com.example.hellojni,建立一個Activity做爲程序進入的Acitivity,命名爲HelloJni。c++
建立一個C文件,放一個函數,該函數的做用是獲取當前cpu架構並以字符串的形式返回。請注意該函數的格式: Java_包名的下劃線鏈接_Java文件名_java函數名。架構
#include <string.h> #include <jni.h> jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) { #if defined(__arm__) #if defined(__ARM_ARCH_7A__) #if defined(__ARM_NEON__) #define ABI "armeabi-v7a/NEON" #else #define ABI "armeabi-v7a" #endif #else #define ABI "armeabi" #endif #elif defined(__i386__) #define ABI "x86" #elif defined(__mips__) #define ABI "mips" #else #define ABI "unknown" #endif return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI "."); }
在該Android項目的根目錄(即AndroidManifest.xml文件所在目錄)下建立一個文件夾,命名爲jni(注意,文件名不能寫錯哦)函數
在jni目錄下,建立Android.mk和Application.mk兩個文件,同時將C文件也放進jni文件夾下面來。以下:ui
這裏的nick文件夾,能夠先忽略不看,這是爲後面的打包多個so準備的。spa
Android.mk文件實際上一個很小的NDK構建腳本,它的語法在: NDK安裝目錄/docs/ANDROID-MK.html,下文代碼也對一些基本屬性添加了註釋。.net
#返回當前文件在系統中的路徑,mk文件開始時必須定義該變量 LOCAL_PATH := $(call my-dir) #CLEAR_VARS 變量由構建系統提供,由於有大量的全局變量,在本次構建前,清除上一次的 include $(CLEAR_VARS) #LOCAL_MODULE 實際是項目名,用於區分各個項目,名字必須是惟一的並且不包含空格,最終的so庫,命名也會是 lib項目名.so LOCAL_MODULE := hello-jni #要編譯的c or cpp文件,注意不須要在這裏列舉頭文件或者include的文件,構建系統會自動幫你依賴這些文件 LOCAL_SRC_FILES := hello-jni.c #構建系統提供的變量 include $(BUILD_SHARED_LIBRARY)
Application.mk文件其實是對應用程序自己描述的文件,它定義了應用程序須要的功能模塊的列表、針對不一樣cpu架構打包不一樣的so]、要構建release或者debug包等。debug
APP_ABI := XXX,這裏的XXX就是指不一樣的平臺,能夠選填的有x86,armeabi,armeabi-v7a,mips,all,值得一提的是,選擇all,則會構建出全部平臺的so,若是不填該項,默認構建爲armeabi的。同時,做者也作過一個實驗,構建armeabi平臺的so是能夠運行在intel x86架構cpu平臺的,可是構建x86平臺的so則不能在armeabi平臺上運行的,這樣看來,應該是intel針對armeabi作了兼容,可是若是想要so 以最小的能耗運行在intel x86平臺,仍是要指定構建的so爲x86平臺。code
在當前Android項目的根目錄下,運行 NDK安裝路徑/ndk-build,則開始打包so。
另外,若是運行 NDK安裝路徑/ndk-build clean,會clean當前全部的so;
運行 NDK安裝路徑/ndk-build -B V=1,則強制從新打包,
若是想要打包多個so,則能夠在Android.mk定義多個modules,或者寫多個Android.mk,每一個Android.mk定義一個modules,我這裏在jni目錄下又建立了一個nick文件夾,用於放置新的C文件。
此時,只須要改動jni目錄下的Android.mk,再次對nick文件夾的C代碼打包便可。jni下的Android.mk文件:
#返回當前文件在系統中的路徑,mk文件開始時必須定義該變量 LOCAL_PATH := $(call my-dir) #CLEAR_VARS 變量由構建系統提供,由於有大量的全局變量,在本次構建前,清除上一次的 include $(CLEAR_VARS) #LOCAL_MODULE 實際是項目名,用於區分各個項目,名字必須是惟一的並且不包含空格,最終的so庫,命名也會是 lib項目名.so LOCAL_MODULE := hello-jni #要編譯的c or cpp文件,注意不須要在這裏列舉頭文件或者include的文件,構建系統會自動幫你依賴這些文件 LOCAL_SRC_FILES := hello-jni.c #構建系統提供的變量 include $(BUILD_SHARED_LIBRARY) #對nick文件夾下的代碼打包so include $(CLEAR_VARS) LOCAL_MODULE := hello-jni-mine LOCAL_SRC_FILES := nick/hello-jni.c include $(BUILD_SHARED_LIBRARY)
是的,你沒看錯,從新加上LOCAL_MODULE和LOCAL_SRC_FILES變量從新配置一下便可。
在Activity中,咱們使用static 關鍵詞將加載so放在函數體中,以保證直接先加載so.
static { System.loadLibrary("hello-jni"); }
要注意的是,System.loadLibrary()中填寫的並非完整的so名,而是去掉前綴lib和後綴.so的,也就是Android.mk中的LOCAL_MODULE變量。
java層的函數要用native關鍵詞聲明此次調用native層的函數,若是該java函數是public native String XXXX(),那麼在這裏就是調用C代碼中的Java_com_example_hellojni_HelloJni_stringFromJNI()函數。
以上就是Android平臺打包so和調用的一個最基本的demo,其實整個流程仍是比較簡單的,有一些規定的命名是不能隨便修改的,若是jni文件夾名,Android.mk,Application.mk文件名,被java層調用的C函數命名等,這些都是有規則的。