Android之从零开始JNI研发

原创 2017年02月15日 14:45:20

转载注明出处:http://blog.csdn.net/xiaohanluo/article/details/55193157

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

Andorid官方JNI文档

Android官方JNI实例文档

JNI维基百科

JNI手册英文版

JNI手册中文版

Oracleg官方JNI文档

1. NDK安装以及环境配置

环境配置完成后,使用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指令,会在工程根目录中自动生成libsobj两个目录,其中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库),会在工程根目录中自动生成libsobj两个目录,其中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

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之间变量以及语法等等一些知识点,这些会在下篇来介绍。本人也是在学习探索过程中,如果有错误希望大家指出来。

版权声明:本文为博主原创文章,未经博主允许不得转载。

NDK-JNI实战教程(一) 在Android Studio运行第一个NDK程序

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN。因为CSDN也支持MarkDown语法了,牛逼啊!NDK开发,其实是为了项目需要调用底层的一些C/C++的一些东西;另...
  • yanbober
  • yanbober
  • 2015年04月27日 13:23
  • 89332

Android开发学习之路--NDK、JNI之初体验

好久没有更新博客了,最近一直在看一个仿微信项目,然后看源码并自己实现下,相信经过这个项目可以让自己了解一个项目中的代码以及种种需要注意的事项。不知不觉中博客已经快要40w访问量,而且排名也即将突破30...
  • eastmoon502136
  • eastmoon502136
  • 2016年02月28日 17:46
  • 14633

Android 中AIDL的使用与理解

AIDL的使用:最常见的aidl的使用就是Service的跨进程通信了,那么我们就写一个Activity和Service的跨进程通信吧。 首先,我们就在AS里面新建一个aidl文件(ps:现在AS建...
  • u011974987
  • u011974987
  • 2016年04月25日 16:58
  • 22568

Android中JNI编程详解

前几天在参加腾讯模拟考的时候,腾讯出了一道关于JNI的题,具体如下: JNI本身是一个非常复杂的知识,但是其实对于腾讯的这道题而言,如果你懂JNI,那么这道题会非常简单,就相当于C语言中的hell...
  • htq__
  • htq__
  • 2016年03月30日 11:13
  • 9191

android JNI开发基本步骤

1.编写java类,定义Native方法,这里的native方法就是后面.c文件(c/c++语言)里面要实现的方法名。示例:public class JniClient { public st...
  • yinzhiwei2014
  • yinzhiwei2014
  • 2016年02月23日 11:56
  • 6363

如何在Android下使用JNI

1.引言 我们知道,Android系统的底层库由c/c++编写,上层Android应用程序通过Java虚拟机调用底层接口,衔接底层c/c++库与Java应用程序间的接口正是JNI(JavaNativ...
  • xnwyd
  • xnwyd
  • 2011年12月20日 09:22
  • 112798

Android NDK开发之旅(2):Android Studio中使用CMake进行NDK/JNI开发(初级)

CMake是一款比make更强大的编译自动配置工具,它可以根据不同平台、不同的编译器,并通过CMakeLists.txt文件中简单的语句来描述所有平台的编译过程,生成相应的Makefile文件或pro...
  • AndrExpert
  • AndrExpert
  • 2017年06月07日 23:20
  • 2729

Android JNI开发流程(android开发艺术探索随笔)

今天来了兴趣想更搞下JNI,于是乎拿起任玉刚的Android开发艺术看了会,看起来挺简单的,但是做的时候各种问题。经过自己的努力,也算是弄好了。那么就来和大家分享下。 这篇博客的所用的是Ubuntu...
  • qq_21430549
  • qq_21430549
  • 2015年10月31日 19:18
  • 981

JNI/NDK开发指南(开山篇)

转载请注明出处:         相信很多做过Java或Android开发的朋友经常会接触到JNI方面的技术,由其做过Android的朋友,为了应用的安全性,会将一些复杂的逻辑和算法通过本地代码(C...
  • xyang81
  • xyang81
  • 2014年12月05日 23:41
  • 18640

一个例子掌握JNI开发

一个示例,带领JNI入门。从代码的角度分析,C和Java混合编程时,能实现的那些功能。以及介绍常用JNI函数的使用。...
  • flueky
  • flueky
  • 2016年03月22日 21:57
  • 1320
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android之从零开始JNI研发
举报原因:
原因补充:

(最多只允许输入30个字)