Flutter 实现安卓多渠道打包

为什么使用多渠道打包

统计与分析 应用打包成不同的版本,投放到不同的市场或平台。统计应用在各个市场的用户下载量、新增用户量等数据,有助于分析应用在不同市场的表现和用户喜好
推广与营销 针对不同的市场或用户群体进行定制化的推广和营销活动
风险管理 需要切换API环境或进行其他配置更改。多渠道打包可以帮助开发者更好地管理不同版本和配置,降低这种风险。
提高效率 多渠道打包方案可以实现快速打包,例如使用gradle变量动态替换或第三方公司的批量打包方案,可以大大提高打包效率,节省开发者的时间。

动态渠道名称变量

xml 复制代码
<!--value的值填写渠道名称,例如yingyongbao。这里设置动态渠道名称变量-->
<meta-data android:value="xiaomi" android:name="UMENG_CHANNEL"/>
<!--<meta-data android:value="${UMENG_CHANNEL_VALUE}" android:name="UMENG_CHANNEL"/>-->

productFlavors 配置渠道

ini 复制代码
/*配置渠道*/
productFlavors {
    yingyongbao  {
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "yingyongbao"]
    }
    oppo  {
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "oppo"]
    }
}

flavorDimensions配置

如果不配置执行多渠道打包命令时会有如下异常:

* 复制代码
A problem occurred evaluating root project 'android'.
> A problem occurred configuring project ':app'.
   > com.android.builder.errors.EvalIssueException: All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com/r/tools/flavorDimensions-missing-error-message.html

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

读取清单文件下的渠道名称

kotlin 复制代码
class MainActivity: FlutterActivity() {

    private val CHANNEL = "channel.flutter.dev"

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
            .setMethodCallHandler { call: MethodCall, result: MethodChannel.Result ->
                //与Flutter Client invokeMethod调用字符串标识符匹配
                if (call.method == "channelMetaValue") {
                    val channelValue: String = channelMetaValue()
                    //initBlueTooth为后面安卓端需要调取的方法
                    result.success(channelValue)
                } else {
                    result.notImplemented()
                }
            }
    }

    private fun channelMetaValue(): String {
        val pm: PackageManager = packageManager
        var channel: String = "";
        try {
            val info: ApplicationInfo = pm.getApplicationInfo(getPackageName(),
                PackageManager.GET_META_DATA)
            channel = info.metaData.getString("UMENG_CHANNEL").toString()
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
        }
        return channel;
    }
}

Flutter工程获取渠道名称

less 复制代码
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late var channel = _channelValue();

  String _channelValue() {
    return '${'这里显示渠道名称'}\n';
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              channel,
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            GestureDetector(
              onTap: () async {
                channel = await channelName();
                setState(() {});
              },
              child: const Text(
                '\n获取渠道名称\n',
              ),
            )
          ],
        ),
      ),
    );
  }

  ///app当前市场
  ///android 例如:小米、华为、opppo
  ///ios - AppStore
  Future<String> channelName() async {
    String channel = '';
    if (Platform.isAndroid) {
      const platform = MethodChannel('channel.flutter.dev');
      channel = await platform.invokeMethod('channelMetaValue');
    } else if (Platform.isIOS) {
      channel = 'ios';
    }
    return channel;
  }
}

执行命令进行多渠道打包

多渠道打包案例

切换到分支flutter_multi_channel

相关推荐
杉氧9 小时前
深入理解 Compose 重组机制:快照系统如何驱动 UI 精准刷新?
android·架构·android jetpack
召钱熏9 小时前
状态枚举正确≠渲染正确:一个语音按钮的状态机边界修复实录
android·前端
杉氧10 小时前
深度解析:Jetpack Compose 核心架构与底层原理 —— 十年安卓老兵的“破茧重生”
android·架构·android jetpack
通玄10 小时前
Jetpack Compose 入门系列(七):ViewModel 与界面状态管理
android
落魄Android在线炒饭10 小时前
Android Framework 开发技巧:android.jar 生成与系统快速编译验证
android
如此风景11 小时前
Kotlin Flow操作符学习
android·kotlin
plainGeekDev11 小时前
GreenDAO → Room
android·java·kotlin
weiggle12 小时前
第八篇:ViewModel + Compose——生产级状态管理实践
android
恋猫de小郭17 小时前
Amper 正式转正 Kotlin Toolchain ,Gradle 未来何去何从
android·前端·flutter
plainGeekDev18 小时前
ButterKnife → ViewBinding
android·java·kotlin