Android進階: 10分鐘實現NDK-JNI 開發教程
專案簡介
JNI:Java Native Interface(Java 本地程式設計介面),一套程式設計規範,它提供了若干的 API 實現了 Java 和其他語言的通訊(主要是 C/C++)。Java 可以通過 JNI 呼叫本地的 C/C++ 程式碼,本地的 C/C++ 程式碼也可以呼叫 java 程式碼。Java 通過 C/C++ 使用本地的程式碼的一個關鍵性原因在於 C/C++ 程式碼的高效性。
NDK:Native Development Kit(本地開發工具),一系列工具的集合,提供了一系列的工具,幫助開發者快速開發 C/C++,極大地減輕了開發人員的打包工作。
專案環境
- Android studio 3.1.2
- gradle 4.4 plugin 3.1.2
- targetSdkVersion 28
Jni三部曲

_20181115163118.png
- 1.新建Java檔案編寫相關程式碼
- 2.通過命令工具Terminal生成.h檔案
- 3.新建.c 或者.cpp檔案編寫相關程式碼
環境配置
1.安裝NDK+CMake

_20181115163801.png
- NDK:這套工具集允許為 Android 使用 C 和 C++ 程式碼。
- CMake:一款外部構建工具,可與 Gradle 搭配使用來構建原生庫。如果只計劃使用 ndk-build,則不需要此元件。
Ps:CMake 是 AS 2.2 之後加入的一個跨平臺的安裝(編譯)工具,可以用簡單的語句來描述所有平臺的安裝(編譯過程),簡單來說就是簡化 JNI 開發的編譯步驟
2.NDK環境配置
1.local.properties
ndk.dir=D\:\\workTime\\android-studio-sdk-2.3\\android-studio-sdk-2.3\\ndk-bundle sdk.dir=D\:\\workTime\\android-studio-sdk-2.3\\android-studio-sdk-2.3
2.gradle.properties
#gradle:3.0.1studio3.0 之前用 android.useDeprecatedNdk=true #gradle:3.0.1studio3.0 之後用 android.deprecatedNdkCompileLease=1511832698813
3.build.gradle中新增CMake
android { ......... externalNativeBuild { cmake { path "CMakeLists.txt" } } }
4.在app目錄下新建CMakeLists.txt
CMakeLists.txt所在目錄和上面path "CMakeLists.txt"相關連
CMakeLists.txt中內容如下:
# CMake的編譯指令碼配置檔案 # 1. 標註需要支援的CMake最小版本 cmake_minimum_required(VERSION 3.4.1) # 2. add_library 定義需要編譯的程式碼庫 名稱, 型別, 包含的原始碼 add_library( # Sets the name of the library. JNIControl # Sets the library as a shared library. SHARED src/main/jni/JNIControl.cpp ) # 3. find_library 定義當前程式碼庫需要依賴的系統或者第三方庫檔案(可以寫多個) find_library( log_lib # 指定要查詢的系統庫, 給一個名字 log# 真正要查詢的liblog.so或者liblog.a ) # 4. target_link_libraries設定最終編譯的目的碼庫 target_link_libraries( JNIControl# add_library 生成的 ${log_lib} # find_library 找到的系統庫 ) }

_20181115165205.png
到這裡環境就搭建完成了,那麼下面我們開始裝逼了。。。
執行裝逼三部曲
1.新建要編譯成.h檔案的java檔案

_20181115172932.png
/** * <pre> *author : Wp *e-mail : [email protected] *time: 2018/11/15 *desc: *version: 1.0 * </pre> */ public class JNIUtils { static { //JNIControl 後面新建的.c 或者.cpp 檔名在這裡可以先註釋掉 System.loadLibrary("JNIControl"); } public static native String printStringByJni(); }
2.開啟Android studio 最下面的命令工具Terminal
1.進入java目錄下,預設為專案根目錄
cd app/src/main/java

_20181115170020.png
2.如上圖,確保在java目錄下,執行以下命令,會在java目錄下生成.h檔案
javah king.bird.ndkjnidemo.JNIUtils
3.main下面新建jni資料夾,將.h檔案拷貝過來

_20181115170622.png
4. .h檔案如下
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class king_bird_ndkjnidemo_JNIUtils */ #ifndef _Included_king_bird_ndkjnidemo_JNIUtils #define _Included_king_bird_ndkjnidemo_JNIUtils #ifdef __cplusplus extern "C" { #endif /* * Class:king_bird_ndkjnidemo_JNIUtils * Method:printStringByJni * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_king_bird_ndkjnidemo_JNIUtils_printStringByJni (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
3.編寫.c或者.cpp檔案

_20181115170848.png

_20181115170953.png
JNIControl.cpp檔案內容:
#include "king_bird_ndkjnidemo_JNIUtils.h" //king_bird_ndkjnidemo_JNIUtils_printStringByJni 包名+檔名+檔案內方法名 JNIEXPORT jstring JNICALL Java_king_bird_ndkjnidemo_JNIUtils_printStringByJni (JNIEnv *env, jclass jclass){ //字串返回 return env->NewStringUTF("沒想到吧!我竟然會JNI了!!!"); }
到這裡已經大功告成了

_20181115171352.png
1.MainActivity檔案
package king.bird.ndkjnidemo import android.support.v7.app.AppCompatActivity import android.os.Bundle import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mBtnLoadNative.setOnClickListener { val jniUtils = JNIUtils.printStringByJni() mTvText.text = jniUtils } } }
2.activity_main.xml檔案
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout 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/mTvText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/mBtnLoadNative" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="LoadNativeText" app:layout_constraintTop_toBottomOf="@+id/mTvText" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" tools:ignore="HardcodedText" /> </android.support.constraint.ConstraintLayout>
參與貢獻
- Fork 本專案
- 新建 Feat_xxx 分支
- 提交程式碼
- 新建 Pull Request
個人說明
- 編譯報錯或有什麼問題call me
- QQ群:830556582
- QQ:1101313414
github地址
- ofollow,noindex">你的star和fork是我永生的追求