这只是个示例,通过静态注册生成的so(模拟三方的so文件),集成到一个自己需要生成的so文件,提供给Java调用。如果不会静态注册生成so,参考之前文章Jni使用方法
com_tayh_buttontest_ndkdemo_Hellojni.h 头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_tayh_buttontest_ndkdemo_Hellojni */
#ifndef _Included_com_tayh_buttontest_ndkdemo_Hellojni
#define _Included_com_tayh_buttontest_ndkdemo_Hellojni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_tayh_buttontest_ndkdemo_Hellojni
* Method: getStringFromC
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_tayh_buttontest_ndkdemo_Hellojni_getStringFromC
(JNIEnv *, jclass);
/*
* Class: com_tayh_buttontest_ndkdemo_Hellojni
* Method: callLogFromJni
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_tayh_buttontest_ndkdemo_Hellojni_callLogFromJni
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
hello.c
#include
#include
#include "com_tayh_buttontest_ndkdemo_Hellojni.h"
#include
#define LOG_TAG "TEST"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
JNIEXPORT jstring JNICALL Java_com_tayh_buttontest_ndkdemo_Hellojni_getStringFromC
(JNIEnv * env, jclass jclass){
LOGI("helloword");
return (*env)-> NewStringUTF(env,"helloword");
}
JNIEXPORT void JNICALL Java_com_tayh_buttontest_ndkdemo_Hellojni_callLogFromJni
(JNIEnv * env, jclass jclass){
__android_log_print(ANDROID_LOG_INFO,LOG_TAG,"from jni log");
active.cpp里 getMethods()有三个方法,getRandomNum打印随机数,printValue打印一句话log,这两个是实现自己里面的用于测试而已,
callLogFromJni2 这个就是自定义方法用于调用三方so库的里的方法(Java_com_tayh_buttontest_ndkdemo_Hellojni_callLogFromJni 这个就是三方头文件里的方法名,作用也是打一句log)
注意:1.com/tayh/buttontest/ndkdemo/ActiveJni 是对应自己的java调用文件。
2.接口参数要与java对应上 如,()V 代表不传参,返回void;()I 代表不传参,返回int。
active.cpp:
#ifndef ACTIVE_CPP
#define ACTIVE_CPP
// jni头文件
#include
#include
#include
#include
#include
#include
using namespace std;
//native 方法实现
jint get_random_num(){
return rand();
}
//native 方法实现
void printValue(){
__android_log_print(ANDROID_LOG_INFO,"TEST","active print");
}
/*需要注册的函数列表,放在JNINativeMethod 类型的数组中,
以后如果需要增加函数,只需在这里添加就行了
参数:
1.java中用native关键字声明的函数名
2.签名(传进来参数类型和返回值类型的说明)
3.C/C++中对应函数的函数名(地址)
*/
static JNINativeMethod getMethods[] = {
"getRandomNum","()I",(void*)get_random_num,
"printValue","()V",(void*)printValue,
"callLogFromJni2","()V",(void*)Java_com_tayh_buttontest_ndkdemo_Hellojni_callLogFromJni
};
//此函数通过调用RegisterNatives方法来注册我们的函数
static int registerNativeMethods(JNIEnv* env, const char* className,JNINativeMethod* getMethods,int methodsNum){
jclass clazz;
//找到声明native方法的类
clazz = env->FindClass(className);
if(clazz == NULL){
return JNI_FALSE;
}
//注册函数 参数:java类 所要注册的函数数组 注册函数的个数
if(env->RegisterNatives(clazz,getMethods,methodsNum) < 0){
return JNI_FALSE;
}
return JNI_TRUE;
}
static int registerNatives(JNIEnv* env){
//指定类的路径,通过FindClass 方法来找到对应的类
const char* className = "com/tayh/buttontest/ndkdemo/ActiveJni";
return registerNativeMethods(env,className,getMethods, sizeof(getMethods)/ sizeof(getMethods[0]));
}
//回调函数
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
JNIEnv* env = NULL;
//获取JNIEnv
if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
assert(env != NULL);
//注册函数 registerNatives ->registerNativeMethods ->env->RegisterNatives
if(!registerNatives(env)){
return -1;
}
//返回jni 的版本
return JNI_VERSION_1_6;
}
#endif
ActiveJni
public class ActiveJni {
static {
System.loadLibrary("active");
}
public static native int getRandomNum();
public static native void callLogFromJni2();
public static native void printValue();
}
Android.mk
手机端是arm64-v8a,预处理这个文件夹里的so
active是我们需要生成的so库名
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello
LOCAL_SRC_FILES := test/arm64-v8a/libhello.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/test
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := active
LOCAL_SRC_FILES := active.cpp
LOCAL_SHARED_LIBRARIES := libhello
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
Application.mk
只生成arm64-v8a里的so
APP_PLATFORM := android-19
APP_ABI := arm64-v8a
ndk编译后libs会生成两个so,libactive是我们需要的,这样Activity就可以直接调用ActiveJni
里的三个方法了
参考文章
动态注册中 JNINativeMethod 结构体中第二个参数需注意
括号内代表传入参数的签名符号,如果为空括号内什么都不用写,括号外代表返回参数的签名符号,为空的话要写大写的V,对应关系见下表
参数对应表’
签名符号 JNI java
V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short
[Z jbooleanArray boolean[]
[I jintArray int[]
[J jlongArray long[]
[D jdoubleArray double[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]
L完整包名加类名; jobject class
举个例子:
传入的java参数有两个 分别是 int 和 long[] 函数返回值为 String 即java函数的定义为:String getString(int a ,long[] b)
签名就应该是 “(I[J)Ljava/lang/String;”
如果有内部类 则用 $ 来分隔 如: Landroid/os/FileUtils$FileStatus; (这个我自己没有试过)
用静态注册方式注册函数时,会生成.h头文件,打开头文件,里面也可以看到对应的签名,它能够自动生成