Android JNI初體驗

1、準備工作:

(1)Android Studio
(2)Android SDK
(3)Android NDK(必須是r9+版本的,至於爲什麼,最後會提到)

2、具體開發流程:

在Android Studio中新建一個project或者在project中新建一個module都行,然後在Project Structure–>SDK Location中配置NDK的位置
這裏寫圖片描述
然後新建一個類NdkJniUtils,在內部聲明native方法

package com.scutee.victor.ndktest;

public class NdkJniUtils {

    public native String getCLanguageString();

}

接着,新建一個MainActivity,在佈局文件中添加一個TextView,用於顯示調用JNI的方法返回的結果

public class MainActivity extends AppCompatActivity {

    private TextView tvNDK = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvNDK = (TextView) findViewById(R.id.tvNDK);

        NdkJniUtils jniUtil = new NdkJniUtils();
        tvNDK.setText(jniUtil.getCLanguageString());
    }
}

然後build project,得到我們需要的字節碼文件(即.class文件),編譯成功後,class文件所在目錄爲:MyApplication\app\build\intermediates\classes\debug。
這裏寫圖片描述
打開AS的Terminal(或者windows下的cmd),轉到上述目錄,然後執行javah命令生成頭文件

xxx\debug>javah -jni com.scutee.victor.ndktest.NdkJniUtils

執行成功後,在該目錄下會生成一個頭文件:com_scutee_victor_ndktest_NdkJniUtils.h

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

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

#ifdef __cplusplus
}
#endif
#endif

接着,在工程main目錄下新建一個jni目錄,將上述的.h頭文件剪切進來;然後在jni根目錄下新建一個c文件,名字隨意,內容代碼如下:

#include "com_scutee_victor_ndktest_NdkJniUtils.h"

JNIEXPORT jstring JNICALL Java_com_scutee_victor_ndktest_NdkJniUtils_getCLanguageString
    (JNIEnv *env, jobject obj) {
        return (*env)->NewStringUTF(env, "Hello JNI");
    }

(注:env是接口指針;obj是“this”指針)
接下來,需要配置一下在app module中的build.gradle,找到其中的defaultConfig,具體配置如下:

defaultConfig {
        ndk {
            moduleName "JniTestLib"
            ldLibs "log", "z", "m"
            abiFilters "armeabi", "armeabi-v7a", "x86"
        }
    }

(注:moduleName是生成的so庫的名字,隨意取,最後編譯出來的.so文件會在該名字前加lib;ldLibs:添加依賴庫文件;abiFilters:輸出指定三種abi體系結構下的so庫)
最後,回到一開始新建的NdkJniUtils這個類,添加靜態初始化加載本地library的代碼:

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

到此AS下NDK JNI開發的代碼編寫和設置就ok了,編譯運行即可
這裏寫圖片描述

3、JNI開發中遇到的錯誤及解決方法:

(1)編譯報錯:
Error:Execution failed for task ':app:compileDebugNdk'. > com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'D:\android\android-ndk-r10d\ndk-build.cmd'' finished with non-zero exit value 2

據說這是ndk在windows的一個bug,通常解決方案:在jni根目錄下新建一個空的c文件,如:test.c

(2)編譯報錯:
Error:Execution failed for task ':app:compileDebugNdk'. > com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'D:\android\android-ndk-r10d\ndk-build.cmd'' finished with non-zero exit value 2

原因:在Android Studio下進行JNI開發,NDK必須要r9+版本

(3)編譯報錯:
Error:(14, 1) A problem occurred evaluating project ':app'.
> Error: NDK integration is deprecated in the current plugin.  Consider trying the new experimental plugin.  For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental.  Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.

解決方法:在project的gradle.properties下加一行代碼:“android.useDeprecatedNdk=true”:

# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.useDeprecatedNdk=true

源碼下載

開發過程中參考的博文:
http://yanbober.github.io/2015/02/14/android_studio_jni_1/

發佈了38 篇原創文章 · 獲贊 17 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章