先导知识:
1.JNI是java中调用其他语言的接口(在NDK开发中也就是调用C\C++),NDK是一组帮助java调用C\C++的工具,可以将so文件和java文件一起编入apk等。
2.java运行在java虚拟机上,是跨平台的。但是C\C++是不跨平台的,根据CPU不同编译生成的so文件(动态链接库)也会不同。安卓中有7中CPU架构,通过NDK工具我们可以快速编译生成这7中各自的so文件。有些型号即使没有自己的so文件也会尝试去支持使用别的so文件,通过一个模拟层,当然这样的话性能肯定会下降,而且可能会出各种各样的问题。所以编译生成全平台的so库是很有必要的,在安装到手机上的时候会根据型号选择相应的so,其他的并不会安装。
3.NDK开发的基本流程:创建java文件,用native关键字标记要在C\C++中实现的函数。
根据java文件生成.h文件。
创建相应的C\C++文件,实现函数。
编写Android.mk和Application.mk文件指导编译过程。
编译生成so文件。
在java中调用函数。
环境搭建:
首先打开Project Structure确认下载了NDK:
在gradle.properties中加入一行,允许低版本NDK编译(不太懂):
android.useDeprecatedNdk=true
在Settings->Tools->External tools里添加两个插件,分别用于将java生成.h和编译C\C++生成so(来自博客http://blog.youkuaiyun.com/xiaoyu_93/article/details/52870395,但是原博客参数中没有编码参数,所以中文会报错编码GBK的不可映射字符)
注意第二个的那个cmd地址是你自己的,其他不用变。
******************************************************************************************************************
开始编写Hello World:
1.在module的gradle中配置一个name,jni会根据这个name在这个module中找so文件,这是设为“JNI_ANDROID_TEST”。(下面会提到)否则报错找不到so文件
defaultConfig {
applicationId "com.example.listtest"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk{
moduleName = "JNI_ANDROID_TEST"
//abiFilters "x86","armeabi-v7a"
// 这里填写两个abi cpu架构,如果什么都不写,则默认支持所有平台
}
}
2.创建一个java类,加载so库并用native修饰要在C\C++中实现的方法:
public class JavaH {
public static native String getPkgName();
/**
* 加载so库或者jni库
*/
static {
System.loadLibrary("JNI_ANDROID_TEST");
}
}
这里加载库用到的名字对应第一步的配置。
3.在该类中右键-->External tools-->javah -jni(自定义的插件),生成.h文件。生成的头文件在cpp文件夹中,名字比较复杂,这里重命名为jnitest.h。
4.在cpp下创建jnitest.cpp并编写:
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include "jnitest.h"
JNIEXPORT jstring JNICALL Java_com_example_listtest_tool_JavaH_getPkgName
(JNIEnv * env, jclass clazz){
return env->NewStringUTF("HelloWorld! I am from JNI !");
}
可以看到,就是引入了jnitest.h头文件然后实现了函数,函数返回Hello World。网上有些博客中的(*env)不是C++而是C的语法。
5.在cpp下创建Android.mk并编写:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := JNI_ANDROID_TEST
LOCAL_SRC_FILES := jnitest.cpp
include $(BUILD_SHARED_LIBRARY)
下面的四行是一个module的mk,有价值的就是JNI_ANDROID_TEST和jnitest.cpp,指出编译的模块和要编译的文件。
6.在cpp下创建Application.mk并编写:
APP_ABI := all
含义很简单,就是支持全平台。
7.cpp文件中右键-->External tools-->ndk build编译生成so文件,可以把视角调到Project看到:
8.在java中调用该函数即可:
Button button= (Button) findViewById(R.id.btn);
button.setText(JavaH.getPkgName());