最终的工程结构如下:
package com.fpliu.jnitest;
public class XX {
static {
System.loadLibrary("xx");
}
public native String getText();
}
这里面特别注意:加载动态库的方式,通常是在Java类的静态代码块中,因为类加载器在加载一个类的时候, 类的静态成员和静态代码块最先执行,然后才会调用构造方法进行构造实例,之后,那些native
方法才能正确执行。 当然,你也可以在其他地方加载,只是需要进行判断操作。
被native
修饰的方法就是要使用C/C++实现的方法,所以,它只是声明,没有方法体。
被native
修饰的方法也可以被其他修饰符所修饰,比如static
。
1、切换到app/src/main/java
目录:
cd ~/JNITest/app/src/main/java
2、使用javah命令生成头文件
javah -jni com.fpliu.jnitest.XX
这样就在app/src/main/java
目录中生成了头文件com.fpliu.jnitest.XX.h
,文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_fpliu_jnitest_XX */
#ifndef _Included_com_fpliu_jnitest_XX
#define _Included_com_fpliu_jnitest_XX
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_fpliu_jnitest_XX
* Method: getText
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_fpliu_jnitest_XX_getText
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
1、创建app/src/main/jni
目录:
mkdir -p app/src/main/jni
2、把com.fpliu.jnitest.XX.h
剪切到app/src/main/jni
目录中:
mv java/com.fpliu.jnitest.XX.h jni/
3、编写实现文件xx.c
,内容如下:
#include "com_fpliu_jnitest_XX.h"
JNIEXPORT jstring JNICALL Java_com_fpliu_jnitest_XX_getText (JNIEnv *env, jobject obj) {
return (*env)->NewStringUTF(env, "Hello NDK !");
}
注意:你可以使用C实现, 也可以使用C++实现,根据自己的需要而定,但是, 语言不同,env
这个变量的使用不一样喔,注意这一点!
1、在app/src/main/jni
目录中创建Android.mk
文件,内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := xx
LOCAL_SRC_FILES := xx.c
include $(BUILD_SHARED_LIBRARY)
2、在app/src/main
目录中执行ndk-build
命令:
3、将生成的app/src/main/libs
目录剪切到某个gradle模块的根目录下:
mv app/src/main/libs app/
4、配置此gradle模块中的build.gradle
:
android {
...
defaultConfig {
...
ndk {
moduleName "xx" //生成的so名字
abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库
}
}
sourceSets.main {
jniLibs.srcDir(['libs'])
jni.srcDirs = [] //disable automatic ndk-build call
}
}
jni.srcDirs = []
这表示,在构建apk
的过程中, 不自动使用ndk-build
构建so
,因为我们自己构建好了。
abiFilters "armeabi", "armeabi-v7a", "x86"
这个有两方面的作用:一方面是, 当gradle自动构建so
的时候,根据此生成对应平台的so
, 没有设置的话,就是所有平台的so
都会生成;另一方面是控制生成的apk
的lib
目录下包含哪些目录, 只有这里列出的才包含,如果这里没有设置,那就看你自己生成的CPU
平台有哪些,如果没有自己生成的,那么就是全部CPU
平台的都有。
这里,在实际使用的过程中要特别注意,因为你引用了别人的SDK
或者库,它可能只支持某些CPU
平台的, 你不得不放弃它不支持的CPU
平台的话,就配置这个就行。
如果你不知道你引用的那些SDK
或者库到底支持了哪些CPU
平台, 构建完成apk
后,解压看看lib
目录下的那些个文件夹里面的so
数量是否一样多, 如果不一样多,一定有问题,少的那个CPU
平台在运行过程中就要崩溃了。
5、如何你是让gradle自动帮你构建你的JNI
代码的, 请确保工程根目录下的local.properties
中配置了正确的ndk
路径:
ndk.dir=/usr/local/opt/android-ndk/android-ndk-r14b
sdk.dir=/usr/local/share/android-sdk
6、运行工程,看效果吧!