您的位置:首页 > 移动开发 > Android开发

Android之从零开始JNI研发

2017-02-15 14:45 197 查看
转载注明出处:http://blog.csdn.net/xiaohanluo/article/details/55193157

本文是基于Mac端Android Studio的JNI开发介绍。

Andorid官方JNI文档

Android官方JNI实例文档

JNI维基百科

JNI手册英文版

JNI手册中文版

Oracleg官方JNI文档

1. NDK安装以及环境配置

Android Studio 2.2及以上参考链接

Getting Started with the NDK

MAC端手撕NDK环境搭建

选择NDK版本下载 NDK Downloads

解压下载文件

设置环境,到用户的根目录,打开.bash_profile文件,设置NDK环境,参考文章Mac OS X配置环境变量

Windows手撕NDK环境搭建,因为C/C++在GCC的环境下编译、运行,所以Windows环境下需要Cygwin模拟Linux编译环境,参考http://www.jb51.net/softjc/159272.html

环境配置完成后,使用ndk-build指令查看一下是否配置成功。

mac下执行效果:

> ndk-build
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.


ndk环境搭建好后就可以开始动手了。

2. 定义带有本地方法Java类

public class JNIDemoUtil {
private native String getString(String input);
}


3. 生成class文件

build -> rebuild
重新构建项目,生成class文件,class文件在
<壳工程>/build/classes/debug
目录下。



图-1 class目录结构图

4. 生成.h头文件

进入到
<壳工程>/build/classes/debug
目录下执行以下指令

# -classpath指定类的路径
javah -classpath . -jni {包名.类名}


例如,
javah -classpath . -jni com.kyo.jnidemo.jni.JNIDemoUtil
,会生成.h文件。



图-2 h文件目录图

5. 编写c/c++文件

native的具体实现

#include <stdlib.h>
#include <jni.h>
#include "com_kyo_jnidemo_jni_JNIDemoUtil.h"

#ifdef __cplusplus
extern "C" {
#endif

jstring Java_com_kyo_jnidemo_jni_JNIDemoUtil_getString(JNIEnv *env, jclass obj) {
return (*env)->NewStringUTF(env, "hello world");
}

#ifdef __cplusplus
}
#endif


6. 生成.so动态库

上面拿到了h头文件和具体实现的c/c++文件,接下来是生成.so动态库,根据放的目录不同有三种方式。

放在工程的根目录jni中

放在工程的内部子文件中

放在
/src/main/jni
目录中

6.1 C/C++代码在根目录jni



图-3 根目录生成so

新建mk文件,设置一些属性。

LOCAL_MODULE := ${call my-dir}/
include ${CLEAR_VARS}
LOCAL_SRC_FILES := /Users/wang/WorkPlace/MyWork/JNIDemo/jni/JNIDemoUtil.c
LOCAL_MODULE = libJNIDemo

include ${BUILD_SHARED_LIBRARY}


进入jni目录,使用
ndk-build
指令,会在工程根目录中自动生成
libs
obj
两个目录,其中libs,目录下就有so库。



图-4 运行结果图

注意:只有C/C++把放在工程根目录中的jni才可以使用ndk-build指令编译

6.2 C/CC++代码在工程内部其他目录



图-5 非根目录接结构图

在工程根目录新建Application.mk文件。

APP_BUILD_SCRIPT := /Users/wang/WorkPlace/MyWork/JNIDemo/jni_c/src/Android.mk
# 因为针对多个CPU架构会生成多个so库,使用APP_ABI限定生成支持某种CPU架构的so库
APP_ABI := armeabi


在C/CC++代码目录新建Android.mk文件

LOCAL_MODULE := ${call my-dir}/
include ${CLEAR_VARS}
LOCAL_SRC_FILES := /Users/wang/WorkPlace/MyWork/JNIDemo/jni_c/src/JNIDemoUtil.c
LOCAL_MODULE = libJNIDemo

include ${BUILD_SHARED_LIBRARY}


在工程的根目录下执行以下指令(可以直接进入C/C++源代码目录执行
ndk-build
生成so库),会在工程根目录中自动生成
libs
obj
两个目录,其中libs,目录下就有so库。

ndk-build NDK_PROJECT_PATH={工程目录} NDK_APPLICATION_MK={工程的Applicaion.mk目录}


指令运行结果图:



图-6 运行结果图

Application.mk指定了编译的mk,而Android.mk指定了编译的一些属性,包括编译源文件等等,这些都可以灵活变化

6.3 C/C++放在
src/main/jni
目录下



图-7 自动生成so目录图

local.properties
中添加ndk路径,我的如下。

sdk.dir=/Users/wang/Android/Android_SDK
ndk.dir=/Users/wang/Android/Android_NDK_r13b


在壳工程(通常是app/build.gradle)的build.gradle配置生成的so库名,找到defaultConfig这个节点,添加如下内容。

defaultConfig {
...
ndk {
moduleName "libJNIDemoJni" // so库名
abiFilters "armeabi" // 指定生成的CPU架构对应的so库
}
}


gradle.properties
文件中添加.

android.useDeprecatedNdk=true


然后rebuild项目,会自动生成so动态库,在
<壳工程>/build/intermedistes/ndk
目录下面,目录如下图:



图-8 自动生成so的目录

7. 载入so库

将生成的so库在
<壳工程>/src/main/jniLibs
目录下。

同时在
JNIDemoUtil
中载入so库代码。

public class JNIDemoUtil {

// 注意库的名字前面没有lib
static {
System.loadLibrary("JNIDemo");
}

public native static String getString();
}


8. 编译运行

准备工作做完后,可以直接运行啦。

public void onClick(View v) {
int id = v.getId();
if(id == R.id.jni_demo_btn){
mInfoTv.setText(JNIDemoUtil.getString());
}
}


运行结果图:



图-9 运行结果图

9. 问题解答

java.lang.UnsatisfiedLinkError: Couldn’t load XXX indLibrary

确认loadLibrary时候库的名字是否正确

so目录有问题,[点这里看设置]http://blog.csdn.net/yy1300326388/article/details/46291417

Android NDK: Could not find application project directory !

Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.

使用以下指令编译

ndk-build NDK_PROJECT_PATH={工程目录} NDK_APPLICATION_MK={工程的Applicaion.mk目录}


附上demo地址:https://github.com/Kyogirante/JNIDemo

10. 结束语

本篇几乎没有涉及C/C++与java之间变量以及语法等等一些知识点,这些会在下篇来介绍。本人也是在学习探索过程中,如果有错误希望大家指出来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android JNI c-c++ java ndk