01运行环境
小工具是运行在受限沙箱环境里的纯 Web 应用(HTML / CSS / JS),请把它当作一个"能力受限的浏览器页面"来开发。
标准 Web 技术栈
使用标准 HTML / CSS / JS 与标准 Web API 开发。
JS API(window.xhs.miniTool)
容器自动注入 JS API SDK,可调用发布笔记、保存相册、写临时文件等端能力(详见 §3),无需自行引入脚本。
安全沙箱
容器对部分敏感 Web 能力做了限制(详见下文),并对文件选择、页面跳转等做了统一管控。
独立隔离
每个小工具拥有独立的存储与运行环境,小工具之间互相隔离、无法访问彼此数据,也无法互相通信。
本地运行、不联网
小工具为纯本地运行,所有页面、脚本、图片、字体等资源都必须打包在小工具内,不支持任何网络请求(详见 §4.2)。请将小工具设计为完全离线自包含。
02可用能力
2.1 页面与渲染
| 能力 | 说明 |
|---|---|
| HTML / CSS / JS | 完整支持,含 Flexbox / Grid / 动画 / 媒体查询等 |
| 内联样式 | <style> 与 style="" 均可用 |
| 页面内脚本 | 页面自带的脚本可正常执行 |
| Canvas 2D | canvas.getContext('2d'),完整支持 |
| WebGL |
getContext('webgl' / 'webgl2'),纯渲染可用(能力边界见 §5)
|
| 文本选择 | 不限制 |
2.2 媒体与文件
| 能力 | 用法 | 说明 |
|---|---|---|
| 摄像头 | getUserMedia({ video }) |
需用户在系统弹窗中授权 |
| 麦克风 | getUserMedia({ audio }) |
需用户在系统弹窗中授权 |
| 选择图片 / 拍照 | <input type="file"> |
系统选择器接管,仅支持选择图片和视频(无论 accept 如何设置) |
| 音视频播放 | <video> / <audio> |
支持内联播放 |
2.3 数据存储
| 能力 | 说明 |
|---|---|
| localStorage / sessionStorage | 可用,按小工具独立隔离 |
| IndexedDB | 可用,按小工具独立隔离 |
| Cookie / Cache API | 可用,按小工具独立隔离 |
- 数据仅属于当前小工具,其他小工具与外部无法访问。请勿假设数据永久持久化。
-
Cookie 仅作本地存储:可正常读写并按 origin 隔离,但因不联网,cookie
不会随请求发往任何服务端,无法用于登录态 / 鉴权透传。需要本地存储优先用
localStorage/IndexedDB。
2.4 交互
| 能力 | 说明 |
|---|---|
alert() / confirm() |
可用,以原生 UI 展示 |
2.5 资源加载规则
小工具为本地运行、不联网,容器对页面如何加载各类资源有明确约束(对应浏览器
CSP 限制)。所有资源须打包在小工具内(下表"包内资源"),另按类型额外允许
data: / blob: 等内存来源。
| 资源类型 | 允许的加载方式 | 不允许 |
|---|---|---|
脚本 <script> |
✅ 引用包内脚本
<script src="./app.js">(同源外链)
|
🔴 内联 <script>...</script>🔴 行内事件 onclick="..." 等、javascript: URI🔴 eval() / new Function()、WebAssembly🔴 外部域名脚本、 data: / blob: 脚本
|
样式 <style> / <link> |
✅ 内联 <style>、style="..." 行内样式✅ 引用包内样式表 |
🔴 外部域名样式表 |
图片 <img> / CSS 背景图 |
✅ 包内图片
<img src="./a.png">✅ data: URI(base64 内嵌)✅ blob:(createObjectURL 内存对象,如选图预览)
|
🔴 外部域名图片 |
字体 @font-face |
✅ 包内字体文件 | 🔴 外部域名字体 |
iframe / object |
🔴 全部禁止 | — |
支持的文件类型
小工具包内仅支持以下文件类型:
| 文件类型 | 原因 |
|---|---|
.html |
小工具主体,必须有且只有一个入口文件 |
.css |
样式文件,虽然口令要求内联,但不排除用户分开放 |
.js |
脚本文件,同上 |
.png / .jpg / .jpeg / .gif / .webp / .svg |
图片资源,内联 base64 太大时用户可能分开放 |
.woff / .woff2 |
字体文件,本地字体场景 |
.json |
静态数据文件,部分小工具需要读取本地配置数据 |
实践要点
-
脚本必须外置:容器禁止内联脚本与行内事件处理器,请把 JS
写进包内
.js文件用<script src>引入,事件绑定改用addEventListener(不要用onclick=属性)。 -
样式可内联:
<style>和style="..."都能用,无需外置。 -
选图预览用
<img src>配data:或blob:均可显示(如FileReader.readAsDataURL或URL.createObjectURL)。
<img> 加载 data: / blob: 需客户端
9.37 及以上版本。
03端能力 JS API
除标准 Web 能力外,容器会自动注入 JS API SDK,小工具可通过
window.xhs.miniTool.* 调用 App 原生能力:发布笔记、保存图片到相册、把
base64 写成临时文件。无需在包内引入任何 SDK 脚本。
3.1 调用约定
| 项 | 规则 |
|---|---|
| 唯一入口 |
window.xhs.miniTool.<apiName>(options);不要自行向原生
bridge postMessage,也不要调用本文未列出的 API
|
| Promise / 回调 |
传入 success / fail /
complete 任一回调时返回 undefined;都不传则返回
Promise
|
| 成功 |
resolve / success 收到结果对象,含
errMsg: "<api>:ok" 及该 API 的业务字段
|
| 失败 |
reject / fail 收到
{ errMsg: "<api>:fail ...", errCode? };参数不合法时会在本地直接失败,不上行
|
| 参数校验 | SDK 上行前按 JSON Schema 校验,Native 侧用同一份 Schema 再校验一次:表中未声明的字段不要传 |
| 可用性判断 |
调用前用 window.xhs?.miniTool 判空,并为未注入的环境准备降级路径
|
const miniTool = window.xhs?.miniTool;
if (!miniTool) return; // 当前环境未注入端能力
// Promise 形态
try {
await miniTool.saveImageToPhotosAlbum({ filePath });
} catch (err) {
console.log(err.errMsg); // "saveImageToPhotosAlbum:fail ..."
}
// 回调形态(返回 undefined)
miniTool.saveImageToPhotosAlbum({
filePath,
success: (res) => console.log(res.errMsg),
fail: (err) => console.log(err.errMsg),
complete: () => {},
});
3.2 API 一览
| API | 能力 | 形态 |
|---|---|---|
postNote |
唤起笔记发布页,带入标题 / 正文 / 图片 / 视频 | 异步 |
saveImageToPhotosAlbum |
保存图片到系统相册 | 异步 |
writeTempFile |
把 base64 数据写成容器内临时文件,换取 filePath |
异步 |
data: base64
或本地文件路径(容器不联网,网络地址不可用)。体积较大的 base64
建议先用 writeTempFile 换成 filePath 再传。
3.3 postNote — 发布笔记
唤起 App 笔记发布页,并带入小工具产出的内容与媒体。用户在发布页可继续编辑或取消。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
title |
string | 否 | 标题,最长 20 字 |
content |
string | 否 | 正文,最长 1000 字 |
tags |
string | 否 | 话题 / 标签 |
mediaInfo |
object | 是 | 媒体信息,下列两种资源至少传一种,可同时传 |
mediaInfo.image_resources |
{ url }[] |
否 | 图片,1–18 张;url 为 base64 或本地路径 |
mediaInfo.video_resources |
{ video_url, cover_url? } |
否 | 单个视频,cover_url 为可选封面 |
// 图文笔记
await window.xhs.miniTool.postNote({
title: "我的作品",
content: "用小工具生成的",
mediaInfo: {
image_resources: [{ url: "data:image/png;base64,iVBORw0KGgo..." }],
},
});
// 视频笔记
await window.xhs.miniTool.postNote({
mediaInfo: {
video_resources: { video_url: videoPath, cover_url: coverPath },
},
});
3.4 saveImageToPhotosAlbum — 保存图片到相册
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
filePath |
string | 是 |
本地图片:data: base64 或
writeTempFile 返回的路径;不支持
http(s):// 网络地址
|
// Canvas 导出直接保存
const dataUrl = canvas.toDataURL("image/png");
await window.xhs.miniTool.saveImageToPhotosAlbum({ filePath: dataUrl });
- 需由用户主动操作(点击等)触发,首次调用可能弹出系统相册权限弹窗;用户拒绝授权会走失败回调。
- 大图建议先
writeTempFile落成文件再保存,避免超长 base64 上行。
3.5 writeTempFile — base64 转临时文件
把内存里的 base64(Canvas 导出、选图预览结果等)写成容器内的临时文件,换取可传给其他 JS API 的
filePath。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
data |
string | 是 | base64 数据(支持带 data: 前缀的 data URI) |
filePath(返回) |
string | — | 写入后的临时文件路径 |
const { filePath } = await window.xhs.miniTool.writeTempFile({
data: canvas.toDataURL("image/png"),
});
await window.xhs.miniTool.saveImageToPhotosAlbum({ filePath });
// 或带入发布页
await window.xhs.miniTool.postNote({
mediaInfo: { image_resources: [{ url: filePath }] },
});
- 返回的是临时文件,不保证长期有效,请即用即弃,不要持久化保存该路径。
- 仅支持常见图片 / 视频类型(png、jpeg、webp、gif、mp4),其他类型会失败。
04不可用能力
以下能力在容器内已被禁用,调用会失败(抛出异常、返回空值或被拦截),请勿使用。
4.1 已禁用的 Web API
| 分类 | 能力 |
|---|---|
| 定位 | 地理定位 navigator.geolocation |
| 剪贴板 |
navigator.clipboard、execCommand('copy'/'cut'/'paste')
|
| 硬件连接 | 蓝牙、USB、HID、串口 |
| 传感器 | 加速度计、陀螺仪、磁力计、环境光、设备运动 / 朝向 |
| 实时通信 | WebRTC、WebSocket、EventSource(SSE) |
| 后台运行 | Web Worker、SharedWorker、Service Worker |
| 屏幕 | 屏幕共享、全屏 requestFullscreen(全屏由容器统一管理) |
| 设备信息 | 电池状态、网络信息、媒体设备枚举 |
| 存储进阶 | 持久化存储、跨域存储访问 |
| 凭据 | WebAuthn / navigator.credentials、Web Locks |
| 窗口 |
window.open(弹新窗口)、window.prompt
|
4.2 已禁用的行为
| 行为 | 说明 |
|---|---|
| 网络请求 |
fetch / XMLHttpRequest、加载外部图片 /
字体 / 媒体等一切联网请求。小工具纯本地运行,所有资源须打包在内
|
| 动态执行代码 | eval()、new Function() |
| WebAssembly | WASM 编译执行(依赖 WASM 的库无法运行,见 §5) |
| iframe | 页面内嵌 iframe / 被外部页面嵌入 |
| 表单跳转提交 | <form> 提交跳转 |
| 插件 | Flash 等浏览器插件 |
| 文件下载 |
a[download]、blob 下载等;保存图片请用
saveImageToPhotosAlbum(见 §3.4)
|
| 打开外链 / 新窗口 | target="_blank"、跳转站外 |
| 跳转其他小工具 | 小工具间互相跳转 |
| 长按菜单 | 已禁用 |
4.3 移动端不支持
以下能力移动端 WebView 本身不支持,无法使用:支付
PaymentRequest、系统通知 / 推送、NFC、MIDI、XR / AR /
VR、后台同步 / 下载、PWA 安装、窗口管理、指针 / 键盘锁定等。
05WebGL / 图形计算边界
纯 WebGL 渲染可用,但组合能力受限:
| 场景 | 是否可用 |
|---|---|
| 本地资源 / Canvas / 内存对象作为纹理 | ✅ 可用 |
| 外部域名图片作为纹理 | 🔴 不可用(不支持网络请求,纹理须打包在内) |
| 依赖 WASM 的加速库(如 Draco / Basis / ONNX / 抠图算法库) | 🔴 不可用 |
| 依赖 Worker 的离屏渲染(OffscreenCanvas + Worker) | 🔴 不可用 |
| SharedArrayBuffer 多线程 | 🔴 不可用 |
WebGL 适合用打包在小工具内的资源做本地渲染;需要 AI 图像处理等重计算的场景无法支持(既不能联网也不能跑 WASM 模型)。
06常见问题 FAQ
<input type="file" accept="video/*"> 为什么只能选图片?
页面里的 <script> 不执行 / 报 CSP 错误?
onclick="...")。请把 JS
放进包内 .js 文件用
<script src="./app.js"> 引入,事件用
addEventListener 绑定。详见 §2.5。
能不能请求我自己的服务端接口 / 加载线上图片?
需要服务端实时推送怎么办?
第三方库报安全错误 / 无法运行?
eval、WebAssembly、Worker,或发起了网络请求,改用容器允许的等价方案。
怎么把小工具生成的图片保存到相册 / 发成笔记?
writeTempFile 把 base64 换成
filePath,再传给 saveImageToPhotosAlbum 或
postNote。详见 §3。
window.xhs 是 undefined?
window.xhs?.miniTool 判空并提供降级路径,不要在无 SDK 时直接调用。
JS API 传网络图片地址为什么失败?
data: base64 或
writeTempFile 返回的本地路径。
能不能调用文档里没列出的其他原生能力?
postMessage。