AndroidStudio 3.0 NDK開發1——環境搭建與編譯
前提
JNI開發主要有兩種方式,一種是在Android原始碼中編譯,另外一種是使用AndroidStuido工具開發。主要是看自己的業務場景。
如果你們公司是平臺型開發方式,很容易或者當前就是在Android原始碼中做專案,推薦使用第一種方式,有Swig工具的加持也是效率很高;
如果公司是偏APP開發,得要適配不同平臺,建議使用AndroidStudio工具來開發。本文講這種方式。
使用AndroidStudio編譯C/C++主要有兩種方式:CMake和ndk-build
CMake:需要自己編寫cmake.txt規則,使用CMake工具來編譯;
ndk-build:需要自己編譯Android.mk檔案,使用ndk-build工具來編譯。
因為Android原始碼是使用Android.mk來編譯,所以我更習慣使用ndk-build這種方式。西方是講這種方式。
Prepare
原始碼Android SDK快速迭代,JNI在AndroidStudio不同版本上使用有較大的區別,我這貼出我使用AndroidStudio相關版本的情況
OS | Windows 10 10.0 | |
NDK | 17.2 | |
JDK | JRE: 1.8.0_152-release-915-b01 amd64 | |
AndroidStudio IDE | Android Studio 3.0 Build #AI-171.4408382, built on October 21, 2017 |
|
gradlewrap 版本 | gradle-4.4-all.zip | |
AS gradle外掛 | com.android.tools.build:gradle:3.0.0 |
Starting
1,安裝NDK,CMake,LLDB
2,編寫並編譯JAVA程式碼
第一步,在自己的專案中新建Java Class: MyJniTest.java
package com.aispeech.aistools.jni; /** * @Author: Gangfeng Xu([email protected]) * @Date: 9/14/2018 */ public class MyJniTest { static { System.loadLibrary("hello-jni"); } public native String getJniVersionName(); }
14
14
1
package com.aispeech.aistools.jni;
2
3
/**
4
* @Author: Gangfeng Xu([email protected])
5
* @Date: 9/14/2018
6
*/
7
8
public class MyJniTest {
9
static {
10
System.loadLibrary("hello-jni");
11
}
12
public native String getJniVersionName();
13
14
}
第二步,Ctrl + F9 make專案
第三步,在app/build目錄找到這個類的class檔案
第四步,生成標頭檔案
第一種:進到debug目錄,執行命令生成標頭檔案
C:\Users\koffuxu\02-sulab\aispeech-tools\app\build\intermediates\classes\debug>javah -jni com.aispeech.aistools.jni.MyJniTest C:\Users\koffuxu\02-sulab\aispeech-tools\app\build\intermediates\classes\debug>dir Volume in drive C has no label. Volume Serial Number is 09C1-B27D Directory of C:\Users\koffuxu\02-sulab\aispeech-tools\app\build\intermediates\classes\debug 09/14/201805:05 PM<DIR>. 09/14/201805:05 PM<DIR>.. 09/14/201804:58 PM<DIR>android 09/14/201804:58 PM<DIR>androidx 09/14/201804:58 PM<DIR>com 09/14/201805:05 PM567 com_aispeech_aistools_jni_MyJniTest.h 1 File(s)567 bytes 5 Dir(s)173,480,382,464 bytes free
16
16
1
C:\Users\koffuxu\02-sulab\aispeech-tools\app\build\intermediates\classes\debug>javah -jni com.aispeech.aistools.jni.MyJniTest
2
3
C:\Users\koffuxu\02-sulab\aispeech-tools\app\build\intermediates\classes\debug>dir
4
Volume in drive C has no label.
5
Volume Serial Number is 09C1-B27D
6
7
Directory of C:\Users\koffuxu\02-sulab\aispeech-tools\app\build\intermediates\classes\debug
8
9
09/14/201805:05 PM<DIR>.
10
09/14/201805:05 PM<DIR>..
11
09/14/201804:58 PM<DIR>android
12
09/14/201804:58 PM<DIR>androidx
13
09/14/201804:58 PM<DIR>com
14
09/14/201805:05 PM567 com_aispeech_aistools_jni_MyJniTest.h
15
1 File(s)567 bytes
16
5 Dir(s)173,480,382,464 bytes free
第二種方法:進入需要建立的模組main下面,其實是一樣的,只是這種方法看起來更合規,並且省掉了第五步
C:\Users\koffuxu\02-sulab\aispeech-tools\usbrcvoicelib\src\main>javah -d jni -classpath C:\Users\koffuxu\02-sulab\aispeech-tools\usbrcvoicelib\build\intermediates\classes\debug com.aispeech.usbrcvoicelib.nativeutils.UsbVoiceManager
x
1
C:\Users\koffuxu\02-sulab\aispeech-tools\usbrcvoicelib\src\main>javah -d jni -classpath C:\Users\koffuxu\02-sulab\aispeech-tools\usbrcvoicelib\build\intermediates\classes\debug com.aispeech.usbrcvoicelib.nativeutils.UsbVoiceManager
第五步,建立JNI資料夾,位於java的同級目錄
第六步,把第四步生成的.h檔案copy到這個資料夾,同時建立my_jni_test.c檔案和Android檔案
內容如下:
Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE:= hello-jni#指定了生成的動態連結庫的名字 LOCAL_SRC_FILES := my_jni_test.c #指定了C的原始檔叫什麼名字 include $(BUILD_SHARED_LIBRARY)# 制定要生成動態連結庫
6
1
LOCAL_PATH := $(call my-dir)
2
include $(CLEAR_VARS)
3
LOCAL_MODULE:= hello-jni#指定了生成的動態連結庫的名字
4
LOCAL_SRC_FILES := my_jni_test.c #指定了C的原始檔叫什麼名字
5
6
include $(BUILD_SHARED_LIBRARY)# 制定要生成動態連結庫
my_jni_test.c
#include "com_aispeech_aistools_jni_MyJniTest.h" JNIEXPORT jstring JNICALL Java_com_aispeech_aistools_jni_MyJniTest_getJniVersionName (JNIEnv * env, jobject obj) { return (*env)->NewStringUTF(env, "Hello , I'm from JNI"); }
5
5
1
#include "com_aispeech_aistools_jni_MyJniTest.h"
2
JNIEXPORT jstring JNICALL Java_com_aispeech_aistools_jni_MyJniTest_getJniVersionName
3
(JNIEnv * env, jobject obj) {
4
return (*env)->NewStringUTF(env, "Hello , I'm from JNI");
5
}
第七步,新增編譯專案
在app下面的build.gradule新增
buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } externalNativeBuild { ndkBuild { path 'src/main/jni/Android.mk' } }
11
11
1
buildTypes {
2
release {
3
minifyEnabled false
4
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
5
}
6
}
7
externalNativeBuild {
8
ndkBuild {
9
path 'src/main/jni/Android.mk'
10
}
11
}
或者通過IDE新增
第八步,編譯完成,將看到不同平臺的so檔案
第九步,驗證
在MainActivity.java裡面調MyJniTest的方法,編譯,安裝驗證
Log.e(TAG, "initDate: Jni version="+new MyJniTest().getJniVersionName());
1
1
Log.e(TAG, "initDate: Jni version="+new MyJniTest().getJniVersionName());
列印檢視
多平臺支援
如果需要支援更多平臺,比如Mips,需要在jni的目錄新增Application.mk新增相差引數