Android native开发技巧
本文主要介绍windows下通过Cmake运行native工程或编译native库的一些基础知识及注意事项。
Windows环境配置
Gradle配置
1.在app下build.gradle的android标签下的defaultConfig标签中增加:
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
cpFlags:设置C++编译器的可选标志 ,可填可不填如:cppFlags "-std=c++11","-fexceptions", "-frtti"
;
abiFilters:指定Gradle应为其输出的平台架构;
arguments:如启用NEON支持,并告诉CMake使用Clang编译器工具链arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"
2.android标签下增加:
//配置cmake
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
若CMakeLissts.txt在其他路径下则直接使用文件夹/
来隔开,如src/main/cpp/CMakeLists.txt
JNI
JNI是Java Native Interface的缩写,通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植。 从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定受支持就可以了。
1、数据类型
- JNI系统类型:JNIEnv(线程上下文)
- 基本数据类型
- 引用类型
- 数组
1.1数据类型映射关系
java类型 | jni.h |
---|---|
boolean | jboolean |
byte | jbyte |
char | jchar |
short | jshort |
int | jint |
long | jlong |
float | jfloat |
double | jdouble |
String | jstring |
Object | jobject |
Class | jclass |
JNI中基本数据类型可当作C的基本数据类型使用;JNI数据类型是C类型的另外一种表述,如下:
C数据类型 | jni数据类型 |
---|---|
typedef unsigned char | jboolean |
typedef signed char | jbyte |
typedef unsigned short | jchar |
typedef short | jshort |
typedef int | jint |
typedef long long | jlong |
typedef float | jfloat |
typedef double | jdouble |
1.2JNI中使用jstring
jstring->char[]
const char* charStr = (*env)->GetStringUTFChars(env,str,NULL);
printf("%s",charStr);
//GetStringUTFChars会申请一块内存,使用后需要对其进行释放
(*env)->ReleaseStringUTFChars(env,str,charStr);
char[]->jstring
const char* charStr = "Hello World";
jstring str = (*env)->NewStringUTF(env,str,charStr );
return str;
1.3JNI内部描述
java方法
public static native void nativeOnPause(String str);
public native void nativeOnResume(String str);
jni方法
/**
*静态方法
*Class: com_test_jni_NativeHelper
*Method:nativeOnPause
*descriptor:(Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_test_jni_NativeHelper_nativeOnPause(JNIEnv* env,jclass clz) ;
/**
*非静态方法
*Class: com_test_jni_NativeHelper
*Method:nativeOnResume
*descriptor:(Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_test_jni_NativeHelper_nativeOnResume(JNIEnv* env,jobject obj) ;
静态方法jni中的参数为jclass来指向类,非静态方法则是参数jobject来接收非静态方法传入的实例化对象。
java类型 | JNI描述 |
---|---|
boolean | Z |
byte | B |
char | C |
short | S |
int | I |
long | L |
float | F |
double | D |
Object | L全路径名称 |
type[] | [Type |
method | (参数类型)返回值 |
可通过javap -s 类路径
指令来查看类的方法描述(若查询本地类的方法描述可以在build/intermediates/javac/类包
下面右键鼠标选择Open in Terminal
后执行上述指令),如图示:
1.4JNI使用技巧
JNI Reference
JNI Reference | 特点 |
---|---|
局部引用LocalRef
|
本地方法栈内有效 |
全局引用 GlobalRef
|
虚拟机全局生效,不会被GC回收 |
弱全局引用WeakGlobalRef
|
虚拟机全局生效,GC时被回收 |
jclass globalClas
extern "C" {
JNIEXPORT void JNICALL Java_com_test_jni_NativeHelper_nativeOnPause(JNIEnv * env, jclass thiz,jobject obj) {
if (globalCls == NULL){
jclass cls = env->GetObjectClass(obj);
//必须调用NewGlobalRef转换成全局引用
globalCls = static_cast<jclass>(env->NewGlobalRef(cls));
}
}
}
//使用结束后调用,删除引用
env->DeleteGlobalRef(globalCls);
jmethodID与jfieldID不是jobject,为指针,直接赋值全局变量即可。
初始化
在初始化时可以提前初始化一些全部变量或进行SDK的授权及签名信息的校验等操作。
JNI_ONLoad
so在被虚拟机加载时调用,只调用一次
JNI_ONUnLoad
//so被卸载时调用
注册方式
静态注册
优点: 理解和使用方式简单,使用相关工具按流程操作就行, 出错率低
缺点: 命名方式遵循特定规则,虚拟机查找方法有一定的性能损耗
动态注册registerNative
优点: 创建java方法与jni方法关联表,灵活性高, 更改类名,包名或方法时, 只需对更改模块进行少量修改, 效率高
缺点: 对新手来说稍微有点难理解, 同时会由于搞错签名, 方法, 导致注册失败