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.
This commit is contained in:
@@ -1,8 +1,4 @@
|
||||
import 'package:openim_common/openim_common.dart' as openim_common;
|
||||
|
||||
enum Environment {
|
||||
production,
|
||||
}
|
||||
import 'dart:math';
|
||||
|
||||
class H5Line {
|
||||
const H5Line({
|
||||
@@ -14,49 +10,29 @@ class H5Line {
|
||||
final String url;
|
||||
|
||||
Uri get uri => Uri.parse(url);
|
||||
|
||||
String get displayAddress {
|
||||
final parsed = uri;
|
||||
final host = parsed.hasPort ? '${parsed.host}:${parsed.port}' : parsed.host;
|
||||
final path = parsed.path.isEmpty || parsed.path == '/' ? '' : parsed.path;
|
||||
return '$host$path';
|
||||
}
|
||||
}
|
||||
|
||||
class AppConfig {
|
||||
static const Environment currentEnvironment = Environment.production;
|
||||
static const String appName = '本地打包';
|
||||
static const String appLogo = '';
|
||||
static const String canonicalWebHost = 'h5-test.imharry.work';
|
||||
static const String clientConfigDevice = 'h5';
|
||||
static const String clientConfigSerialNo = 'h5-domain';
|
||||
static const String _dartDefinedH5LineUrls =
|
||||
String.fromEnvironment('H5_LINE_URLS');
|
||||
static const Set<String> legacyWebHosts = {
|
||||
'h5-test.imharry.work',
|
||||
};
|
||||
|
||||
static final Map<Environment, List<String>> _environmentHosts = {
|
||||
Environment.production: [
|
||||
canonicalWebHost,
|
||||
],
|
||||
};
|
||||
|
||||
static List<String> get environmentHosts {
|
||||
final generatedHosts = _normalizedUniqueUrls(
|
||||
openim_common.Config.environmentHosts,
|
||||
);
|
||||
if (generatedHosts.isNotEmpty) {
|
||||
return generatedHosts;
|
||||
}
|
||||
|
||||
return _normalizedUniqueUrls(_environmentHosts[currentEnvironment] ?? []);
|
||||
}
|
||||
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
|
||||
? environmentHosts
|
||||
? _normalizedUniqueUrls(const [_bootstrapH5LineUrl])
|
||||
: _normalizedUniqueUrls(_dartDefinedH5LineUrls.split(','));
|
||||
final urls = configuredUrls.isEmpty
|
||||
? _normalizedUniqueUrls(const [canonicalWebHost])
|
||||
? _normalizedUniqueUrls(const [_bootstrapH5LineUrl])
|
||||
: configuredUrls;
|
||||
|
||||
return [
|
||||
@@ -65,22 +41,73 @@ class AppConfig {
|
||||
];
|
||||
}
|
||||
|
||||
static String homeUrl({int lineIndex = 0, String? appName, String? appLogo}) {
|
||||
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;
|
||||
final safeIndex = _safeLineIndex(lineIndex, lines.length);
|
||||
return lines[safeIndex].url;
|
||||
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 String withFreshShellParams(String url) {
|
||||
return _removeShellParams(Uri.parse(url)).toString();
|
||||
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 bool shouldRewriteMainFrameUrl(String url) {
|
||||
return false;
|
||||
}
|
||||
static List<String> splitResourceUrlLines(String resourceUrl) {
|
||||
if (resourceUrl.trim().isEmpty) {
|
||||
return const [];
|
||||
}
|
||||
|
||||
static String canonicalizeMainFrameUrl(String url) {
|
||||
return url;
|
||||
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) {
|
||||
@@ -96,46 +123,6 @@ class AppConfig {
|
||||
return _isLoginPath(uri.path) || _isLoginPath(uri.fragment);
|
||||
}
|
||||
|
||||
static int? lineIndexForUrl(String url) {
|
||||
final uri = Uri.tryParse(url);
|
||||
if (uri == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final lines = h5Lines;
|
||||
for (var index = 0; index < lines.length; index += 1) {
|
||||
if (_isSameLine(lines[index].uri, uri)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static Uri _removeShellParams(Uri uri) {
|
||||
final queryParameters = Map<String, String>.from(uri.queryParameters);
|
||||
queryParameters.remove('flutter_shell');
|
||||
queryParameters.remove('shell_cache_bust');
|
||||
queryParameters.remove('shell_app_name');
|
||||
queryParameters.remove('shell_app_logo');
|
||||
final fragmentParameters = Uri.splitQueryString(uri.fragment);
|
||||
fragmentParameters.remove('shell_app_name');
|
||||
fragmentParameters.remove('shell_app_logo');
|
||||
|
||||
return uri.replace(
|
||||
queryParameters: queryParameters,
|
||||
fragment: fragmentParameters.isEmpty
|
||||
? ''
|
||||
: Uri(queryParameters: fragmentParameters).query,
|
||||
);
|
||||
}
|
||||
|
||||
static int _safeLineIndex(int index, int length) {
|
||||
if (length <= 0 || index < 0 || index >= length) {
|
||||
return 0;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
static bool _isLoginPath(String path) {
|
||||
final normalized = path.trim();
|
||||
if (normalized.isEmpty) {
|
||||
@@ -151,29 +138,6 @@ class AppConfig {
|
||||
return segments.last == 'login';
|
||||
}
|
||||
|
||||
static bool _isSameLine(Uri lineUri, Uri uri) {
|
||||
if (lineUri.host.toLowerCase() != uri.host.toLowerCase()) {
|
||||
return false;
|
||||
}
|
||||
if (lineUri.hasPort && lineUri.port != uri.port) {
|
||||
return false;
|
||||
}
|
||||
if (lineUri.scheme.isNotEmpty && lineUri.scheme != uri.scheme) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final linePath = _pathWithTrailingSlash(lineUri.path);
|
||||
final uriPath = _pathWithTrailingSlash(uri.path);
|
||||
return linePath == '/' || uriPath.startsWith(linePath);
|
||||
}
|
||||
|
||||
static String _pathWithTrailingSlash(String path) {
|
||||
if (path.isEmpty) {
|
||||
return '/';
|
||||
}
|
||||
return path.endsWith('/') ? path : '$path/';
|
||||
}
|
||||
|
||||
static List<String> _normalizedUniqueUrls(Iterable<String> values) {
|
||||
final urls = <String>[];
|
||||
final seen = <String>{};
|
||||
@@ -212,4 +176,28 @@ class AppConfig {
|
||||
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)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user