位置: 编程技术 - 正文

静态注册JNI和动态注册JNI(jni静态注册和动态注册)

编辑:rootadmin

推荐整理分享静态注册JNI和动态注册JNI(jni静态注册和动态注册),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:jni 静态注册和动态注册区别,静态注册和动态注册的优缺点,静态注册和动态注册的优缺点,android静态注册和动态注册,静态注册和动态注册的优缺点,js静态注册和动态注册的区别,静态注册和动态注册的区别,静态注册和动态注册,内容如对您有帮助,希望把文章链接给更多的朋友!

Android JNI静态注册实例

andriod的SDK 中没有包括 JNI 的支持,而且对如何支持 JNI 也没有任何文档说明。不过既然整个android平台 是开源的,我们可以通过 Google 发布的源代码来找到一些线索(比如 frameworks/base/media/jni/ 目录),依葫芦画瓢的实现上层 JAVA 程序通过 JNI 来调用 Native C 程序中的函数。

依照下面的步骤可以实现一个非常简单的 JNI 的实例程序:

1. 首先编写 C 模块,实现动态库。(关于如何在 Android 中编译 C 模块的更多细节,请参考《Android编译Native C 模块 》。)

在 development 目录下添加新目录 hellolib ,并添加 hellolib.c 和 Android.mk 文件。 hellolib.c 的内容如下:

[cpp] view plaincopy#include <jni.h> #define LOG_TAG "TestLib" #undef LOG #include <utils/Log.h> JNIEXPORT void JNICALL Java_com_test_TestHelloLib_printHello(JNIEnv * env, jobject jobj) { LOGD("Hello LIB!/n"); }

注意这里的函数名需要按照 JNI 的规范(因此也可以用 javah -jni 工具来生成头文件,来保证函数名的正确性).

Java_com_test_TestHelloLib_printHello 的命名对应后面在 java 代码中, package 名字是 com.test ,类名是TestHelloLib , native 函数名是 printHello 。

另外, LOGD 及 #define LOG_TAG "TestLib" 等打印 log 的方式是采用了 Android 所提供的 LOG 机制,这样才能通过 Android 的 logcat 工具看到 log 。

用于编译 C 模块的 Android.mk 文件内容如下:

[cpp] view plaincopyLOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= / hellolib.c LOCAL_C_INCLUDES := / $(JNI_H_INCLUDE) LOCAL_SHARED_LIBRARIES := / libutils LOCAL_PRELINK_MODULE := false LOCAL_MODULE := libhello include $(BUILD_SHARED_LIBRARY)

该文件中的一些变量分别对应的含义如下:

LOCAL_SRC_FILES - 编译的源文件

LOCAL_C_INCLUDES - 需要包含的头文件目录

LOCAL_SHARED_LIBRARIES - 链接时需要的外部库

LOCAL_PRELINK_MODULE - 是否需要 prelink 处理(参考 prelink 的详细介绍:《 动态库优化 ——Prelink(预连接)技术 》, Android 的 Toolchain, prelink 工具:《 Android Toolchain与 Bionic Libc 》 )

LOCAL_MODULE - 编译的目标对象

BUILD_SHARED_LIBRARY - 指明要编译成动态库。

接下来回到 Android 顶层目录,并执行 make libhello 来编译:

[cpp] view plaincopy# cd $(YOUR_ANDROID) && make libhello target thumb C: libhello <= development/hellolib/hellolib.c target SharedLib: libhello (out/target/product/generic/obj/SHARED_LIBRARIES/libhello_intermediates/LINKED/libhello.so) target Non-prelinked: libhello (out/target/product/generic/symbols/system/lib/libhello.so) target Strip: libhello (out/target/product/generic/obj/lib/libhello.so) Install: out/target/product/generic/system/lib/libhello.so

编译结果可得到位于 out/target/product/generic/system/lib/ 目录的动态共享库 libhello.so

2 .编写 Java 模块,来通过 JNI 方式调用 C 接口。具体 Eclipse 环境的搭建请参考 Android SDK 文档中的详细说明,及 Hello Android 程序的创建过程,这里仅给出我们需要修改的 TestHelloLib.java 文件:

[c-sharp] view plaincopypackage com.test; import android.app.Activity; import android.os.Bundle; public class TestHelloLib extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); printHello(); } static { System.loadLibrary("hello"); } private native void printHello(); }

注意上面代码部分: private native void printHello() 用来声明一个 native 接口;

static {

System.loadLibrary("hello");

}

用来加载上面步骤中生成 libhello.so (注意 loadLibrary 方法的参数不是 ”libhello.so” ,而是去掉前缀和后缀之后的”hello” ), onCreate() 方法中则调用了 printHello() 接口。

通过这一步骤可生成 Android 开发者所熟悉的 apk 文件: TestHelloLib.apk 。

3 .集成测试 TestHelloLib.apk 和 libhello.so 。先运行 emulator 并将 TestHelloLib.apk 和 libhello.so 上传至 emulator中。注意要将 libhello.so 上传到 emulator 的 /system/lib 目录,由于该目录是只读的,上传之前先要执行 adb remount:

[cpp] view plaincopy# adb remount # adb push out/target/product/generic/system/lib/libhello.so /system/lib # adb install TestHelloLib.apk

接下来在模拟器菜单中可以看到已经安装的 TestHelloLib 程序,运行即可。

由于 JNI 接口 printHello() 并没有作界面上的改动,要验证其效果需要用 Android 的 logcat 工具来查看。运行 ”adb logcat” 可以找到下面的 log 片断:

[cpp] view plaincopyI/ActivityManager( ): Starting activity: Intent { action=android.intent.action.MAIN categories={android.intent.category.LAUNCHER} flags=0x comp={com.test/com.test.TestHelloLib} } I/ActivityManager( ): Start proc com.test for activity com.test/.TestHelloLib: pid= uid= gids={} D/dalvikvm( ): Trying to load lib /system/lib/libhello.so 0xc D/dalvikvm( ): Added shared lib /system/lib/libhello.so 0xc D/dalvikvm( ): No JNI_OnLoad found in /system/lib/libhello.so 0xc D/dalvikvm( ): &#;&#;&#; not scanning '/system/lib/libwebcore.so' for 'printHello' (wrong CL) D/dalvikvm( ): &#;&#;&#; not scanning '/system/lib/libmedia_jni.so' for 'printHello' (wrong CL) D/TestLib ( ): Hello LIB! I/ActivityManager( ): Displayed activity com.test/.TestHelloLib: ms

这里包含了调用 printHello() 接口的 log 信息,其中 ” D/TestLib ( ): Hello LIB!” 就是 printHello() 所打印的信息。至此成功完成 Android JNI 的实例验证。

动态注册实例

在在纯java中使用JNI文章中可以看到,java的native方法与C/C&#;&#;代码函数是通过Java_<包名>_<类名>_<方法名>这种方式对应的,即它是静态注册的。当需要使用现有的C/C&#;&#;代码函数时,需要以这种形式定义包装函数,在包装函数中调用现有C/C&#;&#;代码函数;而且这样的函数名也非常长,不适合管理。使用动态注册,可以不受上述命名的限制。

静态注册JNI和动态注册JNI(jni静态注册和动态注册)

运行下面示例需要安装NDK及搭建环境,请看另一篇文章使用NDK与环境搭建

下面我将Android NDK中的sampleshello-jni示例,由原来的静态注册改为动态注册,只需要改JNI部分。

sampleshello-jnijnihello-jni.c的原代码如下

[cpp] view plaincopy#include <string.h> #include <jni.h> /* This is a trivial JNI example where we use a native method * to return a new VM String. See the corresponding Java source * file located at: * * apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java */ jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) { return (*env)->NewStringUTF(env, "Hello from JNI !"); }

将其改为[cpp] view plaincopy#include <stdlib.h> #include <string.h> #include <stdio.h> #include <jni.h> #include <assert.h> /* This is a trivial JNI example where we use a native method * to return a new VM String. See the corresponding Java source * file located at: * * apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java */ jstring native_hello(JNIEnv* env, jobject thiz) { return (*env)->NewStringUTF(env, "动态注册JNI"); } /** * 方法对应表 */ static JNINativeMethod gMethods[] = { {"stringFromJNI", "()Ljava/lang/String;", (void*)native_hello},//绑定 }; /* * 为某一个类注册本地方法 */ static int registerNativeMethods(JNIEnv* env , const char* className , JNINativeMethod* gMethods, int numMethods) { jclass clazz; clazz = (*env)->FindClass(env, className); if (clazz == NULL) { return JNI_FALSE; } if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE; } /* * 为所有类注册本地方法 */ static int registerNatives(JNIEnv* env) { const char* kClassName = "com/example/hellojni/HelloJni";//指定要注册的类 return registerNativeMethods(env, kClassName, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); } /* * System.loadLibrary("lib")时调用 * 如果成功返回JNI版本, 失败返回-1 */ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) { return -1; } assert(env != NULL); if (!registerNatives(env)) {//注册 return -1; } //成功 result = JNI_VERSION_1_4; return result; }

改成动态注册后,当调用HelloJni类的public native String stringFromJNI()方法时,会找到动态注册的native_hello函数。

上面的代码没什么难点,唯一看不明白的可能是方法对应表,下面来讲讲

JNINativeMethod是JNI机制定义的一个结构体

[cpp] view plaincopytypedef struct { const char* name; //Java中函数的名字 const char* signature; //用字符串描述的函数的参数和返回&#; void* fnPtr; //指向C函数的函数指针 } JNINativeMethod;

比较难以理解的是第二个参数,例如

"()V"

"(II)V"

"(Ljava/lang/String;Ljava/lang/String;)V"

实际上这些字符是与函数的参数类型一一对应的。

"()" 中的字符表示参数,后面的则代表返回&#;。例如"()V" 就表示void Func();

"(II)V" 表示 void Func(int, int);

具体的每一个字符的对应关系如下

字符 Java类型 C类型

V void voidZ jboolean booleanI jint intJ jlong longD jdouble doubleF jfloat floatB jbyte byteC jchar charS jshort short

数组则以"["开始,用两个字符表示

[I jintArray int[][F jfloatArray float[][B jbyteArray byte[][C jcharArray char[][S jshortArray short[][D jdoubleArray double[][J jlongArray long[][Z jbooleanArray boolean[]

上面的都是基本类型。如果Java函数的参数是class,则以"L"开头,以";"结尾中间是用"/" 隔开的包及类名。而其对应的C函数名的参数则为jobject. 一个例外是String类,其对应的类为jstring

Ljava/lang/String; String jstringLjava/net/Socket; Socket jobject

如果JAVA函数位于一个嵌入类,则用$作为类名间的分隔符。

例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"

转自:

深入了解android平台的jni---注册native函数 注册native函数有两种方法:静态注册和动态注册。1、静态注册方法根据函数名找到对应的JNI函数:Java层调用函数时,会从对应的JNI中寻找该函数,如果

Android 接口回调实例 Android接口回调方法处处涉及到,比如常用的Button点击事件就是一个接口回调,可见掌握熟练使用接口回调方法的重要性。接口回调的简单解释就是:比

Android中Context详解 大家好,今天给大家介绍下我们在应用开发中最熟悉而陌生的朋友-----Context类,说它熟悉,是应为我们在开发中时刻的在与它打交道,例如:Service、Broa

标签: jni静态注册和动态注册

本文链接地址:https://www.jiuchutong.com/biancheng/378123.html 转载请保留说明!

上一篇:多点触控(苹果多点触控)

下一篇:深入了解android平台的jni---注册native函数(深入了解是啥意思)

  • 计提本月个人所得税
  • 怎么下载税控盘开票软件
  • 减免增值税款怎么算
  • 一次性年金怎么计算
  • 基本户被冻结怎么缴投标保证金
  • 收到货物损失赔偿标准
  • 生产成本二级科目有工资吗
  • 租金收入个人所得税
  • 资产剥离类型
  • 港币转人民币怎么转账
  • 黄金以旧换新工费多少钱一克
  • 购买面粉的税率是多少
  • 红字发票怎么做帐
  • 机打发票领回怎么录入
  • 上个月的印花税,这个月交款怎么做分录
  • 注册资本转让税率
  • 农副产品免税怎么报税
  • 闲置资金购买理财产品
  • 汇算清缴相关分录有哪些
  • 应收账款收不回来了怎么销账
  • 工程预算费用会计怎么做
  • 房地产企业收取的诚意金
  • 出口退税业务流程顺序
  • xp系统咋样
  • 加工费的会计处理
  • 滴滴代驾报酬
  • win11如何设置开机自启动软件
  • type3插件
  • 出口退税转内销的话如何算发票金额
  • php零基础教程
  • controller 层
  • 有关预收账款的会计科目
  • 如何开启framework 3.5
  • vue脚手架安装命令
  • 程序员的表白情书
  • 什么情况下可以赔偿n+1
  • win11设置项改中文
  • php注册和登录界面
  • 进项发票和销项发票统计
  • 帝国cms标题生成图片
  • 公司必须要申报工资流水吗
  • 增发股票购买子公司
  • 外来原始凭证审核内容
  • 什么叫境外所得
  • 个体户电子申报税流程
  • 处置子公司如何纳税
  • 新《准则》适用对象为
  • 超详细的mac重装系统教程
  • 员工工资需要交税吗
  • 对方开给我的专票,我要报税吗?
  • 现金流量表财务费用包括哪些内容
  • 合同履约成本与一份当前或预期取得的区别
  • 申报要补税怎么办
  • 个税手续费返还比例
  • 上年结转会计分录
  • 企业将购进的原材料分录
  • 租入的房子再出租用交房产税吗?
  • 企业收到财政补助收入账务处理
  • 制造费用是借还是贷
  • 公司为员工购买汽车怎么申报
  • 回收锯末木屑价格
  • 担任会计职务的英语
  • sql解析框架
  • linux中的rpm
  • 如何使用光盘做启动盘
  • 升级win10系统后鼠标键盘无法用什么原因
  • win8系统切换桌面
  • windows多屏显示
  • 从五方面解析Linux防火墙框架问题
  • 打开字符面板
  • win10系统自带虚拟机怎么用
  • jquery时间轴插件
  • ObjectAnimator Demo
  • cmd 字符集
  • linux的sed -i
  • js文件保存
  • 海关免税金额现在是多少金额
  • 金税工程什么意思
  • 行政事业单位自办食堂规定
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设