Files
Flutter_Shell/lib/config/app_config.dart
Booker a1e7b3e52c Refactor H5 line management and cache handling in WebView app
- Introduced shared_preferences for initial H5 cache management.
- Added methods to clear H5 caches and probe line availability.
- Enhanced error handling for line loading and switching.
- Removed openim_common package and its configurations.
- Updated widget tests to reflect changes in H5 line handling and URL management.
2026-05-29 17:56:55 +07:00

204 lines
5.2 KiB
Dart

import 'dart:math';
class H5Line {
const H5Line({
required this.label,
required this.url,
});
final String label;
final String url;
Uri get uri => Uri.parse(url);
}
class AppConfig {
static const String appName = '本地打包';
static const String appLogo = '';
static const String clientConfigDevice = 'h5';
static const String clientConfigSerialNo = 'h5-domain';
static const String _dartDefinedH5LineUrls =
String.fromEnvironment('H5_LINE_URLS');
static const String _dartDefinedClientConfigQueryUrl =
String.fromEnvironment('CLIENT_CONFIG_QUERY_URL');
// Bootstrap only: used before /client_config/query returns dynamic H5 domains.
static const String _bootstrapH5LineUrl = String.fromEnvironment(
'BOOTSTRAP_H5_LINE_URL',
defaultValue: 'https://h5-test.imharry.work/');
static final Random _wildcardRandom = Random.secure();
static List<H5Line> get h5Lines {
final configuredUrls = _dartDefinedH5LineUrls.trim().isEmpty
? _normalizedUniqueUrls(const [_bootstrapH5LineUrl])
: _normalizedUniqueUrls(_dartDefinedH5LineUrls.split(','));
final urls = configuredUrls.isEmpty
? _normalizedUniqueUrls(const [_bootstrapH5LineUrl])
: configuredUrls;
return [
for (var index = 0; index < urls.length; index += 1)
H5Line(label: '线路${index + 1}', url: urls[index]),
];
}
static Map<String, String> get clientConfigQueryPayload => const {
'device': clientConfigDevice,
'serialNo': clientConfigSerialNo,
};
static List<Uri> get clientConfigQueryUris {
final dartDefinedUrl = _dartDefinedClientConfigQueryUrl.trim();
if (dartDefinedUrl.isNotEmpty) {
return [Uri.parse(dartDefinedUrl)];
}
final lines = h5Lines;
if (lines.isEmpty) {
return const [];
}
final homeUri = lines.first.uri;
return [
homeUri.replace(
path: '/client_config/query',
queryParameters: const {},
fragment: '',
),
homeUri.replace(
path: '/api/user/client_config/query',
queryParameters: const {},
fragment: '',
),
];
}
static List<H5Line> h5LinesFromResourceUrl(
String resourceUrl, {
String Function()? wildcardFactory,
}) {
final urls = _normalizedUniqueUrls(
splitResourceUrlLines(resourceUrl).map(
(value) => _replaceWildcardHost(
value,
wildcardFactory: wildcardFactory,
),
),
);
return [
for (var index = 0; index < urls.length; index += 1)
H5Line(label: '线路${index + 1}', url: urls[index]),
];
}
static List<String> splitResourceUrlLines(String resourceUrl) {
if (resourceUrl.trim().isEmpty) {
return const [];
}
final lines = <String>[];
final seen = <String>{};
for (final value
in resourceUrl.split(RegExp(r'\\r\\n|\\n|\\r|\\t|[\r\n\t]+'))) {
final line = value.trim();
if (line.isEmpty || seen.contains(line)) {
continue;
}
lines.add(line);
seen.add(line);
}
return List.unmodifiable(lines);
}
static bool isLoginPageUrl(String? url) {
if (url == null || url.isEmpty) {
return false;
}
final uri = Uri.tryParse(url);
if (uri == null) {
return false;
}
return _isLoginPath(uri.path) || _isLoginPath(uri.fragment);
}
static bool _isLoginPath(String path) {
final normalized = path.trim();
if (normalized.isEmpty) {
return false;
}
final pathOnly = normalized.split('?').first.split('#').first;
final segments = pathOnly.split('/').where((segment) => segment.isNotEmpty);
if (segments.isEmpty) {
return false;
}
return segments.last == 'login';
}
static List<String> _normalizedUniqueUrls(Iterable<String> values) {
final urls = <String>[];
final seen = <String>{};
for (final value in values) {
final normalized = _tryNormalizeHomeUrl(value);
if (normalized == null || seen.contains(normalized)) {
continue;
}
urls.add(normalized);
seen.add(normalized);
}
return List.unmodifiable(urls);
}
static String? _tryNormalizeHomeUrl(String value) {
try {
return _normalizeHomeUrl(value);
} catch (_) {
return null;
}
}
static String _normalizeHomeUrl(String host) {
final value = host.trim();
if (value.isEmpty) {
throw const FormatException('Empty H5 line URL');
}
final normalized =
value.startsWith('http://') || value.startsWith('https://')
? value
: 'https://$value';
final uri = Uri.parse(normalized);
final path = uri.path.isEmpty ? '/' : uri.path;
return uri.replace(path: path).toString();
}
static String _replaceWildcardHost(
String value, {
String Function()? wildcardFactory,
}) {
if (!value.contains('*.')) {
return value;
}
return value.replaceAllMapped(
'*.',
(_) => '${(wildcardFactory ?? _randomWildcardLabel)()}.',
);
}
static String _randomWildcardLabel() {
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
return String.fromCharCodes(
List<int>.generate(
16,
(_) => chars.codeUnitAt(_wildcardRandom.nextInt(chars.length)),
),
);
}
}