flutter多渠道打包

正常的flutter打包是進(jìn)入工程根目錄執(zhí)行flutter build ios或者flutter build apk,當(dāng)然前提是已經(jīng)根據(jù)flutter官網(wǎng)的教程進(jìn)行配置,這里不多說(shuō)
Android構(gòu)建發(fā)布https://flutterchina.club/android-release/
iOS構(gòu)建發(fā)布https://flutterchina.club/ios-release/

我們這里所說(shuō)的多渠道打包其實(shí)還是Android原生的多渠道打包再菊,沒(méi)有實(shí)現(xiàn)執(zhí)行命令flutter build apk就生成多個(gè)渠道包的操作业簿。

說(shuō)到安卓原生的多渠道打包應(yīng)該分為兩塊來(lái)說(shuō)披坏,第一是打出渠道包撼唾,第二是能統(tǒng)計(jì)到各個(gè)渠道包的信息,那么我們首先進(jìn)行第一步:打出渠道包

一音婶、打渠道包

這一步很簡(jiǎn)單慨畸,只是在app的build.gradle中增加兩處配置就可以了

//這里不知道具體有啥用,但是不寫(xiě)就報(bào)錯(cuò)
defaultConfig {

        ...

        flavorDimensions "versionCode"

       ...
    }
android {

  ...

    productFlavors {
        yingyongbao {}
        channel360 {}
        wandoujia {}
        xiaomi {}
        huawei {}
        baidu {}
        oppo {}
        vivo {}
        sanxing {}
        lianxiang {}
    }
    productFlavors.all { flavor ->
        flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
    }
    //    修改命名規(guī)則
    applicationVariants.all { variant ->
        variant.outputs.all {
            def formattedDate = new Date().format('yyyy_MM_dd_HH_mm_ss')
            outputFileName = rootProject.getName() + "-" + variant.flavorName + "-" + buildType.name + "-" + formattedDate + "-v" + defaultConfig.versionName + "-" + defaultConfig.versionCode + ".apk";
        }
    }

...

}

我這里遇到了問(wèn)題衣式,flutter項(xiàng)目增加了這些配置之后就不能直接連接Android手機(jī)連調(diào)了寸士,會(huì)報(bào)以下錯(cuò)誤,一直沒(méi)有解決碴卧,如果有人解決煩勞相告??
但是以Android項(xiàng)目打開(kāi)是可以連調(diào)的

The Gradle project does not define a task suitable for the requested build.
The android/app/build.gradle file defines product flavors: baidu, channel360,
huawei, lianxiang, oppo, sanxing, vivo, wandoujia, xiaomi, yingyongbao
You must specify a --flavor option to select one of them.
Gradle build aborted.

二弱卡、統(tǒng)計(jì)各個(gè)渠道包下載量等信息

統(tǒng)計(jì)我選擇的友盟統(tǒng)計(jì),flutter的第三方包選擇的是flutter_umplus住册,地址:
https://pub.dev/packages/flutter_umplus

我們首先需要去友盟官網(wǎng)注冊(cè)app信息婶博,Android和iOS要注冊(cè)兩個(gè),獲取到AndroidKey和iOSKey然后在flutter項(xiàng)目中合適的地方初始化友盟

//集成友盟統(tǒng)計(jì)
    if(Platform.isAndroid){//Android平臺(tái)
      FlutterUmplus.init(AndroidKey,channel:"Android的渠道名稱(chēng)",reportCrash: false,logEnable: true,encrypt: true);
    }else if(Platform.isIOS){//iOS平臺(tái)
      FlutterUmplus.init(iOSKey,channel: "appstore",reportCrash: false,logEnable: true,encrypt: true);
    }

iOS只有AppStore一個(gè)渠道所以固定值appstore就可以了荧飞,Android項(xiàng)目我們?cè)趺传@取到當(dāng)前渠道包的名稱(chēng)呢凡人?很簡(jiǎn)單,在AndroidManifest.xml中添加meta-data原數(shù)據(jù)

<application>

        ...

        <!--友盟統(tǒng)計(jì)-->
        <meta-data android:value="${UMENG_CHANNEL_VALUE}"  android:name="UMENG_CHANNEL"  />

      ...

    </application>

這里的UMENG_CHANNEL_VALUE和build.gradle中的UMENG_CHANNEL_VALUE對(duì)應(yīng)起來(lái)叹阔,在Android項(xiàng)目中可以讀取這里的value值

public static String getChannel(Context context) {
        try {
            PackageManager pm = context.getPackageManager();
            ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
            return appInfo.metaData.getString("UMENG_CHANNEL");
        } catch (PackageManager.NameNotFoundException ignored) {
        }
        return "";
    }

????但是現(xiàn)在問(wèn)題來(lái)了划栓,我不知道flutter代碼中怎么讀取AndroidManifest.xml中的meta-data值,于是乎我就開(kāi)始思考条获,想到了第一個(gè)??個(gè)方案

1. SharedPreferences

使用SharedPreferences存儲(chǔ)數(shù)據(jù),然后在flutter中使用shared_preferences中讀取蒋歌,于是我在MainActivity中讀取數(shù)據(jù)并存儲(chǔ)

//在flutter中不知道怎么獲取manifest中的meta數(shù)據(jù)帅掘,所以在這里先獲取了存起來(lái)委煤,在flutter里邊取出來(lái)用??
    try {
      PackageManager pm = this.getPackageManager();
      ApplicationInfo appInfo = pm.getApplicationInfo(this.getPackageName(), PackageManager.GET_META_DATA);
      String str = appInfo.metaData.getString("UMENG_CHANNEL");

      SharedPreferences sharedPref = this.getApplication().getSharedPreferences("CONFIG_SETTING", Context.MODE_PRIVATE);
      SharedPreferences.Editor editor = sharedPref.edit();
      editor.putString("channelName",str);
      boolean isSucc = editor.commit();
      
      String theStr = sharedPref.getString("channelName","default");
      Log.d("str",theStr);
    } catch (PackageManager.NameNotFoundException ignored) {
    }
SharedPreferences.getInstance().then((sp){
    String channelName = sp.getString("channelName");
    print("渠道名稱(chēng)"+channelName);
  });

很不幸,讀取的時(shí)候一直是空修档,讀取不到碧绞,這里并不是說(shuō)這種方式不行,而是我不會(huì)用????吱窝,所以就暫時(shí)放棄這種方式了讥邻,待以后我對(duì)Android進(jìn)一步熟悉再來(lái)解決。這種方式不行并且現(xiàn)在還沒(méi)有找到有人封裝這種第三方的工具院峡,那么就需要自己動(dòng)手進(jìn)行原生交互了兴使,這里我偷了個(gè)懶,我沒(méi)有自己新建原生交互的plugin照激,而是修改了別人的代碼发魄,項(xiàng)目中用到了package_info,但是看源碼只提供了四種屬性俩垃,沒(méi)有我們需要的励幼,不行就改,改到我們能用就好了口柳。

/// The app name. `CFBundleDisplayName` on iOS, `application/label` on Android.
  final String appName;

  /// The package name. `bundleIdentifier` on iOS, `getPackageName` on Android.
  final String packageName;

  /// The package version. `CFBundleShortVersionString` on iOS, `versionName` on Android.
  final String version;

  /// The build number. `CFBundleVersion` on iOS, `versionCode` on Android.
  final String buildNumber;
2.擴(kuò)展package_info苹粟,增加channelName

package_info.dart

class PackageInfo {
  PackageInfo({
    this.appName,
    this.packageName,
    this.version,
    this.buildNumber,
    this.channelName, //自己新增的渠道名稱(chēng)
  });

  static Future<PackageInfo> _fromPlatform;

  /// Retrieves package information from the platform.
  /// The result is cached.
  static Future<PackageInfo> fromPlatform() async {
    if (_fromPlatform == null) {
      final Completer<PackageInfo> completer = Completer<PackageInfo>();

      // TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter.
      // https://github.com/flutter/flutter/issues/26431
      // ignore: strong_mode_implicit_dynamic_method
      _kChannel.invokeMethod('getAll').then((dynamic result) {
        final Map<dynamic, dynamic> map = result;

        completer.complete(PackageInfo(
          appName: map["appName"],
          packageName: map["packageName"],
          version: map["version"],
          buildNumber: map["buildNumber"],
          channelName: map["channelName"], //自己新增的渠道名稱(chēng)
        ));
      }, onError: completer.completeError);

      _fromPlatform = completer.future;
    }
    return _fromPlatform;
  }

  /// The app name. `CFBundleDisplayName` on iOS, `application/label` on Android.
  final String appName;

  /// The package name. `bundleIdentifier` on iOS, `getPackageName` on Android.
  final String packageName;

  /// The package version. `CFBundleShortVersionString` on iOS, `versionName` on Android.
  final String version;

  /// The build number. `CFBundleVersion` on iOS, `versionCode` on Android.
  final String buildNumber;

  ///自己新增的渠道名稱(chēng)
  final String channelName;
}

PackageInfoPlugin

/** PackageInfoPlugin */
public class PackageInfoPlugin implements MethodCallHandler {
  ...
  @Override
  public void onMethodCall(MethodCall call, Result result) {
    try {
      Context context = mRegistrar.context();
      if (call.method.equals("getAll")) {
        PackageManager pm = context.getPackageManager();
        PackageInfo info = pm.getPackageInfo(context.getPackageName(), 0);

        //獲取渠道名使用
        ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);

        Map<String, String> map = new HashMap<String, String>();
        map.put("appName", info.applicationInfo.loadLabel(pm).toString());
        map.put("packageName", context.getPackageName());
        map.put("version", info.versionName);
        map.put("buildNumber", String.valueOf(getLongVersionCode(info)));
        map.put("channelName", String.valueOf(appInfo.metaData.getString("UMENG_CHANNEL")));

        result.success(map);
      } else {
        result.notImplemented();
      }
    } catch (PackageManager.NameNotFoundException ex) {
      result.error("Name not found", ex.getMessage(), null);
    }
  }
...
}

使用方法

//集成友盟統(tǒng)計(jì)
    if(Platform.isAndroid){//Android平臺(tái)
      PackageInfo.fromPlatform().then((package){
        String channelName = package.channelName;
        print("渠道名"+channelName);
        FlutterUmplus.init(ChannelClass.androidKey,channel: channelName,reportCrash: false,logEnable: true,encrypt: true);
      });
    }else if(Platform.isIOS){//iOS平臺(tái)
      FlutterUmplus.init(ChannelClass.iosKey,channel: ChannelClass.appstore,reportCrash: false,logEnable: true,encrypt: true);
    }

終于獲取到了渠道名稱(chēng)??????

我是修改了第三方的包才讀取到了Android原生的數(shù)據(jù),如果以后別的項(xiàng)目也有這種需要跃闹,那么代碼還要再改一次嵌削,后面還面臨著第三方包升級(jí)等問(wèn)題,最好還是自己寫(xiě)一個(gè)plugin進(jìn)行原生交互一勞永逸辣卒。

參考文章
https://blog.csdn.net/cs_lwb/article/details/82813909

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掷贾,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子荣茫,更是在濱河造成了極大的恐慌想帅,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啡莉,死亡現(xiàn)場(chǎng)離奇詭異港准,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)咧欣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)浅缸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人魄咕,你說(shuō)我怎么就攤上這事衩椒。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵毛萌,是天一觀的道長(zhǎng)苟弛。 經(jīng)常有香客問(wèn)我,道長(zhǎng)阁将,這世上最難降的妖魔是什么膏秫? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮做盅,結(jié)果婚禮上缤削,老公的妹妹穿的比我還像新娘。我一直安慰自己吹榴,他們只是感情好亭敢,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著腊尚,像睡著了一般吨拗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上婿斥,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天劝篷,我揣著相機(jī)與錄音,去河邊找鬼民宿。 笑死娇妓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的活鹰。 我是一名探鬼主播哈恰,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼志群!你這毒婦竟也來(lái)了着绷?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤锌云,失蹤者是張志新(化名)和其女友劉穎荠医,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體桑涎,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡彬向,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了攻冷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片娃胆。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖等曼,靈堂內(nèi)的尸體忽然破棺而出里烦,到底是詐尸還是另有隱情凿蒜,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布招驴,位于F島的核電站篙程,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏别厘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一拥诡、第九天 我趴在偏房一處隱蔽的房頂上張望触趴。 院中可真熱鬧,春花似錦渴肉、人聲如沸冗懦。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)披蕉。三九已至,卻和暖如春乌奇,著一層夾襖步出監(jiān)牢的瞬間没讲,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工礁苗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留爬凑,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓试伙,卻偏偏與公主長(zhǎng)得像嘁信,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子疏叨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348