首先洁奈,我把Windows下NDK開編寫JNI的流程說一下,在整個流程中著重點出里面的一些坑绞灼,以免其他開發(fā)者步我后塵利术。
1、NDK環(huán)境搭建
這個就不在這里說了镀赌,不是重點氯哮,大家自行g(shù)oogle、百度商佛。
2喉钢、JNI開發(fā)
1)創(chuàng)建Android項目。
2)查看項目local.properties中加入ndk和sdk的路徑是否正確
ndk.dir=/Users/userName/AndroidStudioProjects/ndk/android-ndk-r13b
sdk.dir=/Users/userName/Library/Android/sdk
3)配置項目下的gradle.properties文件良姆,表示我們要使用NDK進行開發(fā)肠虽。
android.useDeprecatedNdk=true
4)在moudle根目錄下的的build.gradle中的defaultConfig標(biāo)簽內(nèi)部里加入如下代碼
ndk{
moduleName "secret" //生成的so文件名字,跟System.loadLibrary("secret"); 中的名字相對應(yīng)
abiFilters "armeabi", "armeabi-v7a", "x86" //輸出指定三種平臺下的so庫,
// 還可以添加 'x86_64', 'mips', 'mips64'
}
5)編寫jni代碼
package com.david.ndktest;
-
public class MainActivity extends AppCompatActivity {
//使用靜態(tài)代碼塊玛追,表示我們要加載的資源文件為libsecret.so
static {
System.loadLibrary("secret");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv_msg = (TextView) findViewById(R.id.tv_msg);
tv_msg.setText(stringFromat());
}
//聲明一個本地方法税课,用native關(guān)鍵字修飾
public native String stringFromat();
}
6)生成.h頭文件
直接使用Android Studio 底部的Terminal,默認(rèn)命令行窗口路徑已經(jīng)在當(dāng)前項目痊剖,進入到app/src/main/java目錄韩玩,輸入以下命令(固定格式:javah -jni 包名+類名),這個一般的博客網(wǎng)站告訴我們的命令
javah -jni com.david.ndktest.MainActivity
好了陆馁,這里存在幾個坑找颓,首先第一個坑
1、Terminal提示 錯誤:找不到‘com.david.ndktest.MainActivity’類文件
原因:java沒有包含 Android SDK中的 java 文件
解決辦法:
找到Android sdk目錄叮贩,找到platforms文件夾击狮,進入“android-20”(或者其他版本也行)佛析,然后找到 “android.jar” 文件,將其添加到計算機環(huán)境變量的 CLASSPATH 中彪蓬。重啟一下Terminal或者AndroidStudio
再次執(zhí)行“javah -jni com.david.ndktest.MainActivity”寸莫,好了這里又出了一個小坑
2、Terminal提示 錯誤:編碼GBK的不可映射字符
原因:由于JDK是國際版的档冬,在編譯的時候膘茎,如果我們沒有用-encoding參數(shù)指定我們的JAVA源程序的編碼格式,則javac.exe首先獲得我們操作系統(tǒng)默認(rèn)采用的編碼格式捣郊。
解決辦法:應(yīng)該使用-encoding參數(shù)指明編碼方式辽狈,如:javah -jni -encoding UTF-8 com.david.ndktest.MainActivity
好了,以上兩個坑解決掉了呛牲,再次執(zhí)行命令javah -jni -encoding UTF-8 com.david.ndktest.MainActivity 這次Terminal沒有任何輸出,說明我們已經(jīng)成功的在java文件夾下生成了com.david.ndktest.MainActivity.h頭文件驮配,如下:
我們把頭文件名字改成secret.c(一定要改成.c文件才能編譯), Build ->Build Project 一下工程娘扩,但是問題來了,我們并沒有在項目的build\intermediates\目錄下看到ndk文件夾壮锻,說明編譯之后沒有生成相應(yīng)的so庫琐旁,這是第三個坑
3、原因:secret.c文件在java文件夾下都是java源代碼猜绣,AndroidStudio無法識別其中的c文件灰殴,自然不會去編譯。
解決辦法:將命令:javah -jni -encoding UTF-8 com.david.ndktest.MainActivity 改成
javah -jni -d ../jni -encoding UTF-8 com.david.ndktest.MainActivity 這樣就會在java目錄的上一級main目錄下自動生成jin文件夾掰邢,并將生成的頭文件放到里面牺陶。
好了,我們在執(zhí)行一下命令辣之,然后把jni文件夾下生成的文件的文件名改成secret.c掰伸,再Build ->Build Project 一下,在build\intermediates\ndk文件夾下看到了打包好的so庫怀估,好了狮鸭,到這里終于松了一口氣。
7)如果6)無法進行多搀,可以直接從其他地方復(fù)制頭文件進來歧蕉,或者自己根據(jù)格式寫一個.c的文件,放到src/main/jni目錄下;
如遇到編譯錯誤康铭,如下:
解決辦法:
加上紅線標(biāo)記的代碼即可惯退,因為jni每次運行都會在build\intermediates\ndk中自動編譯生成一個Android.mk文件,這樣我們之前在jni中手動編譯的Android.mk就沒有作用了麻削,加上這句后就不會自動編譯了蒸痹,用的是我們自己的mk文件春弥。
8)在secret.c文件里實現(xiàn)stringFormat方法如下:
9)編譯C/C++文件,輸出 .so文件(第六步無法生成so文件條件下叠荠,采用如下方式)
1匿沛、cd命令進入創(chuàng)建的jni文件夾下;
2、執(zhí)行ndk-build命令
若出現(xiàn)如下圖所示錯誤:
解決辦法:
在build\intermediates\ndk\debug目錄下找到Android.mk文件榛鼎,將其復(fù)制黏貼到src\main\jni文件加下逃呼,再次執(zhí)行ndk-build即可自動生成so文件,可在src\mian\libs目錄下查看者娱。
運行該工程抡笼,OK,native方法調(diào)用成功黄鳍,效果如下:
注意:
1推姻、build.gradle 里面的moduleName "xxx" 跟System.loadLibrary("xxx");的名字要對應(yīng)起來,但是c文件的名字可以自定義框沟,不一定要一樣藏古。
2、相關(guān)參考資料來自
http://blog.csdn.net/qq_36788768/article/details/59487103
http://www.2cto.com/kf/201706/648968.html忍燥。