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
- 品牌配置接口
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();
}
- 品牌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),
),
);
}
}
- 品牌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),
),
);
}
}
- 品牌管理器
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;
}
}
- 品牌按钮组件
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);
}
}
- 主页
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,
],
),
);
}
}
- 主应用组件
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,
);
}
}
- 应用入口
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());
}
- 项目配置文件
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
使用说明
- 运行品牌A应用:
bash
flutter run --dart-define=BRAND=brand_a
- 运行品牌B应用:
bash
flutter run --dart-define=BRAND=brand_b
- 构建品牌AAPK:
bash
flutter build apk --dart-define=BRAND=brand_a --release
- 构建品牌BAPK:
bash
flutter build apk --dart-define=BRAND=brand_b --release
-
创建资产文件:
项目根目录/
├── assets/
│ ├── logo_brand_a.png
│ └── logo_brand_b.png
这样就完成了完整的Flutter多品牌应用架构!