NDK的使用(java调用C方法)

1 篇文章 0 订阅
1 篇文章 0 订阅

一、准备工作

二、使用步骤

2.1 Android Studio工具层接入

2.1.1 项目根目录下local.properties文件中添加NDK地址

window环境和mac环境下的路径形式不一样。
image

2.1.2 主module下的build.gradle中添加ndk的设置。

给出我的配置代码(将生成的so文件放置到src/main/opencv/libs目录下)windows环境下commandLine里面ndk-build需要改成ndk-build.cmd:

android {
    ...

    sourceSets.main.jni.srcDirs = []

    sourceSets.main.jniLibs.srcDirs = ['src/main/opencv/libs','src/main/jniLibs']

    task ndkBuild(type: Exec, description: 'Compile JNI source with NDK') {
        def ndkDir = getNdkDir()
        def mainDir = file('src/main').absolutePath

        commandLine "$ndkDir/ndk-build", '-C', "$mainDir/jni", "NDK_LIBS_OUT=$mainDir/opencv/libs", "NDK_OUT=$mainDir/opencv/obj"
    }

    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }

    task ndkClean(type: Exec, description: 'Clean NDK Binaries') {
        def ndkDir = getNdkDir()
        def mainDir = file('src/main').absolutePath

        commandLine "$ndkDir/ndk-build", 'clean', '-C', "$mainDir/jni", "NDK_LIBS_OUT=$mainDir/opencv/libs", "NDK_OUT=$mainDir/opencv/obj"
    }

    clean.dependsOn 'ndkClean'
}

def getNdkDir() {
    Properties properties = new Properties()
    properties.load(project.rootProject.file('local.properties').newDataInputStream())
    return properties.getProperty('ndk.dir')
}
2.1.3 指定支持的ABIs(可选)

某些library(如fresco)会在项目中生成so文件,为防止ndk打包生成的so包没有包含到library指定的ABIs,可以在主module下的build.gradle文件的defaultConfig中指定项目支持的ABIs。
image

2.2 接入C类库,或者编写C代码

这里已编写C代码为例,使用C打印出”hello from jni”字符串。
在主module的src/main文件夹下新建jni文件夹作为native代码存放目录,如果修改的话,需要同时在build.gradle的ndk配置中修改jni的地址。项目结构如图:

image

2.2.1 新建Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_LDLIBS :=-llog
LOCAL_MODULE = JniTest
LOCAL_SRC_FILES = com_rajesh_jnidemo_JniUtil.cpp

include $(BUILD_SHARED_LIBRARY)
  1. LOCAL_PATH := $(call my-dir)
    每个Android.mk文件必须以定义LOCAL_PATH为开始。它用于在开发tree中查找源文件。
    宏my-dir 则由Build System提供。返回包含Android.mk的目录路径。

  2. include $(CLEAR_VARS)
    CLEAR_VARS 变量由Build System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_xxx.
    例如:LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等。但不清理LOCAL_PATH.
    这个清理动作是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能避免相互影响。

  3. LOCAL_LDLIBS :=-llog
    可以用它来添加系统库

  4. LOCAL_MODULE = JniTest
    LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格。
    Build System会自动添加适当的前缀和后缀。例如,foo,要产生动态库,则生成libfoo.so. 但请注意:如果模块名被定为:libfoo.则生成libfoo.so. 不再加前缀。

  5. LOCAL_SRC_FILES
    LOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ 源码。
    不必列出头文件,build System 会自动帮我们找出依赖文件。

  6. include $(BUILD_SHARED_LIBRARY)
    BUILD_SHARED_LIBRARY:是Build System提供的一个变量,指向一个GNU Makefile Script。
    它负责收集自从上次调用 include $(CLEAR_VARS) 后的所有LOCAL_XXX信息。并决定编译为什么。

2.2.2 新建Application.mk
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_OPTIM := debug
APP_ABI := armeabi
  1. APP_STL := gnustl_static:设置连接的标准模板库,这个变量可以被设置成如下几个值:
    • system
    • gabi++_static
    • gabi++_shared
    • stlport_static
    • stlport_shared
    • gnustl_static
    • gnustl_shared
*C++异常C++ RTTIC++标准库
system不支持不支持不支持
gabi++不支持支持不支持
stlport不支持支持支持
gnustl支持支持支持

默认为system,如果想支持C++异常的话,必须要使用gunstl运行时库。

  1. APP_CPPFLAGS := -frtti -fexceptions:设置支持C++异常捕获
  2. APP_OPTIM := debug:设置编译生成的so文件是否是可编译模式
  3. APP_ABI := armeabi:选择支持的ABI,多个以空格间隔
2.2.3 编写调用C方法的java文件
package com.rajesh.jnidemo;

/**
 * Created by zhufeng on 2016/10/8.
 */

public class JniUtil {
    static {
        System.loadLibrary("JniTest");
    }
    public native String helloWorld();
}

在Terminal中cd进入到文件package所在目录javah命令生成头文件并移动到jni目录中。如图:
image

2.2.4 编写C++代码

新建与头文件同名的cpp文件:

#include <com_rajesh_jnidemo_JniUtil.h>
#include <stdio.h>
using namespace std;

#define TAG "zhufeng-jni" //定义Log的tag
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__)//打印info类型的Log

extern "C" {

    JNIEXPORT jstring JNICALL Java_com_rajesh_jnidemo_JniUtil_helloWorld(JNIEnv *env, jobject obj){
        LOGI("测试Log打印");
        return env->NewStringUTF((char *)"Hello from JNI!");
    }

}
2.2.5 java调用
JniUtil jni = new JniUtil();
TextView.setText(jni.helloWorld());

三、注意事项

  • java与C方法之间的参数传递需要通过JNI语法进行转化,需要了解基本的JNI语法。
  • C方法中申请空间,return前及时释放。
  • C和C++的JNI方法有区别,如:
*返回String
Creturn (*env)->NewStringUTF(env,”Hello from JNI!”);
C++return env->NewStringUTF((char *)”Hello from JNI!”);

四、源码下载

https://github.com/zhufeng1222/JniDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值