- 1.背景
- 2.介紹
- 3.下載 NDK 和工具
- 4.配置NDK的環(huán)境變量
-
5.創(chuàng)建native相關(guān)方法
- 5.1 native相關(guān)方法去掉報紅 -
6.創(chuàng)建c/c++文件
- 6.1 生成頭文件
- 6.2 添加 c/c++文件 -
7.添加mk文件
- 7.1 添加Android.mk
文件(必加)
- 7.2 添加Application.mk
文件(可選) - 8.編譯so庫文件
- 9.用Gradle鏈接c++項目
- 10.加載so庫、運(yùn)行app
1.背景
本來一直在做商城類的項目舒坦著缸托,突然老板拿了一塊Android的主板和芯片過來兆蕉,說我們打算做一款自動售貨機(jī)度宦,從沒做過這類項目的我,當(dāng)時就一臉懵逼了,芯片亡电、自動售貨機(jī)函喉,What?還好我依稀記得酪碘,這類項目是關(guān)于NDK帖世、JNI的,于是棍苹,我來了无宿!
2.介紹
- 什么是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皮迟。
- 為什么使用NDK搬泥?
- 代碼的保護(hù)。由于apk的java層代碼很容易被反編譯伏尼,而C/C++庫反匯難度較大忿檩。
- 可以方便地使用現(xiàn)存的開源庫。大部分現(xiàn)存的開源庫都是用C/C++代碼編寫的爆阶。
- 提高程序的執(zhí)行效率燥透。將要求高性能的應(yīng)用邏輯使用C開發(fā),從而提高應(yīng)用程序的執(zhí)行效率辨图。
- 便于移植班套。用C/C++寫得庫可以方便在其他的嵌入式平臺上再次使用。
- 什么是JNI故河?
JNI的全稱是Java Native Interface吱韭,它提供了若干的API實(shí)現(xiàn)了Java和其他語言的通信(主要是C和C++)。
- 為什么使用JNI鱼的?
JNI的目的是使java方法能夠調(diào)用c實(shí)現(xiàn)的一些函數(shù)理盆。
- 安卓中的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 管理器安裝這些組件
- 依次打開 Settings>Appearance&Behavior>System Settings>Android SDK>SDK Tools
- 勾上LLDB湿刽、CMake 和 NDK進(jìn)行下載
4.配置NDK的環(huán)境變量
- 打開File > Project Structure > SDK Location,選擇默認(rèn)NDK的路徑
- 復(fù)制NDK的路徑
- 右擊我的電腦>屬性>高級系統(tǒng)設(shè)置>環(huán)境變量>新建褐耳,添加一個系統(tǒng)變量NDK_HOME诈闺,并把剛才復(fù)制的ndk-bundle的路徑填上去,記得確認(rèn)。
- 找到Path系統(tǒng)變量(不需要創(chuàng)建)铃芦,新建一個%NDK_HOME%雅镊,也就是上面NDK_HOME的變量添加進(jìn)去襟雷。
-
在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)方法
5.1 native相關(guān)方法去掉報紅
取消檢測即可,打開 Settings>Editor>Inspections>Android>Missing JNI function 去掉勾選征唬。
去掉后捌显,效果如下:
6.創(chuàng)建c/c++文件
6.1 生成頭文件
- Terminal終端,通過下面命令 切換到
項目xx\app\
目錄下鳍鸵。
cd D:\Workspace\NDKFirst\app>
注:由于下面的路徑都比較長苇瓣,我們可以右擊相應(yīng)的目錄進(jìn)行快捷復(fù)制:
- 根據(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的不可映射字符
击罪。
- 執(zhí)行后,收縮app目錄后重新打開贪薪,會發(fā)現(xiàn)多了一個jni的目錄媳禁,
com_brainbg_ndkfirst_NDKUtils.h
就是新生成的頭文件。
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等文件毫别。
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í)行成功后,效果如下
同時項目中會得到相應(yīng)的so包防嗡,其中l(wèi)ib為核心变汪,obj為編譯中產(chǎn)生的文件,可刪除蚁趁。
9.用Gradle鏈接c++項目
- jni目錄中右擊任意文件選擇
Link C++ project with Gradle
- 其中
Build System
選擇ndk-build ,Project Path
選擇Android.mk的路徑,而后確認(rèn)裙盾。
- 完成上面的操作后,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)行后效果
到此為止鲤拿,第一個關(guān)于NDK假褪、JNI的Demo已經(jīng)完成,相關(guān)文章近顷,后續(xù)可能生音、應(yīng)該、大概也會推出吧窒升。
11.下載地址
參考資料
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