262 lines
9.2 KiB
Dart
262 lines
9.2 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:yumi/modules/room_game/data/models/room_game_models.dart';
|
|
|
|
class BaishunBridgeActions {
|
|
static const String getConfig = 'getConfig';
|
|
static const String gameLoaded = 'gameLoaded';
|
|
static const String gameRecharge = 'gameRecharge';
|
|
static const String destroy = 'destroy';
|
|
}
|
|
|
|
class BaishunBridgeMessage {
|
|
const BaishunBridgeMessage({
|
|
required this.action,
|
|
this.payload = const <String, dynamic>{},
|
|
});
|
|
|
|
final String action;
|
|
final Map<String, dynamic> payload;
|
|
|
|
static BaishunBridgeMessage fromAction(String action, String rawMessage) {
|
|
return BaishunBridgeMessage(
|
|
action: action,
|
|
payload: _parsePayload(rawMessage),
|
|
);
|
|
}
|
|
|
|
static BaishunBridgeMessage parse(String rawMessage) {
|
|
try {
|
|
final dynamic decoded = jsonDecode(rawMessage);
|
|
if (decoded is Map<String, dynamic>) {
|
|
return BaishunBridgeMessage(
|
|
action:
|
|
(decoded['action'] ?? decoded['cmd'] ?? decoded['event'] ?? '')
|
|
.toString()
|
|
.trim(),
|
|
payload: _parsePayload(
|
|
decoded['payload'] ?? decoded['data'] ?? decoded['params'],
|
|
),
|
|
);
|
|
}
|
|
} catch (_) {}
|
|
return BaishunBridgeMessage(action: rawMessage.trim());
|
|
}
|
|
|
|
static Map<String, dynamic> _parsePayload(dynamic rawPayload) {
|
|
if (rawPayload is Map<String, dynamic>) {
|
|
return rawPayload;
|
|
}
|
|
if (rawPayload is String) {
|
|
final trimmed = rawPayload.trim();
|
|
if (trimmed.isEmpty) {
|
|
return const <String, dynamic>{};
|
|
}
|
|
try {
|
|
final dynamic decoded = jsonDecode(trimmed);
|
|
if (decoded is Map<String, dynamic>) {
|
|
return decoded;
|
|
}
|
|
} catch (_) {}
|
|
return <String, dynamic>{'raw': trimmed};
|
|
}
|
|
return const <String, dynamic>{};
|
|
}
|
|
}
|
|
|
|
class BaishunJsBridge {
|
|
static const String channelName = 'BaishunBridgeChannel';
|
|
|
|
static String bootstrapScript() {
|
|
return '''
|
|
(function() {
|
|
if (window.__baishunBridgeReady) {
|
|
return;
|
|
}
|
|
window.__baishunBridgeReady = true;
|
|
window.NativeBridge = window.NativeBridge || {};
|
|
function toPayload(input) {
|
|
if (typeof input === 'function') {
|
|
window.__baishunGetConfigCallback = input;
|
|
return {};
|
|
}
|
|
if (typeof input === 'string') {
|
|
try {
|
|
return JSON.parse(input);
|
|
} catch (_) {
|
|
return input.trim() ? { raw: input.trim() } : {};
|
|
}
|
|
}
|
|
if (input && typeof input === 'object') {
|
|
return input;
|
|
}
|
|
return {};
|
|
}
|
|
function rememberJsCallback(payload) {
|
|
if (payload && typeof payload.jsCallback === 'string' && payload.jsCallback.trim()) {
|
|
window.__baishunLastJsCallback = payload.jsCallback.trim();
|
|
}
|
|
}
|
|
function postAction(action, input) {
|
|
const payload = toPayload(input);
|
|
rememberJsCallback(payload);
|
|
$channelName.postMessage(JSON.stringify({ action: action, payload: payload }));
|
|
return payload;
|
|
}
|
|
function ensureChannelAlias(name, handler) {
|
|
if (!window[name] || typeof window[name].postMessage !== 'function') {
|
|
window[name] = { postMessage: handler };
|
|
}
|
|
}
|
|
function ensureWebkitHandler(name, handler) {
|
|
window.webkit = window.webkit || {};
|
|
window.webkit.messageHandlers = window.webkit.messageHandlers || {};
|
|
if (!window.webkit.messageHandlers[name] || typeof window.webkit.messageHandlers[name].postMessage !== 'function') {
|
|
window.webkit.messageHandlers[name] = { postMessage: handler };
|
|
}
|
|
}
|
|
window.NativeBridge.getConfigSync = function() {
|
|
return window.__baishunLastConfig || null;
|
|
};
|
|
window.NativeBridge.getConfig = function(params) {
|
|
postAction('${BaishunBridgeActions.getConfig}', params);
|
|
return window.__baishunLastConfig || null;
|
|
};
|
|
window.NativeBridge.destroy = function(payload) {
|
|
postAction('${BaishunBridgeActions.destroy}', payload);
|
|
};
|
|
window.NativeBridge.gameRecharge = function(payload) {
|
|
postAction('${BaishunBridgeActions.gameRecharge}', payload);
|
|
};
|
|
window.NativeBridge.gameLoaded = function(payload) {
|
|
postAction('${BaishunBridgeActions.gameLoaded}', payload);
|
|
};
|
|
ensureChannelAlias('getConfig', function(message) {
|
|
window.NativeBridge.getConfig(message);
|
|
});
|
|
ensureChannelAlias('destroy', function(message) {
|
|
window.NativeBridge.destroy(message);
|
|
});
|
|
ensureChannelAlias('gameRecharge', function(message) {
|
|
window.NativeBridge.gameRecharge(message);
|
|
});
|
|
ensureChannelAlias('gameLoaded', function(message) {
|
|
window.NativeBridge.gameLoaded(message);
|
|
});
|
|
ensureWebkitHandler('getConfig', function(message) {
|
|
window.NativeBridge.getConfig(message);
|
|
});
|
|
ensureWebkitHandler('destroy', function(message) {
|
|
window.NativeBridge.destroy(message);
|
|
});
|
|
ensureWebkitHandler('gameRecharge', function(message) {
|
|
window.NativeBridge.gameRecharge(message);
|
|
});
|
|
ensureWebkitHandler('gameLoaded', function(message) {
|
|
window.NativeBridge.gameLoaded(message);
|
|
});
|
|
window.baishunChannel = window.baishunChannel || {};
|
|
window.baishunChannel.walletUpdate = function(payload) {
|
|
window.__baishunLastWalletPayload = payload || {};
|
|
if (typeof window.walletUpdate === 'function') {
|
|
window.walletUpdate(payload || {});
|
|
}
|
|
if (typeof window.onWalletUpdate === 'function') {
|
|
window.onWalletUpdate(payload || {});
|
|
}
|
|
if (typeof window.dispatchEvent === 'function' && typeof CustomEvent === 'function') {
|
|
window.dispatchEvent(new CustomEvent('walletUpdate', { detail: payload || {} }));
|
|
}
|
|
};
|
|
if (typeof window.dispatchEvent === 'function' && typeof CustomEvent === 'function') {
|
|
window.dispatchEvent(new CustomEvent('baishunBridgeReady'));
|
|
}
|
|
})();
|
|
''';
|
|
}
|
|
|
|
static String buildConfigScript(
|
|
BaishunBridgeConfigModel config, {
|
|
String? jsCallbackPath,
|
|
}) {
|
|
final payload = jsonEncode(config.toJson());
|
|
final encodedCallbackPath = jsonEncode(jsCallbackPath?.trim() ?? '');
|
|
return '''
|
|
(function() {
|
|
const config = $payload;
|
|
const explicitCallbackPath = $encodedCallbackPath;
|
|
function resolvePath(path) {
|
|
if (!path || typeof path !== 'string') {
|
|
return null;
|
|
}
|
|
const parts = path.split('.').filter(Boolean);
|
|
if (!parts.length) {
|
|
return null;
|
|
}
|
|
let scope = window;
|
|
for (let i = 0; i < parts.length - 1; i += 1) {
|
|
scope = scope ? scope[parts[i]] : null;
|
|
}
|
|
if (!scope) {
|
|
return null;
|
|
}
|
|
const methodName = parts[parts.length - 1];
|
|
const method = scope[methodName];
|
|
if (typeof method !== 'function') {
|
|
return null;
|
|
}
|
|
return { scope: scope, method: method };
|
|
}
|
|
function invokeCallbackPath(path) {
|
|
const target = resolvePath(path);
|
|
if (!target) {
|
|
return false;
|
|
}
|
|
target.method.call(target.scope, config);
|
|
return true;
|
|
}
|
|
window.__baishunLastConfig = config;
|
|
window.baishunBridgeConfig = config;
|
|
window.NativeBridge = window.NativeBridge || {};
|
|
window.NativeBridge.config = config;
|
|
const callbackPath = explicitCallbackPath || window.__baishunLastJsCallback || '';
|
|
let callbackInvoked = false;
|
|
if (explicitCallbackPath) {
|
|
window.__baishunLastJsCallback = explicitCallbackPath;
|
|
}
|
|
if (typeof window.__baishunGetConfigCallback === 'function') {
|
|
window.__baishunGetConfigCallback(config);
|
|
window.__baishunGetConfigCallback = null;
|
|
}
|
|
if (window.__baishunLastJsCallback) {
|
|
callbackInvoked = invokeCallbackPath(window.__baishunLastJsCallback) || callbackInvoked;
|
|
}
|
|
if (typeof window.onBaishunConfig === 'function') {
|
|
window.onBaishunConfig(config);
|
|
}
|
|
if (typeof window.dispatchEvent === 'function' && typeof CustomEvent === 'function') {
|
|
window.dispatchEvent(new CustomEvent('baishunConfig', { detail: config }));
|
|
}
|
|
if (typeof document !== 'undefined' && typeof document.dispatchEvent === 'function' && typeof CustomEvent === 'function') {
|
|
document.dispatchEvent(new CustomEvent('baishunConfig', { detail: config }));
|
|
}
|
|
})();
|
|
''';
|
|
}
|
|
|
|
static String buildWalletUpdateScript({Map<String, dynamic>? payload}) {
|
|
final safePayload = jsonEncode(
|
|
payload ??
|
|
<String, dynamic>{'timestamp': DateTime.now().millisecondsSinceEpoch},
|
|
);
|
|
return '''
|
|
(function() {
|
|
const payload = $safePayload;
|
|
if (window.baishunChannel && typeof window.baishunChannel.walletUpdate === 'function') {
|
|
window.baishunChannel.walletUpdate(payload);
|
|
}
|
|
})();
|
|
''';
|
|
}
|
|
}
|