feat: 添加应用品牌信息支持,重构主页 URL 生成逻辑

This commit is contained in:
Booker
2026-05-25 11:12:54 +07:00
parent abfd3717dc
commit cbe5bbb657
4 changed files with 142 additions and 10 deletions

View File

@@ -4,6 +4,8 @@ enum Environment {
class AppConfig {
static const Environment currentEnvironment = Environment.production;
static const String appName = '本地打包';
static const String appLogo = '';
static final Map<Environment, List<String>> _environmentHosts = {
Environment.production: [
@@ -15,11 +17,15 @@ class AppConfig {
return _environmentHosts[currentEnvironment] ?? const [];
}
static String get homeUrl {
static String homeUrl({String? appName, String? appLogo}) {
final host = environmentHosts.isNotEmpty
? environmentHosts.first
: 'h5-im.imharry.work';
return _normalizeHomeUrl(host);
return _withShellBranding(
_normalizeHomeUrl(host),
appName: appName,
appLogo: appLogo,
);
}
static String _normalizeHomeUrl(String host) {
@@ -29,4 +35,26 @@ class AppConfig {
}
return 'https://$value/';
}
static String _withShellBranding(
String url, {
String? appName,
String? appLogo,
}) {
final uri = Uri.parse(url);
final queryParameters = Map<String, String>.from(uri.queryParameters)
..['flutter_shell'] = '1';
final trimmedName = (appName ?? AppConfig.appName).trim();
if (trimmedName.isNotEmpty) {
queryParameters['shell_app_name'] = trimmedName;
}
final trimmedLogo = (appLogo ?? AppConfig.appLogo).trim();
if (trimmedLogo.isNotEmpty) {
queryParameters['shell_app_logo'] = trimmedLogo;
}
return uri.replace(queryParameters: queryParameters).toString();
}
}

View File

@@ -10,11 +10,12 @@ import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
import 'config/app_config.dart';
final _homeUrl = AppConfig.homeUrl;
const _shellBackground = Color(0xFFF8FBFF);
const _shellAccent = Color(0xFF0089FF);
const _shellSubText = Color(0xFF8E9AB0);
const _resumeCoverDuration = Duration(milliseconds: 700);
const _shellBrandingChannel =
MethodChannel('io.openim.flutter.im_webview_app/shell_branding');
const _stopWebMediaScript = r'''
(() => {
try {
@@ -29,7 +30,7 @@ const _stopWebMediaScript = r'''
})();
''';
void main() {
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
@@ -39,29 +40,70 @@ void main() {
systemNavigationBarIconBrightness: Brightness.dark,
),
);
runApp(const ImWebViewApp());
final shellBranding = await ShellBranding.load();
runApp(ImWebViewApp(shellBranding: shellBranding));
}
class ShellBranding {
const ShellBranding({
required this.appName,
required this.appLogo,
});
static const fallback = ShellBranding(
appName: AppConfig.appName,
appLogo: AppConfig.appLogo,
);
final String appName;
final String appLogo;
static Future<ShellBranding> load() async {
try {
final data = await _shellBrandingChannel
.invokeMapMethod<String, String>('getShellBranding');
final appName = _trim(data?['appName']);
final appLogo = _trim(data?['appLogo']);
return ShellBranding(
appName: appName.isNotEmpty ? appName : fallback.appName,
appLogo: appLogo.isNotEmpty ? appLogo : fallback.appLogo,
);
} catch (_) {
return fallback;
}
}
static String _trim(String? value) => value?.trim() ?? '';
}
class ImWebViewApp extends StatelessWidget {
const ImWebViewApp({super.key});
const ImWebViewApp({
super.key,
this.shellBranding = ShellBranding.fallback,
});
final ShellBranding shellBranding;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '集中营',
title: shellBranding.appName,
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF1F6FEB)),
scaffoldBackgroundColor: _shellBackground,
useMaterial3: true,
),
home: const H5ShellPage(),
home: H5ShellPage(shellBranding: shellBranding),
);
}
}
class H5ShellPage extends StatefulWidget {
const H5ShellPage({super.key});
const H5ShellPage({super.key, required this.shellBranding});
final ShellBranding shellBranding;
@override
State<H5ShellPage> createState() => _H5ShellPageState();
@@ -69,6 +111,7 @@ class H5ShellPage extends StatefulWidget {
class _H5ShellPageState extends State<H5ShellPage> with WidgetsBindingObserver {
late final WebViewController _controller;
late final String _homeUrl;
int _progress = 0;
String? _loadError;
@@ -79,6 +122,10 @@ class _H5ShellPageState extends State<H5ShellPage> with WidgetsBindingObserver {
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_homeUrl = AppConfig.homeUrl(
appName: widget.shellBranding.appName,
appLogo: widget.shellBranding.appLogo,
);
_controller = _buildController()..loadRequest(Uri.parse(_homeUrl));
}