使用Android Studio 進行NDK開發(fā)和調(diào)試

盡管Android Studio已經(jīng)越來越流行了,但很多人還是習(xí)慣于Eclipse或源碼環(huán)境下開發(fā)JNI應(yīng)用。個人認為使用Android Studio作NDK開發(fā)是必然趨勢,所以本文將簡單介紹如何在Android Studio上實現(xiàn)NDK開發(fā)。

簡介

JNI

JNI 是Java Native Inteface的縮寫,是Java中定義的一種用于連接Java和C/C++接口的一種實現(xiàn)方式。

NDK

NDK 是 Native Developmentit的縮寫,是Google在Android開發(fā)中提供的一套用于快速創(chuàng)建native工程的一個工具。
使用這個工具可以很方便的編寫和調(diào)試JNI的代碼。

NDK可從官網(wǎng)AndroidDevTools(個人網(wǎng)站)下載。

Gradle

Gradle 是一個基于Apache Ant和Apache Maven概念的項目自動化建構(gòu)工具。它使用一種基于Groovy的特定領(lǐng)域語言(DSL)來聲明項目設(shè)置。

以往Android NDK開發(fā)需要在Eclipse或源碼環(huán)境下,建立并配置Android.mk和Application.mk,且還要通過java命令生成.h頭文件,才能編譯生成so庫。但在Android Studio中這些步驟都不需要,因為Gradle足夠強大,只需配置Gradle即可編譯生成so庫。

gradle-experimental插件

在2015年5月的Google I/O大會上, Google宣布Android Studio開始支持NDK開發(fā),通過和JetBrains的合作,將Clion整合進了Android Studio 1.3,并免費支持NDK C++開發(fā)。

同年7月,在Android Studio 1.3版本上添加了gradle-experimental插件,該插件支持NDK開發(fā)和調(diào)試,且?guī)в写a不全和重構(gòu)等高級功能。

CAVEAT: Note that this plugin is a preview of the plugin for feedback on performance and NDK integration. The Gradle API for the new component model is not final, which means each plugin will only work with a specific version of Gradle.
Additionally, the DSL may also change.

目前這個插件是預(yù)覽插件,并不是正式的。意味著插件只能運行在特定的Gradle版本上。并且DSL(領(lǐng)域特定語言)也要改變。

使用Experimental插件進行NDK開發(fā)

使用Experimental插件的必要條件

1、Gradle-2.5或更高版本
2、Android Studio 1.3 RC1或更高版本
3、Android NDK r10e 或更高版本
4、Build Tools 19.0.0 或更高版本

每個版本的experimental插件需要特定的Gradle版本

Plugin Version Gradle Version
0.1.0 2.5
0.2.0 2.5
0.3.0-alpha3 2.6
0.4.0 2.8
0.6.0-alpha1 2.8
0.6.0-alpha5 2.10
0.7.0-alpha1 2.10

NDK開發(fā)步驟

1、新建一個Android標準工程

2、按F4打開工程配置

3、使用experimental插件需要對以下三個文件做修改:

./build.gradle
./app/build.gradle
./gradle/wrapper/gradle-wrapper.properties
./gradle/wrapper/gradle-wrapper.properties

將distributionUrl改用gradle-2.10版本


    distributionUrl=https\\://services.gradle.org/distributions/gradle-2.10-all.zip
./build.gradle

使用com.android.tools.build:gradle-experimental代替 com.android.tools.build:gradle


    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            //classpath 'com.android.tools.build:gradle:2.0.0'
            classpath "com.android.tools.build:gradle-experimental:0.7.0-alpha4"

            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
        }
    }
./app/build.gradle

這部分改動比較大,修改及注釋如下:


    // 用com.android.model.application 代替 com.android.application
    apply plugin: 'com.android.model.application'

    // 將原來的配置用 model{}包起來
    model {
        android {
            // 取值必須使用 “=” 形式
            // 否則會報 “Error:Cause: org.gradle.api.internal.ExtensibleDynamicObject” 錯誤
            compileSdkVersion = 23
            buildToolsVersion = '23.0.2'

            defaultConfig {
                // 取值必須使用 “=” 形式
                applicationId = "com.connorlin.jnitest"
                //這里要注意是 xxSdkVersion.apiLevel
                // 否則會報 “Unable to load class com.android.build.gradle.managed.ProductFlavor_Impl”錯誤
                minSdkVersion.apiLevel = 15 
                targetSdkVersion.apiLevel = 23
                versionCode =  1
                versionName = "1.0"
            }

            // 配置NDK
            ndk {
                // 生成so的名字,是必須的
                moduleName ="JNITest"
                toolchain = 'clang'
                CFlags.add('-std=c99')
                // 添加依賴庫
                ldLibs.addAll(['android','OpenSLES', 'log'])
                // 生成不同abi體系的so庫
                abiFilters.addAll(['armeabi', 'armeabi-v7a', 'arm64-v8a',
                                   'x86', 'x86_64',
                                   'mips', 'mips64'])
            }

            buildTypes {
                release {
                    minifyEnabled = false
                    // 這里注意:使用proguardFiles.add()方法
                    proguardFiles.add(file('proguard-rules.txt'))
                }
            }
        }
    }

4、在Java文件(這里以JNIActivity為例)中添加代碼


    static {
        System.loadLibrary("JNITest");
    }

    public native String testJni();

此時,native方法標紅,提示如下:

testJni()方法上按快捷鍵Alt + Enter,出現(xiàn)如下提示

按回車,會自動在main目錄下生成jni文件夾,內(nèi)含JniDemo.c:


    #include <jni.h>

    JNIEXPORT jstring JNICALL
    Java_com_connorlin_jnitest_MainActivity_testJni(JNIEnv *env, jobject instance) {
        // TODO
        return (*env)->NewStringUTF(env, "returnValue");
    }

你會發(fā)現(xiàn),Android Studio已經(jīng)為我們自動生成JNI方法了,你只需要再寫實現(xiàn)就可以了。

至此,最簡單的NDK開發(fā)配置完畢。

其他配置,請參考官方文檔,Demo可以參考官方Demo

換種方式進行NDK開發(fā)

既然預(yù)覽版com.android.tools.build:gradle-experimental支持NDK,
那么正式版com.android.tools.build:gradle 是否也可以實現(xiàn)NDK開發(fā)呢?

經(jīng)過實驗,答案是可以的!

步驟

1、新建一個Android標準工程,并在工程設(shè)置中配置NDK路徑。

2、打開 app level 的 build.gradle, 配置NDK


    ndk {
        moduleName "NdkJniDemo"          //生成的so名字
        abiFilters "armeabi", "armeabi-v7a", "x86" //輸出指定三種abi體系結(jié)構(gòu)下的so庫,可忽略
    }

然后點擊右上角Sync Now, 會有如下錯誤提示:

按提示,在 gradl.properties 文件里加上android.useDeprecatedNdk=true即可。

3、在Java文件(這里以JNIActivity為例)中添加代碼


    static {
        System.loadLibrary("JNITest");
    }

    public native String testJni();

接著在testJni()方法上按快捷鍵Alt + Enter并回車,

同樣,會自動在main目錄下生成jni文件夾,內(nèi)含JniDemo.c:


    #include <jni.h>

但是,你會發(fā)現(xiàn)并不會自動生成JNI方法,這是因為使用experimental插件才會自動生成代碼。

那自動生成代碼該如何實現(xiàn)呢?

方法依然是使用gradle-experimental插件,但是不同的是,在app level的build.gradle中添加com.android.tools.build:gradle-experimental依賴。

4、在./app/build.gradle中添加gradle-experimental依賴


    dependencies {
        compile 'com.android.tools.build:gradle-experimental:0.7.0'
    }

再次在testJni()方法上按快捷鍵Alt + Enter并回車


    #include <jni.h>

    JNIEXPORT jstring JNICALL
    Java_com_connorlin_jnitest_MainActivity_testJni(JNIEnv *env, jobject instance) {
        // TODO
        return (*env)->NewStringUTF(env, "returnValue");
    }

你會發(fā)現(xiàn)成功自動生成JNI方法了。

副作用

這種方式有個副作用是 Run app 時可能會報錯:

此時,只要將gradle-experimental依賴注釋掉即可正常運行,同時會保持自動生成代碼的功能,直到關(guān)閉工程。
這樣我們在需要自動生成代碼的時候,將gradle-experimental依賴再次打開即可。

NDK調(diào)試

默認情況下是不支持NDK調(diào)試的,但要支持NDK調(diào)試也很簡單,只要做些簡單配置即可。

1、打開JNI調(diào)試

2、配置Android Native - Debugger

3、下載LLDB 2.0

首次底部會報錯

點擊 Fix,提示下載LLDB 2.0,照做,下載安裝即可。

4、完成NDK調(diào)試配置,可以正常調(diào)試了。

That's all!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容