JNI在Android Studio2.2中基本配置和使用

  • what?

    1. JNI
      Java Native Interface 它允许Java代码和其他语言写的代码进行交互。JNI 是本地编程接口,它使得在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语言(如 C、C++ 和汇编语言)编写的应用程序和库进行交互操作。
      由于Android的应用层的类都是以Java写的,这些Java类编译为Dex型式的Bytecode之后,必须靠Dalvik虚拟机(VM: Virtual Machine)来执行。
    2. NDK
      Native Develop Kit(本地开发工具包),类似于JDK;只是一套工具,它可以帮助开发者在android开发中,它使用的是JNI机制.
    3. 两者的区别
      JNI Java Native Interface java调用本地接口 的技术名词
      NDK Native Developer Kit 谷歌给开发人员的工具包
  • 使用ndkBuilder进行项目的构建

  1. 下载ndk(已装,略过)
    ndk下载.png

    进入项目设置界面
20160531123154969.png

没有安装的话,直接Download即可,PS.在最终安装的时候会卡很长时间,耐心等待安装完成


  1. 配置app,build.gradle文件

  2. 在app的build.gradle中,也就是要运行的项目中的build.gradle文件中的defaultConfig节点中增加

    ndk {
            moduleName "NdkJniDemo"   //生成的so名字
            ldLibs "log", "z", "m"    //添加依赖库文件,因为有log打印等//非必填加项
            abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库,目前可有可无。//不填写则生成所有
        }

  1. 创建本地需要创建调用C的代码,这里使用一个获取字符串的方法为例
  • 新建一个工具类JniUtils,使用C获取一个字符串,然后展示到一个
public class JniUtils {
    public static native String getStringFormC();
    ...可以有很多的native代码
}

** 使用native关键字,表示调用本地的方法,该方法可以使用C/C++语言来实现**


  1. 生成.h,C/C++的头文件(熟悉C的知道,可以没有头文件,头文件只是定义类中所有方法(C中没有类的概念))
    1. build或rebuild或clear一下程序之后,会在build/intermediates/classes/debug目录中生成项目中的所有的class文件,
class文件路径.png
2. 命令行进入debug目录cd <路径>
3. 编译指令
    javah -jni com.wobiancao.ndkjnidemo.ndk.JniUtils

注意 这里javah -jni后面跟的是JniUtils类的全路径,如果javah报不存在之 类的,是你的java环境没有配置好。

  1. 编译过后会在debug目录下生成一个.h的文件,它的命名方式会很长,基本 是全路径的命名方式
  2. 拷贝文件到项目中的main/jni目录下,如果没有直接创建即可

  1. 编写C的方法实现
    1. 在jni目录下新建C/C++文件,引用头文件,复写其中的java要调用的C/C++方法,返回一个字符串,
  2. 在JniUtils中静态导入C/C++所生成的so包
    static {
        System.loadLibrary("NdkJniDemo");//之前在build.gradle里面设置的so名字,必须一致
    }

此时run之后java代码即可以调用到用C/C++实现的代码了

"PS. 在run之后,会在build/intermediates/ndk/debug/lib目录下会出现在build.gradle中配置的三中cpu架构的so包,此时删除jni目录中的源码,将这些so包直接的拷入到项目中就可以直接的使用了"

遇到的坑

  1. C/C++不能格式化代码,否则会出现,编译通过(可能编译出错,但是没有阻止运行),运行不了,报出找不到so包的异常
  2. 首次run的时候可能报出
Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.

这样的错误,按照里面的提示在gradle.properties文件中增加android.useDeprecatedNdk=true字段即可

  1. 不支持intant run
  2. 两个c同时实现h中的方法,会报错,不允许,逻辑上也是不允许;
  3. JniUtils的位置不能够随便已经,因为和C/C++文件中是一一对应的引用关系

使用cmake进行项目的构建

 * **1.cmake编辑功能是android studio 2.2才支持的新功能;目的是简化jni的开发过程,使用studio2.2新建项目的话,会有相应的让你勾选使用cmake**
1474439172560.png
1474439229866.png

  • 2.当勾选了include C++ Support时,在创建项目的时候,会多出如上界面,选择C/C++的标准,此处的设置在app的build.gradle中的defaultConfig会增加设置
       externalNativeBuild {
            cmake {
                cppFlags "-frtti -fexceptions"//这个标记是第一个选项,如果使用C++11的标准,则使用
                //cppFlags "-std=c++11"
            }
        }

  • 3.在build.gradle中的android节点下面会增加配置,指定生成so文件配置文件的路径
  externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }

  • 4.创建需要调用C/C++代码的java代码,和ndkBuilder相同
public class JniUtils {
    public static native String getStrFromC2();
}

  • 5.在项目中src/main/中创建cpp目录,里面可以直接的创建cpp源代码,和ndkBuild一样,用C/C++所写的源代码中的方法名称必须是全路径的方法名,然后以Java开头,分割使用下划线.
#include <jni.h>
#include <string>

extern "C"
jstring
Java_com_ndkcmaketestapp_utils_JniUtils_getStrFromC2(JNIEnv *env, jobject thiz) {
    std::string hello = "Hello from C++ Two!";
    return env->NewStringUTF(hello.c_str());
}

  • 6.CMakeLists.txt文件中的具体配置
cmake_minimum_required(VERSION 3.4.1) #指定cmake版本
add_library(form SHARED src/main/cpp/form.cpp) #hello是生成的so文件的名称,要和cpp文件的名称相同
target_link_libraries(hello log android) # 此处增加了,日志的链接库

  • 7.在java代码中增加引用so库的代码,使代码生效
public class JniUtils {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("form");//此处的form库的名称需要和CMakeLists.txt中配置的相同
    }
    public static native String getStrFromC2();
}

  • 8.在run成功之后,会在build目录的上方增加.externalNativeBuild目录,其中.externalNativeBuild/cmake/debug/obj包含所有生成的so包,同样的拷贝到项目中的jniLibs就可以直接的使用

CMake的优势

  • 1.可以直接的在C/C++代码中加入断点,进行调试
  • 2.java引用的C/C++中的方法,可以直接ctrl+左键进入
  • 3.对于include的头文件,或者库,也可以直接的进入
  • 4.不需要配置命令行操作,手动的生成头文件,不需要配置android.useDeprecatedNdk=true属性
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容