Android 添加JNI 开发能力

JNI 与 NDK 区别
JNI:JNI是一套编程接口,用来实现Java代码与本地的C/C++代码进行交互;
NDK: NDK是Google开发的一套开发和编译工具集,可以生成动态链接库,主要用于Android的JNI开发;

使用cMake或者ndk-bundle 编译(推荐使用Cmake)

使用cMake

环境需求
要进行jni开发,AS需要以下环境:
在AndroidStudio下载以下插件


image.png

新建支持c的项目


image.png

新建完后在编译即可

有时候,我们的项目已经在进行中或者维护中了,突然需要使用jni调用怎么办呢?AS已经提供了相对便捷的方法。首先在要使用jni调用的工程模块下新建一个CMakeLists.txt:
本文主要讲解在现有老项目如何添加JNI 支持,
1、配置ndk路径


image.png

2、在app目录下新建cMakeList文件(不一定要在app目录下,只要是在build文件里面配置的路径一致即可)


image.png
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

# 配置so库信息
add_library( # Sets the name of the library.
        # 生成的so库名称,此处生成的so文件名称是libnative-lib.so
        hello

        # Sets the library as a shared library.
        # STATIC:静态库,是目标文件的归档文件,在链接其它目标的时候使用
        # SHARED:动态库,会被动态链接,在运行时被加载
        # MODULE:模块库,是不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数动态链接
        SHARED

        # Provides a relative path to your source file(s).
        # 资源文件,可以多个,
        # 资源路径是相对路径,相对于本CMakeLists.txt所在目录
        # src/main/jni/test.cpp
        src/main/jni/hello.c)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

# 从系统查找依赖库
find_library( # Sets the name of the path variable.
        # android系统每个类型的库会存放一个特定的位置,而log库存放在log-lib中
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        # android系统在c环境下打log到logcat的库
        log)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

# 配置库的链接(依赖关系)
target_link_libraries( # Specifies the target library.

        # 目标库
        hello

        # Links the target library to the log library
        # included in the NDK.
        # 依赖于
        ${log-lib})
image.png

CMakeLists.txt具体配置上面已经说过了,这个地方是去掉了注释了的。需要注意的是,如果我们不在c源代码文件中输出日志到logcat,那么我们是不需要依赖log库的,也就是说find_library、target_link_libraries不是必须的。

将 find_library()命令添加到您的 CMake 构建脚本中以定位 NDK 库,并将其路径存储为一个变量。您可以使用此变量在构建脚本的其他部分引用 NDK 库。以下示例可以定位 Android 特定的日志支持库并将其路径存储在 log-lib 中:

find_library( # Defines the name of the path variable that stores the
              # location of the NDK library.
              log-lib

              # Specifies the name of the NDK library that
              # CMake needs to locate.
              log )

为了确保您的原生库可以在 log 库中调用函数,您需要使用 CMake 构建脚本中的 target_link_libraries() 命令关联库:

find_library(...)

# Links your native library against one or more other native libraries.
target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the log library to the target library.
                       ${log-lib} )

NDK 还以源代码的形式包含一些库,您在构建和关联到您的原生库时需要使用这些代码。您可以使用 CMake 构建脚本中的 add_library() 命令,将源代码编译到原生库中。要提供本地 NDK 库的路径,您可以使用 ANDROID_NDK 路径变量,Android Studio 会自动为您定义此变量。

接着配置模块支持jni调用,对项目模块右键:


image.png

image.png
image.png

在JniTest里面定义好暴露出去的方法,新建hello.c文件在c里面实现这里个方法

public class JniTest {
    // Used to load the 'native-lib' library on application startup.
    // 加载库
    static {
        System.loadLibrary("hello");
    }
    // native申明 在c里面实现
    public native String stringTest();

    public native String stringHello();

#include <jni.h>

JNIEXPORT jstring JNICALL
Java_com_jni_JniTest_stringHello(JNIEnv *env, jobject instance) {
    // TODO
    return (*env)->NewStringUTF(env, "helloJNi");
}


JNIEXPORT jstring JNICALL
Java_com_jni_JniTest_stringTest(JNIEnv *env, jobject instance) {

    // TODO

    return (*env)->NewStringUTF(env, "hello_new_eeeeetest");
}

运行在app里面调用new JniTest().stringTest() 即可拿到在c里面给的结果


image.png

然后Make Project成功后,会在如下目录生成.so文件.此时.so库生成成功,可随时调用了!
编译的包里面lib里面已经包含了so

image.png

cmake里面也包含了 当前对应环境的so 文件(这些so文件便可以给第三方使用了)


image.png

总之,JNI入门难度大大降低,AS在这方面还有很多适用的功能提供,例如debug、在c代码中输入日志到logcat等,只需简单操作就可完成,非常人性。
参考文章
使用ndk-build编译 请参考这篇文章
AndroidStudio现有项目添加NDK支持(CMake编译)

使用ndk-build编译 生成头文件方式
使用javac编译生成class

image.png

函数返回值
以下是一个JNI函数:
JNIEXPORT jstring JNICALL Java_com_mm_NativeHelper_sayHello(JNIEnv *, jclass, jstring);
在JNIEXPORT和JNICALL宏中间的jstring,表示函数的返回值类型,对应Java的String类型。

使用javah生成h文件
在不熟悉的情况下,可以通过javah生成JNI函数头文件;
当熟悉了JNI的native函数命名规则之后,直接按照函数命名规则编写相应的函数原型和实现即可。

image.png

githubDemo

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

推荐阅读更多精彩内容