下载 NDK,File --> Project Structure,根据自己的位置配置环境。到时候这些都会在 Androd Studio 中编程一个个环境变量的定义,通过 $$ 来指定(这个后面会介绍)。
在项目上右键 --> 新建文件夹 --> 选择JNI文件夹
Traget Source Set 选 “main”,即可,然后会发现仅在 main 目录下面多了一个 jni,其他的包括 build.gradle 之类的都没变。
public class JniInterface {
static {
System.loadLibrary("LibJni");
}
public native String getMessage(String name, boolean isMale, int age);
}
File --> Settings --> Tools --> External Tools 添加命令
Android Studio 自带的环境变量可以使用右侧的 “Insert Macros” 添加
Program: $JDKPath$\bin\javah.exe
Arguments: -classpath . -jni -d $ModuleFileDir$\src\main\jni $FileClass$
Working directory: $ModuleFileDir$\src\main\java
classpath 表示class的搜索路径
. 号表示当前路径
-d 用来指定生成的 .h 头文件放置的路径
-o 用来指定生成的 .h 头文件名称,默认以类全路径名称生成(包名 + 类名.h)
注意:-d 和 -o 只能使用其中一个参数。
$JDKPath$
是在 Android Studio 中设置JDK目录位置
$ModuleFileDir$
是module的根路径
$FileClass$
是对应文件的类名
有三种方法生成头文件
然后在 jni 对应的 java 文件右击 --> External Tools --> javah
上面的 External Tools 实际上就是在 Terminal 执行 javah 命令帮你生成相应的头文件
"C:\Program Files\Java\jdk1.8.0_201\bin\javah.exe" -classpath . -jni -d C:\workspace\JniDemo\app\src\main\jni com.example.jnidemo.JniInterface
这个是生成的 com_example_jnidemo_JniInterface.h 文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_example_jnidemo_JniInterface */
#ifndef _Included_com_example_jnidemo_JniInterface
#define _Included_com_example_jnidemo_JniInterface
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_jnidemo_JniInterface
* Method: getMessage
* Signature: (Ljava/lang/String;ZI)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_jnidemo_JniInterface_getMessage
(JNIEnv *, jobject, jstring, jboolean, jint);
#ifdef __cplusplus
}
#endif
#endif
C:\workspace\JniDemo>cd app\src\main\java\com\example\jnidemo
C:\workspace\JniDemo\app\src\main\java\com\example\jnidemo>javac JniInterface.java
C:\workspace\JniDemo\app\src\main\java\com\example\jnidemo>cd ..\..\..\
C:\workspace\JniDemo\app\src\main\java>javah -jni com.example.jnidemo.JniInterface
生成的目录结构如下
生成的 JniInterface.class 文件如下
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.example.jnidemo;
public class JniInterface {
public JniInterface() {
}
public native String getMessage(String var1, boolean var2, int var3);
static {
System.loadLibrary("LibJni");
}
}
如果你觉得一直 cd 比较麻烦,可以直接使用拖拽对应目录到 Terminal 的方式,这样 Terminal 会新建一个 Session,并将该目录作为初始目录
还有一种方法生成 class,就是利用 android studio 的 build 自动生成 class 文件
通过在 Windows 资源管理器搜索对应 java 文件名,可以找到生成的 class 文件路径。我这里的是在 app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes\com\example\jnidemo
。之所以通过 Windows 资源管理器去搜索,是因为随着 Android Studio 的更新路径可能不断的变化,目前还没有一个固定的路径。
将头文件复制一下,重命名时,把前面的类名去掉。
然后在cpp文件中删除宏定义,将原 include 改为该头文件即可。
JniInterface.cpp
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
#include "com_example_jnidemo_JniInterface.h"
/* Header for class com_example_jnidemo_JniInterface */
/*
* Class: com_example_jnidemo_JniInterface
* Method: getMessage
* Signature: (Ljava/lang/String;ZI)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_jnidemo_JniInterface_getMessage
(JNIEnv *env, jobject jobject, jstring _name, jboolean _isMale, jint _age) {
char str[50];
const char *name = env->GetStringUTFChars(_name, 0);
sprintf(str, "%s is %s age is %d !", name, _isMale ? "male, his" : "female, her", _age);
return (*env).NewStringUTF(str);
}
新版的 Android Studio 已经不再使用之前 eclipse 的 mk 来指定 C++ 文件了,而改用 gradle 进行配置
首先,在 File --> Settings --> Appearance & Behavior --> System Settings --> Android SDK 中确保 NDK、LLDB、CMake 均已安装
//使用 Cmake 工具
externalNativeBuild {
cmake {
cppFlags ""
//生成多个版本的so,出于包大小和向下兼容性的考虑,去掉其他包
abiFilters 'arm64-v8a', 'armeabi-v7a'//, armeabi, 'x86_64', 'x86', "mips", "mips64"
}
}
//配置 CMakeLists.txt 路径
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
# For more information about using CMake with Android Studio, read the documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
# CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library(
# Sets the name of the library.
# 设置so文件名称.
LibJni
# Sets the library as a shared library.
# 设置这个so文件为共享.
SHARED
# Provides a relative path to your source file(s).
# 设置关联的源文件路径.
src/main/jni/JniInterface.cpp)
# Searches for a specified prebuilt library and stores the path as a variable. Because CMake includes system libraries in the search path by default,
# you only need to specify the name of the public NDK library you want to add. CMake verifies that the library exists before
# completing its build.
find_library(
# Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You can link multiple libraries, such as libraries you define in this build script, prebuilt third-party libraries, or system libraries.
target_link_libraries(
# Specifies the target library.
# 制定目标库,一般设置成跟so名字一样
LibJni
# Links the target library to the log library
# included in the NDK.
${log-lib} )
主要修改如下三个加红框的地方