美文网首页Android 知识美文收集大牛聚集之地
Android NDK-JNI 入门之 CMake 初体验

Android NDK-JNI 入门之 CMake 初体验

作者: stone呀 | 来源:发表于2018-03-13 17:18 被阅读329次

    CMake 是个开源跨平台自动化建构系统,关于维基。

    style.png

    在使用 CMake 编译 so 之前,需要配置 NDK 环境,
    Mac 用户可以参考
    window 用户参考

    在 Android studio 中新建项目

    我的是 Android studio 3.0 版本,官方在新建项目时已经提供对c++的支持,以方便我们开发者更好的使用JNI开发项目。记得勾选 Include C++ support 选项。


    新建项目.png

    和普通 Android 项目的区别

    项目结构.png

    ① 会发现多了一个 CMakeLists.txt 文件和 .externalNativeBuild 文件夹。

    • CMakeLists.txt 相当于 CMake 的配置文件
    • .externalNativeBuild 是自动生成的构建脚本

    ② main 文件夹下多了一个 cpp 文件夹,里面用来放置 C/C++ 代码


    image.png

    ③ build..gradle 文件中会有一些修改,新增了一些配置

    android {
        compileSdkVersion 26
        defaultConfig {
            applicationId "com.muxiaolei.helei.jnitest"
            minSdkVersion 14
            targetSdkVersion 26
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
            //新增
            externalNativeBuild {
                cmake {
                    //配置参数
                    cppFlags ""
                    //设置生成指定 ABI 版本的 so 库
                    abiFilters 'armeabi-v7a', 'armeabi'
                }
            }
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
        //新增
        externalNativeBuild {
            cmake {
                //配置文件路径
                path "CMakeLists.txt"
            }
        }
    }
    

    简单项目分析

    接下来我们拿一个实现两数相加的小项目进行分析
    使用 CMake 编译生成 so 文件并 JNI native 调用,我们大致需要配置

    • CMakeLists.txt 文件修改
    • 编写 .c/.cpp 文件
    • 编写 .c/.cpp 文件对应的 java native 方法
    • 修改 build.gradle 中 externalNativeBuild 闭包中配置
    • System.loadLibrary 加载 so 库
    • Android 端功能调用

    先看看配置文件 CMakeLists.txt 内容,设置了 so 文件的输出路径,编译成功后最终会在src/main/jniLibs/ 下生成 so 文件,生成的文件个数根据 abiFilters 指定的 ABI 类型

    #要求的最低版本
    cmake_minimum_required(VERSION 3.4.1)
    #设置生成的so动态库最后输出的路径
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
    #添加库
    add_library( calculate
                 SHARED
                 #calculate.c的路径
                 src/main/cpp/calculate.c )
    find_library( log-lib
                  log )
    #链接库
    target_link_libraries( calculate
                           ${log-lib} )
    

    calculate.c 源文件代码,

    #include "calculate.h"
    #include <jni.h>
    #include <android/log.h>
    
    #define TAG    "myhello-jni-test" // 这个是自定义的LOG的标识
    #define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) // 定义LOGD类型
    
    JNIEXPORT jint
    JNICALL Java_com_muxiaolei_helei_util_NativeHelper_calculateSum(
            JNIEnv *env, jclass type, jint numberOne, jint numberTwo) {
        LOGD("numberOne-----------", numberOne);
        LOGD("numberTwo-----------", numberTwo);
        return numberOne + numberTwo;
    }
    

    对应的 java 本地 native 方法代码

    public class NativeHelper {
    
        static {
            System.loadLibrary("calculate");
        }
    
        private NativeHelper(){
            //not allow create instance
        }
    
        //计算两个数之和
        public static native int calculateSum(int number, int other);
    }
    

    功能调用代码

            String numberOne = et_first_number.getText().toString().trim();
            String numberSecond = et_second_number.getText().toString().trim();
            if(TextUtils.isEmpty(numberOne)) {
                Toast.makeText(this, "请输入第一个加数", Toast.LENGTH_SHORT).show();
                return;
            }
            if(TextUtils.isEmpty(numberSecond)) {
                Toast.makeText(this, "请输入第二个加数", Toast.LENGTH_SHORT).show();
                return;
            }
            int result = NativeHelper.calculateSum(Integer.parseInt(numberOne), Integer.parseInt(numberSecond));
            tv_result_sum.setText(String.valueOf(result));
    

    如果遇上错误

    Error:Execution failed for task ':app:transformNativeLibsWithMergeJniLibsForDebug'.
    > More than one file was found with OS independent path 'lib/armeabi-v7a/libcompress.so'
    

    在 build.gradle 中加入(pickFirst 的个数和 abiFilters 指定的 ABI 对应)

    packagingOptions {
            pickFirst 'lib/armeabi-v7a/libcalculate.so'
            pickFirst 'lib/armeabi/libcalculate.so'
            pickFirst 'lib/x86/libcalculate.so'
    }
    

    放上效果图,很简陋,😆

    结果.png

    项目源码已经上传到 github,戳我查看源码

    Android NDK-CMake文档
    CMake 官方文档
    CMake手册

    相关文章

      网友评论

        本文标题:Android NDK-JNI 入门之 CMake 初体验

        本文链接:https://www.haomeiwen.com/subject/oixzfftx.html