JNI详解以及使用Java调c代码
来源:互联网 发布:南京大学cssci数据库 编辑:程序博客网 时间:2024/05/19 01:10
**JNI详解**
什么是JNI
JNI Java Native interface 一种协议 提供一套编程框架,java和本地代码相互调用
为什么需要JNI
1.操作底层硬件,Android平台上传感器
2.应用程序对运行效率有要求,图形渲染,音视频解码
3.复用成熟C开源软件,OpenGL,OpenSSL,SQLite3,FFmpeg
4.安全性要求,本地C代码反编译困难
5.复用公司之前成熟代码,跑跑卡丁车
C基本数据类型 c里面char占1byte,而java占2bytes;C里面的long占4bytes ,java中占8bytes c里面没有boolean类型,可以用unsigned char代替 //signed unsigned ,整数类型前缺省表示signedC语言输入输出函数 都需要包含头文件stdio.h d u o x 整数,c s,fC语言格式化输出都需要用到占位符,常用的占位符如下: %d 十进制有符号 int %u 十进制无符号 unsigned int %o 八进制无符号 unsigned int %x 十六进制无符号 unsigned int 在%o和%x中间加#,输出前导0,0x %c - char 表示字符 char 类型如果以%d输出会打印当前字符的ASII值 %c 输出一个字符 %s 输出一个字符串,若干个 若要输出long和double类型,在相应字符前l %ld %lf 输出short类型用 %hd %p输出变量的地址 格式化输入函数scanf d c s f 输入其它数据 printf(“请输入整数:”); scanf(“%d”,&i);//&i告诉scanf输入数据存到哪 输入字符串写法 char buf[10];//字符数组,可以保存字符串 ‘\0’作为字符串的结束标志 printf(“输入字符串:”); scanf(“%s”,buf);//数组名代表数组首元素首地址 buf[0] &buf[0]什么是指针
1.内存:操作系统管理的一类存储资源.
最小单位1byte,8bits,一维线性分布 32cpu 4G内存的地址空间 1k = 1024bytes 2^10 1M = 1024k = 1024 * 1024 bytess 2^20 1G = 1024M = 1024 * 1024 * 1024 bytes 2^30 4G = 4 * 1G = 2^2 * 2^30 = 2^322.内存单元:通过内存编号来区分管理,内存单元的编号可以作为内存单元的地址
3.指针:在C中把内存单元的编号称指针
指针变量 普通变量:一般数据 指针变量:保存内存单元地址,可以利用指针运算符*访问内存的三种应用含义 ## 3 * 5 : *乘法 int *p; : *定义指针变量,*区分了变量类型 *p = i; *取对象运算符指针的指向 :指向:如果一个指针变量保存了一个对应类型变量的首地址,指针变量指向这个变量,可以用指针运算符*访问指向变量。 int i = 20; char c = ‘k’; int *p; char *q; p = &i;//指针变量p指向i q = &c; //p = &c; //p = (int *)&c;//如果真要保存需要强转 (要转的指针类型) //*p数组的特点:
1.元素数据类型相同
2.元素在内存中连续的
3.数组名代表首元素首地址 arr <=> &arr[0]
指针与数组的关系 a[i]函数指针
函数指针:函数在代码段起始地址,函数入口地址
函数指针变量:函数的入口地址
函数名代表函数的入口地址
void funA();//函数声明int funB(int *a,int n);//函数声明void (*pfA)();//函数指针变量,可以保存funA地址int (*pfB)(int *,int);//函数指针变量的定义,可以保存funB函数的入口地址
结构体与联合体
typedef关键字
typedef 作用是给己经存在的数据类型起别名
int a;//a是变量名,是一个标识符ypedef int a;//typedef 让a成为与int 完全等价的类型名a b;//用类型别名定义变量int c;//用原类型名定义量a <=> intstruct Student *pstu;//pstu是一个结构体指针变量,是一个标识符typedef struct Student *pstu;//typedef 让pstu成为了与struct Student*等价的类型别名pstu k;struct Student *m;
相关基本概念
交叉编译:在一个平台上为另一个平台编译程序;不同的操作系统,windows Linux;不同的处理器架构Intel ARM
Host:编译程序的平台,主机Target:运行程序的平台,目标机交叉编译工具链:编译套件提供一系列,顺序调用,形成链条,arm-linux-gcc
使用工具
- NDK: Native Development kit
- CDT: C/C++ Development tools 本质上是一个eclipse插件
- Cygwin:在windows提供了一个unix模拟运行环境
NDK目录介绍
- docs 开发文档 推荐D:/android-ndk-r9d/documentation.html
- build *.mk 指导编译的配置文件
- platforms 系统头文件D:\android-ndk-r9d\platforms\android-18\arch-arm\usr\include
- prebuild 编译工具 make.exe 工程管理器
- samples 开发例子
- source 相关库的源码
- toolchains 交叉编译工具链
ndk-build.cmd 谷歌提供的工程编译命令
JNI开发流程
阶段 编码
1.创建Android工程,用native声明本地方法
public native String helloFromC();
2.在工程新建jni,其中新建.c源文件
#include <jni.h> /** jni规定 本地方法名 Java_调用本地方法类所在的包名_类名_方法名 * JNIEnv * env java环境,提供函数供调用 * jobject obj 调用本地方法的对象 * * typedef const struct JNINativeInterface* JNIEnv; * JNIEnv <=> struct JNINativeInterface* * env : JNIEnv * <=> struct JNINativeInterface** * (*env)->NewStringUTF(); */ jstring Java_com_itheima_helloworld_MainActivity_helloFromC(JNIEnv *env, jobject obj){ //jstring (*NewStringUTF)(JNIEnv*, const char*); 把C字符串转化为java中字符串 // 把C字符串转化为java中字符串 return (*env)->NewStringUTF(env,"hello world"); }
阶段2 编译
3.在jni目录下新建Android.mk文件
LOCAL_PATH := $(call my-dir) #提定当前路径 include $(CLEAR_VARS) #清除全局配置变量,LOCAL_XXX,除了LOCAL_PATH LOCAL_MODULE := hello #指定生成动态库名hello,生成的动态库文件libhello.so LOCAL_SRC_FILES := hello.c #指定生成动态库的源文件 include $(BUILD_SHARED_LIBRARY) #提定生成动态库
4.在jni目录下用ndk-build命令编译生成.so动态库(把ndk-build工具路径添加到path)
5.在类中加载动态库
static{ System.loadLibrary("hello");//加载动态库名而不动态库文件名 }
jni开发过程中常见错误
找不到动态库: Couldn't load resultfr0mc: findLibrary returned null可能原因库名写错;或者生成动态库与运行平台不符合
找不到方法: Caused by: java.lang.UnsatisfiedLinkError: Native method not found: com.itheima.resultfromc.MainActivity.resultFromC:(II)I 解决方法检查JNI函数名, javah命令使用 jdk1.6在工程的bin\classes目录下执行,生成头文件javah com.itheima.resultfromc.MainActivity
jdk1.7在工程的src目录下执行,生成头文件
javah com.itheima.resultfromc.MainActivity
结合eclipse和NDK的JNI开发流程
1.新建Android工程,声明本地方法
2.指定工程添加 add Native suport,修改其中源文件后缀为.c,在Android.mk文件中也要修改,见gif图片add ndk location2.gif(ndk的支持)
3.指定jni.h头文件路径见gif图片include jni head file.gif
4.进入工程执行javah命令 ,把jni函数声明拷贝到.c源文件中
5.实现本地jni函数(删除错误提示)
6.在调用类中加载动态库 System.loadLibrary(“test1”);
需要在所有平台上跑需要创建:Application.mk文件,写: APP_ABI := allC调用java中方法的步骤
//1.装载字节码//jclass (*FindClass)(JNIEnv*, const char*);//所在的包名jclass clazz = (*env)->FindClass(env,"com/itheima/alipay01/MainActivity");//2.get method id 字节码 方法名 方法的签名 //jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); bin/classes,执行javap获取签名jmethodID methodid = (*env)->GetMethodID(env, clazz, "showDialog", "(Ljava/lang/String;)V");//3.call void methoid//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);(*env)->CallVoidMethod(env, obj, methodid, "yong hu mi ma");
jni开发三种情况
1.只有java工程师
2.只有java工程师,但还有.so动态库
3.有java工程师,c工程师;处理方式
* 1.把C程序员写的头文件和.c源文件拷贝工程中jni目录下
* 2.在jni.c文件中包含头文件,再调用其中的函数
* 3.在Android.mk文件中添加用到的.c文件,指定编译进入最终.so动态库
LOCAL_SRC_FILES := smarthome-jni.c get_house_temp.c
C和C++编写jni代码区别
1.源文件后缀不同
2.调用JNIEnv中函数方式不同
//在C中调用 (*env)->NewStringUTF(env,"Hello from C") //在C++中调用 env->NewStringUTF("Hello form Cpp")
3.c++代码需要在jni源文件中包含由javah生成的头文件
#include <jni.h> #include "com_itheima_hellofromcpp_MainActivity.h"
2 0
- JNI详解以及使用Java调c代码
- 使用JNI,让java调用c代码
- jni 使用java 调用C代码
- jni-使用c代码调用java文件
- Android 中 c 代码回调Java代码的详细步骤(jni、NDK的使用)
- 使用JNI在C中调用java代码
- 使用JNI在java中调用C代码
- 使用Qt / C + +通过JNI调用Java代码
- Java使用JNI与C/C++代码实现混合编程
- JNI基础(六)C调java代码
- JNI基础(七)C调java静态方法代码
- JNI c代码回调java空方法
- java高级编程,JNI的使用。java代码调用c程序
- java高级编程,JNI的使用。c程序调用java代码
- Java中JNI的使用详解第五篇:C/C++中操作Java中的数组
- JNI之C代码访问java中的成员和java调C
- 技术转载:Jni学习三:jni使用java对象详解
- Jni学习三:jni使用java对象详解
- Docker 构建redis镜像
- Docker 构建Tomcat镜像
- MySQL存储过程和函数的区别
- Ember.js 入门指南——{{link-to}} 助手
- 【剑指Offer】二叉搜索树的后序遍历序列
- JNI详解以及使用Java调c代码
- 【工具】工作中常用到的工具
- Android内存后台进程管理内存阀值minfree修改
- 【剑指Offer】二叉树中和为某一值的路径
- PopupWindow的使用
- ubuntu 安装tengine
- Leetcode Best Time to Buy and Sell Stock
- Widget的使用
- 【剑指Offer】二叉搜索树与双向链表