Android JNI 入门

来源:互联网 发布:淘宝网发货流程 编辑:程序博客网 时间:2024/06/09 19:39

前言
写在准备面试做直播的公司前。。。
JNI是Java Native Interface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下。 标准的java类库可能不支持你的程序所需的特性。 JNI·或许你已经有了一个用其他语言写成的库或程序,而你希望在java程序中使用它。你可能需要用底层语言实现一个小型的时间敏感代码,比如汇编,然后在你的java程序中调用这些功能。 NDK是Google公司推出的帮助Android开发者通过C/C++本地语言编写应用的开发包,包含了C/C++的头文件、库文件、说明文档和示例代码,我们可以理解为Windows Platform SDK一样,是纯C/C++编写的,但是Android并不支持纯C/C++编写的应用,同时NDK提供的库和函数功能很有限,仅仅处理些算法效率敏感的问题,所以推荐初学者学好Java后再学习JNI。 NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。 NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。

博客的目标
JAVA方法与C函数的互调,已经在C代码中打印log信息。

1.环境配置
NDK环境的配置我就不多提,下载,安装配置环境变量,基本和JDK的配置差不多,大家百度一下就可以了。我这里主要介绍Android Studio中的配置。
(1)在project的local.properties中添加ndk的路径
这里写图片描述
图中ndk路径的对应的我本地的文件
这里写图片描述
(2)在project的gradle.properties中添加android.useDeprecatedNdk=true,原因是保证一些过时的api能够使用

两步,就将NDK的环境集成进来了,接下来就可以愉快的开始JNI的测试了

2.编写本地native方法

public class JNI {    public native String HelloJNI();}

命令窗口中, 进入java文件夹
执行命令: javah 包名.类名(com.jiahuaandroid.frame_sample.ccode.JNI)

经过这一步会生成一个头文件 类的全类名,”.”用”_”代替
(com_jiahuaandroid_frame_sample_ccode_JNI.h)

3.创建jni目录
jni目录的创建
让将头文件(com_jiahuaandroid_frame_sample_ccode_JNI.h)转移到jni目录下。

4.定义对应的函数文件(hello.c)
在jni目录下定义函数文件。里面编写C或者C++的代码

#include "com_jiahuaandroid_frame_sample_ccode_JNI.h"jstring Java_com_jiahuaandroid_frame_1sample_ccode_JNI_HelloJNI        (JNIEnv *env, jobject jobj) {    return (*env)->NewStringUTF(env, "Hello from C");}

接下来我们需要去或者.so文件,也就是我们所需要的通过
rebuild去获取.so文件 这时候会有一个问题,

Error:Execution failed for task ':sample:compileDebugNdk'.> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'D:\android-ndk-r10\ndk-build.cmd'' finished with non-zero exit value 2

会报这个错误,这里不是我们的问题,是AS的一个bug 怎么解决呢 其实很简单,在jni的目录下创建一个空的.c文件 在rebuild就OK了

这里写图片描述
创建完一个空的.c文件后rebuild 到了这一步 基本就已经完成了java调用c的函数了。so文件目录: build\intermediates\ndk\debug\lib…..
这里写图片描述

5.加载.so文件

在JNI.class文件中添加代码

public class JNI {    static {        System.loadLibrary("sample");    }    public native String HelloJNI();}

这里的这个sample是项目的工程的名字。 其实是我们.so文件的名字 除去前面的lib。。。 我们也可以通过moudle的build文件去修改这个名字,这里我就不做更多的描述。 在defaultConfig标签下加上配置信息

ndk{            moduleName "Hello" //so文件: lib+moduleName+.so            abiFilters "armeabi", "armeabi-v7a", "x86" //cpu的类型            }

6.调用
String hello = new JNI().HelloJNI();
Toast.makeText(this, hello, Toast.LENGTH_LONG);
Log.e(“TAG”, hello);

7.添加C的代码中添加Log打印到我们的AS的控制台
(1):同上 在build 的文件中添加配置信息

ndk{       ldLibs "log"   }

完整的hello.c文件代码:

#include "com_jiahuaandroid_frame_sample_ccode_JNI.h"#include <android/log.h>#define LOG_TAG "TAG"#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)jstring Java_com_jiahuaandroid_frame_1sample_ccode_JNI_HelloJNI        (JNIEnv *env, jobject jobj) {    LOGV("来自C的打印log语句v");    LOGD("来自C的打印log语句d");    LOGI("来自C的打印log语句i");    LOGW("来自C的打印log语句w");    LOGE("来自C的打印log语句e");    return (*env)->NewStringUTF(env, "Hello from C");}

9.运行结果
这里写图片描述

结语
相对于java调C的代码来说,C想调用java的代码就比较麻烦了,我们需要通过反射的方式去调用,并且需要我们通过命令的方式去获取每个方法的签名,参数不同返回类型不同的方式 方法的签名也会不一样。
具体链接走你,自己看

0 0
原创粉丝点击