Jni 三方so文件集成到自己so文件

这只是个示例,通过静态注册生成的so(模拟三方的so文件),集成到一个自己需要生成的so文件,提供给Java调用。如果不会静态注册生成so,参考之前文章Jni使用方法

1.在jni目录下新建test文件夹,将通过静态生成的so文件(模拟第三方so),放在test文件夹里,必须将.h头文件也放进去

Jni 三方so文件集成到自己so文件_第1张图片
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");
2.编写自己的需要的C文件

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();
}

3.mk文件配置

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

4.编译产物

ndk编译后libs会生成两个so,libactive是我们需要的,这样Activity就可以直接调用ActiveJni
里的三个方法了
Jni 三方so文件集成到自己so文件_第2张图片

5.附录

参考文章

动态注册中 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头文件,打开头文件,里面也可以看到对应的签名,它能够自动生成

你可能感兴趣的:(Android)