前言:
这段时间由于工作上的问题,所以一直没写博客,最近在做sdk,正好用到了JNI,所以写一篇关于如何在Android studio中使用JNI。PS:去年也写过一篇博客是关于NDK在eclipse上的实现,有兴趣可以了解下。
准备工作:
1.下载最新的android-ndk-r13b-windows-x86_64,这个根据自己系统版本来,链接我就不贴了,这个百度一下很多地方有链接的。我解压出来是放到F盘中的,目录:F/android-ndk-r13b
2.创建一个项目,然后配置NDK路径。
3.在项目中的app下的build.gradle中添加如下信息:moduleName就是我们的so文件名字。
4.接下来在gradle.properties中添加一句 android.useDeprecatedNdk=true
按照上述的4步基本上就已经配置好了开发环境了,这里我就不谈一些基础的部分了,比如JNIEnv 以及java中的数据类型在JNI中的转换例如 int->jint,这个可以自行去了解,这里仅仅谈下实现的步骤,相信对于初学者很多都困扰在这里。
项目实现:
1.先来个demo实现结果,这里由于我的录屏工具出现问题了,所以这里没弄成gif格式的,整个demo的操作流程是,分别点击两个textview 调用两个不同的native方法。
2.创建一个加载so文件以及调用native方法的类
先给张整体项目的目录结构:
JNIUtils就是我们的加载so文件的工具类:
package com.example.ljx.jniproject03;
/**
* Created by ljx on 2017/9/17.
*/
public class JNIUtils {
static {
System.loadLibrary("JniTest");
}
public static native String getStringFromNative();
public static native int sum(int x, int y);
}
3.生成JNIUtils的.h文件,主要的作用还是为了给我们生成native方法的代码,我们的实现还是在.c/.cpp文件中实现。
生成的步骤我直接截图出来了
通过上图的方式生成.h文件,简单方便,这样不需要去找我们的class文件,再通过.h来生成了。并且android studio会直接在main目录下创建一个jni的文件夹,用来放我们的.h还有.c/.cpp文件。
com.example.ljx.jniproject03_JNIUtils.h代码:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_ljx_jniproject03_JNIUtils */
#ifndef _Included_com_example_ljx_jniproject03_JNIUtils
#define _Included_com_example_ljx_jniproject03_JNIUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_ljx_jniproject03_JNIUtils
* Method: getStringFromNative
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_ljx_jniproject03_JNIUtils_getStringFromNative
(JNIEnv *, jclass);
JNIEXPORT jint JNICALL Java_com_example_ljx_jniproject03_JNIUtils_sum
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
4.创建一个.c或者.cpp文件,是具体实现.h文件中声明的native方法的,也就是我们的getStringFromNative还有sum方法。C文件的名字随意取,只是要把.h中的代码全部复制过去,并且实现其中的native方法。
我这里创建的是test.c
test.c代码:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include<util.h>
/* Header for class com_example_ljx_jniproject03_JNIUtils */
#ifndef _Included_com_example_ljx_jniproject03_JNIUtils
#define _Included_com_example_ljx_jniproject03_JNIUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_ljx_jniproject03_JNIUtils
* Method: getStringFromNative
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_ljx_jniproject03_JNIUtils_getStringFromNative
(JNIEnv * env, jobject jObj){
//LOGE("log string from ndk.");
return (*env)->NewStringUTF(env,"Hello From JNI!");
}
JNIEXPORT jint JNICALL Java_com_example_ljx_jniproject03_JNIUtils_sum
(JNIEnv *env, jclass jObj, jint x, jint y){
return sum(x, y);
}
#ifdef __cplusplus
}
#endif
#endif
可以看到,我这还创建了一个util.c/h两个文件,是用来实现sum方法的,这个就和C语言一样了,个人建议,做android最好还是学习下C/C++,并不要求一定要有很深的造诣,毕竟很多底层功能还是需要专业的C/C++程序员来完成的,但是学好C/C++对于理解源码,以及JNI有很大帮助。
5.到这基本就完工了,通过Build->make project 编译一下,就会在app/intermediates/ndk中生成我们的so文件
6.然后在工程的main目录下创建jinLIB文件夹(正规做法是jniLibs文件夹,不过这里并没有什么影响,因为在项目运行的时候,android studio会自动加载jniLibs中的so文件),把armeabi的这个文件夹复制进去,当然也可以把armeabi-v7a..全部复制进去,适配不同CPU类型的手机。一般项目都会生成全部的,并且全部都给复制进去,防止错误。我这仅仅是个demo,所以就图方便了。在项目中千万别这么干。
从上面的流程可以看到,在android studio中实现JNI比在eclipse上方便了很多,Google为我们集成了很好的NDK开发环境,连android.mk都不需要我们自己去写了,可以说,我们仅仅只需要实现我们的C代码,然后通过以上步骤就刽生成我们的so库了,简单方便。
android studio中JNI使用的基本操作就介绍到这里了,如果有问题的话,可以留言,最好是学习下C/C++,当项目中遇到条件变更,需要更改C代码的流程的时候,简单点的东西我们自己也可以改了,并不需要麻烦C/C++工程师了。