-
-
Notifications
You must be signed in to change notification settings - Fork 158
Description
Affected version
0.24.13+1
Flutter versions
3.29.2
No same issues found.
- Yes, I search all issues but not found.
Steps to Reproduce
加载并渲染HTML后,无法触发web的鼠标按下移动事件;
web部分已添加对应的事件
webf-demo.mp4
Code example
`WebF.fromControllerName(
controllerName: _controllerName,
loadingWidget: const shadcn.CustomButtonLoading(size: 24),
errorBuilder: (context, error) => Text('加载失败: $error'),
bundle: WebFBundle.fromUrl(bundleUrl),
createController: () => WebFController(
background: Colors.white,
viewportWidth: _viewportWidth,
viewportHeight: _viewportHeight,
onControllerInit: (c) async {
await c.view.evaluateJavaScripts('''
try {
if (typeof document === 'object') {
if (!document.implementation) {
document.implementation = {};
}
if (!document.implementation.createHTMLDocument) {
document.implementation.createHTMLDocument = function(title) {
// Create a dummy document-like object to satisfy jQuery's support check
// preventing it from wiping the real document.body
var dummyBody = document.createElement('div');
var dummyHead = document.createElement('div');
return {
body: dummyBody,
head: dummyHead,
createElement: function(tag) { return document.createElement(tag); },
title: title
};
};
}
}
// Location Polyfill - Force replacement of native location to avoid 'assets' scheme errors
try {
var fakeLocation = {
href: 'https://captcha.local/index.html',
origin: 'https://captcha.local',
protocol: 'https:',
host: 'captcha.local',
hostname: 'captcha.local',
port: '',
pathname: '/index.html',
search: '',
hash: '',
reload: function() {},
replace: function() {},
assign: function() {},
toString: function() { return this.href; }
};
// Attempt to replace window.location
try {
Object.defineProperty(window, 'location', {
value: fakeLocation,
writable: true,
configurable: true
});
} catch(e1) {
console.log('Failed to replace window.location', e1);
// Fallback: try to override origin on the native object
try {
Object.defineProperty(window.location, 'origin', {
value: 'https://captcha.local',
writable: true,
configurable: true
});
} catch(e2) {
console.log('Failed to override location.origin', e2);
}
}
} catch (e) {
console.log('Location polyfill fatal error', e);
}
if (typeof alert === 'undefined') {
globalThis.alert = function(msg) { console.log('[alert]', msg); };
}
if (typeof globalThis.crypto === 'undefined') {
globalThis.crypto = {
getRandomValues: function(typedArray) {
for (var i = 0; i < typedArray.length; i++) {
typedArray[i] = Math.floor(Math.random() * 256);
}
return typedArray;
}
};
}
try {
if (typeof location === 'object') {
if (!location.origin) {
location.origin = 'https://captcha.local';
}
} else {
globalThis.location = {
href: 'https://captcha.local/index.html',
origin: 'https://captcha.local',
protocol: 'https:',
host: 'captcha.local',
hostname: 'captcha.local',
port: '',
pathname: '/index.html',
search: '',
hash: ''
};
}
} catch (e) {
console.log('location polyfill error', e);
}
if (typeof navigator === 'undefined') {
globalThis.navigator = {
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
language: 'zh-CN',
platform: 'Win32',
appName: 'Netscape',
appVersion: '5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
};
}
if (typeof screen === 'undefined') {
globalThis.screen = {
width: 1920,
height: 1080,
availWidth: 1920,
availHeight: 1040,
colorDepth: 24,
pixelDepth: 24
};
}
if (typeof requestAnimationFrame === 'undefined') {
globalThis.requestAnimationFrame = function(callback) {
return setTimeout(callback, 16);
};
globalThis.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
// Force patch document.cookie to avoid native crash in CookieManager
try {
Object.defineProperty(document, 'cookie', {
get: function() { return ''; },
set: function(v) {},
configurable: true
});
} catch (e) {
console.log('cookie polyfill error', e);
}
// getRootNode Polyfill for jQuery 3.x (WebF missing API)
try {
var Prototypes = [
window.Node,
window.Element,
window.HTMLElement,
window.DocumentFragment,
window.Document
];
Prototypes.forEach(function(Proto) {
if (Proto && Proto.prototype && !Proto.prototype.getRootNode) {
Proto.prototype.getRootNode = function(opts) {
var composed = opts && opts.composed;
var node = this;
while (node.parentNode) {
node = node.parentNode;
}
return node;
};
}
});
} catch(e) {
console.log('getRootNode polyfill error', e);
}
// Mouse Event Polyfill for WebF (Dragging support) - Safe Implementation
try {
if (typeof MouseEvent === 'undefined') {
globalThis.MouseEvent = function(type, params) {
params = params || { bubbles: false, cancelable: false };
// Create a plain object that mimics a MouseEvent instead of calling document.createEvent
// calling document.createEvent('MouseEvent') and initMouseEvent might trigger native side effects causing the loop
this.type = type;
this.bubbles = params.bubbles;
this.cancelable = params.cancelable;
this.view = window;
this.detail = 0;
this.screenX = params.screenX || 0;
this.screenY = params.screenY || 0;
this.clientX = params.clientX || 0;
this.clientY = params.clientY || 0;
this.ctrlKey = false;
this.altKey = false;
this.shiftKey = false;
this.metaKey = false;
this.button = 0;
this.relatedTarget = null;
};
globalThis.MouseEvent.prototype = Event.prototype;
}
} catch (e) {
console.log('MouseEvent polyfill error', e);
}
// Storage Polyfill
if (typeof localStorage === 'undefined') {
var _store = {};
globalThis.localStorage = {
getItem: function(k) { return _store[k] || null; },
setItem: function(k, v) { _store[k] = String(v); },
removeItem: function(k) { delete _store[k]; },
clear: function() { _store = {}; },
key: function(i) { return Object.keys(_store)[i] || null; },
get length() { return Object.keys(_store).length; }
};
}
if (typeof sessionStorage === 'undefined') {
var _sessStore = {};
globalThis.sessionStorage = {
getItem: function(k) { return _sessStore[k] || null; },
setItem: function(k, v) { _sessStore[k] = String(v); },
removeItem: function(k) { delete _sessStore[k]; },
clear: function() { _sessStore = {}; },
key: function(i) { return Object.keys(_sessStore)[i] || null; },
get length() { return Object.keys(_sessStore).length; }
};
}
if (typeof document.referrer === 'undefined') {
Object.defineProperty(document, 'referrer', {
get: function() { return ''; }
});
}
if (typeof window.top === 'undefined') {
window.top = window;
}
if (typeof window.parent === 'undefined') {
window.parent = window;
}
if (typeof window.self === 'undefined') {
window.self = window;
}
if (typeof window.matchMedia === 'undefined') {
window.matchMedia = function(query) {
return {
matches: false,
media: query,
onchange: null,
addListener: function() {},
removeListener: function() {},
addEventListener: function() {},
removeEventListener: function() {},
dispatchEvent: function() { return false; },
};
};
}
} catch (e) {
console.log('polyfill error', e);
}
''');
},
),
forceLoad: true,
setup: (controller) {
controller.onJSError = (error) {
print('🔴 JS Error: ${error} \nStack: ${error}');
};
controller.onDOMContentLoaded = (event) async {
print('📄 DOM Content Loaded !!!');
final data = CustomWebViewSliderCodeData(
lang: ThemeConfigStore.to.appLangName,
device: 'FLUTTER',
codeType: 'SLIDER',
AccessKey: AppEnvConfig.appAccessKey,
AppEndKey: AppEnvConfig.appEndKey,
IP: AppEnvConfig.apiBaseUrl,
theme: theme.brightness == Brightness.light ? 'light' : 'dark',
);
final configJson = jsonEncode(data);
final jsArg = jsonEncode(configJson);
try {
await controller.view.evaluateJavaScripts('initCofig($jsArg);');
final element = controller.view.document.getElementsByTagName(['div']);
print('element: ${element.toString()}');
} catch (e) {
print('Error executing initCofig: $e');
}
};
controller.loadingState.onConstructor((event) {
print('🏗️ Constructor at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onInit((event) {
print('🚀 Initialize at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onPreload((event) {
print('📦 Preload at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onResolveEntrypointStart((event) {
print('🔍 Resolve Entrypoint Start at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onResolveEntrypointEnd((event) {
print('✅ Resolve Entrypoint End at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onParseHTMLStart((event) {
print('📄 Parse HTML Start at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onParseHTMLEnd((event) async {
print('✅ Parse HTML End at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onScriptQueue((event) {
print('📋 Script Queue at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onScriptLoadStart((event) {
print('📥 Script Load Start at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onScriptLoadComplete((event) {
print('✅ Script Load Complete at ${event.elapsed.inMilliseconds}ms ${event.parameters}');
});
controller.loadingState.onAttachToFlutter((event) {
print('🔗 Attach to Flutter at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onScriptExecuteStart((event) {
print('▶️ Script Execute Start at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onScriptExecuteComplete((event) {
print('✅ Script Execute Complete at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onDOMContentLoaded((event) async {
print('📄 DOM Content Loaded at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onWindowLoad((event) {
print('🪟 Window Load at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onBuildRootView((event) {
print('🏗️ Build Root View at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onFirstPaint((event) {
print('🎨 First Paint (FP) at ${event.elapsed.inMilliseconds}ms');
});
controller.loadingState.onFirstContentfulPaint((event) {
print('🖼️ First Contentful Paint (FCP) at ${event.elapsed.inMilliseconds}ms');
});
},
),
`
Expected results
按下鼠标能正常触发移动事件
Actual results
没有任何响应