概述

可能大家觉得javah生成的函数名又臭又长,不太好看。这里可以提供另外一种方法来动态注册c++函数,让其根Java中的native方法关联起来。

实现

这里通过JNIEnv的Resisternatives方法完成方法的注册。相关方法介绍:

//方法映射描述结构体
typedef struct {
const char* name;//Java方法名
const char* signature;//方法签名
void* fnPtr;//C++ 方法指针
} JNINativeMethod; //这是JNIEnv提供的注册本地方法
//clazz:方法对应的class
//methods:对应的方法数组指针
//nMethods:有几个方法
//返回值:注册成功返回JNI_OK
jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,
jint nMethods); //当本地库被加载时VM调用JNI_OnLoad(例如,通过系统调用LoadLibrary)。JNI_OnLoad必须返回由本地库所需的JNI版本。
//为了使用任何新的JNI函数,一个本地库必须导出JNI_OnLoad函数并返回JNI_VERSION_1_2或更高的版本。
//如果本地库不导出JNI_OnLoad功能,VM假定库只需要JNI_VERSION_1_1版本。
//如果虚拟机不认JNI_OnLoad返回的版本号,本地库不能加载。
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved);

看了上面的函数,我们可以知道在loadLibrary的时候会首先调用JNI_OnLoad。因此打算在JNI_OnLoad中完成方法注册:

/filename:my.cpp
// Created by wastrel on 2016/9/8.
//
#include <stddef.h>
#include "jni.h" //返回一个字符串
JNIEXPORT jstring JNICALL native_hello(JNIEnv *env, jclass clazz) {
return env->NewStringUTF("Hello from C++");
}
//求两个int的值
JNIEXPORT jint JNICALL native_add(JNIEnv *env, jobject object, jint a, jint b) {
return a + b;
}
//方法数组,JNINativeMethod的第一个参数是Java中的方法名,第二个参数是函数签名,第三个参数是对应的方法指针。
//Java方法的签名一定要与对应的C++方法参数类型一致,否则注册方法可能失败。
static JNINativeMethod method_table[] = {
{"native_hello", "()Ljava/lang/String;", (void *) native_hello},
{"native_add", "(II)I", (void *) native_add}
}; JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
//OnLoad方法是没有JNIEnv参数的,需要通过vm获取。
JNIEnv *env = NULL;
if (vm->AttachCurrentThread(&env, NULL) == JNI_OK) {
//获取对应声明native方法的Java类
jclass clazz = env->FindClass("com/example/registerjni/HelloJNI");
if (clazz == NULL) {
return JNI_FALSE;
}
//注册方法,成功返回正确的JNIVERSION。
if (env->RegisterNatives(clazz, method_table, sizeof(method_table)/ sizeof(method_table[]))==JNI_OK) {
return JNI_VERSION_1_4;
}
}
return JNI_FALSE;
}

对应的native声明Java文件:

package com.example.registerjni;

/**
* Created by wastrel on 2016/9/8.
*/
public class HelloJNI {
static {
System.loadLibrary("helloJNI");
} public native static String native_hello();
public native int native_add(int a,int b);
}
注意:如果你的方法声明了static,那么对应的第二个参数应该是jclass类型。如果你清楚他的实际类型,即便你写成jobject也不会引起程序错误,因为jclass本身也是jobject。但还是建议写为正确的方式,这样可以显得清晰一些。

注意:C++和Java有所不同,如果把static JNINativeMethod method_table 写在开头,你编译的时候会提示找不到函数指针,这是因为自上而下编译的原因。所以应该把定义写在实现方法后面,或者用一个头文件来完成函数的定义。

后记

这只是一种建立Native方法与Java方法的方式,如果没有特殊的需要,不建议使用这种方法来注册。因为使用这种优雅的注册方法,你必须确保你的函数方法和签名的正确性。这可能会增加出错的概率。

Android Studio NDK JNI动态注册本地方法的更多相关文章

  1. JNI动态注册native方法及JNI数据使用

    前言 或许你知道了jni的简单调用,其实不算什么百度谷歌一大把,虽然这些jni绝大多数情况下都不会让我们安卓工程师来弄,毕竟还是有点难,但是我们还是得打破砂锅知道为什么这样干吧,至少也让我们知道调用流 ...

  2. windows android studio 编译Jni动态库

    项目需要,折腾了半天搞定windows android studio环境编译Jni动态库,现记录下来. 准备安装环境: 1. android studio 下载地址是http://www.androi ...

  3. 【Android】Eclipse自动编译NDK/JNI的三种方法

    [Android]Eclipse自动编译NDK/JNI的三种方法 SkySeraph Sep. 18th  2014 Email:skyseraph00@163.com 更多精彩请直接访问SkySer ...

  4. 【Android】Eclipse自己主动编译NDK/JNI的三种方法

    [Android]Eclipse自己主动编译NDK/JNI的三种方法 SkySeraph Sep. 18th  2014 Email:skyseraph00@163.com 一.Eclipse关联cy ...

  5. Android studio 下JNI编程实例并生成so库

    Android studio 下JNI编程实例并生成so库 因为公司需要为Android相机做美颜等图像后期处理,需要使用JNI编程,最近学了下JNI,并且在Android Studio下实现了一个小 ...

  6. Android Studio NDK环境配置

    本文参考:Android Studio NDK环境配置及JNI使用方法:http://blog.csdn.net/tongseng/article/details/53005123 并添加自己的实践: ...

  7. 【Android】Android Studio NDK 开发

    Android Studio NDK 开发 记录在Android Studio中NDK简单开发的步骤 用到的Android Studio版本为3.5. 配置NDK 下载NDK 一般在SDK下已经有自带 ...

  8. JNI-使用RegisterNatives注册本地方法

    转自: http://blog.chinaunix.net/uid-26009923-id-3410141.html 1. 以前在jni中写本地方法时,都会写成 Java_com_example_he ...

  9. Android Studio下jni应用

    最近在将一个小应用从eclipse开发迁移到android studio,程序中有native代码实现,在eclipse是靠Android.mk这么个mk文件来组织编译的,但到android stud ...

随机推荐

  1. new 操作符 做了什么

    new 操作符 做了什么 new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例. 假设Test是一个构造函数,通常在创建对象的实例时,要使用new,eg:test = new ...

  2. [原创]IIS提权工具-VBS提权脚本免杀生成器

    [原创]添加系统用户 VBS提权脚本随机加密生成器[K.8] 2011-05-05 02:42:53|  分类: 原创工具 VBS提权脚本随机加密生成器[K.8]  Author: QQ吻 QQ:39 ...

  3. PythonDay02——编程语言、python介绍以及安装解释器、运行程序的两种方式、变量

    一.编程语言 1.1 机器语言:直接用计算机能理解的二进制指令编写程序,直接控制硬件 1.2 汇编语言:用英文标签取代二进制指令去编写程序,本质也是直接控制硬件 1.3 高级语言:用人能理解的表达方式 ...

  4. Python GUI之tkinter窗口视窗教程大集合(看这篇就够了)

    一.前言 由于本篇文章较长,所以下面给出内容目录方便跳转阅读,当然也可以用博客页面最右侧的文章目录导航栏进行跳转查阅. 一.前言 二.Tkinter 是什么 三.Tkinter 控件详细介绍 1. T ...

  5. ITP项目:一期版本分享

    摘要: 原创出处: http://www.cnblogs.com/Alandre/ 泥沙砖瓦浆木匠 希望转载,保留摘要,谢谢! 写代码和练书法一样,要坚持.昨晚的提笔留下. 一.项目小结: 项目经历了 ...

  6. [UWP]为什么ContentControl的ControlTemplate里放两个ContentPresenter会出问题(绕口)

    1. 简单的HeaderedContentControl 上周五收到反馈,在一个ContentControl的ControlTemplate中放两个ContentPresenter会出错.出错的例子是 ...

  7. 痞子衡嵌入式:恩智浦LPC系列MCU开发那些事 - 索引

    大家好,我是痞子衡,是正经搞技术的痞子.本系列痞子衡给大家介绍的是恩智浦LPC系列微控制器相关知识. 恩智浦半导体最早于2003年便开始推出LPC系列MCU,但早期的产品LPC2000/3000系列属 ...

  8. java节假日

    public class CalendarTest { //节假日列表 private static List<Calendar> holidayList = new ArrayList& ...

  9. 2017 ACM/ICPC Asia Regional Shenyang Online(部分题解)

    HDU 6197 array array array 题意 输入n和k,表示输入n个整数和可以擦除的次数k,如果至多擦除k次能是的数组中的序列是不上升或者是不下降序列,就是魔力数组,否则不是. 解题思 ...

  10. python模块之pickle、shelve、json

    一 什么是序列化 序列化指的是将内存中的数据结构转化为一种中间格式,并存储到硬盘上. (反序列化:将硬盘上存储的中间格式数据再还原为内存中的数据结构) 二 为什么要序列化 持久保持状态 需知一个软件/ ...