AS下JNI編程實例并生成so庫 - 網(wǎng)絡(luò)參考版

最近需要使用JNI編程,學了下JNI,并且在Android Studio下實現(xiàn)了一個小demo。這期間有一些坑,還好都解決了,想分享出來,希望大家少走彎路。本文中采用的平臺是Windows,NDK環(huán)境已經(jīng)搭建好,這方面資料很多,大家可以自行百度。

參考文檔:https://www.cnblogs.com/jymblog/p/5526865.html

本文分為兩個部分:

1.如何通過編寫Jni實現(xiàn)native方法的調(diào)用。

2.怎樣生成.so動態(tài)庫提供給第三方使用。

以下是正文:

一.編寫jni文件,實現(xiàn)本地方法

1. 建立一個新工程,只有一個MainActivity,里面加載庫文件并且聲明和調(diào)用若干本地方法,然后build-makeProject生成MainActivity對應的.class文件。

publicclassMainActivityextendsActivity {

private final String TAG = "JNITEST"

@Override

protectedvoid onCreate(Bundle savedInstanceState) {

? ? ? ? super.onCreate(savedInstanceState);

? ? ? ? setContentView(R.layout.activity_main);

? ? ? ? String s=returnString();

? ? ? ? Log.d(TAG,s);

? ? ? ? inta=1000;? ? ? ? Log.d(TAG,sayhello(a));? ? }

//加載jni

static {

? ? ? ? System.loadLibrary("nativeTest");? ? }

//聲明native方法

privatenativeintsayhello(int t);

? ? privatenative String returnString();

}

2. 生成.h頭文件,該文件即連接java和c(c++)的橋梁,里面有Android工程里本地方法的聲明。這個文件可以在控制臺用javah命令自動生成。注意,這里可能會碰到問題,比如我第一次就出現(xiàn)了找不到app.activity ,即找不到類文件,這種問題一般是沒有理解javah的用法造成的。可以采用以下兩種方法:

方法1: ? cd到 ? ? ? E:\shijue\JniHello\app\src\main

然后輸入 ? ? ?javah?-d jni?-classpath I:\Andriod\AndroidSDK\platforms\android-15\android.jar;

E:\shijue\JniHello\app\build\intermediates\classes\debug com.example.machenike_pc.jnihello.MainActivity

說明:javah是生成頭文件的命令,深綠色為生成文件夾jni,紫紅色為android.jar所在的位置,淺綠色為class文件的路徑+類全名(路徑最后一個文件夾是debug之后空格+類全名)

(這里補充下-classpath的含義:javah操作是針對類文件,-bootclasspath和-classpath就是指定在哪里進行類文件搜索。JDK搜索類文件先后順序如下:Bootstrap classes,User classes。Bootstrap默認的是JDK自帶的jar或zip文件,它包括jre\lib下rt.jar等文件,JDK首先搜索這些文件.可以通過-bootclasspath來設(shè)置它。文件之間用分號";"進行分割。User classes搜索順序為當前目錄、環(huán)境變量CLASSPATH、-classpath。它們用于告知JDK搜索類文件根目錄名、jar文檔名、zip文檔名,用分號";"進行分隔。)

方法2:? ?cd到E:\shijue\JniHello\app\build\intermediates\classes\debug目錄下,直接javah -d jni com.example.machnike_pc.jnihello.MainActivity 即可

3. 在生成的jni目錄下寫一個c或者c++文件,文件名隨意,實現(xiàn)本地方法 ,之后需要在該路徑下再加一個空的cpp或c文件(估計是軟件的bug,不加的話很可能出ndk錯誤),比如我加了個util.cpp的文件,里面什么都不寫。

?下面是我的c++文件代碼

#include#include#include#ifdef __cplusplus

extern "C" {

#endif

JNIEXPORT jint JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_sayhello

? (JNIEnv *, jobject, jint);

JNIEXPORT jstring JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_returnString

? (JNIEnv *, jobject);

#ifdef __cplusplus

}

#endif

JNIEXPORT jint JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_sayhello

? ? (JNIEnv * env, jobject jobj, jint jnumber)

? ? {

? ? ? ? intmodify=jnumber+1;

? ? ? ? return modify;

? ? }

JNIEXPORT jstring JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_returnString

? ? (JNIEnv *env, jobject jobj)

? ? {

? ? ? returnenv->NewStringUTF("I'm comes from to Native Function!");

}

4,如果ndk版本不是最新的,需要在gradle.properties文件下加入:

android.useDeprecatedNdk=true ?


5,配置ndk路徑,這里也可以在AS的設(shè)置里面配置。我采用的方法是在local.properties文件最后一行加入:

ndk.dir=I\:\\Andriod\\NDK\\android-ndk-r10b


6,build.gradle(app下):文件下加入:(defaultconfig里面)

ndk{

moduleName "nativeTest"

}

此時運行程序已經(jīng)可以實現(xiàn)本地方法了,之后可以再生成so庫文件,方便使用。


二,生成.so動態(tài)庫

(這里說一下,貌似Android studio已經(jīng)寫好了.mk文件,上面的步驟完成后,直接rebuild一下就自動生成為了.so動態(tài)庫,下面的方法也能生成,可以看一下,很有用)

1,在jni文件夾下新建Android.mk文件,寫入以下內(nèi)容:

LOCAL_PATH := $(call my-dir)? ? ? ? ? //固定寫法,把路徑賦給LOCAL_PATH變量

include $(CLEAR_VARS)? ? ? ? ? ? ? ? ? //清除其他LOCAL變量

LOCAL_MODULE := nativeTest? ? ? ? ? ? //這個模塊的名字,最后生成的.so的名字就是它,要跟java里面的loadLibray的名字一樣。

LOCAL_SRC_FILES := nativeTest.cpp\? ? //這里是要編譯的文件,\ 符號是換行

          ? util.cpp

include $(BUILD_SHARED_LIBRARY)? ? ? ? //SHARED_LIBRARY就是動態(tài)庫,即.so文件

?這里的寫法是最簡單的一個例子,用的時候把注釋去掉。每一行都是很關(guān)鍵,不能省略。至于makefile怎么編寫內(nèi)容比較多,此處不贅述。

2,在工程根目錄下新建application.make文件,寫入以下內(nèi)容:

APP_PROJECT_PATH := $(call my-dir)

APP_MODULES := nativeTest

3,在命令行下,cd到j(luò)ni目錄(就是之前javah -d jni生成的那個文件夾)下,輸入指令: ndk-build,等一會即可生成.so文件。位于lib目錄下,將其放到app/src/main/jniLibs目錄下就能用了。


FAQ:

1,生成的so文件在使用時需要注意:包名不能變,拿上文舉例,本地方法位于com_example_machenike_pc_jnitest2_MainActivity這個類下,如果在別的地方用,需要完整的建立這個包名和類。

2,c和cpp文件均可以用來寫jni,寫法上略有不同。

3,需要注意java里面成員方法和靜態(tài)方法通過javah生成的頭文件略有不同,一個參數(shù)是jclass,另一個是jobject。

4,不用javah生成頭文件也行,推薦第一次寫的時候用javah生成,后面修改的時候(比如參數(shù)改變)可以直接在c文件里手動修改。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容