Flutter多品牌应用架构实战:从配置驱动到编译部署的完整解决方案

Flutter多品牌应用实战:完整源码文件

项目结构

复制代码
lib/
├── main.dart
├── app.dart
├── brands/
│   ├── brand_a.dart
│   ├── brand_b.dart
│   ├── brand_config.dart
│   └── brand_manager.dart
├── core/
│   └── widgets/
│       └── brand_button.dart
└── features/
    └── home_page.dart
  1. 品牌配置接口

lib/brands/brand_config.dart

dart 复制代码
import 'package:flutter/material.dart';

abstract class BrandConfig {
  String get brandId;
  String get brandName;
  String get appName;
  Color get primaryColor;
  Color get secondaryColor;
  String get logoAsset;
  String get apiBaseUrl;
  String get supportEmail;
  
  ThemeData get themeData;
  
  bool get enableFeatureA;
  bool get enableFeatureB;
  
  String get welcomeText;
  String get loginButtonText;
  
  ButtonStyle getPrimaryButtonStyle();
  ButtonStyle getSecondaryButtonStyle();
}
  1. 品牌A配置

lib/brands/brand_a.dart

dart 复制代码
import 'package:flutter/material.dart';
import 'brand_config.dart';

class BrandAConfig implements BrandConfig {
  @override
  String get brandId => 'brand_a';

  @override
  String get brandName => 'Brand A';

  @override
  String get appName => '品牌A应用';

  @override
  Color get primaryColor => Colors.blue;

  @override
  Color get secondaryColor => Colors.lightBlue;

  @override
  String get logoAsset => 'assets/logo_brand_a.png';

  @override
  String get apiBaseUrl => 'https://api.brand-a.com';

  @override
  String get supportEmail => 'support@brand-a.com';

  @override
  ThemeData get themeData => ThemeData(
    primaryColor: primaryColor,
    colorScheme: ColorScheme.light(
      primary: primaryColor,
      secondary: secondaryColor,
    ),
    appBarTheme: AppBarTheme(
      backgroundColor: primaryColor,
      foregroundColor: Colors.white,
    ),
  );

  @override
  bool get enableFeatureA => true;

  @override
  bool get enableFeatureB => false;

  @override
  String get welcomeText => '欢迎使用品牌A';

  @override
  String get loginButtonText => '登录品牌A';

  @override
  ButtonStyle getPrimaryButtonStyle() {
    return ElevatedButton.styleFrom(
      backgroundColor: primaryColor,
      foregroundColor: Colors.white,
      padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(8),
      ),
    );
  }

  @override
  ButtonStyle getSecondaryButtonStyle() {
    return OutlinedButton.styleFrom(
      foregroundColor: primaryColor,
      side: BorderSide(color: primaryColor),
      padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(8),
      ),
    );
  }
}
  1. 品牌B配置

lib/brands/brand_b.dart

dart 复制代码
import 'package:flutter/material.dart';
import 'brand_config.dart';

class BrandBConfig implements BrandConfig {
  @override
  String get brandId => 'brand_b';

  @override
  String get brandName => 'Brand B';

  @override
  String get appName => '品牌B应用';

  @override
  Color get primaryColor => Colors.green;

  @override
  Color get secondaryColor => Colors.lightGreen;

  @override
  String get logoAsset => 'assets/logo_brand_b.png';

  @override
  String get apiBaseUrl => 'https://api.brand-b.com';

  @override
  String get supportEmail => 'support@brand-b.com';

  @override
  ThemeData get themeData => ThemeData(
    primaryColor: primaryColor,
    colorScheme: ColorScheme.light(
      primary: primaryColor,
      secondary: secondaryColor,
    ),
    appBarTheme: AppBarTheme(
      backgroundColor: primaryColor,
      foregroundColor: Colors.white,
    ),
  );

  @override
  bool get enableFeatureA => false;

  @override
  bool get enableFeatureB => true;

  @override
  String get welcomeText => '欢迎使用品牌B';

  @override
  String get loginButtonText => '登录品牌B';

  @override
  ButtonStyle getPrimaryButtonStyle() {
    return ElevatedButton.styleFrom(
      backgroundColor: primaryColor,
      foregroundColor: Colors.white,
      padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 15),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(20),
      ),
    );
  }

  @override
  ButtonStyle getSecondaryButtonStyle() {
    return OutlinedButton.styleFrom(
      foregroundColor: primaryColor,
      side: BorderSide(color: primaryColor, width: 2),
      padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 15),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(20),
      ),
    );
  }
}
  1. 品牌管理器

lib/brands/brand_manager.dart

dart 复制代码
import 'brand_config.dart';
import 'brand_a.dart';
import 'brand_b.dart';

class BrandManager {
  static BrandConfig? _currentBrand;
  
  static void initialize({String? brandId}) {
    final brand = brandId ?? const String.fromEnvironment('BRAND', defaultValue: 'brand_a');
    
    switch (brand) {
      case 'brand_a':
        _currentBrand = BrandAConfig();
        break;
      case 'brand_b':
        _currentBrand = BrandBConfig();
        break;
      default:
        _currentBrand = BrandAConfig();
    }
  }
  
  static BrandConfig get currentBrand {
    if (_currentBrand == null) {
      throw Exception('品牌配置未初始化');
    }
    return _currentBrand!;
  }
  
  static bool isBrandA() => _currentBrand is BrandAConfig;
  
  static bool isBrandB() => _currentBrand is BrandBConfig;
  
  static T getBrandValue<T>({
    required T forBrandA,
    required T forBrandB,
  }) {
    if (isBrandA()) {
      return forBrandA;
    } else if (isBrandB()) {
      return forBrandB;
    }
    return forBrandA;
  }
}
  1. 品牌按钮组件

lib/core/widgets/brand_button.dart

dart 复制代码
import 'package:flutter/material.dart';
import '../../brands/brand_manager.dart';

class BrandButton extends StatelessWidget {
  final String text;
  final VoidCallback onPressed;
  final bool isPrimary;
  final IconData? icon;
  
  const BrandButton({
    super.key,
    required this.text,
    required this.onPressed,
    this.isPrimary = true,
    this.icon,
  });
  
  @override
  Widget build(BuildContext context) {
    final config = BrandManager.currentBrand;
    
    return SizedBox(
      width: double.infinity,
      child: isPrimary
          ? ElevatedButton(
              onPressed: onPressed,
              style: config.getPrimaryButtonStyle(),
              child: _buildButtonContent(),
            )
          : OutlinedButton(
              onPressed: onPressed,
              style: config.getSecondaryButtonStyle(),
              child: _buildButtonContent(),
            ),
    );
  }
  
  Widget _buildButtonContent() {
    if (icon != null) {
      return Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(icon),
          const SizedBox(width: 8),
          Text(text),
        ],
      );
    }
    return Text(text);
  }
}
  1. 主页

lib/features/home_page.dart

dart 复制代码
import 'package:flutter/material.dart';
import '../brands/brand_manager.dart';
import '../core/widgets/brand_button.dart';

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    final config = BrandManager.currentBrand;
    
    return Scaffold(
      appBar: AppBar(
        title: Text(config.appName),
        backgroundColor: config.primaryColor,
        foregroundColor: Colors.white,
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Image.asset(
              config.logoAsset,
              width: 150,
              height: 150,
              errorBuilder: (context, error, stackTrace) {
                return CircleAvatar(
                  radius: 75,
                  backgroundColor: config.primaryColor,
                  child: Text(
                    config.brandName.substring(0, 1),
                    style: const TextStyle(
                      fontSize: 40,
                      color: Colors.white,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                );
              },
            ),
            
            const SizedBox(height: 30),
            
            Text(
              config.welcomeText,
              style: const TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
              ),
            ),
            
            const SizedBox(height: 10),
            
            Text(
              BrandManager.getBrandValue(
                forBrandA: '品牌A专有功能:功能A已启用',
                forBrandB: '品牌B专有功能:功能B已启用',
              ),
              style: TextStyle(
                fontSize: 16,
                color: Colors.grey[600],
              ),
            ),
            
            const SizedBox(height: 40),
            
            BrandButton(
              text: config.loginButtonText,
              onPressed: () {
                _showBrandDialog(context);
              },
              isPrimary: true,
              icon: Icons.login,
            ),
            
            const SizedBox(height: 20),
            
            BrandButton(
              text: '查看功能',
              onPressed: () {
                _showFeatures(context);
              },
              isPrimary: false,
              icon: Icons.info,
            ),
            
            const SizedBox(height: 20),
            
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Column(
                  children: [
                    Text(
                      '当前品牌信息',
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                        color: config.primaryColor,
                      ),
                    ),
                    const SizedBox(height: 10),
                    _buildInfoRow('品牌名称', config.brandName),
                    _buildInfoRow('品牌ID', config.brandId),
                    _buildInfoRow('API地址', config.apiBaseUrl),
                    _buildInfoRow('功能A', config.enableFeatureA ? '启用' : '禁用'),
                    _buildInfoRow('功能B', config.enableFeatureB ? '启用' : '禁用'),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
  
  Widget _buildInfoRow(String label, String value) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text('$label:', style: const TextStyle(fontWeight: FontWeight.bold)),
          Text(value),
        ],
      ),
    );
  }
  
  void _showBrandDialog(BuildContext context) {
    final config = BrandManager.currentBrand;
    
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('${config.brandName}对话框'),
        content: Text('这是${config.brandName}特有的对话框内容'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('取消'),
          ),
          ElevatedButton(
            onPressed: () {
              Navigator.pop(context);
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(
                  content: Text('${config.brandName}操作成功'),
                  backgroundColor: config.primaryColor,
                ),
              );
            },
            style: ElevatedButton.styleFrom(
              backgroundColor: config.primaryColor,
              foregroundColor: Colors.white,
            ),
            child: const Text('确定'),
          ),
        ],
      ),
    );
  }
  
  void _showFeatures(BuildContext context) {
    final config = BrandManager.currentBrand;
    
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('${config.brandName}功能'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _buildFeatureItem('主要颜色', config.primaryColor),
            _buildFeatureItem('次要颜色', config.secondaryColor),
            _buildFeatureItem('功能A', config.enableFeatureA),
            _buildFeatureItem('功能B', config.enableFeatureB),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('关闭'),
          ),
        ],
      ),
    );
  }
  
  Widget _buildFeatureItem(String label, dynamic value) {
    Widget valueWidget;
    
    if (value is Color) {
      valueWidget = Row(
        children: [
          Container(
            width: 20,
            height: 20,
            color: value,
            margin: const EdgeInsets.only(right: 8),
          ),
          Text(value.toString()),
        ],
      );
    } else if (value is bool) {
      valueWidget = Chip(
        label: Text(value ? '启用' : '禁用'),
        backgroundColor: value ? Colors.green.shade100 : Colors.red.shade100,
        labelStyle: TextStyle(
          color: value ? Colors.green.shade800 : Colors.red.shade800,
        ),
      );
    } else {
      valueWidget = Text(value.toString());
    }
    
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text('$label:', style: const TextStyle(fontWeight: FontWeight.bold)),
          valueWidget,
        ],
      ),
    );
  }
}
  1. 主应用组件

lib/app.dart

dart 复制代码
import 'package:flutter/material.dart';
import 'brands/brand_manager.dart';
import 'features/home_page.dart';

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    final config = BrandManager.currentBrand;
    
    return MaterialApp(
      title: config.appName,
      theme: config.themeData,
      home: const HomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}
  1. 应用入口

lib/main.dart

dart 复制代码
import 'package:flutter/material.dart';
import 'app.dart';
import 'brands/brand_manager.dart';

void main() {
  const brand = String.fromEnvironment('BRAND', defaultValue: 'brand_a');
  
  BrandManager.initialize(brandId: brand);
  
  runApp(const MyApp());
}
  1. 项目配置文件

pubspec.yaml

yaml 复制代码
name: multi_brand_app
description: Flutter多品牌应用示例
version: 1.0.0+1

environment:
  sdk: '>=3.0.0 <4.0.0'

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^3.0.0

flutter:
  uses-material-design: true
  
  assets:
    - assets/logo_brand_a.png
    - assets/logo_brand_b.png

使用说明

  1. 运行品牌A应用:
bash 复制代码
flutter run --dart-define=BRAND=brand_a
  1. 运行品牌B应用:
bash 复制代码
flutter run --dart-define=BRAND=brand_b
  1. 构建品牌AAPK:
bash 复制代码
flutter build apk --dart-define=BRAND=brand_a --release
  1. 构建品牌BAPK:
bash 复制代码
flutter build apk --dart-define=BRAND=brand_b --release
  1. 创建资产文件:

    项目根目录/
    ├── assets/
    │ ├── logo_brand_a.png
    │ └── logo_brand_b.png

这样就完成了完整的Flutter多品牌应用架构!

相关推荐
Bryce李小白3 小时前
FlutterBoost适配Flutter3.38.4版本生成补丁包
flutter
tangweiguo030519874 小时前
Flutter Packages 设计与实践:构建可维护的模块化应用
flutter
小a杰.4 小时前
Flutter 的编译技术核心
flutter
hudawei9965 小时前
flutter setState(() { … }) 作用
flutter
ujainu小6 小时前
Flutter 结合 local_auth 3.0.0 实现跨平台本地生物识别认证
flutter·local_auth
ujainu小6 小时前
Flutter 本地存储权威指南:sqflite 2.4.2 全平台集成与实战
flutter·sqflite
ujainu小7 小时前
Flutter 生物认证权威指南:local_auth 3.0.0 全平台集成与实战
flutter·local_auth
hh.h.8 小时前
灰度发布与A/B测试:Flutter+鸿蒙的分布式全量发布方案
分布式·flutter·harmonyos