1. 程式人生 > >AndroidStudio如何配置NDK/JNI開發環境

AndroidStudio如何配置NDK/JNI開發環境

參考文章:

http://www.th7.cn/Program/Android/201509/550864.shtml

http://www.open-open.com/lib/view/open1451917048573.html

http://blog.csdn.net/sodino/article/details/41946607

http://www.codes51.com/article/detail_197383.html

        AndroidStudio沒有像Eclipse那樣的一鍵add native support,相對來說比較麻煩,下面就介紹在AndroidStudio中如何實現類似於Eclipse的add native support功能(也就是進行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檔案;

4、確定你要引用本地方法的類:

        其實你也可以先生成jni目錄,再去建立這個類,但是先Google顯然建議先建立要引用C程式碼的Java類,因為AndroidStudio可以根據你在java類中定義的native方法的名稱來自動生成.h標頭檔案。

        比如你想在MainActivity中引用本地方法,那麼你先用

static {

        System.loadLibrary("myNativeLib");

}

來宣告原生代碼庫,然後定義幾個natvie方法,比如

public native String getStringFromNative();

做完這些工作就可以進行下一步了。

5、使用javah命令列生成jni目錄及對應的標頭檔案:

        我用的是AndroidStudio 2.1.1,在主介面最下邊就能找到Terminal,點一下就能開啟系統的命令列工具,並且已經為你自動cd到當前工程所在目錄,如下圖所示:


如上圖所示,開啟命令列編輯工具後,cd到工程的src/main/java目錄,輸入

     javah -d ../jni 你的包名.引用本地方法的類的名稱

javah意思是生成一個.h標頭檔案,-d ../jni的意思是生成一個名字叫做jni的資料夾(directory),位置是在當前目錄(src/main/java)的上一級目錄(即src/main目錄);比如我的工程下,這條命令是

     javah -d ../jni com.example.lixinyu.myapplication2.MainActivity

我直接用了MainActivity類做為呼叫JNI的Java類,你也可以寫一個自己的類,之後就等吧,構建完成後就會在工程的src/main目錄下生成一個jni目錄,下邊還包含.h標頭檔案,如下圖所示:

        如果你事先在java程式碼中定義了native方法,那麼這裡還會自動生成方法對應的.h標頭檔案。當然,要執行javah命令的前提是你的電腦已經安裝過java,並且已經配置了java環境變數。

        這裡再多說幾句,很多網友說要使用javah -d jni -classpath命令來構建jni目錄並生成.h標頭檔案,但是我親測是不行的,會報bash: ../../build/intermediates/classes/debug:is a directory錯誤,大概是版本不同吧,感謝碼蟻之家的網友提供的不一樣的答案。

        至此,我們就基本完成了相當於Eclipse中的add native support功能了,接下來還要配置gradle和一大堆其它的配置檔案;

6、配置build.gradle檔案

這裡的build.gradle是指app模組下的build.gradle,不是整個工程的build.gradle檔案。在模組的build.gradle的defaultConfig下加入以下idk配置:

ndk {

      moduleName"myNativeLib"

ldLibs "log""z""m"

abiFilters "armeabi""armeabi-v7a""x86"

}

其中moduleName是隨便寫的,與將來在Java類中使用System.loadLobrary(“本地庫名稱”);以及生成的.so檔名稱對應;

ldLibs是要用到的jni庫,一般由google提供,比如上邊引入的log庫可以讓我們在C程式碼中使用LogCat日誌;

abiFilters指的是我們要生成哪些平臺的so檔案,這裡生成arm平臺和x86平臺;

配置後的build.gradle檔案如下圖所示:

        至此build.gradle檔案就配置完了,其實這一步有點像我們eclipse中配置.mk檔案;

7、配置local.properties檔案

        開啟工程目錄下的local.properties,感覺這一步是自動配置的,或者說在你一開始在AndroidStudio中指定NDK目錄時已經自動生成了。我的AndroidStudio在開啟local.properties已經有了

ndk.dir=/Develop/Android/android-ndk-r10e

這一行,所以就不用配了;

8、配置gradle.properties

        開啟工程目錄下的gradle.properties檔案(注意不是build.gradle,而是gradle.properties),在檔案的最後一行加入

android.useDeprecatedNdk=true

這句的作用是允許我們使用已經過時的NDK版本,不知道AndroidStudio要求使用哪個版本的NDK才不會報錯,總之只要配置了這一句就可以使用比較舊的NDK版本了,我用的r10;

        至此我們在AndroidStudio中就完成了NDK環境的配置,接下來就可以寫Native程式碼了;

9、寫一個.c檔案測試一下是否執行正常

(1)在我們之前生成src/main/jni目錄下新建一個.c檔案,方法是在jni資料夾上點滑鼠右鍵,選擇New->C/C++ Source File,然後在彈出的對話方塊中填入.c或.cpp檔案的檔名就可以了,比如說mail.c,名字可以隨便起;

(2)在main.c中隨便寫一段JNI程式碼,比如如下所示的一段程式碼:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

#include <android/log.h>

#ifndef LOG_TAG

#define LOG_TAG"ANDROID_LAB"

#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

#endif

/* Header for class lab_sodino_jnitest_MainActivity */

#ifndef _Included_com_example_lixinyu_myapplication2_MainActivity

#define _Included_com_example_lixinyu_myapplication2_MainActivity

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:lab_sodino_jnitest_MainActivity

 * Method: getStringFromNative

 * Signature: ()Ljava/lang/String;

 */

JNIEXPORT jstringJNICALL Java_com_example_lixinyu_myapplication2_MainActivity_getStringFromNative

  (JNIEnv *env, jobject jObj){

      LOGE("log string from ndk.");

      return (*env)->NewStringUTF(env,"HelloFrom JNI!");

  }

#ifdef __cplusplus

}

#endif

#endif

JNI基礎就不多說了;

(3)在Java中呼叫:

比如我在MainActivity中加入以下程式碼:

package com.example.lixinyu.myapplication2;

import android.os.Bundle;

import android.support.v4.app.FragmentActivity;

import android.widget.TextView;

public class MainActivityextends FragmentActivity {

    private TextViewmTextView;

    static {

        System.loadLibrary("myNativeLib");

    }

    publicnative String getStringFromNative();

    @Override

protected voidonCreate(BundlesavedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        mTextView= (TextView) findViewById(R.id.main_textview);

        mTextView.setText(getStringFromNative()+"");

    }

}

       至此NDK/JNI程式碼就算是完成了,可以再次點選單欄的Build->Make Project編譯一下工程,看看在工程目錄下app/build/intermediates/ndk/debug/lib目錄下是否成功生成了相應的.so檔案,如果以上配置都正確的話這裡是會生成對應平臺的.so檔案的,debug目錄下還自動生成了Android.mk檔案,這個確實還不錯,相當於我們用build.gradle檔案的配置替代了Android.mk檔案的配置,執行一下,正常的話是可以執行的,至此就算是在AndroidStudio中配置了NDK/JNI開發環境。