Android Java与Native通信(JNI的使用基础)

1,390 阅读3分钟

NDK

原生开发套件 (NDK) 是一套工具,能够在 Android 应用中使用 C 和 C++ 代码编写,进行Java与Native通信。

流程图

jni流程.png

第一步

编写目标类文件 目录:app/src/main/com/zhyx/jnidemo1/jniclass/JniExample.java

public class JniExample {
    //native
    public static native String getJniStr();
}

第二步

命令生成对应的头文件

javac -h -jni_temp ./jniclass/JniExample.java

javac -h <directory> 指定放置生成的本机标头文件的位置
-jni_temp 生成目录文件名为 "-jni_temp"
./jniclass/JniExample.java 目标类文件名

规则1.png

第三步

编写c/c++具体实现
app/src/main目录下创建一个jni的目录

规则2.png
创建.c文件jniExample.c具体实现:

#include <stdlib.h>
#include <stdio.h>
#include <jni.h>
#include "com_zhyx_jnidemo1_jniclass_JniExample.h"
JNIEXPORT jstring JNICALL Java_com_zhyx_jnidemo1_jniclass_JniExample_getJniStr
  (JNIEnv *env, jclass jcs) {
    char* tempStr = "我是从C创建的字符串";
    return (*env)->NewStringUTF(env,tempStr);
 }

函数名称以及返回值可以直接复制生成的.h文件内容

第四步

① 创建jni/Android.mk文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jniExample
LOCAL_SRC_FILES := jniExample.c
include $(BUILD_SHARED_LIBRARY)
  • LOCAL_PATCH此变量表示源文件在开发树中的位置,my-dir将返回当前目录(Android.mk 文件本身所在的目录)的路径
  • CLEAR_VARS 变量指向一个特殊的 GNU Makefile,后者会为您清除许多 LOCAL_XXX 变量,请注意,GNU Makefile 不会清除 LOCAL_PATH。此变量必须保留其值,因为系统在单一 GNU Make 执行上下文(其中的所有变量都是全局变量)中解析所有构建控制文件。在描述每个模块之前,必须声明(重新声明)此变量
  • LOCAL_MODULE 变量存储您要构建的模块的名称。请在应用的每个模块中使用一次此变量
  • LOCAL_SRC_FILES 变量必须包含要构建到模块中的 C 和/或 C++ 源文件列表
  • BUILD_SHARED_LIBRARY 变量指向一个 GNU Makefile 脚本,该脚本会收集您自最近 include 以来在 LOCAL_XXX 变量中定义的所有信息。此脚本确定要构建的内容以及构建方式

以上是基本必须要写的,更多内容请看Android.mk

② 创建jni/Application.mk文件

APP_ABI := all
APP_OPTM := debug
APP_STL := c++_static
  • APP_ABI 此变量表示支持的Android架构平台 all表示所有平台,多个平台可以用空格隔开,例如: APP_ABI := armeabi-v7a arm64-v8a
  • APP_OPTM 将此可选变量定义为 releasedebug。默认情况下,将构建发布二进制文件。发布模式会启用优化,并可能生成无法与调试程序一起使用的二进制文件。调试模式会停用优化,以便可以使用调试程序。
  • APP_STL 用于此应用的 C++ 标准库。默认情况下使用 system STL。其他选项包括 c++_shared、c++_static 和 none.这里根据你当前的ndk版本可能略有不同,用时请注意查看.

第五步

进入已创建好的jni目录 使用命令生成对应的.so文件

规则3.png

执行 ndk-build

之后生成的so库会自动在前面加上前缀'lib',自动生成libs文件夹

规则5.png 规则4.png

第六步

app/build中配置libs目录

defaultConfig {
    ...
    ndk {
        moduleName "jniExample" //这与LOCAL_MODULE名称一样
    }
}
sourceSets {
    main {
        jniLibs.srcDirs = ["src/main/libs"]
    }
}

第七步

使用C/C++ native方法 JniExample类文件中下加载library

public class JniExample {
    static {
        //系统加载lib方法
        System.loadLibrary("jniExample");
    }
    //native
    public static native String getJniStr();
}

第八步

与普通方法调用一样,直接使用 MainActivity中:

findViewById<TextView>(R.id.text).text = JniExample.getJniStr()

End

规则6.jpg