android studio下啼县,JNI和NDK的簡(jiǎn)單編程

前言

Java JNI 本意是Java Native Interface(java 本地接口)率翅,他是為了方便Java調(diào)用C练俐、C++等本地代碼所封裝的一層接口。
NDK 是android所提供的一個(gè)工具集合安聘,通過NDK可以在Android中更加方便地通過JNI來訪問本地代碼痰洒,比如C或者C++瓢棒。NDK還提供了交叉編譯器浴韭,開發(fā)人員只需要簡(jiǎn)單的修改mk文件就可以生成特定的CPU平臺(tái)的動(dòng)態(tài)庫(kù)。

使用NDK有如下好處:

  • 提高代碼安全性脯宿。由于so庫(kù)反編譯比較困難念颈,因此NDK提高了Android程序的安全性。
  • 可以很方便的使用目前已有的C/C++開源庫(kù)连霉。
  • 便于平臺(tái)間的移植榴芳。通過C/C++實(shí)現(xiàn)的動(dòng)態(tài)庫(kù)可以很方便地在其他平臺(tái)上使用嗡靡。
  • 提高程序在某些特定情形下的執(zhí)行效率,但是并不能明顯提升android程序的性能窟感。

NDK的開發(fā)流程(本文以android studio 為例)

下載配置NDK

首先到官網(wǎng)下載NDK:NDK下載入口
下載完成后讨彼,如圖找到 Project Structure 完成配置。

屏幕快照

創(chuàng)建一個(gè)Android項(xiàng)目柿祈,并聲明所需的native方法

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.textView);
        set("hello world from JniTestApp");
        textView.setText(get());
    }

    /**
     * A native method that is implemented by the 'jni-test' native library,
     * which is packaged with this application.
     */
    public native void set(String str);
    public native String get();

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("jni-test");
    }
}

實(shí)現(xiàn)Android項(xiàng)目中所聲明的native方法

  • 首先說一下android studio 的自動(dòng)編譯產(chǎn)生so庫(kù)哈误。
    先創(chuàng)建test.cpp文件
//test.cpp
#include <jni.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

jstring Java_com_ryg_JniTestApp_MainActivity_get(JNIEnv *env, jobject thiz) {
    printf("invoke get in c++\n");
    return env->NewStringUTF("Hello from JNI in libjni-test.so !");
}

void Java_com_ryg_JniTestApp_MainActivity_set(JNIEnv *env, jobject thiz, jstring string) {
    printf("invoke set from C++\n");
    char* str = (char*)env->GetStringUTFChars(string,NULL);
    printf("%s\n", str);
    env->ReleaseStringUTFChars(string, str);
}

#ifdef __cplusplus
}
#endif

為了能夠讓androidStudio自動(dòng)編譯JNI代碼,首先需要在APP 的build.grade 的 defaultConfig 區(qū)域內(nèi)添加NDK選項(xiàng)躏嚎,其中moduleName指定了模塊的名稱蜜自,這個(gè)名稱指定了打包后的so庫(kù)的文件名。

android {
    ...
    defaultConfig {
       ...
        ndk {
            moduleName "jni-test"
        }
    }
}

接著需要將JNI的代碼放在 app/src/main/jni 目錄下卢佣,

屏幕快照

注意存放 JNI代碼的目錄名必須為jni重荠,如果不想采用jni這個(gè)名稱,可以通過如下方式來指定JNI的代碼路徑虚茶,其中jni.srcDirs 指定了JNI 代碼的路徑:

android {
    ...
    sourceSets.main {
       jni.srcDirs 'src/main/jni_src'
    }
}

經(jīng)過上面步驟戈鲁,AndroidStudio就可以自動(dòng)編譯JNI代碼了,但是這個(gè)時(shí)候AndroidStudio 會(huì)把所有CPU平臺(tái)的so庫(kù)都打包apk嘹叫,一般來說實(shí)際開發(fā)只需要打包armeabi 平臺(tái)的so庫(kù)即可和蚪。 解決這個(gè)問題也簡(jiǎn)單,按照如下方式修改build.gradle配置阀参。

android {
    ...
    productFlavors {
    arm {
        ndk {
            abiFilter "armeabi"
        }
    }
    x86 {
        ndk {
            abiFilter "x86"
        }
    }
 }
}

然后找到Build Variants 面板中選擇armDebug 選項(xiàng)進(jìn)行編輯就可以了摔踱。


屏幕快照
屏幕快照
  • 除了以上方法,我們還可以使用NDK 手動(dòng)的去生成所需要的so庫(kù)

這里首先我們需要配置我們的環(huán)境變量(Macbook為例):
首先打開配置文件

open ~/.bash_profile

然后添加如下信息:

export PATH=/Users/vince/Downloads/adt-bundle-mac-x86_64-20140702/sdk/ndk-bundle/:$PATH

其中 /Users/vince/Downloads/adt-bundle-mac-x86_64-20140702/sdk/ndk-bundle/是我本地NDK的存放路徑暮蹂。

添加完成后寞缝,執(zhí)行

source ~/.bash_profile

來刷新剛設(shè)置好的環(huán)境變量。設(shè)置完成后仰泻,我們通過 ndk-build 命令來編譯生成so庫(kù)荆陆。

接下來需要 在外部創(chuàng)建一個(gè)名為jni的目錄,然后創(chuàng)建三個(gè)文件:test.cpp集侯、Android.mk被啼、Application.mk。

//Application.mk
APP_ABI := armeabi

在Application.mk中棠枉,常用的配置項(xiàng)是 APP_ABI 浓体,表示CPU的架構(gòu)平臺(tái)的類型,常見的架構(gòu)平臺(tái)有 armeabi辈讶、x86命浴、mips,其中移動(dòng)設(shè)備中占據(jù)主要地位的是armeabi,這也是大部分apk中只包含armeabi類型的so庫(kù)的原因生闲。默認(rèn)情況下NDK會(huì)編譯產(chǎn)生各個(gè)CPU平臺(tái)的so庫(kù)媳溺,通過AOO_ABI選項(xiàng)即可指定so庫(kù)的CPU平臺(tái)的類型,比如armeabi碍讯,這樣NDK只會(huì)編譯armeabi平臺(tái)下的so庫(kù)悬蔽。

//Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := jni-test
LOCAL_SRC_FILES := test.cpp

include $(BUILD_SHARED_LIBRARY)

在Android.mk中,LOCAL_MODULE 表示模塊的名稱捉兴,LOCAL_SRC_FILES 表示需要參與編譯的源文件屯阀。

接下來,終端界面(命令行界面)切換到j(luò)ni目錄的父目錄轴术,然后運(yùn)行ndk-build 命令編譯生成so庫(kù)难衰。
編譯過程中,NDK會(huì)創(chuàng)建一個(gè)和jni目錄平級(jí)的目錄libs逗栽,libs下面就存放著生成的so庫(kù)盖袭。需要注意的是,ndk-build 命令默認(rèn)指定jni目錄為bending源碼的目錄彼宠,如果源碼存放的目錄名不是jni鳄虱,那么 ndk-build 則無法成功編譯。

編譯前
編譯后

so庫(kù)的引入使用
在 app/src/main 中創(chuàng)建一個(gè)名為jniLibs 的目錄凭峡,將生成的so庫(kù)復(fù)制到j(luò)niLibs 目錄中拙已,然后通過AndroidStudio 編譯運(yùn)行即可。


屏幕快照

上面步驟需要將NDK編譯的so庫(kù)放置在 jniLibs目錄下摧冀,這個(gè)是AndroidStudio 所識(shí)別的默認(rèn)目錄倍踪,如果想使用其他目錄,可以修改App的build.gradle 文件索昂。

android{
      ...
      sourceSets.main{
            jniLibs.srcDir 'src/main/jni_libs'
      }
}

最后

附上demo的地址 : https://github.com/woshishenxian/NdkDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末建车,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子椒惨,更是在濱河造成了極大的恐慌缤至,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件康谆,死亡現(xiàn)場(chǎng)離奇詭異领斥,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)沃暗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門月洛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人描睦,你說我怎么就攤上這事膊存〉级” “怎么了忱叭?”我有些...
    開封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵隔崎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我韵丑,道長(zhǎng)爵卒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任撵彻,我火速辦了婚禮钓株,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘陌僵。我一直安慰自己轴合,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開白布碗短。 她就那樣靜靜地躺著受葛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪偎谁。 梳的紋絲不亂的頭發(fā)上总滩,一...
    開封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音巡雨,去河邊找鬼闰渔。 笑死,一個(gè)胖子當(dāng)著我的面吹牛铐望,可吹牛的內(nèi)容都是我干的冈涧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼正蛙,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼炕舵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起跟畅,我...
    開封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤咽筋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后徊件,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奸攻,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年虱痕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了睹耐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡部翘,死狀恐怖硝训,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤窖梁,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布赘风,位于F島的核電站,受9級(jí)特大地震影響纵刘,放射性物質(zhì)發(fā)生泄漏邀窃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一假哎、第九天 我趴在偏房一處隱蔽的房頂上張望瞬捕。 院中可真熱鬧,春花似錦舵抹、人聲如沸肪虎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笋轨。三九已至,卻和暖如春赊淑,著一層夾襖步出監(jiān)牢的瞬間爵政,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工陶缺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钾挟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓饱岸,卻偏偏與公主長(zhǎng)得像掺出,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子苫费,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容