1. 程式人生 > >android studio 進行ndk/jni開發

android studio 進行ndk/jni開發

一、前言:之前用eclipse開發ndk的時候大家是不是很痛苦,要做的事情很多:

    //NDK開發流程: 
    1、在java程式碼中 宣告本地方法(native)
    2、通過javah工具完成jni樣式的標頭檔案(.h檔案)的生成    

    3、在工程中 建立jni目錄,在jni目錄中編寫 與java本地方法對應的C方法
        jstring Java_包名_類名_方法名(){...}

    4、編寫Android.mk檔案,來指定如何編譯C程式碼
    5、通過ndk-build工具來完成交叉編譯 ,生成Anroid 中可以呼叫的2進位制檔案(連結庫檔案)
    6、在Java程式碼中引用System.loadLibrary("hello-jni");
   這個過程是非常的繁瑣,執行ndk-build命令還需要裝cgwin

但是現在Android Studio集成了ndk開發環境(ndk如何配置就不說了),我們只需要走這麼幾步就可以了:

二、Android Studio進行ndk開發

1、建立工程的時候需要勾上支援ndk開發

2、預設選擇支援標準c++就可以了

C++ Standard:使用下拉列表選擇使用哪種 C++ 標準。選擇 Toolchain Default 會使用預設的 CMake 設定。
Exceptions Support:如果希望啟用對 C++ 異常處理的支援,請選中此複選框。如果啟用此複選框,Android Studio 會將 -fexceptions 標                                     志新增到模組級 build.gradle檔案的 cppFlags中,Gradle 會將其傳遞到 CMake。
Runtime Type Information Support:如果希望支援 RTTI,請選中此複選框。如果啟用此複選框,Android Studio 會將 -frtti 標誌新增到模                                    塊級 build.gradle檔案的 cppFlags中,Gradle 會將其傳遞到 CMake。

3、建立好的工程

建立好的工程多了cpp目錄,這是寫c++的包,還多了CMakeLists.txt,這是編譯程式碼,makefile都幫我們寫好了,我們用的時候只需要修改裡面的程式碼即可:

看一下build.gradle:

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.jni.jnidemo"
        minSdkVersion 26
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                // 預設是 "cppFlags" "" ,如果要修改 Customize C++ Support 部分,可在這裡加入cppFlags "-frtti -fexceptions"
                cppFlags ""
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    // 指定c++編譯程式碼的路徑
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

三、總結

進行ndk開發要掌握的步驟:

1、在cpp包下建立自己的.cpp或者.c檔案,編寫自己的c語言程式

2、在CMakeLists.txt中新增add_library,可以生成多個library,所以add_library可以自己在後面加

     在CMakeLists.txt中新增target_link_libraries,它也是一樣,可以在後面自己加,不過這個不是必須的

3、在介面中引用一個庫:

static {
    System.loadLibrary("native-lib");
}

4、把用c/c++寫的方法用native來宣告:

public native String stringFromJNI();

5、經過以上步驟就可以像普通的方法一樣來呼叫了

四、注意

1、在Activity或者fragment裡面新加的native方法如果.cpp檔案裡面沒有就會報錯,這時候只需要在native方法上Alt + Enter就會自動在cpp檔案裡面生成

2、不同廠商的 Android 手機支援的 CPU 架構不同,我們可以這樣來限制我們支援的架構

defaultConfig {
    applicationId "com.jni.jnidemo"
    minSdkVersion 26
    targetSdkVersion 28
    versionCode 1
    versionName "1.0"
    externalNativeBuild {
        cmake {
            cppFlags ""
        }
    }

    ndk {
        abiFilters 'armeabi'//,'armeabi-v7a','arm64-v8a','x86','x86_64','mips','mips64'
    }
}

3、常用工具類:把Java字串轉化成c語言字串

// 把Java字串轉化為C語言字串
char* Jstring2CStr(JNIEnv*   env,   jstring   jstr)
{
    char*   rtn   =   NULL;
    jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String");
    jstring   strencode   =   (*env)->NewStringUTF(env,"GB2312");
    jmethodID   mid   =   (*env)->GetMethodID(env,clsstring,   "getBytes",   "(Ljava/lang/String;)[B");
    jbyteArray   barr=   (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");
    jsize   alen   =   (*env)->GetArrayLength(env,barr);
    jbyte*   ba   =   (*env)->GetByteArrayElements(env,barr,JNI_FALSE);
    if(alen   >   0)
    {
     rtn   =   (char*)malloc(alen+1);         //"\0"
     memcpy(rtn,ba,alen);
     rtn[alen]=0;
    }
    (*env)->ReleaseByteArrayElements(env,barr,ba,0);  //
    return rtn;
}