6.6.3 - Alpha5 - webview 元素支持基于 JsBridge 的 Web 页面布局 (Ref to Auto.js Pro) (issue #281)

This commit is contained in:
SuperMonster003
2025-05-25 21:04:08 +08:00
parent 6159302829
commit 299c20ad72
30 changed files with 1454 additions and 30 deletions

View File

@@ -0,0 +1,93 @@
'ui';
ui.layout(
<vertical>
<webview id="web" url="web/index.html" w="*" h="*"/>
</vertical>,
);
ui.statusBarColor('#ffffff');
let FILE_REQ_CODE = 11525;
let fileChooserResolve = null;
let web = ui['web'];
// 监听 WebView 的控制台消息, 打印到控制台
web.events.on('console_message', (event, msg) => {
console.log(`${files.getName(msg.sourceId())}:${msg.lineNumber()}: ${msg.message()}`);
});
// 处理来自 Web 的请求
web.jsBridge
// 处理读取本地文件的请求
.handle('fetch', (event, args) => {
return files.read(files.join(files.path('web'), args.path));
})
// 处理显示日志界面的请求
.handle('show-log', (event) => {
app.startActivity('console');
})
// 处理 toastLog 消息
.handle('toast-log', (event, msg) => {
toastLog(msg);
})
// 处理设置无障碍服务的请求
.handle('set-accessibility-enabled', (event, enabled) => {
enabled ? auto.enable() : auto.disable();
})
// 处理获取无障碍服务状态的请求
.handle('get-accessibility-enabled', (event) => {
return auto.isRunning();
})
// 处理获取应用版本名称的请求
.handle('get-app-version-name', (event) => {
return app.autojs.versionName;
})
// 处理文件选择的请求
.handle('select-file', (event, mimeType) => {
return new Promise((resolve, reject) => {
if (fileChooserResolve) {
toastLog('File chooser is already open.');
return;
}
fileChooserResolve = resolve;
let intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType(mimeType);
intent.addCategory(android.content.Intent.CATEGORY_OPENABLE);
activity.startActivityForResult(intent, FILE_REQ_CODE);
});
})
// 处理显示设备信息的请求
.handle('show-device-info-dialog', (event) => {
new MaterialDialog.Builder(activity)
.title(R.strings.text_app_and_device_info)
.content(DeviceUtils.getDeviceSummaryWithSimpleAppInfo(activity))
.neutralText(R.strings.dialog_button_copy)
.onNeutral((dialog, which) => {
setClip(dialog.contentView.text);
toast(activity.getString(R.strings.text_already_copied_to_clip));
})
.neutralColorRes(R.color.dialog_button_hint)
.negativeText(R.strings.dialog_button_dismiss)
.build()
.show();
})
// 处理打开链接的请求. 这里用广播方式, 也可以使用 handle 的 "请求-响应" 方式
.on('open-url', (event, url) => {
app.openUrl(url);
});
ui.emitter.on('activity_result', (requestCode, resultCode, data) => {
if (requestCode === FILE_REQ_CODE && fileChooserResolve) {
if (resultCode === android.app.Activity.RESULT_OK && data) {
let uri = data.getData();
let path = IntentUtils.getFileName(activity, uri);
fileChooserResolve(path);
} else {
fileChooserResolve(null);
}
fileChooserResolve = null;
}
});

View File

@@ -0,0 +1,16 @@
{
"assets": [],
"useFeatures": [],
"launchConfig": {
"displaySplash": true,
"hideLogs": true,
"splashText": "Powered by AutoJs6",
"stableMode": false
},
"main": "main.js",
"name": "Vue2 + Vant (SFC)",
"packageName": "org.example.vue2_vant",
"scripts": {},
"versionCode": 1,
"versionName": "1.0.0"
}

View File

@@ -0,0 +1,55 @@
<html>
<body>
<div id="app"></div>
<link rel="stylesheet" href="https://unpkg.com/vant@2.12/lib/index.css"/>
<script src="https://unpkg.com/vue@2.6/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue3-sfc-loader@0.8.4/dist/vue2-sfc-loader.js"></script>
<script src="https://unpkg.com/vant@2.12/lib/vant.min.js"></script>
<script src="autojs://sdk/v1.js"></script>
<script>
let { loadModule, vueVersion } = window['vue2-sfc-loader'];
let options = {
moduleCache: {
vue: Vue,
myData: {
vueVersion,
},
},
async getFile(url) {
let getContentData;
if (typeof $autojs !== 'undefined') {
let res = await $autojs.invoke('fetch', { path: url });
getContentData = (asBinary) => asBinary ? str2ab(res) : res;
} else {
let res = await fetch(url);
if (!res.ok) {
throw Object.assign(new Error(res.statusText + ' ' + url), { res });
}
getContentData = (asBinary) => asBinary ? res.arrayBuffer() : res.text();
}
return {
getContentData,
};
function str2ab(str) {
let buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char
let bufView = new Uint16Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
},
addStyle() {
/* unused here */
},
};
loadModule('/main.vue', options)
.then(component => new Vue(component).$mount('#app'));
</script>
</body>
</html>

View File

@@ -0,0 +1,127 @@
<template>
<van-row>
<van-nav-bar title="基于 Vue 的界面"/>
<van-tabs v-model="activeTab">
<van-tab title="配置">
<van-cell-group title="权限">
<van-cell title="无障碍服务" label="用于脚本自动操作 (点击/长按/滑动等)">
<van-switch
v-model="accessibilityServiceEnabled"
@input="onAccessibilityServiceCheckChanged"
/>
</van-cell>
</van-cell-group>
<van-cell-group title="配置">
<van-cell title="开关样本">
<van-switch
v-model="sampleSwitchChecked"
@change="onSampleSwitchChanged"
/>
</van-cell>
<van-field v-model="greeting"
label="问候语"
placeholder="请输入问候语"
maxLength="20"
input-align="right"
/>
<van-field v-model.number="count"
label="运行次数"
placeholder="请输入运行次数"
maxLength="4"
inputmode="numeric"
input-align="right"
/>
<van-field
label="选择文件"
:value="selectedFilePath"
placeholder="选择一个文件"
readonly
clickable
@click.native="selectFile"
input-align="right"
/>
</van-cell-group>
</van-tab>
<van-tab title="运行">
<van-cell title="查看日志" is-link @click="showLog"/>
<van-row type="flex" justify="center">
<van-button type="primary" @click="run" style="margin-top: 12px;">运行</van-button>
</van-row>
</van-tab>
<van-tab title="关于">
<van-cell
value="运行环境"
:title="appVersionName ? `AutoJs6 ${appVersionName}` : `AutoJs6`"
label="WebView + Android"
@click="showDeviceInfoDialog"
/>
<van-cell
title="Vue.js 2.6"
label="渐进式 JavaScript 框架"
is-link
@click="openVueWebsite"
/>
<van-cell
title="Vant 2.12"
label="轻量, 可靠的移动端 Vue 组件库"
is-link
@click="openVantWebsite"
/>
</van-tab>
</van-tabs>
</van-row>
</template>
<script>
export default {
data() {
return {
accessibilityServiceEnabled: false,
activeTab: 0,
sampleSwitchChecked: true,
greeting: 'Hello',
count: 192,
appVersionName: '',
selectedFilePath: '',
};
},
created() {
$autojs.invoke('get-accessibility-enabled').then((value) => {
this.accessibilityServiceEnabled = value;
});
$autojs.invoke('get-app-version-name').then((value) => {
this.appVersionName = value;
});
},
methods: {
onAccessibilityServiceCheckChanged(checked) {
$autojs.invoke('set-accessibility-enabled', checked);
},
onSampleSwitchChanged(checked) {
$autojs.invoke('toast-log', `样本开关已${checked ? '开启' : '关闭'}`);
},
showLog() {
$autojs.invoke('show-log');
},
openVantWebsite() {
$autojs.send('open-url', 'https://vant-ui.github.io/vant/v2/#/zh-CN/');
},
openVueWebsite() {
$autojs.send('open-url', 'https://cn.vuejs.org/');
},
run() {
$autojs.invoke('toast-log', `greeting: "${this.greeting}"\ncount: ${this.count}`);
},
selectFile() {
$autojs.invoke('select-file', '*/*').then((path) => {
this.selectedFilePath = path || '';
});
},
showDeviceInfoDialog() {
$autojs.invoke('show-device-info-dialog');
},
},
};
</script>

View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Interactive HTML</title>
</head>
<body>
<link rel="stylesheet" href="style.css"/>
<script src="autojs://sdk/v1.js"></script>
<script src="index.js"></script>
<button id="testButton">点击测试</button>
</body>
</html>

View File

@@ -0,0 +1,10 @@
const winOnloadBak = window.onload ? window.onload.bind(window) : null;
window.onload = function () {
if (typeof winOnloadBak === 'function') {
winOnloadBak();
}
document.getElementById('testButton').addEventListener('click', () => {
$autojs.invoke('toast-log', '按钮已被点击');
});
};

View File

@@ -0,0 +1,13 @@
'ui';
ui.layout(
<vertical>
<webview id="web" url="index.html" w="*" h="*"/>
</vertical>,
);
let web = ui['web'];
web.jsBridge.handle('toast-log', (event, msg) => {
toastLog(msg);
});

View File

@@ -0,0 +1,16 @@
{
"assets": [],
"useFeatures": [],
"launchConfig": {
"displaySplash": true,
"hideLogs": true,
"splashText": "Powered by AutoJs6",
"stableMode": false
},
"main": "main.js",
"name": "可交互 HTML",
"packageName": "org.example.interactive_html",
"scripts": {},
"versionCode": 1,
"versionName": "1.0.0"
}

View File

@@ -0,0 +1,25 @@
html, body {
height: 100%;
margin: 0;
}
body {
display: flex;
justify-content: center;
align-items: center;
background-color: #f5f5f5;
}
#testButton {
padding: 12px 24px;
font-size: 16px;
color: #fff;
background-color: #006400;
border: none;
border-radius: 4px;
cursor: pointer;
}
#testButton:hover {
background-color: #008000;
}