开发项目
本页面介绍如何一步一步开发一个M8Test脚本项目.
创建文件
settings.config.yaml
文件, 内容如下
language:
name: "Kotlin"
url: "https://github.com/m8test/language-release/releases/download/kotlin-0.1.0/com.m8test.kotlin-release_0.1.0.apk"
version: "0.1.0"
tip
language:
name: "Groovy"
url: "https://github.com/m8test/language-release/releases/download/groovy-0.1.0/com.m8test.groovy-release_0.1.0.apk"
version: "0.1.0"
tip
language:
name: "Javascript"
url: "https://github.com/m8test/language-release/releases/download/javascript-0.1.0/com.m8test.javascript.v8-release_0.1.0.apk"
version: "0.1.0"
tip
language:
name: "Lua"
url: "https://github.com/m8test/language-release/releases/download/lua-0.1.0/com.m8test.lua-release_0.1.0.apk"
version: "0.1.0"
tip
language:
name: "Python"
url: "https://github.com/m8test/language-release/releases/download/python-0.1.0/com.m8test.python-release_0.1.0.apk"
version: "0.1.0"
tip
language:
name: "Ruby"
url: "https://github.com/m8test/language-release/releases/download/ruby-0.1.0/com.m8test.ruby-release_0.1.0.apk"
version: "0.1.0"
tip
其中指定了执行settings
和init.settings
文件脚本语言名称、下载地址以及版本
创建
settings
文件, 每种语言所需要的扩展名不一样
_console.log("settings.kts run")
tip
$console.log("settings.groovy run")
tip
$console.log("settings.js run")
tip
_console:log("settings.lua run")
tip
<?php
$console->log("settings.php run");
tip
_console.log("settings.py run")
tip
$console.log("settings.rb run")
tip
这里简单的打印一句话, 如果包含子项目可以在此文件中配置, 一个项目中只需要一个 settings
文件, 子项目中不需要 settings
文件
创建
build
文件, 每种语言所需要的扩展名不一样
_project.getPlugins().apply("kotlin")
_project.setConfig {
setEntry("com/example/script/primary.kts")
setPackageName("com.example.script.kotlin")
setLogo("logo.png")
}
tip
$project.getPlugins().apply("groovy")
$project.setConfig {
setEntry("com/example/script/primary.groovy")
setPackageName("com.example.script.groovy")
setLogo("logo.png")
}
tip
$project.getPlugins().apply("javascript")
$project.setConfig(config => {
config.setEntry("com/example/script/primary.js")
config.setPackageName("com.example.script.js")
config.setLogo("logo.png")
})
tip
_project:getPlugins():apply("lua")
_project:setConfig(function(c)
c:setEntry("com/example/script/primary.lua")
c:setPackageName("com.example.script.lua")
c:setLogo("logo.png")
end)
tip
<?php
$project->getPlugins()->apply("php");
$project->setConfig(function ($config) {
$config->setEntry("com/example/script/primary.php");
$config->setPackageName("com.example.script.php");
$config->setLogo("logo.png");
});
tip
_project.getPlugins().apply("python")
def configuration(config):
config.setEntry("com/example/script/primary.py")
config.setPackageName("com.example.script.py")
config.setLogo("logo.png")
_project.setConfig(configuration)
tip
$project.getPlugins().apply("ruby")
$project.setConfig { |config|
config.setEntry("com/example/script/primary.rb")
config.setPackageName("com.example.script.rb")
config.setLogo("logo.png")
}
tip
其中配置语言插件以及项目基本信息(脚本入口文件、包名以及logo)
创建目录
src
用于存放脚本源码, 新建上一步骤配置的入口文件
package com.example.script
_console.log("kotlin")
tip
package com.example.script
$console.log("groovy")
tip
创建
res
目录, 并创建第3步配置的logo文件即可实现最简单的项目
tip
Tips: 带ui的项目在简单项目基础上开发, 此处省略开发简单项目步骤
创建
webview
目录用于存放ui相关文件, 实际上此目录就是存放静态网站的. 可以显示任意前端框架(vue,angular,react等) 编译后的产物, 也可以是简单的 index.html 文件, 这里演示简单的网站, 只有两个文件, 一个是index.html
, 一个是index.js
index.html
内容如下, 非常简单, 仅仅是引用了 index.js
文件而已
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView UI</title>
<link href="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM"
crossorigin="anonymous">
<script src="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous"></script>
</head>
<body>
<button id="button" type="button" class="btn btn-primary">Primary</button>
<script src="./index.js"></script>
</body>
</html>
tip
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView UI</title>
<link href="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM"
crossorigin="anonymous">
<script src="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous"></script>
</head>
<body>
<button id="button" type="button" class="btn btn-primary">Primary</button>
<script src="./index.js"></script>
</body>
</html>
tip
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView UI</title>
<link href="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM"
crossorigin="anonymous">
<script src="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous"></script>
</head>
<body>
<button id="button" type="button" class="btn btn-primary">Primary</button>
<script src="./index.js"></script>
</body>
</html>
tip
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView UI</title>
<link href="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM"
crossorigin="anonymous">
<script src="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous"></script>
</head>
<body>
<button id="button" type="button" class="btn btn-primary">Primary</button>
<script src="./index.js"></script>
</body>
</html>
tip
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView UI</title>
<link href="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM"
crossorigin="anonymous">
<script src="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous"></script>
</head>
<body>
<button id="button" type="button" class="btn btn-primary">Primary</button>
<script src="./index.js"></script>
</body>
</html>
tip
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView UI</title>
<link href="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM"
crossorigin="anonymous">
<script src="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous"></script>
</head>
<body>
<button id="button" type="button" class="btn btn-primary">Primary</button>
<script src="./index.js"></script>
</body>
</html>
tip
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebView UI</title>
<link href="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM"
crossorigin="anonymous">
<script src="https://fastly.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous"></script>
</head>
<body>
<button id="button" type="button" class="btn btn-primary">Primary</button>
<script src="./index.js"></script>
</body>
</html>
tip
index.js
内容如下
(function () {
function init() {
// $webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
$webViewBridge.registerHandler("functionForScriptToCall", function (data, responseCallback) {
// data 为脚本端调用处理器时传递过来的参数
// responseCallback 用于返回处理结果到脚本端
if (responseCallback) {
var responseData = "I am from Javascript " + data
responseCallback(responseData)
}
})
}
if (window.$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
document.getElementById("button").addEventListener("click", function (e) {
// $webViewBridge.callHandler() 用于调用脚本端注册的处理器,参数一为处理器名,参数二为需要传递给处理器的参数,参数三为回调函数用于接收脚本端的返回值
$webViewBridge.callHandler("handlerForWebView", "params from js", function (p) {
alert(p)
})
})
tip
(function () {
function init() {
// $webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
$webViewBridge.registerHandler("functionForScriptToCall", function (data, responseCallback) {
// data 为脚本端调用处理器时传递过来的参数
// responseCallback 用于返回处理结果到脚本端
if (responseCallback) {
var responseData = "I am from Javascript " + data
responseCallback(responseData)
}
})
}
if (window.$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
document.getElementById("button").addEventListener("click", function (e) {
// $webViewBridge.callHandler() 用于调用脚本端注册的处理器,参数一为处理器名,参数二为需要传递给处理器的参数,参数三为回调函数用于接收脚本端的返回值
$webViewBridge.callHandler("handlerForWebView", "params from js", function (p) {
alert(p)
})
})
tip
(function () {
function init() {
// $webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
$webViewBridge.registerHandler("functionForScriptToCall", function (data, responseCallback) {
// data 为脚本端调用处理器时传递过来的参数
// responseCallback 用于返回处理结果到脚本端
if (responseCallback) {
var responseData = "I am from Javascript " + data
responseCallback(responseData)
}
})
}
if (window.$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
document.getElementById("button").addEventListener("click", function (e) {
// $webViewBridge.callHandler() 用于调用脚本端注册的处理器,参数一为处理器名,参数二为需要传递给处理器的参数,参数三为回调函数用于接收脚本端的返回值
$webViewBridge.callHandler("handlerForWebView", "params from js", function (p) {
alert(p)
})
})
tip
(function () {
function init() {
// $webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
$webViewBridge.registerHandler("functionForScriptToCall", function (data, responseCallback) {
// data 为脚本端调用处理器时传递过来的参数
// responseCallback 用于返回处理结果到脚本端
if (responseCallback) {
var responseData = "I am from Javascript " + data
responseCallback(responseData)
}
})
}
if (window.$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
document.getElementById("button").addEventListener("click", function (e) {
// $webViewBridge.callHandler() 用于调用脚本端注册的处理器,参数一为处理器名,参数二为需要传递给处理器的参数,参数三为回调函数用于接收脚本端的返回值
$webViewBridge.callHandler("handlerForWebView", "params from js", function (p) {
alert(p)
})
})
tip
(function () {
function init() {
// $webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
$webViewBridge.registerHandler("functionForScriptToCall", function (data, responseCallback) {
// data 为脚本端调用处理器时传递过来的参数
// responseCallback 用于返回处理结果到脚本端
if (responseCallback) {
var responseData = "I am from Javascript " + data
responseCallback(responseData)
}
})
}
if (window.$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
document.getElementById("button").addEventListener("click", function (e) {
// $webViewBridge.callHandler() 用于调用脚本端注册的处理器,参数一为处理器名,参数二为需要传递给处理器的参数,参数三为回调函数用于接收脚本端的返回值
$webViewBridge.callHandler("handlerForWebView", "params from js", function (p) {
alert(p)
})
})
tip
(function () {
function init() {
// $webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
$webViewBridge.registerHandler("functionForScriptToCall", function (data, responseCallback) {
// data 为脚本端调用处理器时传递过来的参数
// responseCallback 用于返回处理结果到脚本端
if (responseCallback) {
var responseData = "I am from Javascript " + data
responseCallback(responseData)
}
})
}
if (window.$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
document.getElementById("button").addEventListener("click", function (e) {
// $webViewBridge.callHandler() 用于调用脚本端注册的处理器,参数一为处理器名,参数二为需要传递给处理器的参数,参数三为回调函数用于接收脚本端的返回值
$webViewBridge.callHandler("handlerForWebView", "params from js", function (p) {
alert(p)
})
})
tip
(function () {
function init() {
// $webViewBridge.registerHandler() 用于设置供脚本端调用的处理器,第一个参数是处理器名,第二个参数是一个函数,会在处理器被调用时执行
$webViewBridge.registerHandler("functionForScriptToCall", function (data, responseCallback) {
// data 为脚本端调用处理器时传递过来的参数
// responseCallback 用于返回处理结果到脚本端
if (responseCallback) {
var responseData = "I am from Javascript " + data
responseCallback(responseData)
}
})
}
if (window.$webViewBridge) {
init();
} else {
document.addEventListener(
'WebViewBridgeReady',
function () {
//do your work here
init();
},
false
);
}
})()
document.getElementById("button").addEventListener("click", function (e) {
// $webViewBridge.callHandler() 用于调用脚本端注册的处理器,参数一为处理器名,参数二为需要传递给处理器的参数,参数三为回调函数用于接收脚本端的返回值
$webViewBridge.callHandler("handlerForWebView", "params from js", function (p) {
alert(p)
})
})
tip
需要注意以下几点
$webViewBridge.registerHandler: 在网页端注册处理器, 处理器注册后可以在脚本端调用已经注册的处理器
$webViewBridge.callHandler: 用于调用脚本端注册的处理器
脚本端(
src
)内容如下
package com.example.script
// WebViewActivity.getBridge() 用于获取 WebViewBridge 对象
val bridge = _webView.getBridge()
// WebViewBridge.registerHandler() 用于注册处理器供 WebView 端调用
bridge.registerHandler("handlerForWebView") {
// it -> String
// it 表示从 WebView 端传来的参数,如果没有则为 null
val handledParams = it + " return from script"
// WebViewBridge.callHandler() 用于调用 WebView 端注册的处理器
bridge.callHandler("functionForScriptToCall", handledParams) { i ->
// it -> String
// it 为 WebView 端js函数返回值
_console.log(i)
}
handledParams
}
// Activity.start() 用于启动Android系统的Activity
_activity.start()
tip
package com.example.script
// WebViewActivity.getBridge() 用于获取 WebViewBridge 对象
def bridge = $webView.getBridge()
// WebViewBridge.registerHandler() 用于注册处理器供 WebView 端调用
bridge.registerHandler("handlerForWebView") {
// it -> String
// it 表示从 WebView 端传来的参数,如果没有则为 null
def handledParams = "$it return from script"
// WebViewBridge.callHandler() 用于调用 WebView 端注册的处理器
bridge.callHandler("functionForScriptToCall", handledParams) {
// it -> String
// it 为 WebView 端js函数返回值
$console.log(it)
}
handledParams
}
// Activity.start() 用于启动Android系统的Activity
$activity.start()
tip
// WebViewActivity.getBridge() 用于获取 WebViewBridge 对象
let bridge = $webView.getBridge()
// WebViewBridge.registerHandler() 用于注册处理器供 WebView 端调用
bridge.registerHandler("handlerForWebView", (it) => {
// it -> String
// it 表示从 WebView 端传来的参数,如果没有则为 null
let handledParams = it + " return from script"
// WebViewBridge.callHandler() 用于调用 WebView 端注册的处理器
bridge.callHandler("functionForScriptToCall", handledParams, (it) => {
// it -> String
// it 为 WebView 端js函数返回值
$console.log(it)
})
return handledParams
})
// Activity.start() 用于启动Android系统的Activity
$activity.start()
tip
-- WebViewActivity.getBridge() 用于获取 WebViewBridge 对象
local bridge = _webView:getBridge()
-- WebViewBridge.registerHandler() 用于注册处理器供 WebView 端调用
bridge:registerHandler("handlerForWebView", function(it)
-- it -> String
-- it 表示从 WebView 端传来的参数,如果没有则为 nil
local handledParams = it .. "return from script"
-- WebViewBridge.callHandler() 用于调用 WebView 端注册的处理器
bridge:callHandler("functionForScriptToCall", handledParams, function(i)
-- it -> String
-- it 为 WebView 端js函数返回值
_console:log(i)
end)
return handledParams
end)
-- Activity.start() 用于启动Android系统的Activity
_activity:start()
tip
<?php
// WebViewActivity.getBridge() 用于获取 WebViewBridge 对象
$bridge = $webView->getBridge();
// WebViewBridge.registerHandler() 用于注册处理器供 WebView 端调用
$bridge->registerHandler("handlerForWebView", function ($it) use ($console, $bridge) {
// it -> String
// it 表示从 WebView 端传来的参数,如果没有则为 nil
$handledParams = $it . "return from script";
// WebViewBridge.callHandler() 用于调用 WebView 端注册的处理器
$bridge->callHandler("functionForScriptToCall", $handledParams, function ($i) use ($console) {
// it -> String
// it 为 WebView 端js函数返回值
$console->log($i);
});
return $handledParams;
});
// Activity.start() 用于启动Android系统的Activity
$activity->start();
tip
# WebViewActivity.getBridge() 用于获取 WebViewBridge 对象
bridge = _webView.getBridge()
def fn1(it):
# it -> String
# it 表示从 WebView 端传来的参数,如果没有则为 null
handledParams = it + " return from script"
def fn2(i):
# it -> String
# it 为 WebView 端js函数返回值
_console.log(i)
# WebViewBridge.callHandler() 用于调用 WebView 端注册的处理器
bridge.callHandler("functionForScriptToCall", handledParams, fn2)
return handledParams
# WebViewBridge.registerHandler() 用于注册处理器供 WebView 端调用
bridge.registerHandler("handlerForWebView", fn1)
# Activity.start() 用于启动Android系统的Activity
_activity.start()
tip
# WebViewActivity.getBridge() 用于获取 WebViewBridge 对象
bridge = $webView.getBridge()
# WebViewBridge.registerHandler() 用于注册处理器供 WebView 端调用
bridge.registerHandler("handlerForWebView") { |it|
# it -> String
# it 表示从 WebView 端传来的参数,如果没有则为 null
handledParams = it + "return from script"
# WebViewBridge.callHandler() 用于调用 WebView 端注册的处理器
bridge.callHandler("functionForScriptToCall", handledParams) { |i|
# it -> String
# it 为 WebView 端js函数返回值
$console.log(i)
}
handledParams
}
# Activity.start() 用于启动Android系统的Activity
$activity.start()
tip
需要注意以下几点
bridge.registerHandler: 用于在脚本端注册处理器, 注册的处理器可以在网页端调用
bridge.callHandler: 用于调用网页端已注册的处理器
tip
Tips: 脚本端和网页端是通过处理器交互的,在网页端注册的处理器可以在脚本端调用, 在脚本端注册的处理器可以在网页端调用.