Andorid Studio NDK開發-使用庫

C語言是一個巨大的寶庫,系統底層的很多的實現都是基于C語言實現的,比如圖像處理,加密等。

C語言的運行效率也是很高的,因此為了效率有時候也會引入第三方的C語言庫。

總而言之,會在NDK開發的過程中會使用大量的庫,系統自帶的庫,第三方庫等。

在 gradle-experimental 中使用C語言的庫是非常便利的。

調用系統庫

Log是在Android開發過程用來調試程序必備的工具之一,如何在NDK中使用 android.util.Log 方便在Logcat中查看JNI程序的運行情況呢?這就需要在NDK中導入Android系統的 Log 庫。

首先需要在在 gradle 中引入Log庫:

model{
 ....
 android {
        compileSdkVersion 23
        buildToolsVersion "23.0.2"
        ndk {
            moduleName "experiment"    
            ldLibs.addAll([ 'log']);
        }
   }
 }

直接在ldLIbs中加入log就可以,如果需要引入其他的系統庫,只要在數組中直接增加即可。再定義一個native的方法:

public static native void callLogFromJni();

在Jni中調用Log庫的方法:

//引入 log
#include <android/log.h>

JNIEXPORT void JNICALL
Java_com_jjz_NativeUtil_callLogFromJni(JNIEnv *env, jclass type) {

    __android_log_print(ANDROID_LOG_INFO,"jni-log","from jni log");

}

第一個參數, ANDROID_LOG_INFO 是log的級別他包含:

typedef enum android_LogPriority {
    ANDROID_LOG_UNKNOWN = 0,
    ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
    ANDROID_LOG_VERBOSE,
    ANDROID_LOG_DEBUG,
    ANDROID_LOG_INFO,
    ANDROID_LOG_WARN,
    ANDROID_LOG_ERROR,
    ANDROID_LOG_FATAL,
    ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
} android_LogPriority;

一般我們常用的是 ADNROID_LOG_VERBOSE , ANDROID_LOG_DEBUG , ANDROID_LOG_INFO , ANDROID_LOG_WARN , ANDROID_LOG_ERROR 分別對應java中的 Log.v , Log.d , Log.i , Log.w , Log.e 。

第二個參數是tag,用來方便的對log分類。

第三個參數是message,對應log的具體信息。

一般還會采用宏定義的方式,定義Log的輸出的方法,方便調用:

#define LOG_TAG "jni-log"
#define LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)

這里定義了一個warning log的宏,在代碼里面可以直接調用:

  LOGW("log from  define");

使用第三方類庫

OpenSSL是最常用的加密庫之一,下面以OpenSSL為例,介紹下在 gradle-experimental 中如何引入第三方類庫。關于如何編譯Android下的OpenSSL詳見: 編譯Android的OpenSSL類庫

首先定義對于庫的 repositories :

model {
   repositories{
        libs(PrebuiltLibraries) {
            // Configure one pre-built lib: static
            openssl {
                // 頭文件地址
                headers.srcDir "/usr/local/ssl/android-23/include"
                // 靜態鏈接庫的引用,
                binaries.withType(StaticLibraryBinary) {
                    staticLibraryFile = file("libs/libcrypto.a")
                }
                //動態鏈接庫的引用
//                binaries.withType(SharedLibraryBinary) {
//                    sharedLibraryFile = file("libs/libcrypto.so")
//                }
            }

        }

    }
  }

c語言的類庫分為靜態鏈接庫(.a)和動態鏈接庫(.so),靜態類庫和動態類庫的引入方式是不一樣的,分為對應: StaticLibraryBinary 和 SharedLibraryBinary 。這里引入的庫為靜態鏈接庫,名稱為: openssl .

指定庫依賴:

model{
 ......
 android{
  .....
   sources {
            main {
                jni {
                    dependencies{
                        library 'openssl' linkage 'static'
                        //動態鏈接庫
                        //  library 'openssl' linkage 'shared'
                    }
                    source {
                        srcDir "src/main/jni"
                    }
                }
                jniLibs{
                    source{
                        srcDir "libs/"
                    }
                }
                java{
                    source{
                        srcDir "src/main/java"
                    }
                }
            }
        }
 }
}

這里在model.android.sources.main中指定庫的依賴為上面定義的 openssl , linkage 類型為static,如果是動態鏈接庫 linkage 就是shared。

因為編譯的OpenSSL只支持arm結構的cpu,因此需要指定abi為對應的cpu,在model.android添加配置:

 ndk {
      moduleName "experiment"
      abiFilters.addAll(['armeabi', 'armeabi-v7a'])      
     }

使用OpenSSL

首先定義一個 native 方法,需要從OpenSSL中讀取隨機數:

public static native byte[] getRandom();

生成對應的JNI方法:

//引入OpenSSL的rand
#include <openssl/rand.h>
JNIEXPORT jbyteArray JNICALL
Java_com_jjz_NativeUtil_getRandom(JNIEnv *env, jclass type) {
    unsigned char rand_str[128];
    RAND_seed(rand_str, 32);
    jbyteArray bytes = (*env)->NewByteArray(env, 128);
    (*env)->SetByteArrayRegion(env, bytes, 0, 128, rand_str);
    return bytes;

}

RAND_seed 是OpenSSL的方法,讀取隨機數。這段代碼就是讀取一個128的隨機數,然后轉換為java的byte[]。

在界面上面使用讀取隨機數的方法:

tv2.setText(Base64.encodeToString(NativeUtil.getRandom(), Base64.DEFAULT));

運行之后可以在界面看到一段隨機的字符串顯示:

源代碼地址: https://github.com/jjz/android/tree/master/experimental

 

來自: https://segmentfault.com/a/1190000005752063

 

 本文由用戶 agvo4493 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!