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多品牌应用架构!

相关推荐
LawrenceLan1 小时前
Flutter 零基础入门(九):构造函数、命名构造函数与 this 关键字
开发语言·flutter·dart
一豆羹2 小时前
macOS 环境下 ADB 无线调试连接失败、Protocol Fault 及端口占用的深度排查
flutter
行者962 小时前
OpenHarmony上Flutter粒子效果组件的深度适配与实践
flutter·交互·harmonyos·鸿蒙
行者964 小时前
Flutter与OpenHarmony深度集成:数据导出组件的实战优化与性能提升
flutter·harmonyos·鸿蒙
小雨下雨的雨4 小时前
Flutter 框架跨平台鸿蒙开发 —— Row & Column 布局之轴线控制艺术
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨5 小时前
Flutter 框架跨平台鸿蒙开发 —— Center 控件之完美居中之道
flutter·ui·华为·harmonyos·鸿蒙
小雨下雨的雨6 小时前
Flutter 框架跨平台鸿蒙开发 —— Icon 控件之图标交互美学
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨6 小时前
Flutter 框架跨平台鸿蒙开发 —— Placeholder 控件之布局雏形美学
flutter·ui·华为·harmonyos·鸿蒙系统
行者966 小时前
OpenHarmony Flutter弹出菜单组件深度实践:从基础到高级的完整指南
flutter·harmonyos·鸿蒙
前端不太难7 小时前
Flutter / RN / iOS,在长期维护下的性能差异本质
flutter·ios