- 編寫native 方法的 Java類別
- 將 Java 源代碼編譯成 class 字節碼文件
- 用 javah -jni 命令生成.h頭文件(javah 是 jdk 自帶的一個命令,-jni 參數表示將 class 中用native 聲明的函數生成 JNI 規則的函數)
- 用本地代碼實現.h HEAD文件中的函數
- 將本地代碼編譯成動態庫(Windows:\*.dll,linux/unix:\*.so,mac os x:\*.jnilib)
- 拷貝動態庫至 java.library.path 本地庫搜索目錄下,並運行 Java 程序
Android Studio環境下載與安裝
解壓縮到指定目錄
Ex: D \android-ndk-r13b
接下來設定 File->Project Structure
-------以上完成基本的環境設定-------
接下來設定External Tools
File->Settings 裡面 Tools-->External Tools
因為我已經透過 Add按鈕已經增加了三個會用到的指令,所以我是用鉛筆符號Edit做修改
1.javah設定
以下提供複製直接貼上去 注意 這些路徑都是右上左下的斜線
快速複製區
$JDKPath$/bin/javah.exe
-v -jni -d $ModuleFileDir$/src/main/jni $FileClass$
$SourcepathEntry$
簡單解說: $JDKPath$是環境變數,該行會自動取得你電腦裡面JDK的javah檔案路徑 參數為的是命令提示字元 下 javah OOOXXX的OOOXXX的內容
主旨就是路徑在Android 專案的src\main\jni下的資源來執行javah的動作
如果有疑問,可以按後面的按鈕 "Insert macro"來查看目前電腦裡環境變數相對應產生的結果
2.NDKBuild設定
快速複製區
D:\android-ndk-r10e\ndk-build.cmd
NDK_PROJECT_PATH=$ModuleFileDir$/build/intermediates/ndk
NDK_LIBS_OUT=$ModuleFileDir$/src/main/jniLibs
NDK_APPLICATION_MK=$ModuleFileDir$/src/main/jni/Application.mk
APP_BUILD_SCRIPT=$ModuleFileDir$/src/main/jni/Android.mk V=1
$ProjectFileDir$
簡單解說:第一行就是指定NDK目錄裡的build.cmd檔案
第二第三行是同一個欄位,因為太長自動分行
重點是 NDK產生的結果會於src/main/jniLibs裡面XX.so的一些檔案
其他的路徑是因人而異,不過 src/main/jni/Application.mk src/main/jni/Android.mk 這兩個必要檔案等一下因為實作關係一定會放在這個路徑裡面,所以就這樣定。
開始針對程式碼實作
1.設定JNI相關資源
產生JNI資料夾於src\main\jni
直接按下finish
2.針對app的Gradle做整體設定
快速複製區
ndk{
moduleName "myJNI"
}
sourceSets.main{
jni.srcDirs=[]
jniLibs.srcDir "src/main/jniLibs"
}
解說:加入ndk路徑,也針對等一下NDK編譯書來的路徑指定出來 按下Sync 會產生編譯錯,系統會建議你加入另一個NDK相關的指令,馬上到下一步修正去.....
3.修正gradle.properties的錯誤
補上以下這行,錯誤就可以修正完畢
android.useDeprecatedNdk=true
4.產生JNI檔案
接著於程式碼中 新增Java Class檔案 檔名我是使用myNDK快速複製區
static {
System.loadLibrary("myJNI");
}
public native String getMycstring();
解說:有產生一個相對應的C語法資源,檔名是myJNI,裡面有可以呼叫的方法叫做getMycstring()
5.產生Header檔案(必須由Javah自動產生比較簡單,盡量不要自己手動建置一個新檔案來產生檔案上按下 右鍵--->external tools-->javah(我的命名)
接著Android Studio內的Terminal會被開啟,執行產生C語言HEAD檔案的步驟,
成功的話會向下圖一樣,就會於jni資料夾中產生一個根據我的Project Name產生的一個HEAD檔
建議檔名不要去動他....
如果有錯誤與失敗,HEAD檔案不會產生,那就要檢查第二個步驟中,External tools 裡的javah內的路徑是不是符合你的電腦環境
產生完成後,檢查一下HEAD內容
自動產生的內容裡面,他會將你的project name
譬如我的範例是:com.example.cheng.testndk
供android java 呼叫的java class 檔名是myNDK,會呼叫到的C方法是getMycstring
所以他會將JAVA的設定全部結合在這個HEAD中,所以我強烈建議由javah自動去產生
6.產生C/C++的原始碼檔
在jni資料夾上右鍵--> new --> c/c++ source file
產生的小視窗,記得把create associated header取消,只產生source檔案
產生之後,就是開始編寫C的內容
首先 先include剛剛自動產生的HEAD檔,因為檔名有長,可以用Copy Path的方式取得
之後方法的初始化,請打開剛剛的HEAD檔,複製其內容後貼來
快速複製區
myJNI.cpp
//
// Created by Cheng on 2016/11/22.
//
#include"com_example_cheng_testndk_myNDK.h"
JNIEXPORT jstring JNICALL Java_com_example_cheng_testndk_myNDK_getMycstring
(JNIEnv * evn, jobject obj)
{
return (*evn).NewStringUTF("Hello NKD demo");
}
7.產生2個MK檔
在jni資料夾上按下右鍵,新增兩個純檔案,第一個Android.mk,第二個是Application.mk
接著是兩個檔案裡面的內容 解說:
LOCAL_MODULE := myJNI
LOCAL_SRC_FILES := myJNI.cpp
第一個模組名稱,必須跟build.gradle裡面的moduleName相同
也跟JAVA程式裡面,myNDK class裡面 System.loadLibrary("myJNI")相同
SCR_FILES的名稱則是真正C語言的原始碼名稱
快速複製區
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := myJNI
LOCAL_SRC_FILES := myJNI.cpp
include $(BUILD_SHARED_LIBRARY)
快速複製區Application.mk
APP_ABI := all
最後 就是真正執行一次C的編譯
請到JNI資料夾按右鍵-->External Tools-->ndkbuild
如果成功,就會向下圖出現一堆編譯順序,之後會寫藍色的字,表示完成。
最後檢查一下編譯產生的XXX.so檔案,是不是有依照各種手機CPU類型編譯在不同的資料夾中
MainActivity.java code
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textTX=(TextView)findViewById(R.id.textTX);
TextView textView3 = (TextView)findViewById(R.id.textView3);
myNDK testNDK=new myNDK();
int a = testNDK.getMyint();
textTX.setText(testNDK.getMycstring());
String s = Integer.toString(a);
textView3.setText(s);
}
}
Reference: http://blog.xuite.net/lwchafter30/blog/373974237-Android+studio+1.5.1+NDK+JNI%E7%92%B0%E5%A2%83%E5%AE%89%E8%A3%9D%E8%88%87%E5%9F%B7%E8%A1%8C%E5%8E%9F%E7%90%86
https://www.youtube.com/watch?v=RmPuwdxR1qs


















No comments:
Post a Comment