美文网首页
flutter build aar 及一键打包aar并上传Mav

flutter build aar 及一键打包aar并上传Mav

作者: 小天使999999 | 来源:发表于2024-01-19 22:24 被阅读0次

    引子

    盼望着,盼望着,华为鸿蒙升级了。�Harmoney OS Next 不再支持 Android 系统了,整个移动端瞬间炸了锅。
    作为一个曾经手机市场王者,任何一家公司都无法忽视华为的市场,Android 阵营瞬间就出现了学习鸿蒙系统的激进力量。
    同时,怕步子超大了,Harmoney OS Next 还是支持 flutter 跨端技术的。鉴于我一直时做跨端开发的,无论是 React Native、小程序,还是阿里系的 mist、weex 都多少有所涉猎,也就直接把三年前的 flutter 代码拉出来遛遛了:https://github.com/hongyi0609/MeiTuanEdwin
    与此同时,也顺手建立另一个 my_fluter 库,把MeiTuanEdwin项目中 my_flutter 模块单独抽出来了:
    https://github.com/hongyi0609/my_flutter
    弄得有其他人合作开发似的~

    背景

    大家对郭霖大佬都不陌生吧?!
    前一段我刷他的文章,发现他在研究 flutter,然后还分享了一篇读者投稿。以此得知,微软未来会有很多的 flutter 的业务,并且大部分处于起步阶段。所以郭老师就开始之前很少关注的 flutter 研究生涯。
    这不是众里寻她千百度,蓦然回首,那人却在微信公众号吗?
    我也就立马着手继续自己的 flutter 研究之路了。如果你对 flutter 一知半解,那我劝你先去读读这篇文章:https://juejin.cn/post/7306579782853754932
    跟你想的基本一致,我就是读这篇文章的时候发现,搭建环境根本不是那么回事儿。

    八卦:大厂是怎么玩儿的?

    很多有电商味道的大厂,都是精细化操作,整个App 采用组件化开发,每个组件都是一个单独的小组 客户端+前端,其中客户端由 Android+iOS+跨端(外包)+小程序+h5组成,前端由小程序+h5+web 组成,这样整个大前端团队就形成了。
    现在开始卷,客户端团队的架构组经过无数次的迭代重构,终于在 325 下来之前,憋出了 taro 、uniapp或者 morjs。由于实现了多端一体化,开发一次代码的成果可以在 Android、iOS、小程序、Web 端等所有平台运行,那么写跨端(外包)的同学就愉快的下岗了。同时,原来的小程序开发时微信、抖音、支付宝,每个平台一个主要负责同学,现在另外两个同学只要不去劳动局都好商量。
    你可能会问,剩余的技术空缺谁来补上。听好啊:
    下一年的 KPI主要是两个方向,
    1. 客户端同学除了会用 Android、iOS 开发,也要具备跨端开发的能力,并且要互为 backup
    2. 前端同学除了自己负责B 端开发业务,也要能够胜任微信小程序各平台的开发工作
    基于第一点,我愉快的玩起了 flutter 。

    进入Flutter篇

    工欲善其事,必先利其器。按照Flutter 开发过程主要是依赖 aar包开发,和依赖源码开发,官方链接:https://docs.flutter.dev/add-to-app/android/project-setup?tab=with-android-studio
    通过照猫画虎的骚操作后,发现根本没有卵用,官方给的文档毕竟玩不转。那么问题来了,你通常时怎么使用 aar 包的?

    打包

    官方打包
    flutter build aar
    
    你想要的打包命令
    flutter clean & flutter build aar --build-number 1.1.1 --no-profile --no-release
    

    profile解释:在 Android 开发中,"profile" 版本通常指的是应用的性能分析版本。这种版本允许开发者在设备上运行应用程序以进行性能分析和调试。这种版本通常会包含更多的日志记录和性能分析工具,用于分析应用在不同设备上的性能表现,并检测可能存在的性能问题。
    Flutter 构建过程中的 --no-profile 标志会指示系统不生成这种性能分析版本。这样做是为了加快构建过程并减小生成的输出文件大小。
    通过以上命令,你会在“/your_flutter/build/host/outputs/repo”目录下拿到 aar包,如下:

    flutter_debug.aar
    那么,aar包怎么用呢?

    aar 包导入推荐策略

    策略一:官方推荐导入

    官方 aar 导入
    配置完成你会发现,flutter 引擎的依赖依赖项一个也拿不到,就是下面这个几个货:
    flutter 引擎依赖项
    你肯定觉得卧槽了:
    是的,兵法上没写,但是打仗的时候要用。马谡就是这么丢街亭的~
    那《兵法》上咋说的呢?
    兵法上说,你按照我说的运行完 flutter build aar 命令,配置你的 project 依赖绝对没问题。看看这句无耻的话:
    兵法云
    说无耻,其实有些过分了。毕竟人家写兵法的人言简意深来着~
    First of all,这兵法主要是给资本主义市场使用的
    Secondly,为了迎合中国市场,也告诉你要配置中国镜像

    中国市场
    问题就在这里,切换镜像之后,flutter 模块的打包aar的依赖没有被上传到指定的服务端。
    墙外:
    执行flutter build aar 后,在'/Users/edwin/edwin/MeiTuanEdwin/my_flutter/build/host/outputs/repo文件夹下面会生成aar包和pom文件,后者标示了flutter引擎依赖项,如下:
    repo目录信息
    flutter_debug-1.1.4.pom文件里存放的是依赖项信息,如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <!-- This module was also published with a richer model, Gradle metadata,  -->
      <!-- which should be used instead. Do not delete the following line which  -->
      <!-- is to indicate to Gradle or any Gradle module metadata file consumer  -->
      <!-- that they should prefer consuming it instead. -->
      <!-- do_not_remove: published-with-gradle-metadata -->
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.example.my_flutter</groupId>
      <artifactId>flutter_debug</artifactId>
      <version>1.1.4</version>
      <packaging>aar</packaging>
      <dependencies>
        <dependency>
          <groupId>io.flutter</groupId>
          <artifactId>flutter_embedding_debug</artifactId>
          <version>1.0.0-9064459a8b0dcd32877107f6002cc429a71659d1</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>io.flutter</groupId>
          <artifactId>armeabi_v7a_debug</artifactId>
          <version>1.0.0-9064459a8b0dcd32877107f6002cc429a71659d1</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>io.flutter</groupId>
          <artifactId>arm64_v8a_debug</artifactId>
          <version>1.0.0-9064459a8b0dcd32877107f6002cc429a71659d1</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>io.flutter</groupId>
          <artifactId>x86_64_debug</artifactId>
          <version>1.0.0-9064459a8b0dcd32877107f6002cc429a71659d1</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>io.flutter</groupId>
          <artifactId>x86_debug</artifactId>
          <version>1.0.0-9064459a8b0dcd32877107f6002cc429a71659d1</version>
          <scope>compile</scope>
        </dependency>
      </dependencies>
    </project>
    

    这些都是Gradle发布的Meta data,最终被发布到storage.googleapis.com 这个服务端,下面的链接试试
    https://storage.googleapis.com/download.flutter.io
    上面提到flutter库在编译是就已经做了架构适配和引擎依赖构建,原则上这些元数据都应该被发布到服务端,这样才能通过dependencies配置依赖获取相应的aar包,事实上根本没有我们想要下载的依赖包,搜索唯一标记 9064459a8b0dcd32877107f6002cc429a71659d1(以编译生成POM里的version为准) 无法得到想要的依赖。

    storage.googleapis.com/download.flutter.io
    墙内
    配置如下,flutter相关配置如下:
    镜像配置
    根据官方指导,domain切换后,源文件会发布到 https://storage.flutter-io.cn/download.flutter.io 点击进入这个站点,同样找不到对应的POM文件中生成的依赖信息
    storage.flutter-io.cn/download.flutter.io
    这就造成了我们在使用aar包时,需要逐个引入POM文件中的依赖项,进行引擎依赖配置:
        implementation 'io.flutter:flutter_embedding_debug:1.0.0-9064459a8b0dcd32877107f6002cc429a71659d1'
        implementation 'io.flutter:armeabi_v7a_debug:1.0.0-9064459a8b0dcd32877107f6002cc429a71659d1'
        implementation 'io.flutter:arm64_v8a_debug:1.0.0-9064459a8b0dcd32877107f6002cc429a71659d1'
        implementation 'io.flutter:x86_64_debug:1.0.0-9064459a8b0dcd32877107f6002cc429a71659d1'
        implementation 'io.flutter:x86_debug:1.0.0-9064459a8b0dcd32877107f6002cc429a71659d1'
    

    我自然是不愿意搞这么多配置的,关于aar包源数据发布上传这部分,我耗了很久反复阅读官方文档,并且在网上查询相关资料,得到如下提示:
    1)Stack Overflow
    给出的策略,是直接更改flutter SDK包里的 aar_init_script.gradle文件,很多大厂也是这么干的
    https://stackoverflow.com/questions/75577692/any-way-to-upload-flutter-local-aar-maven-repository-to-remote-maven-repository
    2)华为开发者联盟
    分析的很透彻,最后希望你通过脚本实现,一言以蔽之:通过执行 flutter build aar -v 查看flutter build aar 的执行秘密。
    https://blog.csdn.net/Ever69/article/details/120494115
    我还真就这么干了,好奇心害死猫。咳~~~
    3)官方指导文档真坑爹
    在我们运行flutter build aar时,其实他是借助于.android项目配置Gradle或者Gradle Wrapper能力,其核心工作在
    flutter-SDK-Dir/flutter/packages/flutter_tools/gradle/aar_init_script.gradle文件中完成aar发布工作,具体逻辑如下:

    publishing aar
    aar 文档相关Gradle 源数据都在本地repo库里,所以通过Maven依赖是断断无法获取的。

    综上所述,官方文档给出的关于aar的配置,是指导开发人员使用发布到本地的aar文件的方法,而且还缺少引擎依赖的相关指导
    为了能够简化使用flutter模块 aar包的引入流程,我们需要有自己的Maven私服,并且将flutter项目的aar包及相关源文件,发布到云端进行更新和迭代。这里选择阿里云效,完成这个任务

    发布AAR包到Maven私服

    云端选择阿里云效 ,打开阿里云的云效Packages官网:
    https://packages.aliyun.com/maven
    你会发现阿里云提供的免费私有Maven库服务,并且介绍了Gradle 7.0前后如何发布项目文档至私有仓库。
    1)更改aar_init_script.gradle文件

    image.png
    这个侵入性比较强,而且每个人都要更改自己的SDK包。哪天编译脚本升级了,大家一起抓瞎~
    2)在flutter项目中直接发布
    As we all know,aar包之所以能够通过Gradle编译成功,是依赖其my_flutter/.android项目,该项目中的有一个Flutter库Module,是执行flutter build aar时自动生成的。通过flutter build aar -v 可以很清晰的看到,编译过程中,flutter 相关产物都放到了.android/Flutter模块的build文件夹下,看编译日志:
    Starting process 'command '/Users/edwin/Library/flutter/bin/flutter''. 
    Working directory: /Users/edwin/edwin/MeiTuanEdwin/my_flutter 
    Command: /Users/edwin/Library/flutter/bin/flutter  #Flutter 工具的路径
     --verbose #启用详细输出,以便查看更多构建信息
     assemble #执行组装操作,即构建过程
     --no-version-check #禁用版本检查,Flutter 不会检查是否有新版本
     --depfile /Users/edwin/edwin/MeiTuanEdwin/my_flutter/.android/Flutter/build/intermediates/flutter/debug/flutter_build.d #指定依赖文件的路径
     --output /Users/edwin/edwin/MeiTuanEdwin/my_flutter/.android/Flutter/build/intermediates/flutter/debug #指定输出目录的路径
     -dTargetFile=lib/main.dart #指定入口文件的路径
     -dTargetPlatform=android #指定目标平台为 Android
     -dBuildMode=debug #指定构建模式为调试模式
     -dTrackWidgetCreation=true #启用 Flutter 的控件创建跟踪
     debug_android_application
    

    看明白了吧,该命令的目标是构建一个用于调试的 Android 版本的 Flutter 应用程序,output命令指定了输出目录。
    我们看看output文件夹所在的环境:


    aar包中间产物

    这说明我们的 Flutter 模块就是用来生成 aar 包的对应资源而建立的,那我们完全可以在 Flutter 项目的 build.gradle 文件中添加一个 task 用于发布 aar 包,发布任务通过publish.gradle文件完成。实现如下:

    // publish flutter-debug.aar
    //plugins {
    //    id 'java'
    //    // Gradle 7.0+ 版本
    //    id 'maven-publish'
    //}
    
    group 'com.example.my_flutter'
    version '1.1.4'
    def artifactIdStr = 'flutter_debug'
    
    apply plugin: 'maven-publish'
    task comps { // 让我们看看它有哪些组件:
        afterEvaluate {
            println("Components: " + components*.name)  // 代码 1
        }
    }
    def directoryToPublish = "$rootDir.parentFile/build/host/outputs/repo/com/example/my_flutter/flutter_debug/$project.version"
    afterEvaluate { // 代码 2
        publishing {
            publications {
                flutter(MavenPublication) { // 代码 3
                    from components.debug
                    println("groupId = " + groupId + ",artifactId = " + artifactIdStr + ",version = " + version + ",buildDir = " + buildDir)
                    groupId = "$project.group" // 代码 4
                    artifactId = artifactIdStr
                    version = "$project.version"
    
    //                artifact "$buildDir/outputs/aar/flutter-debug.aar" //aar artifact you want to publish
                    // artifact "$directoryToPublish/${artifactIdStr}-${project.version}.aar"
                    // artifact "$directoryToPublish/${artifactIdStr}-${project.version}.module"
                    // artifact "$directoryToPublish/${artifactIdStr}-${project.version}.pom"
    
    //                artifact("$directoryToPublish/${artifactIdStr}-${project.version}.aar") /*{
    //                    classifier 'aar' // 使用 'aar' 作为分类器
    //                }*/
    //                artifact("$directoryToPublish/${artifactIdStr}-${project.version}.module") /*{
    //                    classifier 'module' // 使用 'module' 作为分类器
    //                }*/
    //                artifact("$directoryToPublish/${artifactIdStr}-${project.version}.pom")/* {
    //                    classifier 'pom' // 使用 'pom' 作为分类器
    //                    extension 'pom' // 设置为 'pom' 类型
    //                }*/
                }
            }
            repositories { // 代码 5
    //            maven {
    //                url = 'https://packages.aliyun.com/maven/repository/2443959-release-V0Shv7/'
    //                credentials {
    //                    username = '##############'
    //                    password = '*****************'
    //                }
    //            }
                maven {
                    url = 'https://packages.aliyun.com/maven/repository/2443959-snapshot-5T0GnA/'
                    credentials {
                        username = '###############'
                        password = '******************'
                    }
                }
            }
        }
    }
    

    其中, 代码 1 处的 components*.name 用于确认当前Gradle 会构建那些组件用于发布,输出结果如下:

    Components
    从打印结果来看,可以构建 debug、profile、release 三种组件及其all 组合组件,我们使用 debug 版本
    代码 2 处,评估之后开始进入发布工作,依赖 maven-publish 插件进行发布,gradle 要配置成 7.2 以上的版本
    代码 3 处,定义了一个 MavenPublication,命名为 "flutter"。from components.debug 表示将 MavenPublication 的内容从 Gradle 构建中的 components.debug 组件中获取。这里的MavenPublication包含了该组件的输出,例如 AAR 文件、POM 文件等。这是为了将 Flutter 模块构建的输出发布到 Maven 仓库
    代码 4处配置了 GVA 用于唯一标识当前AAR 包,方便其他项目通过 Maven 或gradle 进行依赖,如下:
    GVA
    当然,现在依赖还是无法完成,因为aar 包要发布到远程 Maven,
    代码 5 处就是用于配置远程服务地址的,我们选用的是阿里云效服务,用起来也算是麻烦+坑爹。
    阿里云效:https://packages.aliyun.com/maven
    如果玩不来,这里还有篇文章可以参考一如何把 library 发布到阿里云效
    https://shawlaw.github.io/Fragmentary/publish-aar-to-aliyun-private-maven/publish-aar.html
    发布任务编码完成~
    然后在 Flutter 模块的 build.gradle 中 apply publish.gradle代码如下:
    def currentTask = gradle.startParameter.taskNames.join(" ")
    println("currentTask =" + currentTask)
    if (!currentTask.contains("Aar")) {
        apply from: "../../publish.gradle"
    }
    

    这段代码的意思就是说,在 Flutter 项目编译过程中,准确的说是评估的时候,把发布任务引入,等compile完成后执行发布任务。
    最后,
    咱们再执行一遍 flutter build aar 指令,发现.android/Flutter/build/目录下没有生成 flutter 发布文件夹,
    逗我呢?!
    老铁,这里还得执行一遍 ./gradlew publish 命令,执行发布任务,现在可以愉快的看到如下效果了:


    阿里云效snapshot 库

    那么,现在赶快在另一个项目里试一下配置依赖吧。
    首先在需要使用 aar包的项目根目录下 root.gradle 中配置 Maven 库,参考如下:


    Maven 库地址
    其次在需要使用 aar包的 module 中,配置 AVG 依赖如下:
    dependencies
    现在同步代码,等待依赖完成。flutter 引擎的五个依赖如期而至:
    Flutter 引擎依赖包

    Shell脚本一键打包发布

    等等老哥~
    道理我都听明白了,上面的代码还是要手动更改 Flutter 项目中的 build.gradle 文件啊。更要命的是,如果执行 flutter clean 清理一遍编译工程,刚刚的文档不都白瞎了了么。你这是让我哭吗?我说老兄你等等,这不是上脚本呢嘛~

    1. 首先,我们把发布文件 publish.gradle 移动到 my_flutter 项目根目录下,并在根目录下创建一个shell 脚本文件 apply_patch.sh,如下:


      root 目录
    2. 然后,将 publish.gradle 导入到 Flutter 项目中的诉求未变,通过 shell 脚本实现如下:
    # 获取当前脚本所在目录的绝对路径
    SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
    
    # 切换到Flutter项目的根目录
    cd "$SCRIPT_DIR/.android/Flutter" || exit
    # 在Flutter/build.gradle文件中执行命令:
    # 1)在android配置项前插入 apply 发布应用
    # 2)-i '.bak',备份原始文件
    sed -i '.bak' '/^android {/i\
    def currentTask = gradle.startParameter.taskNames.join(" ") \
    println("currentTask =" + currentTask)\
    if (!currentTask.contains("Aar")) {\
        apply from: "../../publish.gradle"\
    }' "$SCRIPT_DIR/.android/Flutter/build.gradle"
    

    通过脚本的形式,将发布任务添加到 .android/Flutter 项目中,脚本的含义都写在了注释里。

    1. 插入完成后,还要进行发布工作,仍然通过脚本完成,如下:
    # 切换到 ./android 目录下执行发布任务
    cd "$SCRIPT_DIR/.android" || exit
    ./gradlew publish --info > publish.log 2>&1
    if [ $? -ne 0 ]; then
        echo "发布任务失败!查看 publish.log 获取更多信息。"
        exit 1
    fi
    

    这里把发布日志都打印在了 publish.log 文档里,如果发布失败./gradlew publish --info 会提供详细的失败信息。

    1. 版本控制,aar 包是有自己的版本号的,比如 1.1.4。为了统一控制 version号,不要手动更改gradle 文件,我们引入如下脚本:
    # 替换 publish.gradle 中的版本号
    OLD_VERSION=$(grep -o "version '[0-9]\+\.[0-9]\+\.[0-9]\+'" "$SCRIPT_DIR/publish.gradle" | head -n 1)
    if [ -z "$OLD_VERSION" ]; then
      echo "无法获取旧版本号!"
      exit 1
    fi
    
    sed -i'.bak' "s/$OLD_VERSION/version '$BUILD_NUMBER'/" "$SCRIPT_DIR/publish.gradle" || { echo "版本号替换失败!"; exit 1; }
    
    1. 合并所有脚本,得到完整的发布脚本apply_patch.sh,脚本如下
    作为一个广告引流专业户,还是详见 github 代码库吧~
    
    1. 执行 ./apply_patch.sh 脚本

    到这里整个一键打包发布工作就完成了

    FAQ

    1.local.properties 类似文件属性配置时,不要加引号,不然在 gradle 文件中获取到的值要处理


    image.png
    1. gradle 的版本要配置成 7.5,太高版本不见得稳定,而且低版本调用他的时候存在融合问题:


      image.png
    2. gradle 和 ./gradlew 是两码事,前者是你在全局变量配置的 gradle 版本,后者是gradle wrapper 中配置的 gradle 版本7.5
    3. 脚本可能会有一些warning 提示,没有跑通不要随意更改脚本,不然永远跑不起来了


      image.png

    参考文献

    1. my_flutter库地址 https://github.com/hongyi0609/my_flutter
    2. GitHub库地址 https://github.com/hongyi0609/MeiTuanEdwin
    3. flutter 国内镜像 https://flutter.cn/community/china?tab=macos
    4. aar 服务端 https://storage.googleapis.com/download.flutter.io
    5. 华为开发者联盟分析 https://blog.csdn.net/Ever69/article/details/120494115
    6. 私服配置 https://stackoverflow.com/questions/75577692/any-way-to-upload-flutter-local-aar-maven-repository-to-remote-maven-repository
    7. 阿里云效:https://packages.aliyun.com/maven

    相关文章

      网友评论

          本文标题:flutter build aar 及一键打包aar并上传Mav

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