​ 相信大家在开发的过程中,都或多或少的接触过JNI,然后每次要接触JNI的时候,倒吸一口冷气,太难啦!

​ 只有Java代码和C++代码 还好,在新建项目的时候把那个 "Include C++ support"勾选上,然后一路next,最后finish,一个简单的带有C++代码的Android项目就算完成了,然后在看下CMakeLists.txt怎么写的,照猫画虎就可以了,但是实际开发中,并不简单,因为底层(C++)那里给过来的有可能是.a静态库,也有可能是.so动态库,然后如何集成进项目里就是:一脸懵逼,二脸茫然,三脸不知所措。由于客观事实只能去百度,然后百度到的全是用Android.mk实现的居多,然而现在都Android Studio 3.1+时代了,还mk?关于CMake的资料又很少,所以就有了本文。

​ 在去年在公司还是实习的时候,老大丢给我一个.a静态库(当时并不知道这是一个静态库),很是好奇,很想知道.a是怎么构建出来的,a和so的区别又是什么,总之一大堆疑问,在转正后,也尝试过要构建一个.a静态库,无奈!百度到的都是用mk的咯,找到一篇CMake的,但竟然要去Linux下面编译,还要什么自定义工具链,总之,麻烦的一批。

​ 所以就有了这一系列,本系列不阐述什么是CMake,什么是NDK,什么是JNI,只是写一下在Android中使用CMake常遇的问题,解决方法是什么。

​ 本系列涉及到的有:

  • 初次使用CMake构建native项目
  • 如何将现有的cpp代码集成到项目中
    • 拷贝源码
    • 编译成库文件
  • CMake链接a静态库以及so动态库及动态库和静态库的区别

初次使用CMake构建native项目

​ 这个就很简单啦,新建项目的时候把 include C++ support 勾选上就可以了,但,我们还是自己动手来一遍,不依靠IDE,看看可不可以,新建普通项目,名字为:AndCmake,新建完成后如下:

新项目,什么都没有,我们都知道用CMake的话,必须要有CMakeLists.txt(注意名字不能写错),第二个就是需要的cpp资源啦,这就很简单了,在src/main目录下新建就好了,为了整洁在main目录下新建cpp文件夹,且在里面新建CMakeLists.txt和native_hello.cpp文件,然后在去CMakeLists.txt简单的配置下就好了,完成后,如下:

  1. ../src/main/cpp/native_hello.cpp:

    //
    // Created by xong on 2018/9/28.
    //
    #include<jni.h>
    #include <string>extern "C" JNIEXPORT
    jstring JNICALL
    Java_com_xong_andcmake_jni_NativeFun_stringFromJNI(JNIEnv *env, jclass thiz)
    {std::string hello = "Hello,I from C++";return env->NewStringUTF(hello.c_str());
    }
    复制代码

    这里需要说明以下,Java_com_xong_andcmake_jni_是去java的一层一层的包下面去寻找,比如这个就是去com.xong.andcmake.jni下面找,后面的NativeFun_stringFromJNI就是类和方法名了。函数的形参两个必须是这样的,第二个形参可以写成"jobject",我最近写JNI的时候,提示改成"jclass"但是,"jobject"也不能算错,也是对的。

  2. ../src/main/cpp/CMakeLists.txt

    # CMake最低版本
    cmake_minimum_required(VERSION 3.4.1)
    # 将需要打包的资源添加进来
    add_library(# 库名字native_hello# 库类型SHARED# 包含的cppnative_hello.cpp
    )
    # 链接到项目中
    target_link_libraries(native_helloandroidlog
    )
    复制代码

    这就把C++部分写好了

  3. 修改../app/build.gradle,修改后如下:

    android {...defaultConfig {...externalNativeBuild {cmake {arguments '-DANDROID_STL=c++_static'}}...}...externalNativeBuild {cmake {path 'src/main/cpp/CMakeLists.txt'}}...
    }
    复制代码
  4. 写对应的Java层代码,在com.xong.andcmake包下新建jni,然后新建NativeFun类,代码如下:

    package com.xong.andcmake.jni;/*** Create by xong on 2018/9/28*/
    public class NativeFun {static {System.loadLibrary("native_hello");}public static native String stringFromJNI();
    }复制代码
  5. 调用NativeFun.stringFromJNI(),查看是否有正确的信息输出:这就很简单啦,在Activity中添加一个TextView然后显示下就好了,正确的话,应该会有如下显示:

OK,这样我们的第一个带有CPP代码的APP就算完成了,然后我们来思考一下,先来看native_hello.cpp的代码:

//
// Created by xong on 2018/9/28.
//
#include<jni.h>
#include <string>extern "C" JNIEXPORT
jstring JNICALL
// 这里可不可以优化一下?
Java_com_xong_andcmake_jni_NativeFun_stringFromJNI(JNIEnv *env, jclass thiz)
{std::string hello = "Hello,I from C++";// 这里呢?return env->NewStringUTF(hello.c_str());
}
复制代码

对于我们来讲:

  1. 尽量不写重复代码
  2. 代码要高效

对于上面的函数名来讲,Java_com_xong_andcmake_jni_,假如我们在Java中对应的native类和方法,感觉在这个包中不合适,要换下包名,但是我这个类中有很多native方法,只要一换包,那么对应的cpp中的函数名就要挨个改,函数少还好办,假如有1000个,改起来真的是不要太爽,而且容易丢,那么有没有办法来尽量的减少工作量呢?类和包是相对固定的,那么我们能不能把包名抽取出来用一个表达式来表示呢?没错!就是宏定义啦!

对于下面返回的那一句,我为啥要这样写呢,因为用Android Studio创建一个带有cpp项目的时候,里面就是这样写的,然后就很自然的抄来了,但是我们想一下,有这样写的必要吗?可以看到的是在最后返回的时候,string对象又经过了一层转换点进去后可以发现,是将 string对象又转成了char数组(当然在C++中是char*指针还是const的,这里不需要知道const是啥,只需要知道,c_str()其实是又将string对象转成了char[]数组),然后我们这样写是不是就…多此一举,让计算机多做了一些事情呢?所以改完后的代码如下:

//
// Created by xong on 2018/9/28.
//
#include<jni.h>
#define XONGFUNC(name)Java_com_xong_andcmake_jni_##nameextern "C" JNIEXPORT
jstring JNICALL
XONGFUNC(NativeFun_stringFromJNI)(JNIEnv *env, jclass thiz)
{return env->NewStringUTF("Hello,I from C++");
}
复制代码

这样的话,假如NativeFun不在jni包下了,而是在jnia包下,那么我们只需要将上面的宏定义改下就好了;

因为我们没有对string做操作,那么我们就不需要它啦,直接返回就好了,这样计算机就不那么累了。


make project后,发生了什么?

接触过JNI的同学应该了解,项目里面添加了cpp代码,apk会变的很大,那么原因嘞,那么我就来捋一捋,cpp的代码再make project后都发生了什么,都很清楚会生成so,那么…在默认的情况下会生成几个?

打开 ../app/build/intermediates/cmake/debug/obj 目录如下:

在默认的情况下会生成4个,v7a的是最大的,x86_64是最小的,默认情况下,这4个是都会打到apk里面的(因为不清楚到底是往那台手机上安装呀,只能将所有的资源都打到apk里面了),要想缩小apk,那么就把需要的so打入apk就好了。然后,问题来了,怎么才能生成规定的so库呢?上代码,如下:

apply plugin: 'com.android.application'android {...defaultConfig {...externalNativeBuild {cmake {arguments '-DANDROID_STL=c++_static'}ndk {abiFilters "armeabi-v7a", "x86"}}...}...
}
...
复制代码

在../app/build.gradle中添加ndk标签,且在里面写上需要生成的架构名称就可以了,重新build下项目,如下图:

这样打入apk中的就只有v7a和x86两种架构的so库啦! 下篇我们来讲解一下 现有的cpp代码集成到项目中有几种方式,以及如何操作。

点击跳转到下一篇:如何将现有的cpp代码集成到项目中

Demo链接:UseCmakeBuildLib


END

转载于:https://juejin.im/post/5bb025db5188255c38537198

关于在Android中使用CMake你所需要了解的一切(一)相关推荐

  1. 关于在Android中使用CMake你所需要了解的一切(三)

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 本篇基于上篇构建好的a静态库和so动态库,若自己有a或so那么可以直接看本篇了,若没有那么建议先去看上篇----如何将现有的cpp代 ...

  2. 关于在Android中使用CMake你所需要了解的一切(二)

    虽然本篇和上篇没很大的关系,但-还是建议先去看下上篇----初次使用CMake构建native项目 初次使用CMake构建native项目 如何将现有的cpp代码集成到项目中 拷贝源码 编译成库文件 ...

  3. Android studio 使用Cmake完成C/C++ 的使用以及生成so文件

    今天,简单讲讲android中关于Cmake进行NDK编程的相关知识. Android studio 2.2版本以后对C/C++的支持可以说很方便了,当然官方推荐使用Cmake完成对C/C++的支持 ...

  4. Android NDK开发之旅(2):一篇文章搞定Android Studio中使用CMake进行NDK/JNI开发

    Android NDK开发之旅(2):一篇文章搞定android Studio中使用CMake进行NDK/JNI开发 (码字不易,转载请声明出处:http://blog.csdn.NET/andrex ...

  5. 【CMake】Android Studio 中使用 CMake 编译单个 C++ 源文件 ( 常用的 CMake 命令解析 )

    文章目录 一.Android Studio 中使用 CMake 编译单个 C++ 源文件 二.cmake_minimum_required 命令设置最小 CMake 版本 三.project 命令设置 ...

  6. android studio 使用CMAKE

    2019独角兽企业重金招聘Python工程师标准>>> 原文地址 前言 之前,每次需要边写C++代码的时候,我的内心都是拒绝的.  1. 它没有代码提示!!!这意味着我们必须自己手动 ...

  7. android中常用的快捷键

    2019独角兽企业重金招聘Python工程师标准>>> android中常用的快捷键 Eclipse快捷键-方便查找,呵呵,记性不好 行注释/销注释 Ctrl+/  块注释/销注释/ ...

  8. Java IO在Android中应用(三):Apk加固去壳

    Java I/O在Android中应用(三):Apk加固去壳 前言(废话) 现在在动车上,因为最近接到一个紧急的出差任务,需要去一趟江苏我们移动应用的客户现场.说真的,本来其实我是很困的,但是车上有一 ...

  9. 【Android NDK 开发】Android Studio 使用 CMake 导入动态库 ( 构建脚本路径配置 | 指定动态库查找路径 | 链接动态库 )

    文章目录 I . CMake 引入动态库与静态库区别 II . Android Studio 中 CMake 引入动态库流程 III . 指定动态库查找路径 IV . 链接函数库 V . 完整代码示例 ...

最新文章

  1. Oracle的一些经典SQL面试题
  2. BUUCTF的Web真题学习整理(一)
  3. kafka创建topic命令_0748-5.14.4-Kafka的扩容和缩容
  4. Apollo自动驾驶入门课程第②讲 — 高精地图
  5. C++primer第九章 顺序容器 9.4 vector对象是如何增长的
  6. linux进程调度之 FIFO 和 RR 调度策略
  7. 软件测试方法的分类细谈
  8. JVM参数调优详细过程
  9. 二阶振荡环节的谐振频率_晶振频率稳定性的两个重要因素
  10. MariaDB 10.3 解决掉了UPDATE不支持同一张表的子查询更新
  11. 运算符之前加加后加加的运算规则
  12. c语言常用基础代码大全,C语言基础入门必读
  13. 璞华PLM为全场景产品生命周期管理赋能,助力产品主线的企业数字化转型
  14. Ontology对接资源整理
  15. win10移动热点,手机无法连接或连接超时
  16. 深刻认识差模电压和共模电压
  17. Photoshop制作电影胶片效果
  18. 文字-汉字-生僻字:生僻字1
  19. 【前端】Axios完全使用指南
  20. 营业执照、组织机构代码、税务登记号规则

热门文章

  1. 8springboot-SpringBoot+MyBatisPlus
  2. 自动驾驶入门小记(第一篇)
  3. 35 岁佛系程序员,年后第一天被辞退 1
  4. 火狐倍速网盘视频方法(服务考研党)
  5. nsis查询mysql安装路径_NSIS目录
  6. “如何培养出优秀的IT驻场专家“
  7. 小学四年级上册中的计算机,小学四年级上册信息技术.doc
  8. RStudio的语法结构
  9. 四面蚂蚁金服成功拿下offer,分享一下我是怎么从年前的外包到现在的蚂蚁金服架构师的!
  10. 【每日随笔】利益分析法 ① ( 显性秩序和隐性秩序 | 利益分析法 | 买房行为的利益分析 | 利益博弈 | 借钱行为的利益博弈 )