Flutter Multi-Channel Packaging Details (Buried Point Statistics Series)

I'm Zero, not to say a lot, Brain Map

Brain Map Combing

As long as you follow Flutter, this article is definitely useful==>Highly recommended ➕ Collection

Introduction to Multi-Channel Packaging

The main role of multi-channel packaging is to meet the operational needs of products, statistical channels and activity results.
Previously native (Android, iOS) development of App had a variety of tools to assist us in multi-channel packaging.
In our development process, we also need to be responsible for the channel function. Native development tools can basically satisfy our debugging channel package content, but more configuration is needed on Flutter to complete. Below is a description of the entire process and details from Configuration=>Debugging=>Packaging.

Multi-Channel Configuration

From Flutter v1.17 Beginning with the Flutter command tool, the ability to customize parameters was added, dart-define, which allows us to set parameters when packaging or running App.

First determine the Flutter version, my version is v1.22.6

flutter run --dart-define=APP_CHANNEL=ZeroFlutter

Of course you can pass multiple sets of parameters

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

You need to write this in Dart code, it must correspond to the command parameters

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

Run to view results

  • Modify the code for the Flutter project first
// my_home_page.dart
  'App Channels: ${EnvironmentConfig.APP_CHANNEL}',
  style: Theme.of(context).textTheme.bodyText1,
  'Other parameters: ${EnvironmentConfig.OTHER_VAR}',
  style: Theme.of(context).textTheme.bodyText1,
  • Then run the project
flutter run --dart-define=APP_CHANNEL=ZeroFlutter --dart-define=OTHER_VAR=Dart
  • View results

Here you can see that the parameters have been displayed, and the next step is how to use the specific business layer. The following also describes the usage scenario, and continue to look down 👇

Multi-channel Debugging

We've already seen the results, but it's impossible to run them all the time on the command line during the development process. It would be great if you could do multi-channel debugging with the IDE. Here's how to configure VS Code and Android Studio, respectively.

VS Code Configuration

  • Create a launch first. JSON startup file

  • Then configure the startup parameter item
    "version": "0.2.0",
    "configurations": [
            "name": "Flutter",
            "request": "launch",
            "type": "dart",
	          // This is the newly added command parameter
            "args": [
	      // Here is to configure multiple channels
            "name": "Mi",
            "request": "launch",
            "type": "dart",
            "args": [
                "OTHER_VAR=Android Light"

Then there's the channel information for configuration, so let's switch between Flutter and Mi to see what happens.

Android Studio Configuration

  • Configure command parameters first

  • Add Mi Channel Configuration Parameters

Copy the Flutter configuration first, then change the name to Mi, and modify the command parameters to configure Mi and Android Light

Now that Android Studio is almost configured, let's switch runs to see what happens

Now that the IDE has been configured, [detailed configuration files can be accessed from GitHub within the project], there's so much to say about packaging 📦 Don't worry, I need to configure a sophisticated equipment for you, after which our packaging is a command thing.

Configure Native Packaging Scripts


  • Change Gradle Configuration

Usually Android's multi-channel is for Android Manifest. XML writes a <meta-data/>, if you want to keep the original statistics unchanged, then first we need to get the contents of the channel command parameters (--dart-define=APP_CHANNEL=ZeroFlutter --dart-define=OTHER_VAR=Dart), then we need to change the Gradle configuration

// android/app/build.gradle
///Get channel parameter usage, set default here
def dartEnvironmentVariables = [
    APP_CHANNEL: 'main',
    OTHER_VAR: 'other',

if (project.hasProperty('dart-defines')) {
    dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
        .collectEntries { entry ->
            def pair = URLDecoder.decode(entry).split('=')
            [(pair.first()): pair.last()]
  • How to use (rename apk)
// android/app/build.gradle
    // Rename apk
    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            if(variant.buildType.name == "release"){
                // Get Version
                def versionName = variant.versionName
                def versionCode = variant.versionName
             	// Set a new name
                def newApkName ="app_v${defaultConfig.versionName}_${defaultConfig.versionCode}_channel_${dartEnvironmentVariables.APP_CHANNEL}.apk"
                outputFileName = new File(newApkName)
  • Execute Packaging
flutter build apk --dart-define=APP_CHANNEL=ZeroFlutter --dart-define=OTHER_VAR=Dart
// Output path of packaged apk
✓ Built build/app/outputs/flutter-apk/app-release.apk (15.4MB).
// Open packaged apk
open build/app/outputs/apk/release/

Here you can see that the packaged APK has been renamed app_v1.0.0_1_channel_ZeroFlutter.apk, which allows us to distinguish between different app stores.

Packaging script optimization

If we execute the Mi Channel Packaging command again, we will find the previously packaged app_ V1. 0.0_ 1_ Channel_ ZeroFlutter. The apk disappeared because it was cleaned up, so we moved the apk into one channel package folder after each package, and then proceeded with the next channel package.

flutter build apk --dart-define=APP_CHANNEL=Mi --dart-define=OTHER_VAR=Android Light

Optimized script if:

  • Channel Packaging Script
# 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 .
  • Batch Packaging
fapk_channel.sh ZeroFlutter Dart
fapk_channel.sh Mi Android Light

This will allow the packaging to be fully automated. After you start the script, you can go and have a cup of coffee and pack the coffee.
Once packaged, we can test each channel package and upload it to the corresponding app store.

Use scenarios

data statistics

On the operational side, we need to figure out the download, installation, use, daily, weekly, monthly and activity effects of each app store (channel), so it is very necessary to distinguish them according to the channel. The following figure is the distribution of our App daily channel.

On the development side, we need to distinguish the exception of each channel, and the corresponding symbol files are different when packaging. Bugly can do this to complete the configuration of different channel symbol files.

// android/app/build.gradle
bugly {
    appId = 'ZeroFlutter'
    appKey = 'GitHub:https://github.com/yy1300326388'
    // Configure channel parameters here
    appChannel = "${dartEnvironmentVariables.APP_CHANNEL}"

For example, if we need to set up the channel information for the alliance, we can call the Api settings directly from the Dart code.

///Initialize the federation, direct EnvironmentConfig.APP_CHANNEL Inbound Channel Parameters
UmengSdk.initCommon(kUmengAndroidAppkey, kUmengIosAppkey, EnvironmentConfig.APP_CHANNEL);

Then you can see the statistics in the background to facilitate our further operation and development

Channel Distribution

Each app store has different requirements, some are card copy configuration, some are card copyright information, some are card rights use, different processing may be done for different channels, we can add a judgment to handle different logic, or use mixin

EnvironmentConfig.APP_CHANNEL == 'Mi'
? Text(
  "Millet Channel Display",
  style: Theme.of(context).textTheme.bodyText1,
: SizedBox()

Here we run ZeroFlutter and Mi channels to see the effect


This is the end of this article. We mainly talk about the configuration of command parameters, IDE configuration and debugging techniques of channel packages during the development process. Finally, we talk about the use of channel packages scenarios.
This is the first in a series of articles titled Buried Point Statistics in Flutter - Data Mind Wins and Loses. After that, I will continue to share the following to keep an eye on me and let you know when I update it.

Buried Statistical Articles Planning Directory in Flutter

  • Flutter Multi-Channel Packaging Details
  • Flutter Global Routing Monitoring
  • Flutter Global Exception Capture
  • Flutter's latest global traceless buried point

Source warehouse

The scripts and sample code used are all on GitHub

Reference Links

About me

  • 15-18 years of smart hardware-related App development using Android native
  • In May 188, I came across Flutter by chance and started to learn by myself. weather_flutter It's my entry-level practice project for Flutter (I still think he's a great fit for Flutter entry exercises right now)
  • In August 188, tremendous pressure (Flutter did not have Release 1.0 at that time) began to use Flutter to develop enterprise projects and to develop and maintain more than a dozen Flutter plug-in packages (because plug-in resources were scarce at that time)
  • Up to now, four enterprise Flutter App s have been leading and participating online, and one App currently in charge has a cumulative user base of 120W+, which gives you a great experience using Flutter

👏 Welcome ➕ follow ➕ Forward, any questions are always below 👇 Message, I will reply first time Oh

Keywords: iOS Android Android Studio Flutter app

Added by 121212 on Mon, 07 Mar 2022 19:13:19 +0200