Android JNI编程(八)——体验AS2.2.2编写Jni程序、Java调C、C调Java函数、将C代码中的Log打印至Logcat
2016-12-03 16:44
771 查看
不得不说在AS2.2以上的版本进行开发就一个字——爽,在2.0上使用jni出现各种问题现在果断使用新版本开发了。
使用AS2.0创建Jni项目: 使用AndroidStudio编写第一个JNI程序一:编写Jni程序
1. 我们创建一个项目,将Include C++ Support勾选一路Next直到Finish 这样就可以全自动为我们创建好一个带有Jni的项目了
编译过程中需要你为这个工程配置Ndk的路径,只需在
Project Sturcture配置即可(不懂看文章上面的链接文章)。如果你第一次使用,那么他会提示你需要下CMake你也只需下载即可
2. 在AS2.2以上版本中,使用的是CMake来编译我们的C代码
CMake官网:https://cmake.org/
Google官方文档:Jni开发文档
CMakeLists.txt
//以#号开头都是注释,这里把它们都删了也就更清楚了 cmake_minimum_required(VERSION 3.4.1) #生成的库名 add_library( native-lib #编译的文件路径 src/main/cpp/native-lib.c ) find_library( log-lib log ) target_link_libraries( native-lib ${log-lib} )
3. 默认创建的是cpp文件,这里将它改成.c文件同时修改CMakeLists.txt
中的src/main/cpp/native-lib.c
文件后缀名,改完之后记得sync一下
4. 在build.gradle
中配置生成的so库类型,记得sync一下
android { //。。。 defaultConfig { //。。。 ndk { moduleName "native-lib"//生成so库的名字,与CMakeLists中的一致 abiFilters "armeabi", "armeabi-v7a", "x86"//cpu类型 } } }
二:Java调用C代码
1. 创建一个类,存放native函数
public class JniInterface { //加载so文件 static { System.loadLibrary("native-lib"); } /*返回一个字符串*/ public native String stringFromJNI(); }
2. 使用Alt+Enter来自动生成对应的Jni函数,确定之后会在main/jni目录中创建一个C文件,我们只需要将里面的方法复制到我们的native-lib.c
文件中
1. native-lib.c文件
#include <jni.h> /** * jstring: 返回值 * Java_全类名_方法名 * JNIEnv* env: 里面有很多方法 * jobject jobj: 谁调用了这个方法就是谁的实例 */ jstring Java_com_zsy_ajni_JniInterface_stringFromJNI(JNIEnv *env, jobject jobj) { char *str = "Hello from C"; return (*env)->NewStringUTF(env, str); }
3. 在我们的MainActivity中调用stringFromJNI()
便可以调用成功了。
然后在项目的build/intermediates/cmake/debug/obj/这里就可以看到编译生成的so库了
三:C调用Java代码
1. 在JniInterface类中继续增加我们的native方法,让java调用callbackAdd();函数,然后Jni调用add(int a,int b);函数
public class JniInterface { //加载so文件 static { System.loadLibrary("native-lib"); } /** * 返回一个字符串 */ public native String stringFromJNI(); /** * 当执行这个函数的时候,让C代码调用add(int a, int b) */ public native void callbackAdd(); /** * 这个函数让C调用 */ public int add(int a, int b) { Log.d("TAG", "我是add函数被C调用了a = " + a + ";b = " + b); return a + b; } }
2. MainActivity中调用callbackAdd()
函数
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); JniInterface jni = new JniInterface(); TextView tv = (TextView) findViewById(R.id.sample_text); tv.setText(jni.stringFromJNI()); //调用这个函数,让C调用我们的add函数 jni.callbackAdd(); } }
3. 接下来就是重点了,在native-lib.c文件继续中生成callbackAdd()对应的Jni函数代码中来调用我们的add(int a, int b)
函数
/** * C代码调用Java JniInterface类中的add(int a, int b)函数 */ void Java_com_zsy_ajni_JniInterface_callbackAdd(JNIEnv *env, jobject jobj) { //1、得到字节码 FindClass(env,类的全路径); jclass class = (*env)->FindClass(env, "com/zsy/ajni/JniInterface"); //2、得到方法 GetMethodID(env,jclass,方法名,方法签名); //方法签名是要调用的方法名对应的签名 jmethodID methodID = (*env)->GetMethodID(env, class, "add", "(II)I"); //3、实例化该类 jobject obj = (*env)->AllocObject(env, class); //4.调用Java类中的方法 //成功调用add方法;第二三个参数是我们调用add方法传入的参数。value就是add方法的返回值 jint value = (*env)->CallIntMethod(env, obj, methodID, 45, 23); }
4. 上面代码中,我们需要去获取一个方法的签名那我们来获取一下:
将工程build让类生成对应的.class文件。然后使用Terminal进入到app\build\intermediates\classes\debug>目录下,执行
javap -s 类的全路径descriptor就是方法签名。
类的全路径可以通过在类名上右键,点击Copy Reference即可
5. 运行我们的程序,就可以在控制看到Log了也就证明方法调用成功
四:在C代码中打印Log至Logcat
上面我们是在Java函数中打印的Log,现在我们来让C中也可以打印Log1.配置C代码打印Log
在build.gradle中添加日志打印so库ndk { //.... //就是依赖ndk工具包中的一个liblog.so文件 ldLibs "log" }
在.c文件中添加如下代码,看注释就明白了
#include <android/log.h> //日志标签,随意定义 #define LOG_TAG "TAG" //Debug等级 #define LOGD(...)__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) //Info等级 #define LOGI(...)__android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) //Error等级 #define LOGE(...)__android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
配置好了,我们就可以来用了
#include <jni.h>
#include <android/log.h> //日志标签,随意定义 #define LOG_TAG "TAG" //Debug等级 #define LOGD(...)__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) //Info等级 #define LOGI(...)__android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) //Error等级 #define LOGE(...)__android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
/**
* jstring: 返回值
* Java_全类名_方法名
* JNIEnv* env: 里面有很多方法
* jobject jobj: 谁调用了这个方法就是谁的实例
*/
jstring Java_com_zsy_ajni_JniInterface_stringFromJNI(JNIEnv *env, jobject jobj) {
char *str = "Hello from C";
return (*env)->NewStringUTF(env, str);
}
/**
* C代码调用Java JniInterface类中的add(int a, int b)函数
*/
void Java_com_zsy_ajni_JniInterface_callbackAdd(JNIEnv *env, jobject jobj) {
//此处代码省略,与上面代码一致
jint value = (*env)->CallIntMethod(env, obj, methodID, 45, 23);
//调用Log输出,使用与printf函数一致
LOGD("value=%d", value);
}
2. 成功运行后机可以在Logcat查看到日志信息了
在2.2.2版本上可以关联到源码跟踪源码非常方便,写Jni也是个不错的体验。Demo地址
相关文章推荐
- Android JNI编程(八)——体验AS2.2.2编写Jni程序、Java调C、C调Java函数、将C代码中的Log打印至Logcat
- 02_JNI中Java代码调用C代码,Android中使用log库打印日志,javah命令的使用,Android.mk文件的编写,交叉编译
- 02_JNI中Java代码调用C代码,Android中使用log库打印日志,javah命令的使用,Android.mk文件的编写,交叉编译
- Android For JNI(一)——JNI的概念以及C语言开发工具dev-c++,编写你的第一个C语言程序,使用C启动JAVA程序
- Android JNI编程(七)——使用AndroidStudio编写第一个JNI程序
- 用JNI进行Java编程---从Java程序调用C/C++代码
- android-如何在jni中C/C++层打印log到logcat
- 用JNI进行Java编程---从C/C++程序调用Java代码
- Android(java)学习笔记261:JNI之编写jni程序适配所有处理器型号
- Android4.1 JNI 中打印的LOG 无法在 logcat 中输出
- java高级编程,JNI的使用。c程序调用java代码
- Android For JNI(一)——JNI的概念以及C语言开发工具dev-c++,编写你的第一个C语言程序,使用C启动JAVA程序
- Android Jni开发之创建Jni程序和打印log
- Android JNI编程(七)——使用AndroidStudio编写第一个JNI程序
- JNI开发第二篇通过反射实现C中调用java代码,并实现Log打印日志
- Android For JNI(一)——JNI的概念以及C语言开发工具dev-c++,编写你的第一个C语言程序,使用C启动JAVA程序
- java高级编程,JNI的使用。java代码调用c程序
- 在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
- 在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
- 如何编写和调用java的jni程序