Jni实现与原生代码通信

5 篇文章 0 订阅

(以Hello-jni为例)

1.原生方法声明

stringFromJNI方法声明中含有关键字native以通知java编译器,它用另一种语言提供该方法的具体实现。因为原生方法没有方法体,方法声明以语句终结符分号结尾。

public native String stringFromJNI();

尽管虚拟机知道该方法被原生实现,但是仍然不知道到哪去找方法的实现。

2.加载共享库

原生方法被编译成一个共享库。需要先加载该共享库以便于虚拟机能够找到原生方法实现。java.lang.System类提供了两个静态方法。load和loadLibrary用于在运行时加载共享库。
因为想加载原生代码实现,正如类首次加载和初始化一样,所以在静态上下文中调用loadLibary方法。

Java技术的设计目标是平台独立,作为Java框架API的一部分,loadLibrary也要保持平台独立性。尽管Android NDK生成的实际共享库被命名libhello-jni.so,但是loadlibrary方法只采用hello-jni这个库名,在按照所使用的具体操作系统要求加上必要的前缀和后缀。

loadLibrary的参数也不包含共享库的位置。Java库路径,也就是系统属性java.library.path保存loadlibrary方法在共享库搜索的目录列表,Android上的java库路径包含/vendor/lib和system/lib。

需要强调的是,loadlibrary在扫描java库路径时,一旦发现同名的库,立即加载共享的库。因为Java库路径的第一组目录是Android系统的目录,为了避免与系统库命名冲突,强烈建议Android开发人员为每个共享库选择唯一的名字。

3.实现原生方法

hello.c源文件以jni.h头文件包含语句开头,这个头文件中包含JNI数据类型和函数定义。
原生方法stringFromJNI用一个名为Java_com_example_hellojni_stringFromJNI的完全限定的函数来声明,这种显示的函数命名让虚拟机在加载的共享库中自动查找原生函数。

1使用C/C++头文件生成器 javah
2方法声明

JNIEXPORT jstring JNICALL Java_com_example_hellojni_stringFromJNI(JNIEnv*,jobject);

第一个参数JNIENV是只想可用JNI函数表的接口指针;第二个参数jobject是HelloJni类实例的Java对象引用。

(1)JNIEnv接口指针
原生代码通过JNIEnv接口指针提供的各种函数来使用虚拟机的功能。JNIEnv是一个指向县城-局部数据的指针,而县城-局部数据中包含指向函数表 的指针。实现原生方法的函数将JNIEnv接口指针作为他们的第一参数。
(2)实例方法与静态方法
Java程序设计语言有两类方法:实例方法和静态方法。实例方法与类实例相关,他们只能在类实例中调用。静态方法不与类实力相关,他们可以在静态上下文直接调用。他们可以在静态上下文直接调用。静态方法 和实例方法均可以声明为原生的,可以通过JNI技术以原生代码的形式提供他们的实现。原生实例方法通过第二个参数获取实例引用,该参数是jobject类型的。

JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv*,jobject this);

因为静态方法没有与实力绑定,因此通过第二个参数获取类引用而不是实力引用,第二个参数是jclass值类型。

JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv*,jclass this);

正如在方法定义中看到的,JNI提供了自己的数据类型从而让原生代码了解Java数据类型。

源自《Android C++高级编程–使用NDK》书中内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值