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这种方式。西方是讲这种方式。
源码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 |
1,安装NDK,CMake,LLDB
2,编写并编译JAVA代码
第一步,在自己的项目中新建Java Class: MyJniTest.java
package com.aispeech.aistools.jni; /** * @Author: Gangfeng Xu(gangfeng.xu@aispeech.com) * @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(gangfeng.xu@aispeech.com)
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/2018 05:05 PM <DIR> . 09/14/2018 05:05 PM <DIR> .. 09/14/2018 04:58 PM <DIR> android 09/14/2018 04:58 PM <DIR> androidx 09/14/2018 04:58 PM <DIR> com 09/14/2018 05:05 PM 567 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/2018 05:05 PM <DIR> .
10
09/14/2018 05:05 PM <DIR> ..
11
09/14/2018 04:58 PM <DIR> android
12
09/14/2018 04:58 PM <DIR> androidx
13
09/14/2018 04:58 PM <DIR> com
14
09/14/2018 05:05 PM 567 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添加相差参数