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++ RTTI | C++标准库 |
---|---|---|---|
system | 不支持 | 不支持 | 不支持 |
gabi++ | 不支持 | 支持 | 不支持 |
stlport | 不支持 | 支持 | 支持 |
gnustl | 支持 | 支持 | 支持 |
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 |
---|---|
C | return (*env)->NewStringUTF(env,”Hello from JNI!”); |
C++ | return env->NewStringUTF((char *)”Hello from JNI!”); |
四、源码下载
https://github.com/zhufeng1222/JniDemo相关文章推荐
- CXF之使用工厂方法(java代码)发布服务与进行客户端调用
- 使用Java调用DOS命令方法
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- Android-NDK开发之基础--Android JNI实例代码(一)-- 在JNI中执行Java方法--C/C++调用Java
- NDK学习 登录逻辑 C调用java方法
- java使用AXIS调用.net的webservice的小说明(webservice方法里含有对象)
- java反射调用配置文件构造类对象,使用其方法
- NDK学习 登录逻辑 C调用java方法
- Ubuntu下使用Java调用IKAnalyzer中文分词程序失效的解决方法
- 使用java反射中的getMethod,invoke方法调用对象方法的实例
- 使用directjngine、Ext Direct调用服务器端Java方法
- delphi程序参数的使用与java调用外部程序方法
- JAVA 使用httpclient、XFire方式调用Web Service的方法
- 【学习Android NDK开发】Java通过JNI调用native方法
- 2011/06/13 android使用html做UI的方法---js与java的相互调用
- java中使用rmi进行远程方法调用
- 使用C#调用Java带MIME附件WebService方法的初步设想
- JAVA JNI配置教程 使用JAVA调用Native方法打印Hello World
- java中调用Js的方法 & java.net.Url的使用 & Url中文乱码的解决 & Map 排序
- 对JAVA Bean使用PropertyDescriptor反射调用JAVA方法