JNI动态注册封装C语言版

Android  NDK  2023年7月3日 am8:08发布1年前 (2023)更新 城堡大人
126 0 0

前言

在上一篇《JNI调用Java方法》的动态注册并调用Java方法,上次也说了可以把公共部分封装一下。

说干就干,今天就把上次代码封装一下。

正文

我这不介绍完整的动态注册,有需要可以看《JNI动态注册》。这里只是个人流水账。

Hello.java

package com.biumall.dynamic.one;
public class Hello {
    //1. load Hello.so
    static {
        System.loadLibrary("Hello");
    }
    // 2. define native computer()
    public static native int computer(String type, int a, int b);
    //add
    public int add(int x, int y) {
        return x + y;
    }
    //sub
    public int sub(int x, int y) {
        return x - y;
    }
}

JNI

把之前Hello.c的代码拆分为Log.h,JNICommon.h和Hello.c,也就是吧公共部分单独抽出,这样移植就方便多了。

Log.h
#include <android/log.h>

//定义TAG日志打印
#define LOG_TAG "from_dynamic_jni_"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

网上有封装Log等级控制,方便控制日志打印,目前没空,后续补上。

JNICommon.h

就获取数组大小和本地方法注册。

#include <jni.h>

//获取数组大小
#define ARRAY_LENGTH(x) ((int)(sizeof(x) / sizeof((x)[0])))

//注册本地方法
int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods,int methods_size) {
    jclass clazz = (*env)->FindClass(env, className);
    if (!clazz) {
        return JNI_ERR;
    }
    int result = (*env)->RegisterNatives(env, clazz, methods, methods_size);
    if (result < 0) {
        return JNI_ERR;
    }
    return JNI_OK;
}
Hello.c

特意把每步单独隔开,方便初学者(我就是)查看。

#include "JNICommon.h"
#include "Log.h"
#include<string.h>

/**
 * ---------------------------第一步 start ---------------------------
 * 定义Hello.java类路径[包名+类名,只不过.换成了/]
 * 包名+类名:com.biumall.dynamic.one.Hello
 */
#define DYNAMIC_CLASS "com/biumall/dynamic/one/Hello"
/**
 * ---------------------------第一步  end  ---------------------------
 */

/**
 * ---------------------------第二步 start ---------------------------
 * c_add()用于调用Java方法
 * @param env env
 * @param jclazz jclazz
 * @param x x
 * @param y y
 * @return
 */
int c_add(JNIEnv *env, jclass jclazz, int x, int y) {
    jmethodID methodID = (*env)->GetMethodID(env, jclazz, "add", "(II)I");
    jobject object = (*env)->AllocObject(env, jclazz);
    return (*env)->CallIntMethod(env, object, methodID, x, y);
}

/**
 * c_sub()用于调用Java方法
 * @param env env
 * @param jclazz jclazz
 * @param x x
 * @param y y
 * @return
 */
int c_sub(JNIEnv *env, jclass jclazz, int x, int y) {
    jmethodID methodID = (*env)->GetMethodID(env, jclazz, "sub", "(II)I");
    jobject object = (*env)->AllocObject(env, jclazz);
    return (*env)->CallIntMethod(env, object, methodID, x, y);
}

/**
 * 本地方法computer实现
 */
JNIEXPORT jint JNICALL native_computer(JNIEnv *env, jclass jclazz, jstring type, jint a, jint b) {
   
    const char *charType = (*env)->GetStringUTFChars(env, type, 0);
    int count;
    if (!strcmp(charType, "-")) {
        count = c_sub(env, jclazz, a, b);
    } else if (!strcmp(charType, "+")) {
        count = c_add(env, jclazz, a, b);
    }
    (*env)->ReleaseStringUTFChars(env, type, charType);
    return count;
}
/**
 * ---------------------------第二步  end  ---------------------------
 */

/**
 * ---------------------------第三步 start ---------------------------
 * 定义Java和JNI函数的绑定表
 * 方法数组,分别为:(native方法 , 方法签名 , 函数指针[JNI中需要实现的方法名])
 * 通过javac和javap 获取 方法签名
 */
JNINativeMethod method_table[] = {
        {"computer", "(Ljava/lang/String;II)I", (void *) native_computer},
};
/**
 * ---------------------------第三步  end  ---------------------------
 */

/**
 * ---------------------------第四步 start ---------------------------
 * JNI_OnLoad
 */
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved ){
    JNIEnv *env = NULL;
    int result = (*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6);
    LOGD("JNI_OnLoad 1 result : %d", result);
    if(result != JNI_OK){
        return JNI_ERR;
    }
    result = registerNativeMethods(env, DYNAMIC_CLASS, method_table, ARRAY_LENGTH(method_table));
    LOGD("JNI_OnLoad 2 result : %d", result);
    if(result != JNI_OK){
        return JNI_ERR;
    }
    return JNI_VERSION_1_6;
}
/**
 * ---------------------------第四步  end  ---------------------------
 */

参考文章

  1. JNI调用Java方法

 历史上的今天

  1. 2021: 西蒙·阿米德奇 :黄昏(0条评论)
  2. 2020: [摘]System.exit(0)和System.exit(1)区别(0条评论)
  3. 2019: 刘继荣:不想当英雄,只想做那个坐在路边为英雄鼓掌的人(0条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

AS动态配置module时异常

前言动态配置module时出现如下错误提示。Could not compile build file 'D:\Android\WaterFun\UserCenter\build.gradle'.> startup failed: build file 'D:\Android\Wat...

付志勇:故乡

魂牵梦绕的故乡常被我瘦弱的文字描绘成梦中的新娘 带着他简单的行囊夜夜步入我的心房与我一诉衷肠 而今我走在陌生的路上故乡成为我真实的阳光恬静地照耀我的天空让我不再感到山高水远不在犹豫彷徨幸福春天一样抵达身旁

Ubuntu16.04搭建LAMP架构服务器笔记

这是在自己电脑上搭建的LAMP环境自己开发和练习使用,在这里总记录一下1、安装Apache2sudo apt-get install apache2PS:这里会生产服务器根目录/var/www/,我们可以改变到自己想要的目录下方法一:修改配置文件sudo vim /etc/apa...

【摘】Android:获取内部存储信息方法总结

前言Android开发中,需要获取磁盘的大小信息。项目中也有获取磁盘信息的方法,但只有一种,因此摘抄了网上的 《Android : 获取内部存储信息方法总结》正文方法一private long getSDCardAvailSize() { String state = Envir...

[摘]adb 查看系统设置参数

获取系统默认输入法adb shell settings get secure default_input_method更改默认输入法(改为com.sohu.inputmethod.sogouoem/.SogouIME)adb shell settings put secure default_...

史铁生:合欢树

10岁那年,我在一次作文比赛中得了第一。母亲那时候还年轻,急着跟我说她自己,说她小时候的作文作得比我还要好,老师甚至不相信那么好的文章会是她写的。“老师找到家来问,是不是家里的大人帮了忙。我那时可能还不到10岁呢。”我听得扫兴,故意笑:“可能?什么叫‘可能还不到’?”她就解释,我装作根本不在意她的话...