Android開發(fā)之NDK

NDK

NDK全稱:Native Development Kit。

關(guān)于NDK,360百科是這么說的:
1.NDK是一系列工具的集合。

  • NDK提供了一系列的工具,幫助開發(fā)者快速開發(fā)C(或C++)的動態(tài)庫,并能自動將so和java應(yīng)用一起打包成apk。這些工具對開發(fā)者的幫助是巨大的。

  • NDK集成了交叉編譯器,并提供了相應(yīng)的mk文件隔離平臺、CPU、API等差異,開發(fā)人員只需要簡單修改mk文件(指出“哪些文件需要編譯”、“編譯特性要求”等),就可以創(chuàng)建出so。

  • NDK可以自動地將so和Java應(yīng)用一起打包,極大地減輕了開發(fā)人員的打包工作。

2.NDK提供了一份穩(wěn)定、功能有限的API頭文件聲明。

Google明確聲明該API是穩(wěn)定的,在后續(xù)所有版本中都穩(wěn)定支持當(dāng)前發(fā)布的API。從該版本的NDK中看出,這些API支持的功能非常有限,包含有:C標(biāo)準(zhǔn)庫(libc)、標(biāo)準(zhǔn)數(shù)學(xué)庫(libm)、壓縮庫(libz)、Log庫(liblog)。

NDK產(chǎn)生的背景

Android平臺從誕生起,就已經(jīng)支持C、C++開發(fā)。眾所周知,Android的SDK基于Java實現(xiàn),這意味著基于Android SDK進行開發(fā)的第三方應(yīng)用都必須使用Java語言。但這并不等同于“第三方應(yīng)用只能使用Java”。在Android SDK首次發(fā)布時,Google就宣稱其虛擬機Dalvik支持JNI編程方式,也就是第三方應(yīng)用完全可以通過JNI調(diào)用自己的C動態(tài)庫,即在Android平臺上,“Java+C”的編程方式是一直都可以實現(xiàn)的。
  不過,Google也表示,使用原生SDK編程相比Dalvik虛擬機也有一些劣勢,Android SDK文檔里,找不到任何JNI方面的幫助。即使第三方應(yīng)用開發(fā)者使用JNI完成了自己的C動態(tài)鏈接庫(so)開發(fā),但是so如何和應(yīng)用程序一起打包成apk并發(fā)布?這里面也存在技術(shù)障礙。比如程序更加復(fù)雜,兼容性難以保障,無法訪問Framework API,Debug難度更大等。開發(fā)者需要自行斟酌使用。
  于是NDK就應(yīng)運而生了,2011發(fā)布NDK。NDK全稱是Native Development Kit。NDK的發(fā)布,使“Java+C”的開發(fā)方式終于轉(zhuǎn)正,成為官方支持的開發(fā)方式。NDK將是Android平臺支持C開發(fā)的開端。

NDK作用

  • 代碼的保護。由于apk的java層代碼很容易被反編譯,而C/C++庫反匯難度較大。

  • 可以方便地使用現(xiàn)存的開源庫。大部分現(xiàn)存的開源庫都是用C/C++代碼編寫的。

  • 提高程序的執(zhí)行效率。將要求高性能的應(yīng)用邏輯使用C開發(fā),從而提高應(yīng)用程序的執(zhí)行效率。(在前面性能優(yōu)化中有提及)

  • 便于移植。用C/C++寫得庫可以方便在其他的嵌入式平臺上再次使用。

具體可參考NDK 入門指南

JNI

JNI是Java Native Interface的縮寫,它提供了若干的API實現(xiàn)了Java和其他語言的通信(主要是C&C++)。從Java1.1開始,JNI標(biāo)準(zhǔn)成為java平臺的一部分,它允許Java代碼和其他語言寫的代碼進行交互。JNI一開始是為了本地已編譯語言,尤其是C和C++而設(shè)計的,但是它并不妨礙你使用其他編程語言,只要調(diào)用約定受支持就可以了。使用java與本地已編譯的代碼交互,通常會喪失平臺可移植性。但是,有些情況下這樣做是可以接受的,甚至是必須的。例如,使用一些舊的庫,與硬件、操作系統(tǒng)進行交互,或者為了提高程序的性能。JNI標(biāo)準(zhǔn)至少要保證本地代碼能工作在任何Java 虛擬機環(huán)境。

通俗點的意思就是用JAVA調(diào)用C或者C++。在實際開發(fā)過程中很可能會使用到C或者C++開發(fā)的DLL(windows平臺),或者so(Linux平臺),這個時候就需要用JAVA來調(diào)用DLL或者so文件。

開發(fā)NDK時,需要用到JNI。

接口分析

JNIEXPORT void JNICALL Java_com_test01_Test_firstTest (JNIEnv * env, jobject obj);

  • JNIEXPORT :在Jni編程中所有本地語言實現(xiàn)Jni接口的方法前面都有一個"JNIEXPORT",這個可以看做是Jni的一個標(biāo)志,至今為止沒發(fā)現(xiàn)它有什么特殊的用處。

  • void :這個學(xué)過編程的人都知道,當(dāng)然是方法的返回值了。

  • JNICALL :這個可以理解為Jni 和Call兩個部分,和起來的意思就是 Jni調(diào)用XXX(后面的XXX就是JAVA的方法名)。

  • Java_com_test01_Test_firstTest:這個就是被上一步中被調(diào)用的部分,也就是Java中的native 方法名,這里起名字的方式比較特別,是:包名+類名+方法名。

  • JNIEnv * env:這個env可以看做是Jni接口本身的一個對象,jni.h頭文件中存在著大量被封裝好的函數(shù),這些函數(shù)也是Jni編程中經(jīng)常被使用到的,要想調(diào)用這些函數(shù)就需要使用JNIEnv這個對象。例如:env->GetObjectClass()。

Jni中的數(shù)據(jù)類型

每一個Java的數(shù)據(jù)類型在Jni中都一個和它相對應(yīng)的數(shù)據(jù)類型,這樣才能保證Java調(diào)用C或者C++的過程中數(shù)據(jù)的正確性。jni.h頭文件中定義的類型:

![2.png](http://upload-images.jianshu.io/upload_images/4623465-45b6afc193305be2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

NDK環(huán)境搭建

下載NDK,下載具體文件解壓即可,也可使用studio的sdk manager下載安裝

Android-Studio配置

配置NDK路徑

  • 右擊Module->Open Module Setting->SDK Location->Android NDK Location
  • 或者直接修改local.properties文件
QQ圖片20170410212255.png

創(chuàng)建Library項目,定義模板類,此類主要為了生成so文件用,so文件生成后可刪除

// 包名和類名要和.cpp或者.c文件中一致
package com.ndkdemo;

public class MathKit
{
   // 定義native本地方法,和普通方法相同,加上native關(guān)鍵字
    public static native int square(int num);
}

創(chuàng)建jni目錄,默認(rèn)為src/main/jni

javah命令生成.h文件

在Android Studio找到View->Tool Windows->Terminal 打開命令行:
執(zhí)行如下命令:

javah -d NDKDemo/src/main/jni/ -classpath D:/AndroidStudioProjects/MyWork/NDKDemo/build/intermediates/classes/debug  -jni com.ndkdemo.MathKit

或者

cd D:/AndroidStudioProjects/MyWork/NDKDemo/build/intermediates/classes/debug
javah com.ndkdemo.MathKit

-d . 表示將在當(dāng)前目錄下生成一個當(dāng)前命令行文件夾,產(chǎn)生的頭文件就在這里面了;
-classpath < PATH> 指明class文件所在的位置(目錄)
-jni com.ndkdemo.MathKit 指定類名

javah命令主要用于在JNI開發(fā)的時,把java代碼聲明的JNI方法轉(zhuǎn)化成C\C++ 頭文件,以便進行JNI的C\C++ 端程序的開發(fā)。
但是需要注意的是javah命令對Android編譯生成的類文件并不能正常工作。如果對于Android的JNI要想生成C\C++ 頭文件的話,可能只有先寫個純的java代碼來進行JNI定義,接著用JDK編譯,然后再用javah命令生成JNI的C\C++ 頭文件。當(dāng)然你也可以不用javah命令,直接手寫JNI的C\C++ 頭文件。

創(chuàng)建cpp文件,文件名最好和.h文件同名,便于管理編輯.cpp文件

#include <com_ndkdemo_MathKit.h>

JNIEXPORT jintJNICALL Java_com_ndkdemo_MathKit_square
        (JNIEnv *env, jclass cls, jint num){
    return num * num;
}

在app module目錄下的build.gradle配置ndk選項

defaultConfig {
    ......
    ndk{
           moduleName "ndklib"         //生成的so名字,實際為 libndklib.so
           abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86"  //輸出指定三種abi體系結(jié)構(gòu)下的so庫
        }
}
buildTypes {
        release {
            minifyEnabled false
            proguardFiles 'proguard-rules.pro'
            ndk {
                moduleName "jnimain"
                abiFilters "armeabi", "armeabi-v7a"
            }
        }
    }

Make上述Library項目,生成so文件

先在gradle.properties中添加:android.useDeprecatedNdk=true

生成的so文件在如下目錄,生成的so文件為 =lib+ 配置生成名 .so
<Module主目錄>/build/intermediates/ndk/debug/lib/arm64-v8a/libndklib.so
<Module主目錄>/build/intermediates/ndk/debug/lib/armeabi/libndklib.so
<Module主目錄>/build/intermediates/ndk/debug/lib/armeabi-v7a/libndklib.so
<Module主目錄>/build/intermediates/ndk/debug/lib/x86/libndklib.so

在其他Application項目中引用

1.直接引用Library Module
定義和模板類相同類,包名+類名和此前jni中一致

// 包名和類名要和.cpp或者.c文件中一致
package com.ndkdemo;

public class MathKit{
    static{
        // 對應(yīng)庫文件名稱,要一致。生成的.so文件名為libndklib.so,
        // 那么loadLibrary為ndklib,去掉前面的lib及后面的.so
        System.loadLibrary("NDKDemo");
    }
   // 定義native本地方法,和普通方法相同,加上native關(guān)鍵字
    public static native int square(int num);
}

在應(yīng)用中使用靜態(tài)方式調(diào)用native方法
例如: MathKit.square(10)

2.創(chuàng)建src/main/jniLibs目錄,把生成的so文件拷貝進去調(diào)用natvie方法方式同上

自定義jni路徑和so文件路徑

1.jni編輯路徑自定義

android {

  sourceSets.main {
      jni.srcDirs 'src/main/source'
  }
}

2.so文件路徑自定義

sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

由于Android Studio以強大的方式集成了NDK, 所以上面很多配置都不需要寫. 方便了很多..mk文件不用自己寫。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容