使用 WebViewBridge
从脚本调用JavaScript
import com.m8test.script.GlobalVariables.*
// ----------------------------------------------------
// 示例 3.1: 脚本调用JS (完整代码)
// ----------------------------------------------------
_console.info("\n--- 开始示例 3.1: 脚本调用JS ---")
// 1. 基础设置
val scope = _coroutines.newScope { setDispatcher { it.getIO() } }
val bridge = _webView.getBridge()
val controller = bridge.getController()
_activity.start()
// 2. 准备HTML
val html = """
<html><body>
<div id="message">...</div>
<script>
(function () {
function init() {
// ${'$'}webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
${'$'}webViewBridge.registerHandler("updateMessage", function (name, callback) {
// name 为脚本端调用处理器时传递过来的参数
// callback 用于返回处理结果到脚本端
if (callback) {
document.getElementById('message').innerText = '你好, ' + name + '!';
callback('JS已成功更新消息');
}
})
}
if (window.${'$'}webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
</script>
</body></html>
"""
// 3. 开始异步操作链
scope.delay(1000) // 关键延时:等待Activity和WebView初始化完成
.then { s, _ ->
controller.loadDataWithBaseURL(s, "https://native2js.test", html, null, null, "https://native2js.test")
}
.then { s, _ ->
_console.log("页面加载指令已发出,等待渲染...")
s.delay(1000)
}
.then { s, _ ->
bridge.callHandler("updateMessage", "\"M8Test\"") { result ->
_console.log("来自JS的回调:", result)
}
s.delay(500) // 等待JS执行和DOM更新
}
.then { s, _ ->
controller.getTextContent(s, "//*[@id='message']")
}
.then { s, message ->
_console.assertTrue(message.toString().contains("M8Test"), "JS函数调用验证失败")
_console.info("--- 示例 3.1: 成功 ---")
s.resolve(null)
}
.onError { e -> _console.error("--- 示例 3.1: 失败 ---", e.stackTraceToString()) }
// ----------------------------------------------------
// 示例 3.1: 脚本调用JS (完整代码)
// ----------------------------------------------------
$console.info("\n--- 开始示例 3.1: 脚本调用JS ---")
// 1. 基础设置
def scope = $coroutines.newScope { it.setDispatcher { it.getIO() } }
def bridge = $webView.getBridge()
def controller = bridge.getController()
$activity.start()
// 2. 准备HTML
def html = """
<html><body>
<div id="message">...</div>
<script>
(function () {
function init() {
// \$webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
\$webViewBridge.registerHandler("updateMessage", function (name, callback) {
// name 为脚本端调用处理器时传递过来的参数
// callback 用于返回处理结果到脚本端
if (callback) {
document.getElementById('message').innerText = '你好, ' + name + '!';
callback('JS已成功更新消息');
}
})
}
if (window.\$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
</script>
</body></html>
"""
// 3. 开始异步操作链
scope.delay(1000) // 关键延时:等待Activity和WebView初始化完成
.then { s, _ ->
return controller.loadDataWithBaseURL(s, "https://native2js.test", html, null, null, "https://native2js.test")
}
.then { s, _ ->
$console.log("页面加载指令已发出,等待渲染...")
return s.delay(1000)
}
.then { s, _ ->
bridge.callHandler("updateMessage", '"M8Test"') { result ->
$console.log("来自JS的回调:", result)
}
return s.delay(500) // 等待JS执行和DOM更新
}
.then { s, _ ->
return controller.getTextContent(s, "//*[@id='message']")
}
.then { s, message ->
$console.assertTrue(message.contains("M8Test"), "JS函数调用验证失败")
$console.info("--- 示例 3.1: 成功 ---")
return s.resolve(null)
}
.onError { e -> $console.error("--- 示例 3.1: 失败 ---", e.stackTraceToString()) }
// ----------------------------------------------------
// 示例 3.1: 脚本调用JS (完整代码)
// ----------------------------------------------------
$console.info("\n--- 开始示例 3.1: 脚本调用JS ---");
// 1. 基础设置
const scope = $coroutines.newScope(it => it.setDispatcher(it => it.getIO()));
const bridge = $webView.getBridge();
const controller = bridge.getController();
$activity.start();
// 2. 准备HTML
const html = `
<html><body>
<div id="message">...</div>
<script>
(function () {
function init() {
// \$webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
\$webViewBridge.registerHandler("updateMessage", function (name, callback) {
// name 为脚本端调用处理器时传递过来的参数
// callback 用于返回处理结果到脚本端
if (callback) {
document.getElementById('message').innerText = '你好, ' + name + '!';
callback('JS已成功更新消息');
}
})
}
if (window.\$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
</script>
</body></html>
`;
// 3. 开始异步操作链
scope.delay(1000) // 关键延时:等待Activity和WebView初始化完成
.then((s, _) => {
return controller.loadDataWithBaseURL(s, "https://native2js.test", html, null, null, "https://native2js.test");
})
.then((s, _) => {
$console.log("页面加载指令已发出,等待渲染...");
return s.delay(1000);
})
.then((s, _) => {
bridge.callHandler("updateMessage", '"M8Test"', result => {
$console.log("来自JS的回调:", result);
});
return s.delay(500); // 等待JS执行和DOM更新
})
.then((s, _) => {
return controller.getTextContent(s, "//*[@id='message']");
})
.then((s, message) => {
$console.assertTrue(message.includes("M8Test"), "JS函数调用验证失败");
$console.info("--- 示例 3.1: 成功 ---");
return s.resolve(null);
})
.onError(e => $console.error("--- 示例 3.1: 失败 ---", e.stackTraceToString()));
-- ----------------------------------------------------
-- 示例 3.1: 脚本调用JS (完整代码)
-- ----------------------------------------------------
_console:info("\n--- 开始示例 3.1: 脚本调用JS ---")
-- 1. 基础设置
local scope = _coroutines:newScope(function(it) it:setDispatcher(function(it) return it:getIO() end) end)
local bridge = _webView:getBridge()
local controller = bridge:getController()
_activity:start()
-- 2. 准备HTML
local html = [[
<html><body>
<div id="message">...</div>
<script>
(function () {
function init() {
// $webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
$webViewBridge.registerHandler("updateMessage", function (name, callback) {
// name 为脚本端调用处理器时传递过来的参数
// callback 用于返回处理结果到脚本端
if (callback) {
document.getElementById('message').innerText = '你好, ' + name + '!';
callback('JS已成功更新消息');
}
})
}
if (window.$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
</script>
</body></html>
]]
-- 3. 开始异步操作链
scope:delay(1000) -- 关键延时:等待Activity和WebView初始化完成
:_then(function(s, _)
return controller:loadDataWithBaseURL(s, "https://native2js.test", html, nil, nil, "https://native2js.test")
end)
:_then(function(s, _)
_console:log("页面加载指令已发出,等待渲染...")
return s:delay(1000)
end)
:_then(function(s, _)
bridge:callHandler("updateMessage", '"M8Test"', function(result)
_console:log("来自JS的回调:", result)
end)
return s:delay(500) -- 等待JS执行和DOM更新
end)
:_then(function(s, _)
return controller:getTextContent(s, "//*[@id='message']")
end)
:_then(function(s, message)
-- 修复: 1. 检查 message 是否为 nil. 2. 使用 string.find 替代 :contains
_console:assertTrue(message and string.find(message, "M8Test"), "JS函数调用验证失败")
_console:info("--- 示例 3.1: 成功 ---")
return s:resolve(nil)
end)
:onError(function(e) _console:error("--- 示例 3.1: 失败 ---", e:stackTraceToString()) end)
<?php
/** @var m8test_java\com\m8test\script\core\api\console\Console $console */
global $console;
/** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */
global $coroutines;
/** @var m8test_java\com\m8test\script\core\api\ui\webview\WebView $webView */
global $webView;
/** @var m8test_java\com\m8test\script\core\api\ui\Activity $activity */
global $activity;
/** @var m8test_java\com\m8test\script\core\api\resource\StringResources $strings */
global $strings;
// ----------------------------------------------------
// 示例 3.1: 脚本调用JS (完整代码)
// ----------------------------------------------------
$console->info(javaString("\n--- 开始示例 3.1: 脚本调用JS ---"));
// 1. 基础设置
$scope = $coroutines->newScope(function ($it) {
$it->setDispatcher(function ($dispatchers) {
return $dispatchers->getScriptMain();
});
});
$bridge = $webView->getBridge();
$controller = $bridge->getController();
$activity->start();
// 2. 准备HTML
$html = <<<HTML
<html><body>
<div id="message">...</div>
<script>
(function () {
function init() {
// \$webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
\$webViewBridge.registerHandler("updateMessage", function (name, callback) {
// name 为脚本端调用处理器时传递过来的参数
// callback 用于返回处理结果到脚本端
if (callback) {
document.getElementById('message').innerText = '你好, ' + name + '!';
callback('JS已成功更新消息');
}
})
}
if (window.\$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
</script>
</body></html>
HTML;
// 3. 开始异步操作链
$scope->delay(1000) // 关键延时:等待Activity和WebView初始化完成
->then(function ($s, $unused) use ($controller, $html) {
return $controller->loadDataWithBaseURL($s, javaString("https://native2js.test"), javaString($html), null, null, javaString("https://native2js.test"));
})
->then(function ($s, $unused) {
global $console;
$console->log(javaString("页面加载指令已发出,等待渲染..."));
return $s->delay(1000);
})
->then(function ($s, $unused) use ($bridge) {
$bridge->callHandler(javaString("updateMessage"), javaString('"M8Test"'), function ($result) {
global $console;
$console->log(javaString("来自JS的回调:"), $result);
});
return $s->delay(500); // 等待JS执行和DOM更新
})
->then(function ($s, $unused) use ($controller) {
return $controller->getTextContent($s, javaString("//*[@id='message']"));
})
->then(function ($s, $message) {
global $console, $strings;
$console->assertTrue($strings->contains($message, javaString("M8Test")), javaString("JS函数调用验证失败"));
$console->info(javaString("--- 示例 3.1: 成功 ---"));
return $s->resolve(null);
})
->onError(function ($e) {
global $console;
$console->error(javaString("--- 示例 3.1: 失败 ---"), $e->stackTraceToString());
});
# ----------------------------------------------------
# 示例 3.1: 脚本调用JS (完整代码)
# ----------------------------------------------------
# 导入所需的全局变量
from m8test_java.com.m8test.script.GlobalVariables import _console
from m8test_java.com.m8test.script.GlobalVariables import _coroutines
from m8test_java.com.m8test.script.GlobalVariables import _webView
from m8test_java.com.m8test.script.GlobalVariables import _activity
_console.info("\n--- 开始示例 3.1: 脚本调用JS ---")
# 1. 基础设置
# 【已修正】: 使用 getScriptMain()
scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain()))
bridge = _webView.getBridge()
controller = bridge.getController()
_activity.start()
# 2. 准备HTML
html = """
<html><body>
<div id="message">...</div>
<script>
(function () {
function init() {
// $webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
$webViewBridge.registerHandler("updateMessage", function (name, callback) {
// name 为脚本端调用处理器时传递过来的参数
// callback 用于返回处理结果到脚本端
if (callback) {
document.getElementById('message').innerText = '你好, ' + name + '!';
callback('JS已成功更新消息');
}
})
}
if (window.$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
</script>
</body></html>
"""
# 3. 开始异步操作链
scope.delay(1000).then(lambda s, _:
controller.loadDataWithBaseURL(s, "https://native2js.test", html, None, None, "https://native2js.test")
).then(lambda s, _: (
_console.log("页面加载指令已发出,等待渲染..."),
s.delay(1000)
)[-1]).then(lambda s, _: (
# Groovy's trailing closure is converted to a positional lambda argument
bridge.callHandler("updateMessage", '"M8Test"', lambda result:
_console.log("来自JS的回调:", str(result))
),
s.delay(500) # 等待JS执行和DOM更新
)[-1]).then(lambda s, _:
controller.getTextContent(s, "//*[@id='message']")
).then(lambda s, message: (
_console.assertTrue("M8Test" in str(message), "JS函数调用验证失败"),
_console.info("--- 示例 3.1: 成功 ---"),
s.resolve(None)
)[-1]).onError(lambda e:
_console.error("--- 示例 3.1: 失败 ---", e.stackTraceToString())
)
# encoding: utf-8
# ----------------------------------------------------
# 示例 3.1: 脚本调用JS (完整代码)
# ----------------------------------------------------
$console.info("\n--- 开始示例 3.1: 脚本调用JS ---")
# 1. 基础设置
scope = $coroutines.newScope { |it| it.setDispatcher { |d| d.getIO() } }
bridge = $webView.getBridge()
controller = bridge.getController()
$activity.start()
# 2. 准备HTML
html = <<-HTML
<html><body>
<div id="message">...</div>
<script>
(function () {
function init() {
// $webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
$webViewBridge.registerHandler("updateMessage", function (name, callback) {
// name 为脚本端调用处理器时传递过来的参数
// callback 用于返回处理结果到脚本端
if (callback) {
document.getElementById('message').innerText = '你好, ' + name + '!';
callback('JS已成功更新消息');
}
})
}
if (window.$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
</script>
</body></html>
HTML
# 3. 开始异步操作链
scope.delay(1000). # 关键延时:等待Activity和WebView初始化完成
then { |s, _|
controller.loadDataWithBaseURL(s, "https://native2js.test", html, nil, nil, "https://native2js.test")
}.
then { |s, _|
$console.log("页面加载指令已发出,等待渲染...")
s.delay(1000)
}.
then { |s, _|
bridge.callHandler("updateMessage", '"M8Test"') { |result|
$console.log("来自JS的回调:", result)
}
s.delay(500) # 等待JS执行和DOM更新
}.
then { |s, _|
controller.getTextContent(s, "//*[@id='message']")
}.
then { |s, message|
$console.assertTrue(message.include?("M8Test"), "JS函数调用验证失败")
$console.info("--- 示例 3.1: 成功 ---")
s.resolve(nil)
}.
onError { |e| $console.error("--- 示例 3.1: 失败 ---", e.to_s) }
从JavaScript调用脚本
import com.m8test.script.GlobalVariables.*
// ----------------------------------------------------
// 示例 3.2: JS调用脚本 (完整代码)
// ----------------------------------------------------
_console.info("\n--- 开始示例 3.2: JS调用脚本 ---")
// 1. 基础设置
val scope = _coroutines.newScope { setDispatcher { it.getIO() } }
val bridge = _webView.getBridge()
val controller = bridge.getController()
_activity.start()
// 2. 同步注册处理器
bridge.registerHandler("getDeviceInfo") { params ->
_console.log("JS调用了 getDeviceInfo, 参数:", params)
"{\"platform\": \"Android\"}"
}
// 3. 准备HTML
val html = """
<html><body>
<div id="device-info"></div>
<script>
setTimeout(function() {
window.WebViewJavascriptBridge.callHandler('getDeviceInfo', null, function(info) {
var data = JSON.parse(info);
document.getElementById('device-info').innerText = '平台: ' + data.platform;
});
}, 1000);
</script>
</body></html>
"""
// 4. 开始异步操作链
scope.delay(1000) // 关键延时:等待Activity和WebView初始化完成
.then { s, _ ->
controller.loadDataWithBaseURL(s, "https://js2native.test", html, null, null, "https://js2native.test")
}
.then { s, _ ->
// 等待页面加载和JS中的setTimeout执行
s.delay(2000)
}
.then { s, _ ->
controller.getTextContent(s, "//*[@id='device-info']")
}
.then { s, infoText ->
_console.log("页面显示的设备信息:", infoText)
_console.assertTrue(infoText.toString().contains("Android"), "JS调用脚本验证失败")
_console.info("--- 示例 3.2: 成功 ---")
s.resolve(null)
}
.onComplete { bridge.unregisterHandler("getDeviceInfo") }
.onError { e -> _console.error("--- 示例 3.2: 失败 ---", e.stackTraceToString()) }
// ----------------------------------------------------
// 示例 3.2: JS调用脚本 (完整代码)
// ----------------------------------------------------
$console.info("\n--- 开始示例 3.2: JS调用脚本 ---")
// 1. 基础设置
def scope = $coroutines.newScope { it.setDispatcher { it.getIO() } }
def bridge = $webView.getBridge()
def controller = bridge.getController()
$activity.start()
// 2. 同步注册处理器
bridge.registerHandler("getDeviceInfo") { params ->
$console.log("JS调用了 getDeviceInfo, 参数:", params)
return '{"platform": "Android"}'
}
// 3. 准备HTML
def html = """
<html><body>
<div id="device-info"></div>
<script>
setTimeout(function() {
window.WebViewJavascriptBridge.callHandler('getDeviceInfo', null, function(info) {
var data = JSON.parse(info);
document.getElementById('device-info').innerText = '平台: ' + data.platform;
});
}, 1000);
</script>
</body></html>
"""
// 4. 开始异步操作链
scope.delay(1000) // 关键延时:等待Activity和WebView初始化完成
.then { s, _ ->
return controller.loadDataWithBaseURL(s, "https://js2native.test", html, null, null, "https://js2native.test")
}
.then { s, _ ->
// 等待页面加载和JS中的setTimeout执行
return s.delay(2000)
}
.then { s, _ ->
return controller.getTextContent(s, "//*[@id='device-info']")
}
.then { s, infoText ->
$console.log("页面显示的设备信息:", infoText)
$console.assertTrue(infoText.contains("Android"), "JS调用脚本验证失败")
$console.info("--- 示例 3.2: 成功 ---")
return s.resolve(null)
}
.onComplete { bridge.unregisterHandler("getDeviceInfo") }
.onError { e -> $console.error("--- 示例 3.2: 失败 ---", e.stackTraceToString()) }
// ----------------------------------------------------
// 示例 3.2: JS调用脚本 (完整代码)
// ----------------------------------------------------
$console.info("\n--- 开始示例 3.2: JS调用脚本 ---");
// 1. 基础设置
const scope = $coroutines.newScope(it => it.setDispatcher(it => it.getIO()));
const bridge = $webView.getBridge();
const controller = bridge.getController();
$activity.start();
// 2. 同步注册处理器
bridge.registerHandler("getDeviceInfo", params => {
$console.log("JS调用了 getDeviceInfo, 参数:", params);
return '{"platform": "Android"}';
});
// 3. 准备HTML
const html = `
<html><body>
<div id="device-info"></div>
<script>
setTimeout(function() {
window.WebViewJavascriptBridge.callHandler('getDeviceInfo', null, function(info) {
var data = JSON.parse(info);
document.getElementById('device-info').innerText = '平台: ' + data.platform;
});
}, 1000);
</script>
</body></html>
`;
// 4. 开始异步操作链
scope.delay(1000) // 关键延时:等待Activity和WebView初始化完成
.then((s, _) => {
return controller.loadDataWithBaseURL(s, "https://js2native.test", html, null, null, "https://js2native.test");
})
.then((s, _) => {
// 等待页面加载和JS中的setTimeout执行
return s.delay(2000);
})
.then((s, _) => {
return controller.getTextContent(s, "//*[@id='device-info']");
})
.then((s, infoText) => {
$console.log("页面显示的设备信息:", infoText);
$console.assertTrue(infoText.includes("Android"), "JS调用脚本验证失败");
$console.info("--- 示例 3.2: 成功 ---");
return s.resolve(null);
})
.onComplete(() => bridge.unregisterHandler("getDeviceInfo"))
.onError(e => $console.error("--- 示例 3.2: 失败 ---", e.stackTraceToString()));
-- ----------------------------------------------------
-- 示例 3.2: JS调用脚本 (完整代码)
-- ----------------------------------------------------
_console:info("\n--- 开始示例 3.2: JS调用脚本 ---")
-- 1. 基础设置
local scope = _coroutines:newScope(function(it) it:setDispatcher(function(it) return it:getIO() end) end)
local bridge = _webView:getBridge()
local controller = bridge:getController()
_activity:start()
-- 2. 同步注册处理器
bridge:registerHandler("getDeviceInfo", function(params)
_console:log("JS调用了 getDeviceInfo, 参数:", params)
return '{"platform": "Android"}'
end)
-- 3. 准备HTML
local html = [[
<html><body>
<div id="device-info"></div>
<script>
setTimeout(function() {
window.WebViewJavascriptBridge.callHandler('getDeviceInfo', null, function(info) {
var data = JSON.parse(info);
document.getElementById('device-info').innerText = '平台: ' + data.platform;
});
}, 1000);
</script>
</body></html>
]]
-- 4. 开始异步操作链
scope:delay(1000) -- 关键延时:等待Activity和WebView初始化完成
:_then(function(s, _)
return controller:loadDataWithBaseURL(s, "https://js2native.test", html, nil, nil, "https://js2native.test")
end)
:_then(function(s, _)
-- 等待页面加载和JS中的setTimeout执行
return s:delay(2000)
end)
:_then(function(s, _)
return controller:getTextContent(s, "//*[@id='device-info']")
end)
:_then(function(s, infoText)
_console:log("页面显示的设备信息:", infoText)
-- [修正]
_console:assertTrue(_strings:contains(infoText, "Android"), "JS调用脚本验证失败")
_console:info("--- 示例 3.2: 成功 ---")
return s:resolve(nil)
end)
:onComplete(function() bridge:unregisterHandler("getDeviceInfo") end)
:onError(function(e) _console:error("--- 示例 3.2: 失败 ---", e:stackTraceToString()) end)
<?php
/** @var m8test_java\com\m8test\script\core\api\console\Console $console */
global $console;
/** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */
global $coroutines;
/** @var m8test_java\com\m8test\script\core\api\ui\webview\WebView $webView */
global $webView;
/** @var m8test_java\com\m8test\script\core\api\ui\Activity $activity */
global $activity;
/** @var m8test_java\com\m8test\script\core\api\resource\StringResources $strings */
global $strings;
// ----------------------------------------------------
// 示例 3.2: JS调用脚本 (完整代码)
// ----------------------------------------------------
$console->info(javaString("\n--- 开始示例 3.2: JS调用脚本 ---"));
// 1. 基础设置
$scope = $coroutines->newScope(function ($it) {
$it->setDispatcher(function ($dispatchers) {
return $dispatchers->getScriptMain();
});
});
$bridge = $webView->getBridge();
$controller = $bridge->getController();
$activity->start();
// 2. 同步注册处理器
$bridge->registerHandler(javaString("getDeviceInfo"), function ($params) {
global $console;
$console->log(javaString("JS调用了 getDeviceInfo, 参数:"), $params);
return javaString('{"platform": "Android"}');
});
// 3. 准备HTML
$html = <<<HTML
<html><body>
<div id="device-info"></div>
<script>
setTimeout(function() {
window.WebViewJavascriptBridge.callHandler('getDeviceInfo', null, function(info) {
var data = JSON.parse(info);
document.getElementById('device-info').innerText = '平台: ' + data.platform;
});
}, 1000);
</script>
</body></html>
HTML;
// 4. 开始异步操作链
$scope->delay(1000) // 关键延时:等待Activity和WebView初始化完成
->then(function ($s, $unused) use ($controller, $html) {
return $controller->loadDataWithBaseURL($s, javaString("https://js2native.test"), javaString($html), null, null, javaString("https://js2native.test"));
})
->then(function ($s, $unused) {
// 等待页面加载和JS中的setTimeout执行
return $s->delay(2000);
})
->then(function ($s, $unused) use ($controller) {
return $controller->getTextContent($s, javaString("//*[@id='device-info']"));
})
->then(function ($s, $infoText) {
global $console, $strings;
$console->log(javaString("页面显示的设备信息:"), $infoText);
$console->assertTrue($strings->contains($infoText, javaString("Android")), javaString("JS调用脚本验证失败"));
$console->info(javaString("--- 示例 3.2: 成功 ---"));
return $s->resolve(null);
})
->onComplete(function () use ($bridge) {
$bridge->unregisterHandler(javaString("getDeviceInfo"));
})
->onError(function ($e) {
global $console;
$console->error(javaString("--- 示例 3.2: 失败 ---"), $e->stackTraceToString());
});
# ----------------------------------------------------
# 示例 3.2: JS调用脚本 (完整代码)
# ----------------------------------------------------
# 导入所需的全局变量
from m8test_java.com.m8test.script.GlobalVariables import _console
from m8test_java.com.m8test.script.GlobalVariables import _coroutines
from m8test_java.com.m8test.script.GlobalVariables import _webView
from m8test_java.com.m8test.script.GlobalVariables import _activity
_console.info("\n--- 开始示例 3.2: JS调用脚本 ---")
# 1. 基础设置
# 【已修正】: 使用 getScriptMain()
scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain()))
bridge = _webView.getBridge()
controller = bridge.getController()
_activity.start()
# 2. 同步注册处理器
bridge.registerHandler("getDeviceInfo", lambda params: (
_console.log("JS调用了 getDeviceInfo, 参数:", str(params)),
'{"platform": "Android"}'
)[-1])
# 3. 准备HTML
html = """
<html><body>
<div id="device-info"></div>
<script>
setTimeout(function() {
window.WebViewJavascriptBridge.callHandler('getDeviceInfo', null, function(info) {
var data = JSON.parse(info);
document.getElementById('device-info').innerText = '平台: ' + data.platform;
});
}, 1000);
</script>
</body></html>
"""
# 4. 开始异步操作链
scope.delay(1000).then(lambda s, _:
controller.loadDataWithBaseURL(s, "https://js2native.test", html, None, None, "https://js2native.test")
).then(lambda s, _:
# 等待页面加载和JS中的setTimeout执行
s.delay(2000)
).then(lambda s, _:
controller.getTextContent(s, "//*[@id='device-info']")
).then(lambda s, infoText: (
_console.log("页面显示的设备信息:", str(infoText)),
_console.assertTrue("Android" in str(infoText), "JS调用脚本验证失败"),
_console.info("--- 示例 3.2: 成功 ---"),
s.resolve(None)
)[-1]).onComplete(lambda:
bridge.unregisterHandler("getDeviceInfo")
).onError(lambda e:
_console.error("--- 示例 3.2: 失败 ---", e.stackTraceToString())
)
# encoding: utf-8
# ----------------------------------------------------
# 示例 3.2: JS调用脚本 (完整代码)
# ----------------------------------------------------
$console.info("\n--- 开始示例 3.2: JS调用脚本 ---")
# 1. 基础设置
scope = $coroutines.newScope { |it| it.setDispatcher { |d| d.getIO() } }
bridge = $webView.getBridge()
controller = bridge.getController()
$activity.start()
# 2. 同步注册处理器
bridge.registerHandler("getDeviceInfo") { |params|
$console.log("JS调用了 getDeviceInfo, 参数:", params)
'{"platform": "Android"}'
}
# 3. 准备HTML
html = <<-HTML
<html><body>
<div id="device-info"></div>
<script>
setTimeout(function() {
window.WebViewJavascriptBridge.callHandler('getDeviceInfo', null, function(info) {
var data = JSON.parse(info);
document.getElementById('device-info').innerText = '平台: ' + data.platform;
});
}, 1000);
</script>
</body></html>
HTML
# 4. 开始异步操作链
scope.delay(1000). # 关键延时:等待Activity和WebView初始化完成
then { |s, _|
controller.loadDataWithBaseURL(s, "https://js2native.test", html, nil, nil, "https://js2native.test")
}.
then { |s, _|
# 等待页面加载和JS中的setTimeout执行
s.delay(2000)
}.
then { |s, _|
controller.getTextContent(s, "//*[@id='device-info']")
}.
then { |s, info_text|
$console.log("页面显示的设备信息:", info_text)
$console.assertTrue(info_text.include?("Android"), "JS调用脚本验证失败")
$console.info("--- 示例 3.2: 成功 ---")
s.resolve(nil)
}.
onComplete { bridge.unregisterHandler("getDeviceInfo") }.
onError { |e| $console.error("--- 示例 3.2: 失败 ---", e.to_s) }
直接执行JavaScript代码
import com.m8test.script.GlobalVariables.*
// ----------------------------------------------------
// 示例 3.3: 直接执行JS (完整代码)
// ----------------------------------------------------
_console.info("\n--- 开始示例 3.3: 直接执行JS ---")
// 1. 基础设置
val scope = _coroutines.newScope { setDispatcher { it.getIO() } }
val bridge = _webView.getBridge()
val controller = bridge.getController()
_activity.start()
// 2. 准备HTML和JS脚本
val html = """<html><body><h1 id="title">旧标题</h1></body></html>"""
val script = "document.getElementById('title').innerText = '新标题';"
// 3. 开始异步操作链
scope.delay(1000) // 关键延时:等待Activity和WebView初始化完成
.then { s, _ ->
controller.loadDataWithBaseURL(s, "https://eval.test", html, null, null, "https://eval.test")
}
.then { s, _ ->
_console.log("页面加载指令已发出,等待渲染完成...")
s.delay(1000)
}
.then { s, _ ->
bridge.evaluateJsString(script, true, null)
s.delay(500) // 等待JS执行完毕
}
.then { s, _ ->
controller.getTextContent(s, "//*[@id='title']")
}
.then { s, newTitle ->
_console.log("执行JS后的标题:", newTitle)
_console.assertTrue(newTitle == "新标题", "evaluateJsString 验证失败")
_console.info("--- 示例 3.3: 成功 ---")
s.resolve(null)
}
.onError { e -> _console.error("--- 示例 3.3: 失败 ---", e.stackTraceToString()) }
// ----------------------------------------------------
// 示例 3.3: 直接执行JS (完整代码)
// ----------------------------------------------------
$console.info("\n--- 开始示例 3.3: 直接执行JS ---")
// 1. 基础设置
def scope = $coroutines.newScope { it.setDispatcher { it.getIO() } }
def bridge = $webView.getBridge()
def controller = bridge.getController()
$activity.start()
// 2. 准备HTML和JS脚本
def html = """<html><body><h1 id="title">旧标题</h1></body></html>"""
def script = "document.getElementById('title').innerText = '新标题';"
// 3. 开始异步操作链
scope.delay(1000) // 关键延时:等待Activity和WebView初始化完成
.then { s, _ ->
return controller.loadDataWithBaseURL(s, "https://eval.test", html, null, null, "https://eval.test")
}
.then { s, _ ->
$console.log("页面加载指令已发出,等待渲染完成...")
return s.delay(1000)
}
.then { s, _ ->
bridge.evaluateJsString(script, true, null)
return s.delay(500) // 等待JS执行完毕
}
.then { s, _ ->
return controller.getTextContent(s, "//*[@id='title']")
}
.then { s, newTitle ->
$console.log("执行JS后的标题:", newTitle)
$console.assertTrue(newTitle == "新标题", "evaluateJsString 验证失败")
$console.info("--- 示例 3.3: 成功 ---")
return s.resolve(null)
}
.onError { e -> $console.error("--- 示例 3.3: 失败 ---", e.stackTraceToString()) }
// ----------------------------------------------------
// 示例 3.3: 直接执行JS (完整代码)
// ----------------------------------------------------
$console.info("\n--- 开始示例 3.3: 直接执行JS ---");
// 1. 基础设置
const scope = $coroutines.newScope(it => it.setDispatcher(it => it.getIO()));
const bridge = $webView.getBridge();
const controller = bridge.getController();
$activity.start();
// 2. 准备HTML和JS脚本
const html = `<html><body><h1 id="title">旧标题</h1></body></html>`;
const script = "document.getElementById('title').innerText = '新标题';";
// 3. 开始异步操作链
scope.delay(1000) // 关键延时:等待Activity和WebView初始化完成
.then((s, _) => {
return controller.loadDataWithBaseURL(s, "https://eval.test", html, null, null, "https://eval.test");
})
.then((s, _) => {
$console.log("页面加载指令已发出,等待渲染完成...");
return s.delay(1000);
})
.then((s, _) => {
bridge.evaluateJsString(script, true, null);
return s.delay(500); // 等待JS执行完毕
})
.then((s, _) => {
return controller.getTextContent(s, "//*[@id='title']");
})
.then((s, newTitle) => {
$console.log("执行JS后的标题:", newTitle);
$console.assertTrue(newTitle == "新标题", "evaluateJsString 验证失败");
$console.info("--- 示例 3.3: 成功 ---");
return s.resolve(null);
})
.onError(e => $console.error("--- 示例 3.3: 失败 ---", e.stackTraceToString()));
-- ----------------------------------------------------
-- 示例 3.3: 直接执行JS (完整代码)
-- ----------------------------------------------------
_console:info("\n--- 开始示例 3.3: 直接执行JS ---")
-- 1. 基础设置
local scope = _coroutines:newScope(function(it) it:setDispatcher(function(it) return it:getIO() end) end)
local bridge = _webView:getBridge()
local controller = bridge:getController()
_activity:start()
-- 2. 准备HTML和JS脚本
local html = [[<html><body><h1 id="title">旧标题</h1></body></html>]]
local script = "document.getElementById('title').innerText = '新标题';"
-- 3. 开始异步操作链
scope:delay(1000) -- 关键延时:等待Activity和WebView初始化完成
:_then(function(s, _)
return controller:loadDataWithBaseURL(s, "https://eval.test", html, nil, nil, "https://eval.test")
end)
:_then(function(s, _)
_console:log("页面加载指令已发出,等待渲染完成...")
return s:delay(1000)
end)
:_then(function(s, _)
bridge:evaluateJsString(script, true, nil)
return s:delay(500) -- 等待JS执行完毕
end)
:_then(function(s, _)
return controller:getTextContent(s, "//*[@id='title']")
end)
:_then(function(s, newTitle)
_console:log("执行JS后的标题:", newTitle)
_console:assertTrue(newTitle == "新标题", "evaluateJsString 验证失败")
_console:info("--- 示例 3.3: 成功 ---")
return s:resolve(nil)
end)
:onError(function(e) _console:error("--- 示例 3.3: 失败 ---", e:stackTraceToString()) end)
<?php
/** @var m8test_java\com\m8test\script\core\api\console\Console $console */
global $console;
/** @var m8test_java\com\m8test\script\core\api\coroutines\Coroutines $coroutines */
global $coroutines;
/** @var m8test_java\com\m8test\script\core\api\ui\webview\WebView $webView */
global $webView;
/** @var m8test_java\com\m8test\script\core\api\ui\Activity $activity */
global $activity;
// ----------------------------------------------------
// 示例 3.3: 直接执行JS (完整代码)
// ----------------------------------------------------
$console->info(javaString("\n--- 开始示例 3.3: 直接执行JS ---"));
// 1. 基础设置
$scope = $coroutines->newScope(function ($it) {
$it->setDispatcher(function ($dispatchers) {
return $dispatchers->getScriptMain();
});
});
$bridge = $webView->getBridge();
$controller = $bridge->getController();
$activity->start();
// 2. 准备HTML和JS脚本
$html = "<html><body><h1 id=\"title\">旧标题</h1></body></html>";
$script = "document.getElementById('title').innerText = '新标题';";
// 3. 开始异步操作链
$scope->delay(1000) // 关键延时:等待Activity和WebView初始化完成
->then(function ($s, $unused) use ($controller, $html) {
return $controller->loadDataWithBaseURL($s, javaString("https://eval.test"), javaString($html), null, null, javaString("https://eval.test"));
})
->then(function ($s, $unused) {
global $console;
$console->log(javaString("页面加载指令已发出,等待渲染完成..."));
return $s->delay(1000);
})
->then(function ($s, $unused) use ($bridge, $script) {
$bridge->evaluateJsString(javaString($script), true, null);
return $s->delay(500); // 等待JS执行完毕
})
->then(function ($s, $unused) use ($controller) {
return $controller->getTextContent($s, javaString("//*[@id='title']"));
})
->then(function ($s, $newTitle) {
global $console;
$console->log(javaString("执行JS后的标题:"), $newTitle);
$console->assertTrue($newTitle == javaString("新标题"), javaString("evaluateJsString 验证失败"));
$console->info(javaString("--- 示例 3.3: 成功 ---"));
return $s->resolve(null);
})
->onError(function ($e) {
global $console;
$console->error(javaString("--- 示例 3.3: 失败 ---"), $e->stackTraceToString());
});
# ----------------------------------------------------
# 示例 3.3: 直接执行JS (完整代码)
# ----------------------------------------------------
# 导入所需的全局变量
from m8test_java.com.m8test.script.GlobalVariables import _console
from m8test_java.com.m8test.script.GlobalVariables import _coroutines
from m8test_java.com.m8test.script.GlobalVariables import _webView
from m8test_java.com.m8test.script.GlobalVariables import _activity
_console.info("\n--- 开始示例 3.3: 直接执行JS ---")
# 1. 基础设置
# 【已修正】: 使用 getScriptMain()
scope = _coroutines.newScope(lambda it: it.setDispatcher(lambda d: d.getScriptMain()))
bridge = _webView.getBridge()
controller = bridge.getController()
_activity.start()
# 2. 准备HTML和JS脚本
html = """<html><body><h1 id="title">旧标题</h1></body></html>"""
script = "document.getElementById('title').innerText = '新标题';"
# 3. 开始异步操作链
scope.delay(1000).then(lambda s, _:
controller.loadDataWithBaseURL(s, "https://eval.test", html, None, None, "https://eval.test")
).then(lambda s, _: (
_console.log("页面加载指令已发出,等待渲染完成..."),
s.delay(1000)
)[-1]).then(lambda s, _: (
bridge.evaluateJsString(script, True, None),
s.delay(500) # 等待JS执行完毕
)[-1]).then(lambda s, _:
controller.getTextContent(s, "//*[@id='title']")
).then(lambda s, newTitle: (
_console.log("执行JS后的标题:", str(newTitle)),
_console.assertTrue(newTitle == "新标题", "evaluateJsString 验证失败"),
_console.info("--- 示例 3.3: 成功 ---"),
s.resolve(None)
)[-1]).onError(lambda e:
_console.error("--- 示例 3.3: 失败 ---", e.stackTraceToString())
)
# encoding: utf-8
# ----------------------------------------------------
# 示例 3.3: 直接执行JS (完整代码)
# ----------------------------------------------------
$console.info("\n--- 开始示例 3.3: 直接执行JS ---")
# 1. 基础设置
scope = $coroutines.newScope { |it| it.setDispatcher { |d| d.getIO() } }
bridge = $webView.getBridge()
controller = bridge.getController()
$activity.start()
# 2. 准备HTML和JS脚本
html = %Q{<html><body><h1 id="title">旧标题</h1></body></html>}
script = "document.getElementById('title').innerText = '新标题';"
# 3. 开始异步操作链
scope.delay(1000). # 关键延时:等待Activity和WebView初始化完成
then { |s, _|
controller.loadDataWithBaseURL(s, "https://eval.test", html, nil, nil, "https://eval.test")
}.
then { |s, _|
$console.log("页面加载指令已发出,等待渲染完成...")
s.delay(1000)
}.
then { |s, _|
bridge.evaluateJsString(script, true, nil)
s.delay(500) # 等待JS执行完毕
}.
then { |s, _|
controller.getTextContent(s, "//*[@id='title']")
}.
then { |s, new_title|
$console.log("执行JS后的标题:", new_title)
$console.assertTrue(new_title == "新标题", "evaluateJsString 验证失败")
$console.info("--- 示例 3.3: 成功 ---")
s.resolve(nil)
}.
onError { |e| $console.error("--- 示例 3.3: 失败 ---", e.to_s) }
09 December 2025