Android NDK彤钟、JNI入門

1.背景

本來一直在做商城類的項目舒坦著缸托,突然老板拿了一塊Android的主板和芯片過來兆蕉,說我們打算做一款自動售貨機(jī)度宦,從沒做過這類項目的我,當(dāng)時就一臉懵逼了,芯片亡电、自動售貨機(jī)函喉,What?還好我依稀記得酪碘,這類項目是關(guān)于NDK帖世、JNI的,于是棍苹,我來了无宿!

2.介紹

  1. 什么是NDK?

NDK全稱是Native Development Kit枢里,NDK提供了一系列的工具孽鸡,幫助開發(fā)者快速開發(fā)C(或C++)的動態(tài)庫,并能自動將so和java應(yīng)用一起打包成apk栏豺。NDK集成了交叉編譯器(交叉編譯器需要UNIX或LINUX系統(tǒng)環(huán)境)梭灿,并提供了相應(yīng)的mk文件隔離CPU、平臺冰悠、ABI等差異堡妒,開發(fā)人員只需要簡單修改mk文件(指出“哪些文件需要編譯”、“編譯特性要求”等)溉卓,就可以創(chuàng)建出so皮迟。

  1. 為什么使用NDK搬泥?
  • 代碼的保護(hù)。由于apk的java層代碼很容易被反編譯伏尼,而C/C++庫反匯難度較大忿檩。
  • 可以方便地使用現(xiàn)存的開源庫。大部分現(xiàn)存的開源庫都是用C/C++代碼編寫的爆阶。
  • 提高程序的執(zhí)行效率燥透。將要求高性能的應(yīng)用邏輯使用C開發(fā),從而提高應(yīng)用程序的執(zhí)行效率辨图。
  • 便于移植班套。用C/C++寫得庫可以方便在其他的嵌入式平臺上再次使用。
  1. 什么是JNI故河?

JNI的全稱是Java Native Interface吱韭,它提供了若干的API實(shí)現(xiàn)了Java和其他語言的通信(主要是C和C++)。

  1. 為什么使用JNI鱼的?

JNI的目的是使java方法能夠調(diào)用c實(shí)現(xiàn)的一些函數(shù)理盆。

  1. 安卓中的so文件是什么?

android中用到的so文件是一個c++的函數(shù)庫凑阶。在android的JNI中猿规,要先將相應(yīng)的C語言打包成so庫,然后導(dǎo)入到lib文件夾中供java調(diào)用宙橱。

3.下載 NDK 和工具

為了給應(yīng)用編譯和調(diào)試原生代碼姨俩,我們需要以下組件:

  • Android 原生開發(fā)工具包 (NDK):這套工具集允許您為 Android 使用 C 和 C++ 代碼,并提供眾多平臺庫养匈,讓您可以管理原生 Activity 和訪問物理設(shè)備組件,例如傳感器和觸摸輸入都伪。
  • CMake:一款外部構(gòu)建工具呕乎,可與 Gradle 搭配使用來構(gòu)建原生庫。如果您只計劃使用 ndk-build陨晶,則不需要此組件猬仁。
  • LLDB:一種調(diào)試程序,Android Studio 使用它來調(diào)試原生代碼先誉。

我們可以在SDK 管理器安裝這些組件

  1. 依次打開 Settings>Appearance&Behavior>System Settings>Android SDK>SDK Tools
  2. 勾上LLDB湿刽、CMake 和 NDK進(jìn)行下載
image

4.配置NDK的環(huán)境變量

  • 打開File > Project Structure > SDK Location,選擇默認(rèn)NDK的路徑
image
  • 復(fù)制NDK的路徑
image
  • 右擊我的電腦>屬性>高級系統(tǒng)設(shè)置>環(huán)境變量>新建褐耳,添加一個系統(tǒng)變量NDK_HOME诈闺,并把剛才復(fù)制的ndk-bundle的路徑填上去,記得確認(rèn)。
image
  • 找到Path系統(tǒng)變量(不需要創(chuàng)建)铃芦,新建一個%NDK_HOME%雅镊,也就是上面NDK_HOME的變量添加進(jìn)去襟雷。
image
  • 在Terminal/cmd中不需要考慮路徑,直接輸入 ndk-build 仁烹,如出現(xiàn)如下內(nèi)容耸弄,則表明NDK環(huán)境配置成功!(配置NDK環(huán)境前如果已經(jīng)打開了Android Studio或者Cmd需要重新啟動卓缰,否則可能沒效果计呈!)


    image

5.創(chuàng)建native相關(guān)方法

image

5.1 native相關(guān)方法去掉報紅

取消檢測即可,打開 Settings>Editor>Inspections>Android>Missing JNI function 去掉勾選征唬。

image

去掉后捌显,效果如下:

image

6.創(chuàng)建c/c++文件

6.1 生成頭文件

  1. Terminal終端,通過下面命令 切換到項目xx\app\目錄下鳍鸵。
cd D:\Workspace\NDKFirst\app>

注:由于下面的路徑都比較長苇瓣,我們可以右擊相應(yīng)的目錄進(jìn)行快捷復(fù)制:

image
  1. 根據(jù)java文件生成c的頭文件, 執(zhí)行如下命令

格式:javah -d jni -encoding utf-8 -classpath java文件夾路徑 包名+類名

javah -d jni -classpath D:\Workspace\NDKFirst\app\src\main\java com.brainbg.ndkfirst.NDKUtils
或者
javah -d jni -encoding utf-8 -classpath D:\Workspace\NDKFirst\app\src\main\java com.brainbg.ndkfirst.NDKUtils

其中

  • javah :
  • -d jni :創(chuàng)建jni目錄
  • -encoding utf-8 :指定編碼格式為utf-8
  • -classpath D:\Workspace\NDKFirst\app\src\main\java\ :到j(luò)ava目錄的路徑
  • com.brainbg.ndkfirst.JNIUtils :包名+類名

注:不加上-encoding utf-8偿乖,可能會提示錯誤: 編碼GBK的不可映射字符击罪。

  1. 執(zhí)行后,收縮app目錄后重新打開贪薪,會發(fā)現(xiàn)多了一個jni的目錄媳禁,com_brainbg_ndkfirst_NDKUtils.h就是新生成的頭文件。
image

com_brainbg_ndkfirst_NDKUtils.h內(nèi)容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_brainbg_ndkfirst_NDKUtils */

#ifndef _Included_com_brainbg_ndkfirst_NDKUtils
#define _Included_com_brainbg_ndkfirst_NDKUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_brainbg_ndkfirst_NDKUtils
 * Method:    getStringFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_brainbg_ndkfirst_NDKUtils_getStringFromJNI
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

中間一段最為核心:

格式:Java_包名類名方法名

6.2 添加 c/c++文件

  • 添加cpp文件

first.cpp

  • 添加c文件

first.c

#include <jni.h>
#include "com_brainbg_ndkfirst_NDKUtils.h"
 JNIEXPORT jstring JNICALL
 Java_com_brainbg_ndkfirst_NDKUtils_getStringFromJNI(JNIEnv* env, jobject obj) {
     return (*env)->NewStringUTF(env,"This is my first jni!");
 }

修改好的內(nèi)容后画切,你會留意到上面還有提示:大意就是目前的c/c++文件還不屬于項目中的一部分竣稽!為此,我們還需要處理build.gradle霍弹、Android.mk等文件毫别。

image

7.添加mk文件

7.1 添加 Android.mk文件(必加)

注意mk文件里面不能添加注釋,不然編譯不通過典格。

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE        := first-jni
LOCAL_SRC_FILES     := first.c
include $(BUILD_SHARED_LIBRARY)

更多內(nèi)容岛宦,可以直接查看:Android.mk 官方介紹

7.2 添加 Application.mk文件(可選)

APP_PLATFORM := android-16
APP_ABI :=all
  • APP_PLATFORM :指定so庫所支持最低的API
  • APP_ABI:指定生成平臺的so庫

注:不添加Application.mk,會提示Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-16.

更多內(nèi)容耍缴,可以直接查看:Application.mk 官方介紹

8.編譯so庫文件

進(jìn)入app目錄砾肺,執(zhí)行ndk-build進(jìn)行編譯

cd D:\Workspace\NDKFirst\app

ndk-build

執(zhí)行成功后,效果如下

image

同時項目中會得到相應(yīng)的so包防嗡,其中l(wèi)ib為核心变汪,obj為編譯中產(chǎn)生的文件,可刪除蚁趁。

image

9.用Gradle鏈接c++項目

  1. jni目錄中右擊任意文件選擇Link C++ project with Gradle
image
  1. 其中Build System 選擇ndk-build ,Project Path 選擇Android.mk的路徑,而后確認(rèn)裙盾。
image
  1. 完成上面的操作后,app/build.gradle里面會出現(xiàn)如下代碼
android {
   ......

   externalNativeBuild {
        ndkBuild {
            path file('jni/Android.mk')
        }
    }
}

當(dāng)然,下次項目的話闷煤,我們直接加入上面代碼也可童芹。

10.加載so庫、運(yùn)行app

  • NDKUtils.java
public class NDKUtils {
    public static final String TAG = NDKUtils.class.getSimpleName();

    static {
        try {
            System.loadLibrary("first-jni");  //加載so庫
        } catch (UnsatisfiedLinkError e) {
            e.printStackTrace();
            Log.e(TAG,"loadLibrary fail !");
        }
    }

    public static native String getStringFromJNI();
}
  • MainActivity.java
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tvContent = findViewById(R.id.tv_content);
        tvContent.setText(NDKUtils.getStringFromJNI());
    }
}
  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Hello World!" />

</RelativeLayout>
  • 運(yùn)行后效果
image

到此為止鲤拿,第一個關(guān)于NDK假褪、JNI的Demo已經(jīng)完成,相關(guān)文章近顷,后續(xù)可能生音、應(yīng)該、大概也會推出吧窒升。

11.下載地址

GitHub項目下載

參考資料

https://developer.android.google.cn/ndk/guides
https://blog.csdn.net/young_time/article/details/80346631
https://yq.aliyun.com/articles/60710?spm=a2c4e.11153940.0.0.11bc68d9CLrDix

作者:Brainbg
GitHub:https://github.com/Brainbg
博客:https://www.brainbg.com/
簡書:http://www.reibang.com/u/94518ede7100
CSDN:https://blog.csdn.net/u014720022

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缀遍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子饱须,更是在濱河造成了極大的恐慌域醇,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蓉媳,死亡現(xiàn)場離奇詭異譬挚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)酪呻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門减宣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人玩荠,你說我怎么就攤上這事漆腌。” “怎么了阶冈?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵闷尿,是天一觀的道長。 經(jīng)常有香客問我女坑,道長填具,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任堂飞,我火速辦了婚禮灌旧,結(jié)果婚禮上绑咱,老公的妹妹穿的比我還像新娘绰筛。我一直安慰自己,他們只是感情好描融,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布铝噩。 她就那樣靜靜地躺著,像睡著了一般窿克。 火紅的嫁衣襯著肌膚如雪骏庸。 梳的紋絲不亂的頭發(fā)上毛甲,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天,我揣著相機(jī)與錄音具被,去河邊找鬼玻募。 笑死,一個胖子當(dāng)著我的面吹牛一姿,可吹牛的內(nèi)容都是我干的七咧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼叮叹,長吁一口氣:“原來是場噩夢啊……” “哼艾栋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蛉顽,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蝗砾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后携冤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悼粮,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年噪叙,在試婚紗的時候發(fā)現(xiàn)自己被綠了矮锈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,567評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡睁蕾,死狀恐怖苞笨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情子眶,我是刑警寧澤瀑凝,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站臭杰,受9級特大地震影響粤咪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渴杆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一寥枝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧磁奖,春花似錦囊拜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春蜜托,著一層夾襖步出監(jiān)牢的瞬間抄囚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工橄务, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留幔托,地道東北人。 一個月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓蜂挪,卻偏偏與公主長得像柑司,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锅劝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評論 2 359