1. 程式人生 > >NDK實戰教程(一) 在Android Studio執行第一個NDK程式

NDK實戰教程(一) 在Android Studio執行第一個NDK程式

1、新建一個Android工程,這一步就不多說了;

2、在AndroidStudio中配置NDK路徑,方法是:

(1)先下載NDK並安裝(這句基本是廢話);

(2)點選單欄的File->ProjectStructure…->在開啟的視窗中左側選中SDKLocation->在右側Android NDK Location中填入NDK目錄所在路徑,如下圖所示:

  

3、編譯生成.class檔案,方法是:

點選單欄的Build->Make Project,如下圖所示;

        這時,在工程的app/build/intermediates下就會生成classes資料夾,開啟classes目錄下的debug目錄就會看到以你的包名命名的各級資料夾,最裡邊資料夾下有你的Java類對應的.class檔案;

然後:

在AS中新建一個Project,然後再新建一個class為NdkJniUtils,在內部宣告native方法(jni使用的定義,後面系列教程會細說)。

package io.github.yanbober.ndkapplication;

public class NdkJniUtils {
    public native String getCLanguageString();
}

在工程主檔案Activity中寫入如下程式碼調運JNI的東西顯示在UI上。

public class MainActivity extends ActionBarActivity {
    private
TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) this.findViewById(R.id.test); NdkJniUtils jni = new NdkJniUtils(); mTextView.setText(jni.getCLanguageString()); } }

然後Mark project得到其中中間檔案,我們關注的是.class檔案。編譯OK以後生成的class檔案在AS工程的如下目錄:

NDKApplication\app\build\intermediates\classes\debug

然後接下來的步驟就是根據生成的class檔案,利用javah生成對應的 .h標頭檔案。

點開AS的Terminal標籤,預設進入到該專案的app資料夾下。我在windows平臺下輸入如下命令跳轉到class中間檔案生成路徑:

xxxxx\app> cd build\intermediates\classes\debug

然後執行如下javah命令生成h檔案。

xxxxx\debug> javah -jni io.github.yanbober.ndkapplication.NdkJniUtils

執行完之後你可以在資料夾NDKApplication\app\build\intermediates\classes\debug下看見生成的 .h標頭檔案為:

io_github_yanbober_ndkapplication_NdkJniUtils.h
 

其內容為:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class io_github_yanbober_ndkapplication_NdkJniUtils */

#ifndef _Included_io_github_yanbober_ndkapplication_NdkJniUtils
#define _Included_io_github_yanbober_ndkapplication_NdkJniUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     io_github_yanbober_ndkapplication_NdkJniUtils
 * Method:    getCLanguageString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_io_github_yanbober_ndkapplication_NdkJniUtils_getCLanguageString
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

在工程的main目錄下新建一個名字為jni的目錄,然後將剛才的 .h檔案剪下過來。在jni目錄下新建一個c檔案,隨意取名,我的叫jnitest.c 。然後編輯程式碼如下(後面會解釋啥意思,這裡重在工具使用):

#include "io_github_yanbober_ndkapplication_NdkJniUtils.h"
/*
 * Class:     io_github_yanbober_ndkapplication_NdkJniUtils
 * Method:    getCLanguageString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_io_github_yanbober_ndkapplication_NdkJniUtils_getCLanguageString
  (JNIEnv *env, jobject obj){
     return (*env)->NewStringUTF(env,"This just a test for Android Studio NDK JNI developer!");
  }

接下來在工程的local.properties檔案中新增NDK路徑(上面下載好的那個NDK),類似其中的SDK路徑一樣,我的新增後如下:

sdk.dir=D\:\\AndroidStdioSDK\\sdk
#add by 工匠若水
ndk.dir=D\:\\AndroidStdioSDK\\android-ndk-r10d-64bit

接下來在app module目錄下的build.gradle中設定庫檔名(生成的so檔名)。找到gradle檔案的defaultConfig這項,在裡面新增如下內容:

defaultConfig {
    ......
    ndk{
        moduleName "YanboberJniLibName"         //生成的so名字
        abiFilters "armeabi", "armeabi-v7a", "x86"  //輸出指定三種abi體系結構下的so庫。目前可有可無。
    }
}

現在生成的so庫名字也有了,那就去程式碼的NdkJniUtils java檔案新增靜態初始化load程式碼,新增如下:

static {
        System.loadLibrary("YanboberJniLibName");   //defaultConfig.ndk.moduleName
    }

好了,到此AS下NDK JNI開發的程式碼編寫和設定就OK了,接下來就是編譯工程執行就可以了。

在gradle.properties檔案中增加

android.useDeprecatedNdk=true

在這裡需要特別注意一點的是:

標頭檔案中函式宣告引數列表中只有引數型別,沒有引數名。一般我們在.c檔案中實現該方法時,很多時候是直接拷貝該函式到.c檔案中寫函式體,但是卻忽略了實現函式時給該函式的引數列表中的引數寫個臨時的引數名。只要實現時加上引數名就行了: