M0: 引入桥 JS(T-M0-06)
- WebViewJavascriptBridge.js 原样复刻到 feature_bridge/src/main/resources/rawfile (与原 Android assets 去尾随空白后逐字一致,lzyzsd 协议 100% 复刻) - BridgeJsLoader:从 rawfile 读取桥 JS(getRawFileContentSync + TextDecoder)并缓存, 供 M1 BridgeController 在 onPageEnd 注入;HarmonyOS 走 runJavaScript 无需去注释 - 经 build smoke 验证 rawfile 读取 API 签名与编译通过 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f7f208e6c8
commit
f89275ea4b
@@ -1,3 +1,4 @@
|
|||||||
// feature_bridge HAR —— 桥引擎层(导出入口 SSOT)
|
// feature_bridge HAR —— 桥引擎层(框架 §5,100% 复刻 lzyzsd/JsBridge 协议)
|
||||||
// 各子模块实现完成后在此统一 export。占位常量确保 HAR 可编译。
|
// M0:桥 JS 读取器。M1 将补 BridgeController/MessageCodec/HandlerRegistry/IWebController。
|
||||||
export const feature_bridge_MODULE_VERSION: string = '1.0.0';
|
|
||||||
|
export { BridgeJsLoader, BRIDGE_JS_RAWFILE } from './src/main/ets/assets/BridgeJsLoader';
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* 桥 JS 读取器(《契约规范》§2.6,框架 §5.1)。
|
||||||
|
*
|
||||||
|
* 从 rawfile 读取 lzyzsd 原版 `WebViewJavascriptBridge.js`(与 Android 端逐字一致),
|
||||||
|
* 供 BridgeController 在 `Web().onPageEnd` 时 `runJavaScript` 注入,使
|
||||||
|
* `window.WebViewJavascriptBridge` 与 `WebViewJavascriptBridgeReady` 事件就绪。
|
||||||
|
*
|
||||||
|
* 注:原 Android 在注入前用正则去除以 `//` 开头的注释行(因 loadUrl("javascript:")
|
||||||
|
* 不支持注释);HarmonyOS 走 `runJavaScript`,对 `//` 注释无此限制,可直接注入原文。
|
||||||
|
* 首次读取后缓存,避免重复 IO。
|
||||||
|
*/
|
||||||
|
import { common } from '@kit.AbilityKit';
|
||||||
|
import { util } from '@kit.ArkTS';
|
||||||
|
|
||||||
|
/** rawfile 中的桥 JS 文件名。 */
|
||||||
|
export const BRIDGE_JS_RAWFILE: string = 'WebViewJavascriptBridge.js';
|
||||||
|
|
||||||
|
export class BridgeJsLoader {
|
||||||
|
private static cache: string | undefined = undefined;
|
||||||
|
|
||||||
|
/** 读取并缓存桥 JS 文本。context 取自容器(UIAbilityContext 等)。 */
|
||||||
|
static load(context: common.Context): string {
|
||||||
|
const cached: string | undefined = BridgeJsLoader.cache;
|
||||||
|
if (cached !== undefined) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
const bytes: Uint8Array = context.resourceManager.getRawFileContentSync(BRIDGE_JS_RAWFILE);
|
||||||
|
const text: string = util.TextDecoder.create('utf-8').decodeToString(bytes);
|
||||||
|
BridgeJsLoader.cache = text;
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
//notation: js file can only use this kind of comments
|
||||||
|
//since comments will cause error when use in webview.loadurl,
|
||||||
|
//comments will be remove by java use regexp
|
||||||
|
(function() {
|
||||||
|
if (window.WebViewJavascriptBridge) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var messagingIframe;
|
||||||
|
var sendMessageQueue = [];
|
||||||
|
var receiveMessageQueue = [];
|
||||||
|
var messageHandlers = {};
|
||||||
|
|
||||||
|
var CUSTOM_PROTOCOL_SCHEME = 'yy';
|
||||||
|
var QUEUE_HAS_MESSAGE = '__QUEUE_MESSAGE__/';
|
||||||
|
|
||||||
|
var responseCallbacks = {};
|
||||||
|
var uniqueId = 1;
|
||||||
|
|
||||||
|
// 创建队列iframe
|
||||||
|
function _createQueueReadyIframe(doc) {
|
||||||
|
messagingIframe = doc.createElement('iframe');
|
||||||
|
messagingIframe.style.display = 'none';
|
||||||
|
doc.documentElement.appendChild(messagingIframe);
|
||||||
|
}
|
||||||
|
|
||||||
|
//set default messageHandler 初始化默认的消息线程
|
||||||
|
function init(messageHandler) {
|
||||||
|
if (WebViewJavascriptBridge._messageHandler) {
|
||||||
|
throw new Error('WebViewJavascriptBridge.init called twice');
|
||||||
|
}
|
||||||
|
WebViewJavascriptBridge._messageHandler = messageHandler;
|
||||||
|
var receivedMessages = receiveMessageQueue;
|
||||||
|
receiveMessageQueue = null;
|
||||||
|
for (var i = 0; i < receivedMessages.length; i++) {
|
||||||
|
_dispatchMessageFromNative(receivedMessages[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
function send(data, responseCallback) {
|
||||||
|
_doSend({
|
||||||
|
data: data
|
||||||
|
}, responseCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册线程 往数组里面添加值
|
||||||
|
function registerHandler(handlerName, handler) {
|
||||||
|
messageHandlers[handlerName] = handler;
|
||||||
|
}
|
||||||
|
// 调用线程
|
||||||
|
function callHandler(handlerName, data, responseCallback) {
|
||||||
|
_doSend({
|
||||||
|
handlerName: handlerName,
|
||||||
|
data: data
|
||||||
|
}, responseCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
//sendMessage add message, 触发native处理 sendMessage
|
||||||
|
function _doSend(message, responseCallback) {
|
||||||
|
if (responseCallback) {
|
||||||
|
var callbackId = 'cb_' + (uniqueId++) + '_' + new Date().getTime();
|
||||||
|
responseCallbacks[callbackId] = responseCallback;
|
||||||
|
message.callbackId = callbackId;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessageQueue.push(message);
|
||||||
|
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提供给native调用,该函数作用:获取sendMessageQueue返回给native,由于android不能直接获取返回的内容,所以使用url shouldOverrideUrlLoading 的方式返回内容
|
||||||
|
function _fetchQueue() {
|
||||||
|
var messageQueueString = JSON.stringify(sendMessageQueue);
|
||||||
|
sendMessageQueue = [];
|
||||||
|
//android can't read directly the return data, so we can reload iframe src to communicate with java
|
||||||
|
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://return/_fetchQueue/' + encodeURIComponent(messageQueueString);
|
||||||
|
}
|
||||||
|
|
||||||
|
//提供给native使用,
|
||||||
|
function _dispatchMessageFromNative(messageJSON) {
|
||||||
|
setTimeout(function() {
|
||||||
|
var message = JSON.parse(messageJSON);
|
||||||
|
var responseCallback;
|
||||||
|
//java call finished, now need to call js callback function
|
||||||
|
if (message.responseId) {
|
||||||
|
responseCallback = responseCallbacks[message.responseId];
|
||||||
|
if (!responseCallback) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
responseCallback(message.responseData);
|
||||||
|
delete responseCallbacks[message.responseId];
|
||||||
|
} else {
|
||||||
|
//直接发送
|
||||||
|
if (message.callbackId) {
|
||||||
|
var callbackResponseId = message.callbackId;
|
||||||
|
responseCallback = function(responseData) {
|
||||||
|
_doSend({
|
||||||
|
responseId: callbackResponseId,
|
||||||
|
responseData: responseData
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var handler = WebViewJavascriptBridge._messageHandler;
|
||||||
|
if (message.handlerName) {
|
||||||
|
handler = messageHandlers[message.handlerName];
|
||||||
|
}
|
||||||
|
//查找指定handler
|
||||||
|
try {
|
||||||
|
handler(message.data, responseCallback);
|
||||||
|
} catch (exception) {
|
||||||
|
if (typeof console != 'undefined') {
|
||||||
|
console.log("WebViewJavascriptBridge: WARNING: javascript handler threw.", message, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//提供给native调用,receiveMessageQueue 在会在页面加载完后赋值为null,所以
|
||||||
|
function _handleMessageFromNative(messageJSON) {
|
||||||
|
console.log(messageJSON);
|
||||||
|
if (receiveMessageQueue) {
|
||||||
|
receiveMessageQueue.push(messageJSON);
|
||||||
|
}
|
||||||
|
_dispatchMessageFromNative(messageJSON);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var WebViewJavascriptBridge = window.WebViewJavascriptBridge = {
|
||||||
|
init: init,
|
||||||
|
send: send,
|
||||||
|
registerHandler: registerHandler,
|
||||||
|
callHandler: callHandler,
|
||||||
|
_fetchQueue: _fetchQueue,
|
||||||
|
_handleMessageFromNative: _handleMessageFromNative
|
||||||
|
};
|
||||||
|
|
||||||
|
var doc = document;
|
||||||
|
_createQueueReadyIframe(doc);
|
||||||
|
var readyEvent = doc.createEvent('Events');
|
||||||
|
readyEvent.initEvent('WebViewJavascriptBridgeReady');
|
||||||
|
readyEvent.bridge = WebViewJavascriptBridge;
|
||||||
|
doc.dispatchEvent(readyEvent);
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user