您的位置:首页 > 编程语言 > Java开发

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

2017-07-25 09:50 344 查看

一、准备工作

配置好Android开发环境

能正常运行的Android Studio

下载最新的ndk:https://developer.android.google.cn/ndk/downloads/index.html

二、使用步骤

2.1 Android Studio工具层接入

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

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



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。



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

这里已编写C代码为例,使用C打印出”hello from jni”字符串。

在主module的src/main文件夹下新建jni文件夹作为native代码存放目录,如果修改的话,需要同时在build.gradle的ndk配置中修改jni的地址。项目结构如图:



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)


LOCAL_PATH := $(call my-dir)

每个Android.mk文件必须以定义LOCAL_PATH为开始。它用于在开发tree中查找源文件。

宏my-dir 则由Build System提供。返回包含Android.mk的目录路径。

include $(CLEAR_VARS)

CLEAR_VARS 变量由Build System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_xxx.

例如:LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等。但不清理LOCAL_PATH.

这个清理动作是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能避免相互影响。

LOCAL_LDLIBS :=-llog

可以用它来添加系统库

LOCAL_MODULE = JniTest

LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格。

Build System会自动添加适当的前缀和后缀。例如,foo,要产生动态库,则生成libfoo.so. 但请注意:如果模块名被定为:libfoo.则生成libfoo.so. 不再加前缀。

LOCAL_SRC_FILES

LOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ 源码。

不必列出头文件,build System 会自动帮我们找出依赖文件。

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


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运行时库。

APP_CPPFLAGS := -frtti -fexceptions:设置支持C++异常捕获

APP_OPTIM := debug:设置编译生成的so文件是否是可编译模式

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目录中。如图:



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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android ndk c语言 jni