Android JNI之Java和C互相调用
来源:互联网 发布:如何删除mac桌面图标 编辑:程序博客网 时间:2024/05/22 01:15
概述
JNI是什么
JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。
NDK是什么
NDK是Native Development Kit的缩写。是SDK(software development kit)软件开发工具包的一部分,不过通常需要单独下载。详见关于NDK。
JNI的优缺点
- 优点:
- 和其他语言进行交互,各取所长。
- 增加反编译难度
- 缺点:
- 失去Java跨平台的优势
Java调用C
配置
module
下的build.gradle
android { compileSdkVersion 25 buildToolsVersion "25.0.0" defaultConfig { ... ndk { moduleName "CallEachOther" //编译生成so库的名字,要和loadLibrary里面的参数一致 abiFilters "armeabi","armeabi-v7a","x86","x86_64","mips","arm64-v8a","mips64"//编译支持的平台 } }}
新建
Java
类public class JNITest_Java { static { System.loadLibrary("CallEachOther"); } public native String getStringFromC();}
这里
System.loadLibrary
中的参数就是build.gradle
中moduleName
的值,即CallEachOther
。这里我们定义了一个native
方法getStringFromC()
。现在为止,Java
端可以暂时告一段落。接下来,就该生成头文件。生成
.h
头文件打开
AS
自带的Terminal
,cd src/main/java
命令进入到Java
文件夹下。ps:使用cmd
命令一样的效果输入命令
javah 完整包名.类名
。例如:javah com.dongyk.jnitest.JNITest_Java。
此时会在
Java
目录下生成包名_类名.h
。AS2.2.2
打开会一片红,貌似是AS
的bug
。不过不影响正常编译。
在
main
目录下新建jni
文件夹,新建JniTestC.c
。#include <stdio.h>#include <stdlib.h>#include "com_dongyk_jnitest_JNITest_Java.h"JNIEXPORT jstring JNICALL Java_com_dongyk_jnitest_JNITest_1Java_getStringFromC(JNIEnv * env, jobject jobj){ char* str = "I come from C"; return (*env)->NewStringUTF(env,str);};
这里方法的名字有一定的规则。格式:
Java_包名_类名
。方法名太长建议从刚生成的.h
文件中复制过来。下面对这个方法简单解释下:JNIEnv * env
env
指针指向一个函数指针表。jobject jobj
指向在Java
代码中实例化的Java
对象 ,相当于this指针。(*env)->NewStringUTF
代表调用env#NewStringUTF()
方法。- 最后返回”I come from C”。
在
MainActivity
中调用。public class MainActivity extends AppCompatActivity { private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); String result = new JNITest_Java().getStringFromC(); tv.setText(result); }}
C调用Java
在
Java
类中添加方法public class JNITest_Java { static { System.loadLibrary("JavaCallC"); } public native String getStringFromC(); public native int callAdd(); public int add(int a, int b) { Log.i("TAG","add was called"); return a + b; }}
先搞明白流程。在
Java
层调用的肯定是Java
代码,这里写了一个callAdd()
方法,在调用这个方法的时候,通知C
调用add()
方法。这个过程中首先是C
作为Java
方法的具体实现,而且在C
中调用了Java
方法。之后调用javah
命令生成.h
头文件。/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_dongyk_jnitest_JNITest_Java */#ifndef _Included_com_dongyk_jnitest_JNITest_Java#define _Included_com_dongyk_jnitest_JNITest_Java#ifdef __cplusplusextern "C" {#endif/* * Class: com_dongyk_jnitest_JNITest_Java * Method: getStringFromC * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL ava_com_dongyk_jnitest_JNITest_1Java_getStringFromC(JNIEnv*, jobject);/* * Class: com_dongyk_jnitest_JNITest_Java * Method: callAdd * Signature: ()V */JNIEXPORT jint JNICALL Java_com_dongyk_jnitest_JNITest_1Java_callAdd(JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif
.c
主函数的具体实现JNIEXPORT jint JNICALL Java_com_dongyk_jnitest_JNITest_1Java_callAdd(JNIEnv *env, jobject jobj){ // 得到字节码 jclass clazz = (*env)->FindClass(env,"com/dongyk/jnitest/JNITest_Java"); // 得到方法 jmethodID jmethodid = (*env)->GetMethodID(env,clazz,"add","(II)I"); // 实例化类 jobject jobject = (*env)->AllocObject(env,clazz); // 调用方法 return (*env)->CallIntMethod(env,jobject,jmethodid,3,5);};
(*env)->GetMethodID中
最后一个参数是方法签名。因为Java
支持方法重载,但是这些重载的方法在Jni
中命名是一样的,为了区分函数重载才引入方法签名。得到方法签名:首先rebulid
下工程,之后cd build\intermediates\classes\debug
,之后使用javap -s 包名/类名
得到所有的方法签名。例如:javap -s com/dongyk/jnitest/JNITest_Java
public int add(int, int); descriptor: (II)I
descriptor
对应的就是方法签名。当然。里面还有FindClass、GetMethodID
等方法,详见 XXX\sdk\ndk-bundle\platforms\android-xx\arch-arm\usr\include\jni.h。在
MainActivity
中调用。public class MainActivity extends AppCompatActivity { private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); int result = new JNITest_Java().callAdd(); tv.setText(result+""); }}
至此,一个
Jni
初入门的小Demo
编写完毕~
- Android JNI之Java和C互相调用
- JNI学习(一)(c和java层对象互相调用)
- Android JNI中C和JAVA代码之间的互相调用
- JNI JAVA与C的互相调用
- android Java与JNI层互相调用
- JNI--java和C++互相调用
- Android之webkit内核JNI层与Java层 函数互相调用方法
- 【转载】Android之webkit内核JNI层与Java层 函数互相调用方法
- 转战Android之NDK(jni, java调用c/c++)
- Android之NDK(jni, java调用c/c++)
- android之JNI(C和Java互调)
- Android JNI C调用Java
- Android开发学习之路--Java和Js互相调用
- Java使用JNI调用C/C++(windows和android平台)
- android jni中C++与java互相调用小结
- JNI 之c/c++和Java交互,调用java成员
- 如何让Java和C++接口互相调用:JNI使用指南
- 如何让Java和C++接口互相调用:JNI使用指南
- oracle 定时器的定义及使用
- Drupal8模板中替换系统的jquery库
- iOS 多级菜单控件
- HTML5开发之绘制图形canvas
- http4cpp - 易用的C++ http开发微框架
- Android JNI之Java和C互相调用
- java开发常用jar包
- 【初学者指南】在ASP.NET MVC 5中创建GridView
- Unity+高通Vuforia SDK——AR
- 在任何一个java工程下(即便是j2ee工程)都可以直接对某一个java文件run as Java Application,但是为什么有的java文件右击,没有“Java Application”
- RabbitMQ消息队列(1)走进RabbitMQ
- Android系统Recovery工作原理之使用update.zip升级过程分析(九)---updater-script脚本语法简介以及执行流程
- Operation category READ is not supported in state standby解决
- The Truth about Sessions(你必须了解的Session的本质)