最近项目用到了jni比较频繁,android studio 配置jni也是必须的。但不知道是不是运气问题,我在自己电脑使用jni一点问题都没有,可以说是无障碍。
但是,一使用公司电脑配置就出现了一大片编译报错,编译不通过的问题。
抱着不怕搞事情的态度,我要将android studio jni配置出现的问题给解决掉。哈哈,不然有问题留着会非常不爽。也可以算帮有问题的小伙伴扫除障碍,
避免掉坑。好啦,现在我们就开始搞事情......
1. 首先我们创建一个项目,然后创建一个JniUtils.java文件
2.点击build重构一下代码,在app/build/intermediates下生成了一个classes文件夹
3.接下来一步是要编译我们刚在创建的JniUtils.java,生成c的头文件。我们需要在Terminal板块中,跳到指的文件夹目录,做一些常规操作
cd app/build/intermediates/classes/debug //跳到指定的文件夹下
javah -jni com.andy.testjni.JniUtils //编译c的头文件
4.在app目录下右键创建jni文件夹
接下来将我们刚才生成的头文件复制到我们刚创建的jni文件夹里面,我们再创建一个JniUtils.c文件
5.创建JniUtils.c文件后,我们需要引用头文件,我们先看一下有文件的方法名,然后我们c中引用该头文件方法
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_andy_testjni_JniUtils */
#ifndef _Included_com_andy_testjni_JniUtils
#define _Included_com_andy_testjni_JniUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_andy_testjni_JniUtils
* Method: getStringFromC
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_andy_testjni_JniUtils_getStringFromC
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
JniUtils.c文件
//
// Created by andy on 2017/10/28.
//
#include "com_andy_testjni_JniUtils.h"
/*
* Class: com_andy_testjni_JniUtils
* Method: getStringFromC
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_andy_testjni_JniUtils_getStringFromC
(JNIEnv * env, jclass object){
return (*env)->NewStringUTF(env,"这里是来自c的string");
}
6.文件都有了,接下来我们需要重新编译一下代码,问题开始来了
编译之后会出现两个问题,一是你还没有关联ndk,二是你没开启
A.配置ndk,你需要关联你下载好的ndk路径
B.开启ndk
android.useDeprecatedNdk=true
7.接下来我们继续配置我们的ndk模块,在build.gradle继续配置
注意moudleName很重要,名字我们自己定义,这是我们java调用c关键的一步
ndk{
moduleName "jniGetFromC"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
sourceSets.main {
jni.srcDirs = ['libs']
}
没有做此操作,将会出现引用不到路径
{NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=F:\workspace\TestJni\app\build\intermediates\ndk\debug\Android.mk APP_PLATFORM=android-25 NDK_OUT=F:\workspace\TestJni\app\build\intermediates\ndk\debug\obj NDK_LIBS_OUT=F:\workspace\TestJni\app\build\intermediates\ndk\debug\lib APP_ABI=all}
8.接下来我们java文件需要载入到jni library我们才可以调用,所以我们需要在JniUtils.java增加载入库
static {
System.loadLibrary("jniGetFromC");
}
9.现在我们已经完成过了大部分工作,我们build一下项目,现在开始用java调用c
当项目跑起来的时候,肯定会出现异常问题
只是因为我们还没有build-ndk,生成so库,所以jvm找不到library,所以就找不到c中的方法。所以,这时候我们就要去配置ndk-build,手动生成so库。
10.配置ndk-build
点击file--setting我们就可以看到
具体可以参考我的图进行配置
Program:C:\Users\AppData\Local\Android\sdk\ndk-bundle\ndk-build.cmd
Working directory: $ModuleFileDir$\src\main\
点击ok,我们将配置完成External Tools,接下来我们测试一下是否配置成功,右键我们项目中的jni文件夹,然后执行ndk-build
将会肯定又有一个异常问题,慢慢来,我们快成功了,很明显,我们看错误日志,缺少.mk文件。
11.在jni文件夹创建.mk文件,让ndk-build动态生成so库
注意注意moduleName哦
我讲解一下.mk文件语法
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.
3> LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格
4> LOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ 源码,不必列出头文件,build System 会自动帮我们找出依赖文件。
application.mk文件代码
APP_ABI := armeabi armeabi-v7a x86
Android.mk文件代码
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
TARGET_PLATFORM := android-23
LOCAL_MODULE := jniGetFromC
LOCAL_SRC_FILES := JniUtils.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
12.mk文件创建好后,我们重新ndk-build一下,我们将会成功编译好so库,将会自动生成一个obj文件夹
13.走到这一步,操作基本就完成了,因为我们也编译生成到我们需要的so库了,但是最后一步切记不能少,我们还需要手动创建一个jniLibs文件夹,将我们手动编译完成的so库复制
到jniLibs文件下,不然还是会报找不到liabrary的异常
重构项目,开启运行我们将会成功跑起来和调用到c的方法
小节:通过解决异常和配置,希望能够帮助到你。