開始嘗試NDK開發(fā)
圖片用的自己的Github圖床,好像會出現(xiàn)無法識別,看不了的可以轉(zhuǎn)github NDK開發(fā)—Hello World
前言廢語
關(guān)于NDK和JNI的概念介紹,網(wǎng)上一搜一麻袋就不做介紹了,站在初學(xué)者的角度,我們可以簡單的這樣李姐:
NDK(Native develop kit)就是一套工具,能夠使用C/C++語言來實(shí)現(xiàn)部分功能。。
JNI(Java Native Interface)一種接口約定,滿足java和C/C++之間的相互調(diào)用。
當(dāng)然這里面有很多內(nèi)容,比如JavaVM、JNIEnv、JNI原理等等,這些對于初學(xué)者都不重要,我也不懂,先會用,再深入吧。
環(huán)境配置
這一節(jié)可以參考官方教程向您的項(xiàng)目添加 C 和 C++ 代碼
Android studio版本 Bumblebee
NDK版本 20+
- 在
sdk manager中安裝NDK和CMake
[站外圖片上傳中...(image-71e18-1662220675755)]
- 在
Project Structure中指定NDK路徑,如果說沒有,按照提示下載即可。
[站外圖片上傳中...(image-449825-1662220675755)]
下載結(jié)束后Apply時如果提示
NDK does not contain any platforms,自己到相應(yīng)的路徑下面新建一個名為platforms的目錄文件。注意到local.properties文件中確認(rèn)是否有
ndk.dir
開始打代碼
編寫C相關(guān)的代碼
- 新建一個NDKTools類文件,內(nèi)如如下,加上native修飾符,表示這個方法是native實(shí)現(xiàn)。
package com.jiajia.mypractisedemos.module.ndk;
/**
* Created by Numen_fan on 2022/9/1
* Desc:
**/
public class NDKTools {
public static native String getStringFromNDK();
}
- 進(jìn)行項(xiàng)目的編譯,就是build一下,生成NDKTools.class文件。這個class文件在
/app/build/intermediates/javac/debug/classes目錄下。 - 終端進(jìn)入到
/app/build/intermediates/javac/debug/classes目錄,執(zhí)行如下命令。
javah -jni com.jiajia.mypractisedemos.module.ndk.NDKTools
注意前面拼上完整的包名,這里我嘗試進(jìn)入到ndk目錄下,然后執(zhí)行javah -jni NDKTools,提示失敗。
- 執(zhí)行完之后,會在
/app/build/intermediates/javac/debug/classes下生成一個.h的頭文件;內(nèi)容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_jiajia_mypractisedemos_module_ndk_NDKTools */
#ifndef _Included_com_jiajia_mypractisedemos_module_ndk_NDKTools
#define _Included_com_jiajia_mypractisedemos_module_ndk_NDKTools
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_jiajia_mypractisedemos_module_ndk_NDKTools
* Method: getStringFromNDK
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_jiajia_mypractisedemos_module_ndk_NDKTools_getStringFromNDK
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
- 還記得
.h文件在C語言中的角色嗎?其實(shí)就是函數(shù)聲明拉。 - 注意看第一行,提示我們不要擅自編輯呢。
- 新建jni目錄,如果你的項(xiàng)目沒有jni目錄,按照下面的方式新建,不要
New -> Package
[站外圖片上傳中...(image-1f505e-1662220675755)]
這樣新建的jni目錄,會在app的build.gradle中自動添加如下配置
sourceSets {
main {
jni {
srcDirs 'src/main/jni'
}
}
}
- 將剛才生成的
.h聲明文件,移動到j(luò)ni目錄下。 - 在jni目錄下新建一個C語言文件
ndkdemotest.c,編寫代碼如下
#include "com_jiajia_mypractisedemos_module_ndk_NDKTools.h"
JNIEXPORT jstring JNICALL Java_com_jiajia_mypractisedemos_module_ndk_NDKTools_getStringFromNDK (JNIEnv *env, jclass obj) {
return (*env) -> NewStringUTF(env, "我是JNI的Hello World啊");
}
- 注意第一行,需要將剛才的
.h聲明文件引入。 - NewStringUTF是啥,不重要,先知道他返回了一個字符串就行。
- 同在jni目錄下新建
Android.mk文件,寫上如下內(nèi)容
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndkdemotest-jni
LOCAL_SRC_FILES := ndkdemotest.c
include $(BUILD_SHARED_LIBRARY)
- 關(guān)于各個字段的含義,可以找些資料看一下,我還沒搞懂。大體意思就是一些配置,來生成產(chǎn)物。
- 注意
LOCAL_SRC_FILES,這個應(yīng)該就是指定要編譯的C文件;TODO:如果需要編譯多個C文件呢? -
LOCAL_MODULE應(yīng)該就是指定產(chǎn)物的名稱,xxxx.so ?
- 在app的build.gradle中添加如下兩處配置。
android {
defaultConfig {
……
ndk{ // 1
moduleName "ndkdemotest-jni"
abiFilters "arm64-v8a", "armeabi-v7a"
}
}
externalNativeBuild { // 2
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
……
}
- 在代碼中l(wèi)oad產(chǎn)物,我就寫在NDKTools類中。
static {
System.loadLibrary("ndkdemotest-jni");
}
到這里,C相關(guān)的編碼和配置就完成了,這時候可以跑一下代碼,看看會不會報錯,如果報錯的話,就網(wǎng)上找找辦法如何解決。
編寫Android層代碼
- Android層的代碼就很簡單了。
String text = NDKTools.getStringFromNDK();
((TextView)findViewById(R.id.tv_ndk_string)).setText(text);
- 運(yùn)行效果
[站外圖片上傳中...(image-65f270-1662221046008)]