JNI使用技巧点滴
Android中JNI编程的那些事儿

Android中JNI编程的那些事儿(1)2011-06-08 09:19 佚名互联网字号: |JNI译为Java本地接口。
它允许Java代码和其他语言编写的代码进行交互。
在android中提供JNI的方式,让Java程序可以调用C语言程序。
android中很多Java类都具有native 接口,这些接口由本地实现,然后注册到系统中。
AD:Android系统不允许一个纯粹使用C/C++的程序出现,它要求必须是通过Java代码嵌入Native C/C++——即通过JNI的方式来使用本地(Native)代码。
因此JNI对Android底层开发人员非常重要。
如何将.so文件打包到.APK让我们先从最简单的情况开始,假如已有一个JNI实现——libxxx.so文件,那么如何在APK中使用它呢?在我最初写类似程序的时候,我会将libxxx.so文件push到/system/lib/目录下,然后在Java代码中执行System.loadLibrary(xxx),这是个可行的做法,但需要取得/system/lib 目录的写权限(模拟器通过adb remount取得该权限)。
但模拟器重启之后libxxx.so文件会消失。
现在我找到了更好的方法,把.so 文件打包到apk中分发给最终用户,不管是模拟器或者真机,都不再需要system分区的写权限。
实现步骤如下:1、在你的项目根目录下建立libs/armeabi目录;2、将libxxx.so文件copy到 libs/armeabi/下;3、此时ADT插件自动编译输出的.apk文件中已经包括.so文件了;4、安装APK文件,即可直接使用JNI中的方法;我想还需要简单说明一下libxxx.so的命名规则,沿袭Linux传统,lib<something>.so是类库文件名称的格式,但在Java的System.loadLibrary(" something ")方法中指定库名称时,不能包括前缀—— lib,以及后缀——.so。
Android中JNI的使用之一:Java原生JNI的使用、javah指令的使用以及图解教材

Android中JNI的使用之一:Java原生JNI的使用、javah指令的使用以及图解教材Java Nativie Interface(JNI,中文名称Java本地接口)标准时Java平台的一部分,它允许Java代码和其他语言写得代码进行交互。
JNI是本地编程接口,它使得Java虚拟机(VM)内部运行的Java代码能够用其他编程语言(如C、C++和汇编语言)编写的应用程序和库进行交互操作。
JNI的主要用途是为了对硬件进行访问以及追求高效率或可重用C/C++库。
Android系统中采用了JNI的方式来调用C/C++方法,然而,在Android系统里进一步加强了Java JNI的使用,使JNI的调用更具有效率。
因此,总的来说,Android 系统里可以采用两种方式来使用JNI。
第一种:Java原生JNI,使用dll等动态链接库;第二种,Android加强版JNI,通过动态加载*.so链接库来进行JNI调用。
今天,我们分析第一种JNI使用方式,也称得上是JNI入门。
由于Java与其他编程语言采用的语法不同,为了让Java与C/C++库函数能进行通信,约定的一个参数类型映射如下:Java类型C/C++类型void voidjboolean booleanjint intjlong longjdouble doublejfloat floatjbyte jbytejchar charjshort shor上面的只是简单类型的一个映射,后面我们会完善其他参数类型的映射。
开发环境介绍(Windows下):Eclipse:主要用来创建Java工程MicrosoftVC++6.0:生成动态链接库供相应的Java文件加载一、使用Eclipse创建Java工程本例中,我们简单的创建了一个Java工程HelloBabyJNI,工程绝对路径位于E:\MyCode\AndroidCode\HelloBabyJNI路径下,主文件路径位于\src\lover\hellojni路径下(路径对后面的javah编译很重要)HelloBabyJNI.java文件如下:[java] view plaincopyprint?1.package com.lover.hellojni;2.3./**4. * 一个简单的Java JNI实例5. *6. */7.public class HelloBabyJNI {8.9./*10. * 静态构造函数,动态加载HelloBabyJNI动态库,其dll文件名为:HelloBabyJNI.dll --->由MSVC6.0软件创建11. */12.static {13. System.load("E:/HelloBabyJNI.dll"); // 可能需要 dll链接库的绝对存放路径14. }15.16./*17. * 在Java中注册需要调用的C/C++本地方法(native method),也就是需要C/C++来实现的方法18. */19.public native int add(int a, int b);20.21.// main方法,加载动态库来调用C/C++本地方法22.public static void main(String[] args) {23. HelloBabyJNI helloBabyJNI = new HelloBabyJNI();24.// 调用注册的add方法来得到返回值25.int result = helloBabyJNI.add(2, 3);26.// 输出27. System.out.println("after invoke the native method,the result is "+ result);28. }29.}2,编译HelloBabyJNI.java文件,生成HelloBabyJNI.class文件,位于路径\src\lover\hellojni\HelloBabyJNI.class3,使用javah指令编译HelloBabyJNI.class文件,生成Java与C/C++之间进行通信的约定接口,它规定了Java中nativemethod在C/C++的具体接口。
jni method 三种调用方法详解 -回复

jni method 三种调用方法详解-回复JNI(Java Native Interface)是Java提供的一种编程接口,用于在Java 程序中调用C/C++编写的本地代码。
在JNI中,有三种主要的调用方法,分别是:1. 静态方法调用2. 实例方法调用3. 字段访问下面将详细介绍每种调用方法的使用步骤和具体操作。
一、静态方法调用静态方法调用是指在Java程序中通过JNI调用C/C++编写的静态方法。
1. 创建Java类和Java本地方法接口(JNI):首先,我们需要创建一个Java类,并在该类中声明一个native方法,用于和本地代码进行交互。
然后,使用`javac`命令编译Java类,生成字节码文件。
接着,使用`javah`命令生成C/C++头文件,该头文件中声明了Java本地方法接口的函数签名。
2. 在C/C++中实现Java本地方法接口:使用C/C++编写实现Java本地方法接口的代码,并编译成动态链接库(DLL/SO)。
确保实现的函数原型和Java本地方法接口中声明的函数原型一致。
3. 加载和调用本地方法:在Java程序中使用System.loadLibrary()或者System.load()加载编译生成的动态链接库。
然后,通过Java类对象的方法调用,调用C/C++编写的静态方法。
二、实例方法调用实例方法调用是指在Java程序中通过JNI调用C/C++编写的实例方法。
1. 创建Java类和Java本地方法接口(JNI):同样的,首先创建一个Java类,并在该类中声明一个native方法,用于和本地代码进行交互。
然后,使用`javac`命令编译Java类,生成字节码文件。
接着,使用`javah`命令生成C/C++头文件,该头文件中声明了Java 本地方法接口的函数签名。
2. 在C/C++中实现Java本地方法接口:使用C/C++编写实现Java本地方法接口的代码,并编译成动态链接库(DLL/SO)。
jni 函数

jni 函数JNI(Java Native Interface)函数是Java语言与本地代码(C/C++)交互的接口协议,可以实现Java应用程序与本地程序之间的互操作。
在使用JNI函数时需要注意一些问题。
首先,调用本地代码需要在Java程序中载入本地库文件。
通过System.loadLibrary函数可以载入本地库文件,也可以通过System.load函数手动载入一个本地库文件。
其次,编写本地代码时需要按照JNI规范编写函数接口。
JNI函数名格式为Java_packagename_Classname_Methodname。
其中,packagename、Classname、Methodname分别为Java程序中类的包名、类名和方法名。
在编写本地代码时,需要使用C/C++编程语言,同时符合JNI规定的函数接口格式,即:JNIEXPORT returnType JNICALLJava_packagename_Classname_Methodname(JNIEnv *env, jobject obj, argtype arg);其中,JNIEXPORT和JNICALL是宏定义,returnType表示函数返回值类型,env是JNIEnv结构的指针,obj是Java对象,argtype是函数参数类型。
最后,需要注意内存管理问题。
Java内存管理由JVM(Java Virtual Machine)自动管理,但在本地代码中需要手动对内存进行管理。
在使用指针时需要注意内存泄漏和空指针异常问题。
总之,JNI函数是Java程序与本地代码交互的桥梁,需要注意本地库文件载入、JNI规范编写函数接口和内存管理等问题。
熟练掌握JNI函数是提高Java程序性能和实现复杂功能的必备技能。
jni跨线程调用注意事项

jni跨线程调用注意事项在Android开发中,JNI(Java Native Interface)是实现Java与C/C++之间交互的桥梁。
通过JNI,我们可以在Java代码中调用C/C++的函数,并且在C/C++中也可以调用Java的方法。
而在JNI 中跨线程调用时,需要特别注意一些事项,以确保线程安全和正确性。
1. 线程安全问题:JNI调用涉及到多个线程之间的交互,因此首先要考虑线程安全性。
在JNI中,每个线程都有自己的JNIEnv环境,因此可以使用JNIEnv来保证线程安全。
在JNI函数中,可以使用JNIEnv的函数来获取当前线程的JNIEnv环境,并在使用JNIEnv时进行同步操作,以避免多线程并发操作引发的竞态条件和数据不一致问题。
2. 线程切换开销:JNI跨线程调用涉及到线程的切换,而线程切换会引入一定的开销。
因此,在设计JNI跨线程调用时,要尽量减少线程切换的次数。
可以通过合理的线程划分和任务调度来减少线程切换的开销,提高JNI跨线程调用的效率。
3. 线程同步问题:在JNI跨线程调用过程中,可能存在多个线程同时修改共享数据的情况,因此需要进行线程同步操作,以避免数据竞争和数据一致性问题。
可以使用互斥锁、条件变量等同步机制来保证线程间的同步和互斥访问。
4. 线程优先级问题:在JNI跨线程调用中,不同的线程可能具有不同的优先级。
因此,在设计JNI跨线程调用时,要考虑线程优先级的问题,合理设置不同线程的优先级,以防止线程优先级导致的饥饿和优先级反转等问题。
5. 线程异常处理:在JNI跨线程调用中,可能出现线程异常的情况,如线程死锁、线程崩溃等。
因此,要合理处理线程异常,及时捕获和处理异常,以确保程序的稳定性和可靠性。
6. JNI函数调用的原子性:在JNI中,函数调用是原子性的,即一个JNI函数的调用是不可被中断的。
因此,在设计JNI跨线程调用时,要考虑JNI函数的原子性,避免在JNI函数执行过程中被中断导致的状态不一致和数据异常。
详解AndroidJNI的基本使用(CMake)

详解AndroidJNI的基本使⽤(CMake)简介什么是JNIJNI的全称是Java Native Interface:Java本地开发接⼝,它提供了若⼲的API实现了Java和其他语⾔的通信(主要是C和C++),⽬的就是Java可以调⽤C或C++开发的函数,C或C++也能调⽤Java的⽅法。
这样有很多有点,其⼀就是效率,C/C++是本地语⾔,⽐java更⾼效;其⼆就是可以复⽤已经存在的C/C++代码;其三是Java反编译⽐C语⾔容易,⼀般加密算法都是⽤C语⾔编写,不容易被反编译。
什么是NDK和CMakeNDK全称是Native Development Kit,NDK提供了⼀系列的⼯具,帮助开发者快速开发C(或C++)的动态库,并能⾃动将so和Java应⽤⼀起打包成apk。
NDK集成了交叉编译器,并提供了相应的mk⽂件隔离CPU、平台、ABI等差异,开发⼈员只需要简单修改mk⽂件(指出“哪些⽂件需要编译”、“编译特性要求”等),就可以创建出so。
CMake是⼀个⽐make更⾼级的编译配置⼯具,它可以根据不同平台、不同的编译器,⽣成相应的Makefile或者vcproj项⽬。
通过编写CMakeLists.txt,可以控制⽣成的Makefile,从⽽控制编译过程。
CMake⾃动⽣成的Makefile不仅可以通过make命令构建项⽬⽣成⽬标⽂件,还⽀持安装(make install)、测试安装的程序是否能正确执⾏(make test,或者ctest)、⽣成当前平台的安装包(make package)、⽣成源码包(make package_source)、产⽣Dashboard显⽰数据并上传等⾼级功能,只要在CMakeLists.txt中简单配置,就可以完成很多复杂的功能,包括写测试⽤例。
如果有嵌套⽬录,⼦⽬录下可以有⾃⼰的CMakeLists.txt。
使⽤流程1、在java⽂件中创建本地⽅法2、build项⽬后⾃动⽣成“.h”⽂件3、创建.cpp⽂件,实现.h⽂件中的⽅法4、配置Cmake⽂件,⽣成“.so”⽂件笔者项⽬⽬录如下:测试实例public class MyJNI {private static final String TAG=MyJNI.class.getName();@Testpublic void test(){JNITest jniTest=new JNITest();Log.d(TAG,jniTest.nativeCalculate(2)+"");}}1、调⽤native⽅法nativeCalculate,传⼊参数2。
java jni方法

java jni方法一、JNI简介JNI(Java Native Interface)是Java虚拟机(JVM)的一个组成部分,它允许Java代码与其他编程语言(如C、C++等)编写的本地代码进行交互。
通过JNI,Java程序可以调用本地代码,实现Java与本地代码的互操作,充分发挥Java平台的可扩展性。
二、JNI的应用场景1.性能优化:当Java代码需要执行一些耗时较长的本地操作时,可以通过JNI调用本地代码,提高程序的执行效率。
2.集成现有系统:在很多情况下,我们需要继承和改造现有的本地系统,通过JNI可以方便地实现这一目标。
3.跨平台开发:JNI允许在不同平台上编写本地代码,实现跨平台应用的开发。
三、JNI编程步骤1.编写Java代码:首先,我们需要编写一个Java类,声明native方法,并在Java代码中调用该方法。
2.编写本地代码:接着,根据Java方法的签名,编写相应的本地代码(如C、C++等)。
3.编译Java代码:将Java代码编译成字节码,并使用javac或javah命令生成JNI头文件。
4.编译本地代码:将本地代码编译成可执行文件。
5.编写Java代码调用本地代码:在Java代码中,使用JNI API调用本地代码。
四、JNI实战案例案例:使用JNI实现文件上传功能1.编写Java代码:创建一个Java类,声明一个native方法,用于实现文件上传功能。
2.编写本地代码:使用C语言编写一个文件上传的本地函数。
3.编译并调用:编译Java代码和本地代码,实现在Java代码中调用本地代码实现文件上传功能。
五、JNI的未来发展趋势随着Java技术的不断发展,JNI在跨平台开发、性能优化等方面的应用将更加广泛。
同时,Java 11等新版本的出现,也为JNI带来了更多便利。
我们可以预见,JNI在未来将继续发挥重要作用,助力Java开发者构建高效、跨平台的应用。
总结:JNI作为Java虚拟机的一个重要组成部分,为Java程序提供了与本地代码互操作的途径。
jni语法

jni语法JNI是Java Native Interface的缩写,它是一种Java与本地代码交互的技术。
在Java应用程序中,JNI提供了一种机制,使其能够调用本地代码(如C或C++代码),并允许本地代码访问Java中的数据和对象。
在本文中,我们将重点介绍JNI语法,帮助读者更好地理解和掌握这项技术。
1. 定义本地方法首先,我们需要在Java代码中定义一个需要调用本地方法的类。
例如,我们有一个名为MyClass的Java类,我们需要在其中定义一个本地方法:public native void someMethod();注意,在本地方法的方法名后加上native关键字是必要的,以标识这是一个本地方法。
2. 生成本地方法头文件现在,我们需要使用Java本机开发工具(如Java开发包中的javah命令)生成一个本地方法头文件。
使用如下命令生成本地方法头文件:javah -classpath . MyClass然后,我们将得到名为MyClass.h的头文件,在其中我们可以看到以下本地方法的定义:JNIEXPORT void JNICALL Java_MyClass_someMethod(JNIEnv *, jobject);其中,JNIEXPORT和JNICALL是两个宏定义,对应于JNI的标准API方法。
3. 实现本地方法现在,我们需要在本地代码中实现someMethod()方法。
在C或C++代码中,我们可以实现这个方法如下:JNIEXPORT void JNICALL Java_MyClass_someMethod(JNIEnv*env, jobject obj) {printf("Hello World!");}在这个本地方法中,有两个参数:JNIEnv和jobject。
JNIEnv指针允许访问Java的运行时系统,而jobject指向调用方法的Java对象。
4. 将本地代码连接到Java一旦我们实现了本地方法,我们需要将本地代码连接到Java代码,使Java应用程序能够调用本地方法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
文章来源:csdn 作者:normalnotebook摘要本文为在32 位Windows 平台上实现Java 本地方法提供了实用的示例、步骤和准则。
本文中的示例使用Sun Microsystems 公司创建的Java Development Kit (JDK) 版本1.4.1。
用C 语言编写的本地代码是用Microsoft Visual C++ 编译器编译生成。
简介近日,由于项目需要,要在WEB页面实现图像转换功能,而VC在图像转换方面有着得天独厚的优势。
我们首先用VC封装出图像转换的DLL,然后用JAVA的本地化方法JNI 调用用于图像转换的DLL,最后用JavaBean调用JNI生成的DLL。
通过近几天在网上找资料和自己的摸索,收获很多,现总结如下,让以后做这方面的人少走弯路。
一. JAVA部分1. 无包的情况:实例一:public class MyNative{static{System.loadLibrary( "MyNative" );}public native static void HelloWord();public native static String cT oJava();}说明:1)在JAVA程序中,首先需要在类中声明所调用的库名称System.loadLibrary( String libname );,在库的搜寻路径中定位这个库。
定位库的具体操作依赖于操作系统。
在windows 下,首先从当前目录查找,然后再搜寻”PATH”环境变量列出的目录。
如果找不到该库,则会抛出UnsatisfiedLinkError。
2)这里加载的是JNI生成的DLL,而不是其他生成的DLL的名称。
在这里,库的扩展名字可以不用写出来,究竟是DLL还是SO,由系统自己判断。
3) 还需要对将要调用的方法做本地声明,关键字为native。
并且只需要声明,而不需要具体实现。
实现放在C中实现,稍后将做说明。
4)如果加了static,表明是静态方法。
如果不加,表明是一般的方法。
加与不加,生成的头文件中有一个参数不同。
稍后将做说明。
现在开始编译它:用javac MyNative.h编译它,生成对应的class文件。
用javah MyNative ,就会生成对应的MyNative.h头文件。
剩下的是就开始交给VC来完成了(我们用VC来实现对应的C实现部分)。
2. 有包的情况:实例二:package com..myNative;public class MyNative{static{System.loadLibrary( "MyNative" );}public native static void HelloWord();public native static String cT oJava();}其他与上面相同,就是在用javac和javah时有所不同。
对于有包的情况一定要注意这一点,开始时我的程序始终运行都不成功,问题就出在这里。
javac ./com/myNative/MyNative.javajavah com.myNative.MyNative上面一句就不用解释了。
对下面的一句解释一下:本类的前面均是包名。
这样生成的头文件就是:com.myNative.MyNative.h。
开始时,在这种情况下我用javah MyNative生成的头文件始终是MyNative.h。
在网上查资料时,看见别人的头文件名砸那长,我的那短。
但不知道为什么,现在大家和我一样知道为什么了吧。
:)。
有时还需要带上路径。
具体查看javah的语法。
二.C实现部分刚才用javah MyNative生成的MyNative.h头文件内容如下:/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class MyNative */#ifndef _Included_MyNative#define _Included_MyNative#ifdef __cplusplusextern "C" {#endif/** Class: MyNative* Method: HelloWord* Signature: ()V*/JNIEXPORT void JNICALL Java_MyNative_HelloWord (JNIEnv *, jclass);/** Class: MyNative* Method: cToJava* Signature: ()Ljava/lang/String;*/JNIEXPORT jstring JNICALL Java_MyNative_cToJava (JNIEnv *, jclass);#ifdef __cplusplus}#endif#endif接下来,就是如何实现它了。
其实,用JNI作出的东西也是DLL,被JAVA所调用。
在具体实现的时候,我们只关心两个函数原型:JNIEXPORT void JNICALL Java_MyNative_HelloWord(JNIEnv *, jclass);和JNIEXPORT jstring JNICALL Java_MyNative_cToJava(JNIEnv *,jclass);现在让我们开始激动人心的第一步吧: ) 。
在project里面选择win32 Dynamic-link Library,然后点击下一步,其余的取默认。
如果不取默认的,将会有dllmain()函数。
取空DLL工程的话,将无这个函数。
我在这里取的是空。
然后选择new->File->C++ Source File,生成一个空*.cpp文件。
我们把他取名为MyNative。
把JNIEXPORT void JNICALL Java_MyNative_HelloWord(JNIEnv *, jclass);和JNIEXPORT jstring JNICALL Java_MyNative_cT oJava(JNIEnv *, jclass);拷贝到CPP文件中去。
然后把头文件包含进来。
生成的MyNative.cpp内容如下:#include <stdio.h>#include "MyNative.h"JNIEXPORT void JNICALL Java_MyNative_HelloWord (JNIEnv *env, jclass jobject){printf("hello word!\n");}JNIEXPORT jstring JNICALL Java_MyNative_cToJavaJNIEnv *env, jclass obj){jstring jstr;char str[]="Hello,word!\n";jstr=env->NewStringUTF(str);return jstr;}在编译前一定要注意下列情况。
注意:一定要把SDK中的include文件夹中(和它下面的win32文件夹下的头文件)的几个头文件拷贝到VC的include文件夹中。
或者在VC的tools\options\directories中设置,把头文件给包含进来。
对程序的一点解释:1)前文不是说过,加了static和不加只是一个参数的区别吗。
就是jclass的不同,不加static这里就是jobject。
也就是JNIEXPORT void JNICALLJava_MyNative_HelloWord(JNIEnv *env, jobject obj)。
2)这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。
而jstring是以JNI为中介使JAVA的String类型与本地的string沟通的一种类型,我们可以视而不见,就当做String使用(具体对应见表一)。
函数的名称是JAVA_再加上java程序的package路径再加函数名组成的(参见有包的情况)。
参数中,我们也只需要关心在JAVA 程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。
3)NewStringUTF()是JNI函数,从一个包含UTF格式编码字符的char类型数组中创建一个新的jstring对象。
4) 以上程序片断jstr=env->NewStringUTF(str);是C++中的写法,不必使用env指针。
因为JNIEnv函数的C++版本包含有直接插入成员函数,他们负责查找函数指针。
而对于C 的写法,应改为:jstr=(*env)->NewStringUTF(env,str);因为所有JNI函数的调用都使用env 指针,它是任意一个本地方法的第一个参数。
env指针是指向一个函数指针表的指针。
因此在每个JNI函数访问前加前缀(*env)->,以确保间接引用函数指针。
在C和Java编程语言之间传送值时,需要理解这些值类型在这两种语言间的对应关系。
这些都在头文件jni.h中,用typedef语句声明了这些类在目标平台上的代价类。
头文件也定义了常量如:JNI_FALSE=0 和JNI_TRUE=1;表一说明了Java类型和C类型之间的对应关系。
表一Java类型和C类型Java编程语C编程语字节言言boolean jboolean 1byte jbyte 1char jchar 2short jshort 2int jint 4long jlong 8float jfloat 4double jdouble 8现在开始对所写的程序进行编译。
选择build->rebuild all对所写的程序进行编译。
点击build->build MyNative.DLL生成DLL文件。
也可以用命令行cl来编译。
具体参看其他书籍。
再次强调(曾经为这个东西大伤脑筋):DLL放置地方1) 当前目录。
2) 放在path所指的路径中3) 自己在path环境变量中设置一个路径,要注意所指引的路径应该到.dll文件的上一级,如果指到.dll,则会报错。
下面就开始测试我们的所写的DLL吧(假设DLL已放置正确)。
public class mytest{public static void main(String[] args){MyNative a=new MyNative();a.HelloWord();System.out.println(a.cToJava());}}注意也要把MyNative.class放在与mytest.java同一个路径下。