V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yy1300326388
V2EX  ›  Flutter

Flutter 中如何优雅的实现多渠道打包(埋点统计系列)

  •  1
     
  •   yy1300326388 ·
    yy1300326388 · 2021-12-18 17:22:07 +08:00 · 1602 次点击
    这是一个创建于 1078 天前的主题,其中的信息可能已经有所发展或是发生改变。

    🔥🔥🔥 最新适配 Flutter 2.2 版本

    我是 Zero ,废话不多说,脑图先奉上

    • 先赞后看,更新永不断👏

    image.png

    只要你关注 Flutter ,这篇文章你绝对用得着,==> 强烈建议➕收藏

    多渠道打包介绍

    多渠道打包的主要作用是满足产品的运营需求,统计渠道和活动效果。
    在之前原生(Android 、iOS)开发 App 有各种工具来辅助我们完成多渠道打包。
    在我们开发过程中也需要为渠道功能负责,原生的开发工具就基本满足我们调试渠道包内容,但是在 Flutter 上需要更多的配置才可以完成,下文将一一介绍从配置=>调试=>打包的全部流程和细节。

    多渠道配置

    Flutter v1.17 开始,Flutter 命令工具增加了自定义参数的功能 --dart-define,我们可以用这个命令参数在打包或运行 App 时设置参数即可。

    首先确定 Flutter 版本,我的版本是 v1.22.6

    flutter run --dart-define=APP_CHANNEL=ZeroFlutter
    

    当然你可以传递多组参数

    flutter run --dart-define=APP_CHANNEL=ZeroFlutter --dart-define=OTHER_VAR=Dart
    

    在 Dart 代码中你需要这样写,一定是和命令参数是对应的

    // main.dart
    class EnvironmentConfig {
      static const APP_CHANNEL = String.fromEnvironment('APP_CHANNEL');
      static const OTHER_VAR = String.fromEnvironment('OTHER_VAR');
    }
    

    运行查看结果

    • 先修改 Flutter 项目对应的代码
    // my_home_page.dart
    Text(
      'App 渠道:${EnvironmentConfig.APP_CHANNEL}',
      style: Theme.of(context).textTheme.bodyText1,
    ),
    Text(
      '其他参数:${EnvironmentConfig.OTHER_VAR}',
      style: Theme.of(context).textTheme.bodyText1,
    ),
    
    • 然后运行项目
    flutter run --dart-define=APP_CHANNEL=ZeroFlutter --dart-define=OTHER_VAR=Dart
    
    • 查看结果

    image.png
    这里可以看到已经把对应的参数内容显示出来了,接下来就是具体业务层怎么来使用的问题了,下面内容也会介绍使用场景,继续往下看👇

    多渠道调试

    我们已经初步看到效果了,但是在开发过程中我们不可能一直在命令行运行看效果,如果可以配合 IDE 进行多渠道调试开发那就很棒了,下面分别介绍一下 VS CodeAndroid Studio 的配置方法。

    VS Code 配置

    • 先创建一个 launch.json 启动文件

    Kapture 2021-04-08 at 21.51.39.gif

    • 然后配置启动参数项目
    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "Flutter",
                "request": "launch",
                "type": "dart",
    	          // 这里是新加的命令参数
                "args": [
                    "--dart-define",
                    "APP_CHANNEL=Flutter",
                    "--dart-define",
                    "OTHER_VAR=Dart"
                ]
            },
    	      // 这里是配置多个渠道
            {
                "name": "Mi",
                "request": "launch",
                "type": "dart",
                "args": [
                    "--dart-define",
                    "APP_CHANNEL=Mi",
                    "--dart-define",
                    "OTHER_VAR=安卓之光"
                ]
            }
        ]
    }
    

    然后这里就出现了配置的渠道信息,我们分别切换 FlutterMi 运行看看效果
    image.png
    image.pngimage.png

    Android Studio 配置

    • 先配置上命令参数

    img_06.gif

    • 添加 Mi 渠道配置参数

    先复制一下 Flutter 配置,然后修改名字为 Mi,同时修改命令参数配置为 Mi安卓之光
    image.png
    到这里 Android Studio 的配置就基本完毕了,我们切换运行看看效果
    img_08.png
    img_04.pngimg_05.png
    到这里已经完成了 IDE 的配置, [详细的配置文件可以访问 GitHub 在项目内获取] ,讲了这么多怎么还不说打包📦的事情,别着急我需要给你配置一个精良的装备,后面我们的打包就是一个命令的事情。

    配置原生打包脚本

    🔥🔥🔥 最新适配 Flutter 2.2 版本

    Android

    • 更改 Gradle 配置

    通常 Android 的多渠道是给 AndroidManifest.xml 写一个 <meta-data/> ,如果要保持原来原生的统计方式不变,那么首先我们需要获渠道 命令参数(--dart-define=APP_CHANNEL=ZeroFlutter --dart-define=OTHER_VAR=Dart)的内容,则需要更改 Gradle 配置

    // android/app/build.gradle
    /// 获取渠道参数使用,这里设置一下默认值
    def dartEnvironmentVariables = [
        APP_CHANNEL: 'main',
        OTHER_VAR: 'other',
    ]
    
    if (project.hasProperty('dart-defines')) {
        dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
            .split(',')
            .collectEntries { entry ->
                // 1.22.6 版本
                //def pair = URLDecoder.decode(entry).split('=')
                // 2.2 版本
                def pair = new String(entry.decodeBase64(), 'UTF-8').split('=')
                [(pair.first()): pair.last()]
            }
    }
    
    • 如何使用(重命名 apk )
    // android/app/build.gradle
    android{
        // 重命名 apk
        applicationVariants.all { variant ->
            variant.outputs.all { output ->
                if(variant.buildType.name == "release"){
                    // 获取版本
                    def versionName = variant.versionName
                    def versionCode = variant.versionName
                 	// 设置新名称
                    def newApkName ="app_v${defaultConfig.versionName}_${defaultConfig.versionCode}_channel_${dartEnvironmentVariables.APP_CHANNEL}.apk"
                    outputFileName = new File(newApkName)
                }
            }
        }
    }
    
    • 执行打包
    flutter build apk --dart-define=APP_CHANNEL=ZeroFlutter --dart-define=OTHER_VAR=Dart
    // 打包后 apk 的输出路径
    ✓ Built build/app/outputs/flutter-apk/app-release.apk (15.4MB).
    // 打开打包后的 apk
    open build/app/outputs/apk/release/
    

    img_09.png
    这里看到已经将打包后的 APK 重命名为 app_v1.0.0_1_channel_ZeroFlutter.apk,方便我们区分发布到不同的应用商店。

    iOS

    这里 iOS 打包需要先执行 build 命令,然后再去 Xcode 上进行打包上传

    flutter build ios --dart-define=APP_CHANNEL=ZeroFlutter --dart-define=OTHER_VAR=Dart
    

    打包脚本优化

    此时如果我们再执行Mi 渠道打包命令,则会发现之前打包好的 app_v1.0.0_1_channel_ZeroFlutter.apk 不见了,因为被清理了,所以我们每打包好一个后将 apk 移动到一个渠道包文件夹中,然后继续执行下一个渠道的打包。

    flutter build apk --dart-define=APP_CHANNEL=Mi --dart-define=OTHER_VAR=安卓之光
    

    优化后的脚本如果下:

    • 渠道打包脚本
    # fapk_channel.sh
    flutter build apk --dart-define=APP_CHANNEL=$1 --dart-define=OTHER_VAR=$2
    cd build/app/outputs/apk/release/
    cp -R *.apk /Users/zero/apk/$1/
    cd /Users/zero/apk/$1/
    open .
    
    • 批量打包
    fapk_channel.sh ZeroFlutter Dart
    fapk_channel.sh Mi 安卓之光
    

    img_10.gif
    这样打包就可以全自动完成啦,启动脚本后,就可以去喝杯咖啡啦,喝完咖啡也打包好了。
    打包完毕后我们就可以分别对渠道包测试完毕后就上传到对应的应用商店啦

    使用场景

    数据统计

    在运营侧,需要统计出每个应用商店(渠道)的下载、安装、使用、日活、周活、月活、活动效果等情况,所以按照渠道区分是非常有必要的,如下图就是我们 App 日活渠道分布的情况。
    img_11.png
    在开发侧,我们需要区分每个渠道的异常情况,打包时对应的符号文件也是不同的,比如 Bugly 可以这样配置就完成不同渠道符号文件的配置。

    // android/app/build.gradle
    bugly {
        appId = 'ZeroFlutter'
        appKey = 'GitHub:https://github.com/yy1300326388'
        // 这里配置渠道参数即可
        appChannel = "${dartEnvironmentVariables.APP_CHANNEL}"
    }
    

    img_12.png再比如我们需要设置友盟渠道信息,可以直接通过 Dart 代码调用 Api 设置即可。

    /// 初始化友盟,直接将 EnvironmentConfig.APP_CHANNEL 传入渠道参数
    UmengSdk.initCommon(kUmengAndroidAppkey, kUmengIosAppkey, EnvironmentConfig.APP_CHANNEL);
    

    然后在后台就可以看到统计数据了,方便我们进一步运营和开发
    img_13.png

    渠道分发

    每个应用商店的要求各不相同,有的卡文案配置,有的卡版权信息,有的卡权限使用,针对不同的渠道可能要做不同的处理,我们可以增加一个判断来处理不同的逻辑,或者是用 mixin

    EnvironmentConfig.APP_CHANNEL == 'Mi'
    ? Text(
      "小米渠道显示",
      style: Theme.of(context).textTheme.bodyText1,
    )
    : SizedBox()
    

    这里我们分别运行 ZeroFlutterMi 渠道看看效果
    image.pngimg_01.png

    总结

    到这里本文就完毕了,我们主要聊了命令参数的使用配置,以及在开发过程当中渠道包的 IDE 配置和调试技巧,最后聊了一下渠道包的使用场景。
    本文是 《 Flutter 中的埋点统计-数据思维定胜负》专栏文章的第一篇,之后将持续分享以下 Flutter 的内容,可以持续✅关注,内容更新后会第一时间收到通知。

    Flutter 中的埋点统计文章规划目录

    • Flutter 多渠道打包详解
    • Flutter 全局路由监控
    • Flutter 全局异常捕获
    • Flutter 最新的全局无痕埋点

    源码仓库

    用到的脚本示例代码均在 GitHub 上了

    🔗 参考链接

    关于我

    • 15 年~ 18 年,使用 Android 原生做智能硬件相关的 App 研发
    • 18 年 5 月,一次偶然的机会接触到了 Flutter ,然后开始自学,可以看 weather_flutter 是我练习 Flutter 的入门实战项目(我现在依然觉得他非常适合 Flutter 入门练习使用)
    • 18 年 8 月,顶着巨大的压力( Flutter 当时还没有 Release 1.0 )开始使用 Flutter 开发企业级项目,并且开发维护了十几个 Flutter 插件包(因为当时插件资源非常的匮乏)
    • 截止目前主导并参与上线了 4 款企业级Flutter App ,当前正在负责的一款 App 累计用户 2 百万+,使用 Flutter 得到了极佳的体验

    👏 欢迎点赞➕关注➕转发,有任何问题随时在下面👇评论,我会第一时间回复哦

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2460 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 02:10 · PVG 10:10 · LAX 18:10 · JFK 21:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.