使用情景:
1).C/C++的开发人员完成底层的算法,并编译成一个
so库,并且提供
.h头文件;
2).在Android端需要调用其中的函数完成一些操作;
3).但提供的so库不符合标准的JNI规范,java中不能直接使用,所以需要再封装;
Android studio的jni使用的基础就不需要更多的赘述了,自己百度下;
1.新建项目
2.添加NativeUtils.java类:(测试加法,后面有我编译的so库和.h头文件,纯c++编写,不符合jni规范) 点击打开链接
public class NativeUtils {
public static final native int exeAddMethod(int a,int b);
static {
System.loadLibrary("jnidemo");
}
}
3.编译对应的头文件
...\JNIDemo\src\main\java> javah -jni -d ../jni project.vvizware.com.myapplication.NativeUtils
目录结构:
编译好的头文件:
project_vvizware_com_myapplication_NativeUtils.h
#include
/* Header for class project_vvizware_com_myapplication_NativeUtils */
#ifndef _Included_project_vvizware_com_myapplication_NativeUtils
#define _Included_project_vvizware_com_myapplication_NativeUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: project_vvizware_com_myapplication_NativeUtils
* Method: exeAddMethod
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_project_vvizware_com_myapplication_NativeUtils_exeAddMethod
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
4.新建c++文件NAtiveUtils.cpp 并且将之前提供的libs文件放置到对应的目录,如图:
然后看代码:
#include "project_vvizware_com_myapplication_NativeUtils.h"
#include "./vvw/include/vvwUtils.h"
#ifdef __Cplusplus
extern "C"{
#endif
JNIEXPORT jint JNICALL Java_project_vvizware_com_myapplication_NativeUtils_exeAddMethod
(JNIEnv *env, jclass clazz, jint a, jint b) {
int res = addMethod(a, b);
return (jint)res;
}
#ifdef __Cplusplus
};
#endif
Android中的调用:
5.在src/jni 目录下添加Android.mk,Application.mk文件
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jnidemo
LOCAL_SRC_FILES := NatvieUtils.cpp
LOCAL_LDFLAGS := -L$(LOCAL_PATH)/vvw/libs/$(TARGET_ARCH_ABI)
LOCAL_LDLIBS := \
-lz \
-lm \
-lvvw\
#LOCAL_SHARED_LIBRARIES := vvw
include $(BUILD_SHARED_LIBRARY)
Application.mk
6.下面开始编辑build.gradle
applyplugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "project.vvizware.com.myapplication"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
jni.srcDirs = []//设置禁止gradle生成Android.mk
jniLibs.srcDirs = ['src/main/jniLibs']//设置目标的so存放路径
}
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn 'ndkBuild','copyThirdso', 'copyJniLibs'
}
}
task ndkBuild(type: Exec) {//设置新的so的生成目录
def ndkBuildingDir = project.plugins.findPlugin('com.android.application').sdkHandler.getNdkFolder().absolutePath
commandLine ndkBuildingDir + "/ndk-build.cmd", '-C', 'src/main/jni',
"NDK_OUT=$buildDir/intermediates/ndk/obj",
"NDK_APP_DST_DIR=$buildDir/intermediates/ndk/libs/\$(TARGET_ARCH_ABI)"
}
task copyJniLibs(type: Copy) {//将新生成的so拷贝到jniLibs目录
from fileTree(dir: file(buildDir.absolutePath + '/intermediates/ndk/libs'), include: '**/*.so')
into file('src/main/jniLibs')
}
task copyThirdso(type: Copy) {//将第三方的so拷贝到jniLibs目录
from file('src/main/jni/vvw/libs')
into file('src/main/jniLibs')
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:design:23.1.1'
}
7.编译打包apk,尝试下,是不是成功了呢!
忙活了差不多一个多星期,本来eclipse上可以轻松搞定,但是目前AS是主流嘛,还是需要研究下的,还好有大神帮我看看makefile文件,不然我也搞不定啊!
我采用的方式是屏蔽gradle自动生成的Android.mk,而去使用自己编写的Android.mk文件去编译;
但是gradle应该提供了更简单的方式去自动生成Android.mk文件调用第三方的so库,还得要好好研究下,有大神知道该怎么做请告知,灰常感谢!
参考了文章: http://coolerfall.com/tools/use-ndk-in-android-studio/
源码: 点击打开链接