Android Studio 3.x 搭建 JNI NDK开发环境

1. 环境配置

1.1 安装 ndk,配置环境变量

ndk安装位置:

 

配置环境变量:

1.2 项目配置 ndk

Android Studio 打开 File / Project Structure / SDK Location / Android NDK location:

 

1.3 安装CMake

 

2. 项目配置

2.1 配置 app 的 build.gradle

添加如下节点:

android 节点下 添加配置:

externalNativeBuild {
    cmake {
    path "CMakeLists.txt"
    version "3.10.2"
	}
}

android / defaultConfig 节点下 添加配置:

externalNativeBuild {
    cmake {
    cppFlags ""
	}
}
ndk {
    //moduleName"native-xx" //生成的so文件名字,程序中加载so库时需要用到
    abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' // 生成so库的CPU平台
}

 

2.2 /src/目录下创建 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.

# 设置构建本地库所需要的CMake最低版本
cmake_minimum_required(VERSION 3.4.1)

# 设置生成的so动态库最后输出的路径 src/main/jniLibs
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})

# 创建并命名一个库,设置为静态或共享,并且指定源码的关联路径
# 可以定义多个库,由CMake负责编译它们
# Gradle自动打包并和你的APK包共享这些库
# 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. 库名称
        native-lib

        # Sets the library as a shared library. 设置库为共享库
        SHARED

        # Provides a relative path to your source file(s). 源码路径
        src/main/cpp/native-lib.c)

# 搜索一个明确的预先构建的库并且存储路径变量.
# 因为CMake默认在搜索路径中包含了系统库,你仅需明确指定你想添加的公共NDK库的名称即可.
# CMake编译库之前会对存在的库进行验证
# 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 明确指定你想CMake定位加载的NDK库的名称
        # you want CMake to locate.
        log)

# 明确指定CMake应该链接到目标库的库.
# 你可以链接多个库,比如自定义脚本/第三方库/系统库
# 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. 指定目标库
        native-lib

        # Links the target library to the log library 链接目标库到 log 库,包含NDK
        # included in the NDK.
        ${log-lib})

2.3 新建 Jni 接口,本地库调用接口

新建 JNI.java类,定义 native 方法:

package com.dongzz.android.javac;

/**
 * C/C++ 代码调用接口
 */
public class JNI {

    //加载本地库
    static {
        System.loadLibrary("native-lib");
    }


    /**
     * 让C代码做加法运算,把结果返回
     *
     * @param x
     * @param y
     * @return
     */
    public native int add(int x, int y);
}

2.4 生成 .h 头文件

打开 File / Settings / External Tools / Create Tool,创建工具;

Tool Settings 节点下添加如下配置:

Program : javah
Arguments : -classpath . -jni -encoding UTF-8 -d $ModuleFileDir$/src/main/jni $FileClass$
Working directory : $ModuleFileDir$\src\main\java

如图所示:

2.4 JNI类上,右键 / External Tools 执行上步创建的命令

生成 JNI.java 类对应的 .h 头文件:com_dongzz_android_javac_JNI.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_dongzz_android_javac_JNI */

#ifndef _Included_com_dongzz_android_javac_JNI
#define _Included_com_dongzz_android_javac_JNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_dongzz_android_javac_JNI
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_dongzz_android_javac_JNI_add
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

2.5  创建C代码包 /src/main/cpp

将  com_dongzz_android_javac_JNI.h 头文件拷贝到 cpp 目录下;

新建 native-lib.c 或 native-lib.cpp 源文件,内容如下:

//
// Created by Administrator on 2020/11/5.
//

#include "com_dongzz_android_javac_JNI.h"
#include <string.h>
#include <malloc.h>
#include <jni.h>

/**
 * 加法运算
 * @param env 结构体指针,结构体中包含许多函数
 * @param job 实例 谁调用就是谁的实例
 * @param a 参数1
 * @param b 参数2
 * @return
 */
jint Java_com_dongzz_android_javac_JNI_add
        (JNIEnv *env, jobject job, jint a, jint b) {

    int result = a + b;
    return result;
}

执行 Clean Project / Make Project 重新编译项目;/src/main/jniLibs 目录下会生成适应各个CPU平台的 .so 库文件;

 

3. 常见问题

3.1 More than one file was found with OS independent path lib/armeabi-v7a/libnative_lib.so

解决方案:

app / build.gradle  的 android 节点下添加配置:

// 打包
packagingOptions {
    //当出现重复文件,会使用第一个匹配的文件打包进入apk
    //解决 More than one file was found with OS independent path 异常
    pickFirst 'lib/armeabi-v7a/libnative-lib.so'
    pickFirst 'lib/arm64-v8a/libnative-lib.so'
    pickFirst 'lib/x86_64/libnative-lib.so'
    pickFirst 'lib/x86/libnative-lib.so'
}

重新编译项目,问题解决;