1.首先新建一个DynamicTest类。
package com.demo.dynamicjni;
public class DynamicTest {
public native int doTwo(int param1, int param2);
}
2.使用External Tools生成.h文件。
点击File-Settings-Tools,选择External Tools,然后点击add,弹出Create Tool.
配置参数如下:
Name:javah
Description:javah
Program:$JDKPath$\bin\javah.exe
Parameters:-classpath . -jni -d $ModuleFileDir$\src\main\jni $FileClass$
Working directory:$ModuleFileDir$\src\main\Java
然后选中DynamicTest,右键,点击javah。
修改.h文件。
修改
JNIEXPORT jint JNICALL Java_com_demo_dynamicjni_DynamicTest_doTwo
为
JNIEXPORT jint JNICALL addTwoNumber
3.新建dynamicJni.cpp文件。
#include <com_demo_dynamicjni_DynamicTest.h>
#ifdef __cplusplus
extern "C" {
#endif
//指向类
static const char *className = "com/demo/dynamicjni/DynamicTest";
//doTwo是DynamicTest类中声明的函数,addTwoNumber是.h文件中声明的
static JNINativeMethod gJni_Methods_DynamicTest[] = {
{"doTwo", "(II)I", (void*)addTwoNumber},
};
JNIEXPORT jint JNICALL addTwoNumber(JNIEnv *env, jobject, jint param1, jint param2) {
return 1000 * (param1 + param2);
}
static int jniRegisterNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
clazz = (env)->FindClass( className);
if (clazz == NULL) {
return -1;
}
int result = 0;
if ((env)->RegisterNatives(clazz, gMethods, numMethods) < 0) {
result = -1;
}
(env)->DeleteLocalRef(clazz);
return result;
}
jint JNI_OnLoad(JavaVM* vm, void* reserved){
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return result;
}
jniRegisterNativeMethods(env, className, gJni_Methods_DynamicTest, sizeof(gJni_Methods_DynamicTest) / sizeof(JNINativeMethod));
return JNI_VERSION_1_4;
}
#ifdef __cplusplus
}
#endif
4.新建Android.mk和Application.mk文件。
Android.mk如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := dynamic
LOCAL_SRC_FILES := dynamicJni.cpp
include $(BUILD_SHARED_LIBRARY)
Application.mk如下:
APP_ABI:= all
5.修改build.gradle(Module:app)。
增加
sourceSets.main {
jni.srcDirs = []
}
task ndkBuild(type:Exec,description:'Compile JNI source via NDK'){
commandLine getNdkBuildCmd(),
//配置ndk的路径
'NDK_PROJECT_PATH=build/intermediates/ndk',
//ndk默认的生成so的文件
'NDK_LIBS_OUT=src/main/jniLibs',
//配置的我们想要生成的so文件所在的位置
'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
//指定项目以这个mk的方式
'NDK_APPLOCATION_MK=src/main/jni/Application.mk'
//指定项目以这个mk的方式
}
tasks.withType(JavaCompile){
//使用ndkBuild
compileTask ->compileTask.dependsOn ndkBuild
}
以及
def getNdkDir() {
if (System.env.ANDROID_NDK_ROOT != null)
return System.env.ANDROID_NDK_ROOT
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def ndkdir = properties.getProperty('ndk.dir', null)
if (ndkdir == null)
throw new GradleException("NDK location not found. Define location with ndk.dir in the local.properties file or with an ANDROID_NDK_ROOT environment variable.")
return ndkdir
}
def getNdkBuildCmd() {
def ndkbuild = getNdkDir() + "/ndk-build"
if (Os.isFamily(Os.FAMILY_WINDOWS))
ndkbuild += ".cmd"
return ndkbuild
}
最终完整版文件如下:
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.demo.dynamicjni"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets.main {
jni.srcDirs = []
}
task ndkBuild(type:Exec,description:'Compile JNI source via NDK'){
commandLine getNdkBuildCmd(),
//配置ndk的路径
'NDK_PROJECT_PATH=build/intermediates/ndk',
//ndk默认的生成so的文件
'NDK_LIBS_OUT=src/main/jniLibs',
//配置的我们想要生成的so文件所在的位置
'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
//指定项目以这个mk的方式
'NDK_APPLOCATION_MK=src/main/jni/Application.mk'
//指定项目以这个mk的方式
}
tasks.withType(JavaCompile){
//使用ndkBuild
compileTask ->compileTask.dependsOn ndkBuild
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
def getNdkDir() {
if (System.env.ANDROID_NDK_ROOT != null)
return System.env.ANDROID_NDK_ROOT
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def ndkdir = properties.getProperty('ndk.dir', null)
if (ndkdir == null)
throw new GradleException("NDK location not found. Define location with ndk.dir in the local.properties file or with an ANDROID_NDK_ROOT environment variable.")
return ndkdir
}
def getNdkBuildCmd() {
def ndkbuild = getNdkDir() + "/ndk-build"
if (Os.isFamily(Os.FAMILY_WINDOWS))
ndkbuild += ".cmd"
return ndkbuild
}
6.调用DynamicTest中的doTwo,测试so。
修改MainActivity,增加DynamicTest的使用。
记得要调用System.loadLibrary("dynamic")
package com.demo.dynamicjni;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private DynamicTest dynamicTest;
static {
System.loadLibrary("dynamic");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dynamicTest = new DynamicTest();
Log.d(TAG,"dynamicTest test = " + dynamicTest.doTwo(1,2));
}
}
7.最后,build project即可(build project的时候会自动执行ndkBuild)。
log如下所示。
附上简单demo链接:
https://github.com/VIVILL/DynamicJNI
参考链接: