Flutter 多渠道打包實(shí)踐

背景

??在原生開(kāi)發(fā)中經(jīng)常要根據(jù)不同的渠道打不同的包,主要有以下場(chǎng)景:

  • 開(kāi)發(fā)環(huán)境、測(cè)試環(huán)境、生產(chǎn)環(huán)境等

??不同的環(huán)境對(duì)應(yīng)的要求也不一樣,這樣就要求根據(jù)需求打出不同的包以便于開(kāi)發(fā)、測(cè)試方便的使用。

  • 各個(gè)應(yīng)用市場(chǎng)等

??由于國(guó)內(nèi)存在著有眾多的應(yīng)用市場(chǎng),在不同的應(yīng)用市場(chǎng)可能有不同的統(tǒng)計(jì)需求,為此開(kāi)發(fā)人員需要為每個(gè)應(yīng)用市場(chǎng)發(fā)布一個(gè)安裝包,在安裝包中添加不同的標(biāo)識(shí),以此區(qū)分各個(gè)渠道,方便統(tǒng)計(jì)app在應(yīng)用市場(chǎng)的各種效果。

??因此,每當(dāng)發(fā)新版本時(shí),運(yùn)營(yíng)會(huì)提供一個(gè)渠道列表,開(kāi)發(fā)同學(xué)會(huì)根據(jù)這些渠道相應(yīng)地生成等量的渠道包。隨著渠道越來(lái)越多,為了提高渠道打包的效率,因此催生了對(duì)多渠道打包的方式的研究。

??同樣在 Flutter的項(xiàng)目開(kāi)發(fā)中也涉及到這個(gè)問(wèn)題,在這里主要講怎么配置開(kāi)發(fā)包與生產(chǎn)包,并快速打出并運(yùn)行相應(yīng)的渠道包。

??在這里我將分別從Android 端、IOS 端、Flutter 端進(jìn)行講解配置。

Android 配置

對(duì)于android,我們只要在app gradle模塊中配置productFlavors即可,這里我們?cè)赽uild.gradle 中 android 下面定義了dev、production兩種flavors。

[...]

android {
   
    [...]

    flavorDimensions "app"

    productFlavors {
        dev {//development
            dimension "app"
            resValue "string", "app_name", "多渠道打包${defaultConfig.versionCode}"   // 設(shè)置默認(rèn)的app_name
            applicationId "${defaultConfig.applicationId}.dev"
            manifestPlaceholders = [
                    QQ_APP_ID: "xxx",
                    CHANNEL_NAME: "dev",
                    LOCATION_APP_KEY : "xxx", /// 高德地圖key
            ]
        }
        production{
            dimension "app"
        }
    }

}

[...]

配置非常簡(jiǎn)單,這里可以設(shè)置不同的應(yīng)用程序applicationId后綴,
同樣也可以設(shè)置不同flavors 的app_name,CHANNEL_NAME。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xx.xx">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:usesCleartextTraffic="true"
        android:name="io.flutter.app.FlutterApplication"
        android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- This keeps the window background of the activity showing
                 until Flutter renders its first frame. It can be removed if
                 there is no splash screen (such as the default splash screen
                 defined in @style/LaunchTheme). -->
            <meta-data
                android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
                android:value="true" />

            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <!--        多渠道打包           -->
        <meta-data
            android:name="UMENG_CHANNEL"
            android:value="${CHANNEL_NAME}" />
    </application>
</manifest>

IOS 配置

對(duì)于 ios,我們只需要在ios / Flutter文件夾中為每一個(gè)flavor創(chuàng)建相應(yīng)的配置文件,就像Flutter中默認(rèn)預(yù)定義Debug.xcconfig和Release.xcconfig一樣,因?yàn)閜roduction正式包不用變包名與應(yīng)用名,所以這里就只創(chuàng)建 dev_debug.xcconfig、dev_release.xcconfig兩個(gè)文件,

image

并在dev flavor對(duì)應(yīng)的xcconfig中配置bundle_suffix,name_suffix。

#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
bundle_suffix=.dev
name_suffix=${FLUTTER_BUILD_NUMBER}

并在Info.plist文件添加您定義的變量

image

然后針對(duì)每個(gè) flavor 創(chuàng)建對(duì)應(yīng)的scheme

image

記得在對(duì)話框中勾選上 shared

image

現(xiàn)在選擇Runner項(xiàng)目并添加您需要選擇的配置作為之前創(chuàng)建的配置文件作為配置文件。

image

注意,對(duì)于每個(gè)以Release- [flavorName]和Debug- [flavorName]命名的falvor都有兩個(gè)配置。這里注意名字不要重復(fù)。

為了使在打包、發(fā)布時(shí)iOS應(yīng)用使用正確的配置,這里需要編輯scheme,將構(gòu)建配置設(shè)置為所需的配置:

image

Flutter 配置

將main.dart重命名為main_common.dart,把公共配置、運(yùn)行部分定義在這里,然后創(chuàng)建 main_dev.dart和main_production.dart文件,引入main_common,根據(jù)需要在main_dev.dart和main_production.dart文件設(shè)置不同的配置參數(shù)。

可在 main_dev.dart 中設(shè)置網(wǎng)絡(luò)代理、以及第三方庫(kù)等的測(cè)試key。

import 'dart:io';

import 'package:dio/adapter.dart';
import 'package:flutter_common_utils/http/http_manager.dart';

import 'main_common.dart';

/// @desc 開(kāi)發(fā)、測(cè)試環(huán)境入口
/// @time 2019-07-17 15:08
/// @author Cheney
Future<Null> main() async {
  await initConfig();

  //debug 抓包
  (HttpManager().client.httpClientAdapter as DefaultHttpClientAdapter)
      .onHttpClientCreate = (client) {
    client.findProxy = (uri) {
      return "PROXY http://10.1.10.111:8080";
    };
    client.badCertificateCallback =
        (X509Certificate cert, String host, int port) {
      return true;
    };
  };

  ///第三方庫(kù) 測(cè)試 key
}

在main_production.dar配置正式的第三方庫(kù) key等。

import 'main_common.dart';

/// @desc 正式環(huán)境入口
/// @time 2019-07-17 15:08
/// @author Cheney
Future<Null> main() async {
  await initConfig();

  ///第三方庫(kù) 正式 key todo

  initMaterialApp();
}

在main_common 中初始公共配置:

import 'dart:async';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_common_utils/http/http_manager.dart';
import 'package:flutter_common_utils/log_util.dart';
import 'package:flutter_common_utils/sp_util.dart';
import 'package:oktoast/oktoast.dart';

import 'main.dart';

/// @desc 入口公共部分
/// @time 2019-07-17 15:08
/// @author Cheney
Future<Null> initConfig() async {
  await SpUtil().init();

  //日志輸出
  LogUtil.init(isDebug: true);

  //初始化存儲(chǔ)管理
//  await StorageUtil.getInstance();
}

///初始化 App
void initMaterialApp() {
  HttpManager().init(
    baseUrl: "xxx",
    interceptors: [],
  );

  runApp(OKToast(child: HomeApp()));
}

這樣在命令行就可以分渠道運(yùn)行了:

flutter build --flavor dev -t lib/main-dev.dart

flutter build --flavor production -t lib/main-production.dart

如果你想直接大 IDE中直接分渠道包運(yùn)行,則要編輯配置創(chuàng)建兩個(gè)對(duì)應(yīng)的運(yùn)行配置:

image
image

這里創(chuàng)建了兩個(gè) flutter 運(yùn)行配置項(xiàng),main_dev、main_production。

在Dart entrypoint 中選擇上面創(chuàng)建的對(duì)應(yīng)的 main_dev.dart、dart_production.dart。

在Build flavor 中選擇對(duì)應(yīng)的 flavor(dev、production)。

此時(shí)在運(yùn)行對(duì)應(yīng)的main_dev、main_production就可以了。

最后

??如果在使用過(guò)程遇到問(wèn)題,歡迎下方留言交流。

參考資料:

學(xué)習(xí)資料

請(qǐng)大家不吝點(diǎn)贊!因?yàn)槟狞c(diǎn)贊是對(duì)我最大的鼓勵(lì),謝謝!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容