Android Studio中jni的使用

mymdeep發表於2017-02-03

最近在專案中需要使用JNI的相關東西,尤其是.so檔案,發現許多開發者都是非常陌生的,所以有必要在這裡做個簡單的介紹。

JNI的基本概念

CPU的基本架構

早起Android只支援ARMv5的CPU架構,而發展到現在,支援一下7種架構:
ARMv5:現在很少了,應該不需要支援了
ARMv7(2010年起):魅族M9,iphone 3GS,三星I9000等
x86(2011年起):聯想K800,使用這種架構的較少,畢竟Android手機大部分是ARM。
MIPS(2012年):可能有些國產廠商在用
ARMv8:華為 Mate 8,Galaxy S
MIPS64:暫時沒發現什麼手機在用
x86_64(2014年):64位平板
每種架構關聯著一種ABI(application binary interface應用程式二進位制介面),所以每一種架構都對應一個.so檔案。
如圖所示:

Android Studio中jni的使用
Paste_Image.png

這裡需要注意很重要的一點:
arm64-v8a是可以向下相容的,但前提是你的專案裡面沒有arm64-v8a的資料夾,如果你有兩個資料夾armeabi和arm64-v8a,兩個資料夾,armeabi裡面有a.so 和 b.so,arm64-v8a裡面只有a.so,那麼arm64-v8a的手機在用到b的時候發現有arm64-v8a的資料夾,發現裡面沒有b.so,就報錯了,所以這個時候刪掉arm64-v8a資料夾,這個時候手機發現沒有適配arm64-v8a,就會直接去找armeabi的so庫,所以要麼你別加arm64-v8a,要麼armeabi裡面有的so庫,arm64-v8a裡面也必須有。

如何依賴.so檔案

對於eclipse就不用多說了,放在libs中即可。
如果使用Android Studio,有兩種方式可以依賴.so檔案
第一種放在src/main/jniLibs中如圖所示:

Android Studio中jni的使用
Paste_Image.png

第二種方式,也可以放到libs中,但是需要在build.gradle中設定一下目錄結構:

sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }複製程式碼

編寫.so檔案

配置工程

在app的build.gradle中:

 defaultConfig {
        applicationId "umeng.testjni"
        minSdkVersion 15
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        ndk {
            moduleName "JniTest"
            ldLibs "log", "z", "m"
            abiFilters "armeabi", "armeabi-v7a", "x86"
        }
    }複製程式碼

其中moduleName是生成的.so檔案的名字,如果設定成JniTest,生成的.so檔案會是libJniTest.so,ldLibs是依賴的庫。
開啟gradle.properties檔案,增加配置:

android.useDeprecatedNdk = true複製程式碼

local.properties增加ndk的配置路徑:

ndk.dir=/Users/xxxx/xxxx/sdk/android-ndk-r10e
sdk.dir=/Users/xxxxx/Library/Android/sdk複製程式碼

程式碼檔案

然後在工程中建立呼叫jni的檔案:

public class UmengJni {

   static {
        System.loadLibrary("JniTest");
    }
    public static native String sayHello();

}複製程式碼

其中 System.loadLibrary("JniTest");是載入.so檔案,sayHello是c++的方法名字。
這時開啟命令列,切到當前應用工程的目錄下,輸入如下命令:

Android Studio中jni的使用
Paste_Image.png

其中umeng.testjni.UmengJni是我們剛剛編寫的檔案,這時會在對應的路徑下生成一個.h檔案

Android Studio中jni的使用
Paste_Image.png

在java目錄下建立jni資料夾,新建main.c實現剛才生成的標頭檔案中的方法:

#include <jni.h>
/* Header for class umeng_testjni_UmengJni */

#ifndef _Included_umeng_testjni_UmengJni
#define _Included_umeng_testjni_UmengJni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     umeng_testjni_UmengJni
 * Method:    sayHello
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_umeng_testjni_UmengJni_sayHello
  (JNIEnv *env, jclass object){
    return (*env)->NewStringUTF(env,"JNI hahahahahahahaha");
}

#ifdef __cplusplus
}
#endif
#endif複製程式碼

此時執行即可編譯.so檔案,在build/intermediates/ndk目錄下可以找到對應檔案:

Android Studio中jni的使用
Paste_Image.png

*更多的開發知識,可以關注我的公眾號:

Android Studio中jni的使用

相關文章