mirror of
https://github.com/StarCitizenToolBox/app.git
synced 2026-01-14 04:00:27 +00:00
feat: web request_interceptor
This commit is contained in:
parent
e212928f57
commit
cabe05eb03
232
assets/request_interceptor.js
Normal file
232
assets/request_interceptor.js
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
/// ------- Request Interceptor Script --------------
|
||||||
|
/// 轻量级网络请求拦截器,不破坏网页正常功能
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
if (window._sctRequestInterceptorInstalled) {
|
||||||
|
console.log('[SCToolbox] Request interceptor already installed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window._sctRequestInterceptorInstalled = true;
|
||||||
|
|
||||||
|
// 被屏蔽的域名和路径
|
||||||
|
const blockedPatterns = [
|
||||||
|
'google-analytics.com',
|
||||||
|
'www.google.com/ccm/collect',
|
||||||
|
'www.google.com/pagead',
|
||||||
|
'www.google.com/ads',
|
||||||
|
'googleapis.com',
|
||||||
|
'doubleclick.net',
|
||||||
|
'reddit.com/rp.gif',
|
||||||
|
'alb.reddit.com',
|
||||||
|
'pixel-config.reddit.com',
|
||||||
|
'conversions-config.reddit.com',
|
||||||
|
'redditstatic.com/ads',
|
||||||
|
'analytics.tiktok.com',
|
||||||
|
'googletagmanager.com',
|
||||||
|
'facebook.com',
|
||||||
|
'facebook.net',
|
||||||
|
'gstatic.com/firebasejs'
|
||||||
|
];
|
||||||
|
|
||||||
|
// 判断 URL 是否应该被屏蔽
|
||||||
|
const shouldBlock = (url) => {
|
||||||
|
if (!url || typeof url !== 'string') return false;
|
||||||
|
const urlLower = url.toLowerCase();
|
||||||
|
return blockedPatterns.some(pattern => urlLower.includes(pattern.toLowerCase()));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 记录被拦截的请求
|
||||||
|
const logBlocked = (type, url) => {
|
||||||
|
console.log(`[SCToolbox] ❌ Blocked ${type}:`, url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TRANSPARENT_GIF = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
||||||
|
|
||||||
|
// ============ 1. 拦截 Fetch API ============
|
||||||
|
const originalFetch = window.fetch;
|
||||||
|
window.fetch = function(...args) {
|
||||||
|
const url = typeof args[0] === 'string' ? args[0] : args[0]?.url;
|
||||||
|
if (shouldBlock(url)) {
|
||||||
|
logBlocked('fetch', url);
|
||||||
|
return Promise.reject(new Error('Blocked by SCToolbox'));
|
||||||
|
}
|
||||||
|
return originalFetch.apply(this, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============ 2. 拦截 XMLHttpRequest ============
|
||||||
|
const OriginalXHR = window.XMLHttpRequest;
|
||||||
|
const originalXHROpen = OriginalXHR.prototype.open;
|
||||||
|
const originalXHRSend = OriginalXHR.prototype.send;
|
||||||
|
|
||||||
|
OriginalXHR.prototype.open = function(method, url, ...rest) {
|
||||||
|
this._url = url;
|
||||||
|
if (shouldBlock(url)) {
|
||||||
|
logBlocked('XHR', url);
|
||||||
|
this._blocked = true;
|
||||||
|
}
|
||||||
|
return originalXHROpen.apply(this, [method, url, ...rest]);
|
||||||
|
};
|
||||||
|
|
||||||
|
OriginalXHR.prototype.send = function(...args) {
|
||||||
|
if (this._blocked) {
|
||||||
|
setTimeout(() => {
|
||||||
|
const errorEvent = new Event('error');
|
||||||
|
this.dispatchEvent(errorEvent);
|
||||||
|
}, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return originalXHRSend.apply(this, args);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============ 3. 拦截 Image 元素的 src 属性 ============
|
||||||
|
const imgSrcDescriptor = Object.getOwnPropertyDescriptor(HTMLImageElement.prototype, 'src');
|
||||||
|
if (imgSrcDescriptor && imgSrcDescriptor.set) {
|
||||||
|
Object.defineProperty(HTMLImageElement.prototype, 'src', {
|
||||||
|
get: imgSrcDescriptor.get,
|
||||||
|
set: function(value) {
|
||||||
|
if (shouldBlock(value)) {
|
||||||
|
logBlocked('IMG.src', value);
|
||||||
|
// 设置为透明 GIF,避免请求
|
||||||
|
imgSrcDescriptor.set.call(this, TRANSPARENT_GIF);
|
||||||
|
this.style.cssText += 'display:none !important;width:0;height:0;';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return imgSrcDescriptor.set.call(this, value);
|
||||||
|
},
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ 3.5. 拦截 Script 元素的 src 属性 ============
|
||||||
|
const scriptSrcDescriptor = Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype, 'src');
|
||||||
|
if (scriptSrcDescriptor && scriptSrcDescriptor.set) {
|
||||||
|
Object.defineProperty(HTMLScriptElement.prototype, 'src', {
|
||||||
|
get: scriptSrcDescriptor.get,
|
||||||
|
set: function(value) {
|
||||||
|
if (shouldBlock(value)) {
|
||||||
|
logBlocked('SCRIPT.src', value);
|
||||||
|
// 阻止加载,不设置 src
|
||||||
|
this.type = 'javascript/blocked';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return scriptSrcDescriptor.set.call(this, value);
|
||||||
|
},
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ 4. 拦截 setAttribute(用于 img.setAttribute('src', ...))============
|
||||||
|
const originalSetAttribute = Element.prototype.setAttribute;
|
||||||
|
Element.prototype.setAttribute = function(name, value) {
|
||||||
|
if (name.toLowerCase() === 'src' && this.tagName === 'IMG' && shouldBlock(value)) {
|
||||||
|
logBlocked('IMG setAttribute', value);
|
||||||
|
originalSetAttribute.call(this, name, TRANSPARENT_GIF);
|
||||||
|
this.style.cssText += 'display:none !important;width:0;height:0;';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (name.toLowerCase() === 'src' && this.tagName === 'SCRIPT' && shouldBlock(value)) {
|
||||||
|
logBlocked('SCRIPT setAttribute', value);
|
||||||
|
return; // 阻止设置
|
||||||
|
}
|
||||||
|
return originalSetAttribute.call(this, name, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============ 5. 拦截 navigator.sendBeacon ============
|
||||||
|
if (navigator.sendBeacon) {
|
||||||
|
const originalSendBeacon = navigator.sendBeacon.bind(navigator);
|
||||||
|
navigator.sendBeacon = function(url, data) {
|
||||||
|
if (shouldBlock(url)) {
|
||||||
|
logBlocked('sendBeacon', url);
|
||||||
|
return true; // 假装成功
|
||||||
|
}
|
||||||
|
return originalSendBeacon(url, data);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ 6. 使用 MutationObserver 监听动态添加的元素 ============
|
||||||
|
const observer = new MutationObserver((mutations) => {
|
||||||
|
mutations.forEach((mutation) => {
|
||||||
|
mutation.addedNodes.forEach((node) => {
|
||||||
|
if (node.nodeType !== 1) return; // 只处理元素节点
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检查 IMG 元素
|
||||||
|
if (node.tagName === 'IMG') {
|
||||||
|
const src = node.getAttribute('src') || node.src;
|
||||||
|
if (src && shouldBlock(src)) {
|
||||||
|
logBlocked('Dynamic IMG', src);
|
||||||
|
node.src = TRANSPARENT_GIF;
|
||||||
|
node.style.cssText += 'display:none !important;width:0;height:0;';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 检查 SCRIPT 元素
|
||||||
|
else if (node.tagName === 'SCRIPT') {
|
||||||
|
const src = node.getAttribute('src');
|
||||||
|
if (src && shouldBlock(src)) {
|
||||||
|
logBlocked('Dynamic SCRIPT', src);
|
||||||
|
node.type = 'javascript/blocked';
|
||||||
|
node.removeAttribute('src');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 检查 IFRAME 元素
|
||||||
|
else if (node.tagName === 'IFRAME') {
|
||||||
|
const src = node.getAttribute('src');
|
||||||
|
if (src && shouldBlock(src)) {
|
||||||
|
logBlocked('Dynamic IFRAME', src);
|
||||||
|
node.src = 'about:blank';
|
||||||
|
node.style.cssText += 'display:none !important;';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归检查子元素
|
||||||
|
if (node.querySelectorAll) {
|
||||||
|
node.querySelectorAll('img').forEach(img => {
|
||||||
|
const src = img.getAttribute('src') || img.src;
|
||||||
|
if (src && shouldBlock(src)) {
|
||||||
|
logBlocked('Child IMG', src);
|
||||||
|
img.src = TRANSPARENT_GIF;
|
||||||
|
img.style.cssText += 'display:none !important;width:0;height:0;';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
node.querySelectorAll('script[src]').forEach(script => {
|
||||||
|
const src = script.getAttribute('src');
|
||||||
|
if (src && shouldBlock(src)) {
|
||||||
|
logBlocked('Child SCRIPT', src);
|
||||||
|
script.type = 'javascript/blocked';
|
||||||
|
script.removeAttribute('src');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 忽略错误
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 延迟启动 observer,等待页面初始化完成
|
||||||
|
const startObserver = () => {
|
||||||
|
if (document.body) {
|
||||||
|
observer.observe(document.documentElement, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
console.log('[SCToolbox] ✅ MutationObserver started');
|
||||||
|
} else {
|
||||||
|
setTimeout(startObserver, 50);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', startObserver);
|
||||||
|
} else {
|
||||||
|
startObserver();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[SCToolbox] ✅ Request interceptor installed');
|
||||||
|
console.log('[SCToolbox] 🛡️ Blocking', blockedPatterns.length, 'patterns');
|
||||||
|
})();
|
||||||
@ -278,8 +278,8 @@ class AdvancedLocalizationUIModel extends _$AdvancedLocalizationUIModel {
|
|||||||
state = state.copyWith(classMap: classMap);
|
state = state.copyWith(classMap: classMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: avoid_build_context_in_providers
|
|
||||||
Future<bool> doInstall(
|
Future<bool> doInstall(
|
||||||
|
// ignore: avoid_build_context_in_providers
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
bool isEnableCommunityInputMethod = false,
|
bool isEnableCommunityInputMethod = false,
|
||||||
bool isEnableVehicleSorting = false,
|
bool isEnableVehicleSorting = false,
|
||||||
|
|||||||
@ -26,8 +26,7 @@ class WebViewModel {
|
|||||||
|
|
||||||
bool get isClosed => _isClosed;
|
bool get isClosed => _isClosed;
|
||||||
|
|
||||||
WebViewModel(this.context,
|
WebViewModel(this.context, {this.loginMode = false, this.loginCallback, this.loginChannel = "LIVE"});
|
||||||
{this.loginMode = false, this.loginCallback, this.loginChannel = "LIVE"});
|
|
||||||
|
|
||||||
String url = "";
|
String url = "";
|
||||||
bool canGoBack = false;
|
bool canGoBack = false;
|
||||||
@ -35,6 +34,7 @@ class WebViewModel {
|
|||||||
final localizationResource = <String, dynamic>{};
|
final localizationResource = <String, dynamic>{};
|
||||||
|
|
||||||
var localizationScript = "";
|
var localizationScript = "";
|
||||||
|
var requestInterceptorScript = "";
|
||||||
|
|
||||||
bool enableCapture = false;
|
bool enableCapture = false;
|
||||||
|
|
||||||
@ -51,20 +51,22 @@ class WebViewModel {
|
|||||||
|
|
||||||
final RsiLoginCallback? loginCallback;
|
final RsiLoginCallback? loginCallback;
|
||||||
|
|
||||||
Future<void> initWebView(
|
Future<void> initWebView({
|
||||||
{String title = "",
|
String title = "",
|
||||||
required String applicationSupportDir,
|
required String applicationSupportDir,
|
||||||
required AppVersionData appVersionData}) async {
|
required AppVersionData appVersionData,
|
||||||
|
}) async {
|
||||||
try {
|
try {
|
||||||
final userBox = await Hive.openBox("app_conf");
|
final userBox = await Hive.openBox("app_conf");
|
||||||
isEnableToolSiteMirrors =
|
isEnableToolSiteMirrors = userBox.get("isEnableToolSiteMirrors", defaultValue: false);
|
||||||
userBox.get("isEnableToolSiteMirrors", defaultValue: false);
|
|
||||||
webview = await WebviewWindow.create(
|
webview = await WebviewWindow.create(
|
||||||
configuration: CreateConfiguration(
|
configuration: CreateConfiguration(
|
||||||
windowWidth: loginMode ? 960 : 1920,
|
windowWidth: loginMode ? 960 : 1920,
|
||||||
windowHeight: loginMode ? 720 : 1080,
|
windowHeight: loginMode ? 720 : 1080,
|
||||||
userDataFolderWindows: "$applicationSupportDir/webview_data",
|
userDataFolderWindows: "$applicationSupportDir/webview_data",
|
||||||
title: Platform.isMacOS ? "" : title));
|
title: Platform.isMacOS ? "" : title,
|
||||||
|
),
|
||||||
|
);
|
||||||
// webview.openDevToolsWindow();
|
// webview.openDevToolsWindow();
|
||||||
webview.isNavigating.addListener(() async {
|
webview.isNavigating.addListener(() async {
|
||||||
if (!webview.isNavigating.value && localizationResource.isNotEmpty) {
|
if (!webview.isNavigating.value && localizationResource.isNotEmpty) {
|
||||||
@ -74,14 +76,10 @@ class WebViewModel {
|
|||||||
final replaceWords = _getLocalizationResource("zh-CN");
|
final replaceWords = _getLocalizationResource("zh-CN");
|
||||||
const org = "https://robertsspaceindustries.com/orgs";
|
const org = "https://robertsspaceindustries.com/orgs";
|
||||||
const citizens = "https://robertsspaceindustries.com/citizens";
|
const citizens = "https://robertsspaceindustries.com/citizens";
|
||||||
const organization =
|
const organization = "https://robertsspaceindustries.com/account/organization";
|
||||||
"https://robertsspaceindustries.com/account/organization";
|
const concierge = "https://robertsspaceindustries.com/account/concierge";
|
||||||
const concierge =
|
const referral = "https://robertsspaceindustries.com/account/referral-program";
|
||||||
"https://robertsspaceindustries.com/account/concierge";
|
const address = "https://robertsspaceindustries.com/account/addresses";
|
||||||
const referral =
|
|
||||||
"https://robertsspaceindustries.com/account/referral-program";
|
|
||||||
const address =
|
|
||||||
"https://robertsspaceindustries.com/account/addresses";
|
|
||||||
|
|
||||||
const hangar = "https://robertsspaceindustries.com/account/pledges";
|
const hangar = "https://robertsspaceindustries.com/account/pledges";
|
||||||
|
|
||||||
@ -95,13 +93,8 @@ class WebViewModel {
|
|||||||
await Future.delayed(const Duration(milliseconds: 100));
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
await webview.evaluateJavaScript(localizationScript);
|
await webview.evaluateJavaScript(localizationScript);
|
||||||
|
|
||||||
if (url.startsWith(org) ||
|
if (url.startsWith(org) || url.startsWith(citizens) || url.startsWith(organization)) {
|
||||||
url.startsWith(citizens) ||
|
replaceWords.add({"word": 'members', "replacement": S.current.webview_localization_name_member});
|
||||||
url.startsWith(organization)) {
|
|
||||||
replaceWords.add({
|
|
||||||
"word": 'members',
|
|
||||||
"replacement": S.current.webview_localization_name_member
|
|
||||||
});
|
|
||||||
replaceWords.addAll(_getLocalizationResource("orgs"));
|
replaceWords.addAll(_getLocalizationResource("orgs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,21 +104,9 @@ class WebViewModel {
|
|||||||
|
|
||||||
if (url.startsWith(referral)) {
|
if (url.startsWith(referral)) {
|
||||||
replaceWords.addAll([
|
replaceWords.addAll([
|
||||||
{
|
{"word": 'Total recruits: ', "replacement": S.current.webview_localization_total_invitations},
|
||||||
"word": 'Total recruits: ',
|
{"word": 'Prospects ', "replacement": S.current.webview_localization_unfinished_invitations},
|
||||||
"replacement":
|
{"word": 'Recruits', "replacement": S.current.webview_localization_finished_invitations},
|
||||||
S.current.webview_localization_total_invitations
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": 'Prospects ',
|
|
||||||
"replacement":
|
|
||||||
S.current.webview_localization_unfinished_invitations
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"word": 'Recruits',
|
|
||||||
"replacement":
|
|
||||||
S.current.webview_localization_finished_invitations
|
|
||||||
},
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,48 +120,43 @@ class WebViewModel {
|
|||||||
|
|
||||||
_curReplaceWords = {};
|
_curReplaceWords = {};
|
||||||
for (var element in replaceWords) {
|
for (var element in replaceWords) {
|
||||||
_curReplaceWords?[element["word"] ?? ""] =
|
_curReplaceWords?[element["word"] ?? ""] = element["replacement"] ?? "";
|
||||||
element["replacement"] ?? "";
|
|
||||||
}
|
}
|
||||||
await webview.evaluateJavaScript("InitWebLocalization()");
|
await webview.evaluateJavaScript("InitWebLocalization()");
|
||||||
await Future.delayed(const Duration(milliseconds: 100));
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
dPrint("update replaceWords");
|
dPrint("update replaceWords");
|
||||||
await webview.evaluateJavaScript(
|
await webview.evaluateJavaScript(
|
||||||
"WebLocalizationUpdateReplaceWords(${json.encode(replaceWords)},$enableCapture)");
|
"WebLocalizationUpdateReplaceWords(${json.encode(replaceWords)},$enableCapture)",
|
||||||
|
);
|
||||||
|
|
||||||
/// loginMode
|
/// loginMode
|
||||||
if (loginMode) {
|
if (loginMode) {
|
||||||
dPrint(
|
dPrint("--- do rsi login ---\n run === getRSILauncherToken(\"$loginChannel\");");
|
||||||
"--- do rsi login ---\n run === getRSILauncherToken(\"$loginChannel\");");
|
|
||||||
await Future.delayed(const Duration(milliseconds: 200));
|
await Future.delayed(const Duration(milliseconds: 200));
|
||||||
webview.evaluateJavaScript(
|
webview.evaluateJavaScript("getRSILauncherToken(\"$loginChannel\");");
|
||||||
"getRSILauncherToken(\"$loginChannel\");");
|
|
||||||
}
|
}
|
||||||
} else if (url.startsWith(await _handleMirrorsUrl(
|
} else if (url.startsWith(await _handleMirrorsUrl("https://www.erkul.games", appVersionData))) {
|
||||||
"https://www.erkul.games", appVersionData))) {
|
|
||||||
dPrint("load script");
|
dPrint("load script");
|
||||||
await Future.delayed(const Duration(milliseconds: 100));
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
await webview.evaluateJavaScript(localizationScript);
|
await webview.evaluateJavaScript(localizationScript);
|
||||||
dPrint("update replaceWords");
|
dPrint("update replaceWords");
|
||||||
final replaceWords = _getLocalizationResource("DPS");
|
final replaceWords = _getLocalizationResource("DPS");
|
||||||
await webview.evaluateJavaScript(
|
await webview.evaluateJavaScript(
|
||||||
"WebLocalizationUpdateReplaceWords(${json.encode(replaceWords)},$enableCapture)");
|
"WebLocalizationUpdateReplaceWords(${json.encode(replaceWords)},$enableCapture)",
|
||||||
} else if (url.startsWith(await _handleMirrorsUrl(
|
);
|
||||||
"https://uexcorp.space", appVersionData))) {
|
} else if (url.startsWith(await _handleMirrorsUrl("https://uexcorp.space", appVersionData))) {
|
||||||
dPrint("load script");
|
dPrint("load script");
|
||||||
await Future.delayed(const Duration(milliseconds: 100));
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
await webview.evaluateJavaScript(localizationScript);
|
await webview.evaluateJavaScript(localizationScript);
|
||||||
dPrint("update replaceWords");
|
dPrint("update replaceWords");
|
||||||
final replaceWords = _getLocalizationResource("UEX");
|
final replaceWords = _getLocalizationResource("UEX");
|
||||||
await webview.evaluateJavaScript(
|
await webview.evaluateJavaScript(
|
||||||
"WebLocalizationUpdateReplaceWords(${json.encode(replaceWords)},$enableCapture)");
|
"WebLocalizationUpdateReplaceWords(${json.encode(replaceWords)},$enableCapture)",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
webview.addOnUrlRequestCallback((url) {
|
webview.addOnUrlRequestCallback(_onUrlRequest);
|
||||||
dPrint("OnUrlRequestCallback === $url");
|
|
||||||
this.url = url;
|
|
||||||
});
|
|
||||||
webview.onClose.whenComplete(dispose);
|
webview.onClose.whenComplete(dispose);
|
||||||
if (loginMode) {
|
if (loginMode) {
|
||||||
webview.addOnWebMessageReceivedCallback((messageString) {
|
webview.addOnWebMessageReceivedCallback((messageString) {
|
||||||
@ -199,8 +175,7 @@ class WebViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _handleMirrorsUrl(
|
Future<String> _handleMirrorsUrl(String url, AppVersionData appVersionData) async {
|
||||||
String url, AppVersionData appVersionData) async {
|
|
||||||
var finalUrl = url;
|
var finalUrl = url;
|
||||||
if (isEnableToolSiteMirrors) {
|
if (isEnableToolSiteMirrors) {
|
||||||
for (var kv in appVersionData.webMirrors!.entries) {
|
for (var kv in appVersionData.webMirrors!.entries) {
|
||||||
@ -219,28 +194,28 @@ class WebViewModel {
|
|||||||
|
|
||||||
Future<void> initLocalization(AppWebLocalizationVersionsData v) async {
|
Future<void> initLocalization(AppWebLocalizationVersionsData v) async {
|
||||||
localizationScript = await rootBundle.loadString('assets/web_script.js');
|
localizationScript = await rootBundle.loadString('assets/web_script.js');
|
||||||
|
requestInterceptorScript = await rootBundle.loadString('assets/request_interceptor.js');
|
||||||
|
|
||||||
/// https://github.com/CxJuice/Uex_Chinese_Translate
|
/// https://github.com/CxJuice/Uex_Chinese_Translate
|
||||||
// get versions
|
// get versions
|
||||||
final hostUrl = URLConf.webTranslateHomeUrl;
|
final hostUrl = URLConf.webTranslateHomeUrl;
|
||||||
dPrint("AppWebLocalizationVersionsData === ${v.toJson()}");
|
dPrint("AppWebLocalizationVersionsData === ${v.toJson()}");
|
||||||
|
|
||||||
localizationResource["zh-CN"] = await _getJson("$hostUrl/zh-CN-rsi.json",
|
localizationResource["zh-CN"] = await _getJson("$hostUrl/zh-CN-rsi.json", cacheKey: "rsi", version: v.rsi);
|
||||||
cacheKey: "rsi", version: v.rsi);
|
|
||||||
localizationResource["concierge"] = await _getJson(
|
localizationResource["concierge"] = await _getJson(
|
||||||
"$hostUrl/concierge.json",
|
"$hostUrl/concierge.json",
|
||||||
cacheKey: "concierge",
|
cacheKey: "concierge",
|
||||||
version: v.concierge);
|
version: v.concierge,
|
||||||
localizationResource["orgs"] =
|
);
|
||||||
await _getJson("$hostUrl/orgs.json", cacheKey: "orgs", version: v.orgs);
|
localizationResource["orgs"] = await _getJson("$hostUrl/orgs.json", cacheKey: "orgs", version: v.orgs);
|
||||||
localizationResource["address"] = await _getJson("$hostUrl/addresses.json",
|
localizationResource["address"] = await _getJson(
|
||||||
cacheKey: "addresses", version: v.addresses);
|
"$hostUrl/addresses.json",
|
||||||
localizationResource["hangar"] = await _getJson("$hostUrl/hangar.json",
|
cacheKey: "addresses",
|
||||||
cacheKey: "hangar", version: v.hangar);
|
version: v.addresses,
|
||||||
localizationResource["UEX"] = await _getJson("$hostUrl/zh-CN-uex.json",
|
);
|
||||||
cacheKey: "uex", version: v.uex);
|
localizationResource["hangar"] = await _getJson("$hostUrl/hangar.json", cacheKey: "hangar", version: v.hangar);
|
||||||
localizationResource["DPS"] = await _getJson("$hostUrl/zh-CN-dps.json",
|
localizationResource["UEX"] = await _getJson("$hostUrl/zh-CN-uex.json", cacheKey: "uex", version: v.uex);
|
||||||
cacheKey: "dps", version: v.dps);
|
localizationResource["DPS"] = await _getJson("$hostUrl/zh-CN-dps.json", cacheKey: "dps", version: v.dps);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Map<String, String>> _getLocalizationResource(String key) {
|
List<Map<String, String>> _getLocalizationResource(String key) {
|
||||||
@ -254,15 +229,13 @@ class WebViewModel {
|
|||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replaceAll(RegExp("/\xa0/g"), ' ')
|
.replaceAll(RegExp("/\xa0/g"), ' ')
|
||||||
.replaceAll(RegExp("/s{2,}/g"), ' ');
|
.replaceAll(RegExp("/s{2,}/g"), ' ');
|
||||||
localizations
|
localizations.add({"word": k, "replacement": element.value.toString().trim()});
|
||||||
.add({"word": k, "replacement": element.value.toString().trim()});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return localizations;
|
return localizations;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map> _getJson(String url,
|
Future<Map> _getJson(String url, {String cacheKey = "", String? version}) async {
|
||||||
{String cacheKey = "", String? version}) async {
|
|
||||||
final box = await Hive.openBox("web_localization_cache_data");
|
final box = await Hive.openBox("web_localization_cache_data");
|
||||||
if (cacheKey.isNotEmpty) {
|
if (cacheKey.isNotEmpty) {
|
||||||
final localVersion = box.get("${cacheKey}_version}", defaultValue: "");
|
final localVersion = box.get("${cacheKey}_version}", defaultValue: "");
|
||||||
@ -277,7 +250,8 @@ class WebViewModel {
|
|||||||
final data = json.decode(r);
|
final data = json.decode(r);
|
||||||
if (cacheKey.isNotEmpty) {
|
if (cacheKey.isNotEmpty) {
|
||||||
dPrint(
|
dPrint(
|
||||||
"update $cacheKey v == $version time == ${(endTime.microsecondsSinceEpoch - startTime.microsecondsSinceEpoch) / 1000 / 1000}s");
|
"update $cacheKey v == $version time == ${(endTime.microsecondsSinceEpoch - startTime.microsecondsSinceEpoch) / 1000 / 1000}s",
|
||||||
|
);
|
||||||
await box.put(cacheKey, data);
|
await box.put(cacheKey, data);
|
||||||
await box.put("${cacheKey}_version}", version);
|
await box.put("${cacheKey}_version}", version);
|
||||||
}
|
}
|
||||||
@ -288,15 +262,26 @@ class WebViewModel {
|
|||||||
webview.addOnWebMessageReceivedCallback(callback);
|
webview.addOnWebMessageReceivedCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeOnWebMessageReceivedCallback(
|
void removeOnWebMessageReceivedCallback(OnWebMessageReceivedCallback callback) {
|
||||||
OnWebMessageReceivedCallback callback) {
|
|
||||||
webview.removeOnWebMessageReceivedCallback(callback);
|
webview.removeOnWebMessageReceivedCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
FutureOr<void> dispose() {
|
FutureOr<void> dispose() {
|
||||||
|
webview.removeOnUrlRequestCallback(_onUrlRequest);
|
||||||
if (loginMode && !_loginModeSuccess) {
|
if (loginMode && !_loginModeSuccess) {
|
||||||
loginCallback?.call(null, false);
|
loginCallback?.call(null, false);
|
||||||
}
|
}
|
||||||
_isClosed = true;
|
_isClosed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onUrlRequest(String url) {
|
||||||
|
dPrint("OnUrlRequestCallback === $url");
|
||||||
|
this.url = url;
|
||||||
|
|
||||||
|
// 在页面开始加载时立即注入拦截器
|
||||||
|
if (requestInterceptorScript.isNotEmpty) {
|
||||||
|
dPrint("Injecting request interceptor for: $url");
|
||||||
|
webview.evaluateJavaScript(requestInterceptorScript);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user