Android studio 下JNI編程實(shí)例并生成so庫的實(shí)現(xiàn)代碼
最近需要使用JNI編程,學(xué)了下JNI,并且在Android Studio下實(shí)現(xiàn)了一個(gè)小demo。這期間有一些坑,還好都解決了,想分享出來,希望大家少走彎路。本文中采用的平臺(tái)是Windows,NDK環(huán)境已經(jīng)搭建好,這方面資料很多,大家可以自行百度。
本文分為兩個(gè)部分:
1.如何通過編寫Jni實(shí)現(xiàn)native方法的調(diào)用。
2.怎樣生成.so動(dòng)態(tài)庫提供給第三方使用。
以下是正文:
一,編寫jni文件,實(shí)現(xiàn)本地方法
1,建立一個(gè)新工程,只有一個(gè)MainActivity,里面加載庫文件并且調(diào)用若干本地方法,然后通過Android Studio里的build-makeProject生成class文件。
public class MainActivity extends Activity { private final String TAG = "JNITEST" @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String s=returnString(); Log.d(TAG,s); int a=1000; Log.d(TAG,sayhello(a)); } //加載jni static { System.loadLibrary("nativeTest"); } //聲明native方法 private native int sayhello(int t); private native String returnString(); }
2,生成.h頭文件,里面有Android工程里本地方法的聲明。這個(gè)文件可以自己寫,但是推薦用javah自動(dòng)生成。生成方法為:在控制臺(tái)或者Android studio自帶的控制臺(tái)使用javah命令將上一步make之后生成的class文件生成.h頭文件,這里在用javah的時(shí)候有可能會(huì)出問題,比如我第一次就出現(xiàn)了找不到app.activity ,即找不到類文件,這種問題一般是沒有理解javah的用法造成的。我當(dāng)時(shí)采用以下兩種方法:
方法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文件的路徑+類全名(路徑最后一個(gè)文件夾是debug之后空格+類全名)
(這里補(bǔ)充下-classpath的含義:javah操作是針對類文件,-bootclasspath和-classpath就是指定在哪里進(jìn)行類文件搜索。JDK搜索類文件先后順序如下:Bootstrap classes,User classes。Bootstrap默認(rèn)的是JDK自帶的jar或zip文件,它包括jre\lib下rt.jar等文件,JDK首先搜索這些文件.可以通過-bootclasspath來設(shè)置它。文件之間用分號(hào)";"進(jìn)行分割。User classes搜索順序?yàn)楫?dāng)前目錄、環(huán)境變量 CLASSPATH、-classpath。它們用于告知JDK搜索類文件根目錄名、jar文檔名、zip文檔名,用分號(hào)";"進(jìn)行分隔。)
方法2: cd到E:\shijue\JniHello\app\build\intermediates\classes\debug目錄下,直接javah -d jni com.example.machnike_pc.jnihello.MainActivity 即可
3,在生成的jni目錄下寫一個(gè)c或者c++文件,文件名隨意,實(shí)現(xiàn)本地方法 ,之后需要在該路徑下再加一個(gè)空的cpp或c文件(估計(jì)是軟件的bug,不加的話很可能出ndk錯(cuò)誤),比如我加了個(gè)util.cpp的文件,里面什么都不寫。
下面是我的c++代碼
#include<jni.h> #include<stdio.h> #include<com_example_machenike_pc_jnitest2_MainActivity.h> #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) { int modify=jnumber+1; return modify; } JNIEXPORT jstring JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_returnString (JNIEnv *env, jobject jobj) { return env->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"
}
此時(shí)運(yùn)行程序已經(jīng)可以實(shí)現(xiàn)本地方法了,之后可以再生成so庫文件,方便使用。
二,生成.so動(dòng)態(tài)庫
(這里說一下,貌似Android studio已經(jīng)寫好了.mk文件,上面的步驟完成后,直接rebuild一下就自動(dòng)生成為了.so動(dòng)態(tài)庫,下面的方法也能生成,可以看一下,很有用)
1,在jni文件夾下新建Android.mk文件,寫入以下內(nèi)容:
LOCAL_PATH := $(call my-dir) //固定寫法,把路徑賦給LOCAL_PATH變量
include $(CLEAR_VARS) //清除其他LOCAL變量
LOCAL_MODULE := nativeTest //這個(gè)模塊的名字,最后生成的.so的名字就是它,要跟java里面的loadLibray的名字一樣。
LOCAL_SRC_FILES := nativeTest.cpp\ //這里是要編譯的文件,\ 符號(hào)是換行
util.cpp
include $(BUILD_SHARED_LIBRARY) //SHARED_LIBRARY就是動(dòng)態(tài)庫,即.so文件
這里的寫法是最簡單的一個(gè)例子,用的時(shí)候把注釋去掉。每一行都是很關(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生成的那個(gè)文件夾)下,輸入指令: ndk-build,等一會(huì)即可生成.so文件。位于lib目錄下,將其放到app/src/main/jniLibs目錄下就能用了。
FAQ:
1,生成的so文件在使用時(shí)需要注意:包名不能變,拿上文舉例,本地方法位于com_example_machenike_pc_jnitest2_MainActivity這個(gè)類下,如果在別的地方用,需要完整的建立這個(gè)包名和類。
2,c和cpp文件均可以用來寫jni,寫法上略有不同。
3,需要注意java里面成員方法和靜態(tài)方法通過javah生成的頭文件略有不同,一個(gè)參數(shù)是jclass,另一個(gè)是jobject。
4,不用javah生成頭文件也行,推薦第一次寫的時(shí)候用javah生成,后面修改的時(shí)候(比如參數(shù)改變)可以直接在c文件里手動(dòng)修改。
補(bǔ)充:
SourcePath: D:\work\androidstudio\VisualRecognition\app\src\main\java (絕對路徑)
TargetPath: D:\work\androidstudio\VisualRecognition\visual\src\main\jni (絕對路徑)
TargetClassName: com.yf.visualrecognition.UnityPlayerActivity (你的包名+類名)
格式: javah -d ${SourceFile} -classpath ${TargetPath} ${TargetClassName}
生成.h文件:javah -d E:\AndroidProject\GitHubProject\OpenCV\OpenCV\app\src\main\jni -classpath E:\AndroidProject\GitHubProject\OpenCV\OpenCV\app\src\main\java com.cosco.opencv.OpenCVHelper
相關(guān)文章
APP添加CNZZ統(tǒng)計(jì)插件教程 Android版添加phonegap
這篇文章主要介紹了APP添加CNZZ統(tǒng)計(jì)插件教程,Android版添加phonegap,感興趣的小伙伴們可以參考一下2015-12-12Matrix的set,pre,post調(diào)用順序詳解
下面小編就為大家?guī)硪黄狹atrix的set,pre,post調(diào)用順序詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04Android實(shí)現(xiàn)短信驗(yàn)證碼自動(dòng)攔截讀取功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)短信驗(yàn)證碼自動(dòng)攔截讀取功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08Android 定位系統(tǒng)(GPS)開發(fā)詳解
GPS定位是智能手機(jī)上一個(gè)比較有意思的功能,LBS等服務(wù)都有效的利用了GPS定位功能,本文就跟大家分享下Android開發(fā)中的GPS定位知識(shí)2016-07-07Ubuntu中為Android系統(tǒng)上編寫Linux內(nèi)核驅(qū)動(dòng)程序?qū)崿F(xiàn)方法
本文主要介紹在Ubuntu 上為Android系統(tǒng)編寫Linux內(nèi)核驅(qū)動(dòng)程序, 這里對編寫驅(qū)動(dòng)程序做了詳細(xì)的說明,對研究Android源碼和HAL都有巨大的幫助,有需要的小伙伴可以參考下2016-08-08Android手勢滑動(dòng)實(shí)現(xiàn)ImageView縮放圖片大小
這篇文章主要為大家詳細(xì)介紹了Android手勢滑動(dòng)實(shí)現(xiàn)ImageView縮放圖片大小的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-02-02Android開發(fā)之sqlite3命令行簡單使用方法
這篇文章主要介紹了Android開發(fā)之sqlite3命令行簡單使用方法,分析了Android增刪改查等常用sqlite3的數(shù)據(jù)庫操作命令使用方法,需要的朋友可以參考下2016-02-02Android通過LIstView顯示文件列表的兩種方法介紹
過ListView顯示SD卡中的文件列表一共有兩種方法,一是:通過繼承ListActivity顯示;二是:利用BaseAdapter顯示,具體實(shí)現(xiàn)如下,感興趣的朋友可以參考下哈2013-06-06Android應(yīng)用的多語言支持的實(shí)現(xiàn)方法
本篇文章主要介紹了Android應(yīng)用的多語言支持的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06