@spopc/wechat-miniprogram
v0.5.0
Published
Web SDK for the WeChat Mini Program URL bridge
Maintainers
Readme
@spopc/wechat-miniprogram
H5 调用微信小程序原生能力的 TypeScript SDK。使用 URL 协议连接小程序原生页面,零 Taro / React / Vue 运行时依赖。基础能力使用统一执行页;Extended Bridge 提供订单确认等原生业务页面。
安装
npm install @spopc/wechat-miniprogram包提供 ESM 和 TypeScript 类型声明,供浏览器 H5 项目使用;在客户端创建实例,SSR 项目需放在挂载后的客户端代码中。普通浏览器使用真实 Web 能力;微信能力需要小程序宿主实现本文的 URL 协议。仅安装 H5 SDK 不会自动添加原生小程序页面。
源码仓库内使用 npm workspace 开发,无需先发布到 npm。
快速接入
从 0.2.0 起,默认自动识别环境:小程序 WebView 使用原生桥接,普通浏览器使用真实浏览器 API,不再自动 mock。需要旧的模拟行为时显式设置 mode: 'mock'。真实小程序调用需要网页加载微信 JSSDK:https://res.wx.qq.com/open/js/jweixin-1.6.0.js;浏览器模式不需要它。每个页面创建一个 SDK 实例。
import { createWechatBridge } from '@spopc/wechat-miniprogram'
const bridge = createWechatBridge({
mode: 'auto', // 默认值;也可强制 'native'、'browser' 或 'mock'
onResult({ result, delivery, source }) {
// 唯一业务结果入口:live 与文档重建后的 recovered 都经过这里。
// 若同时消费 Promise,请避免对同一调用重复执行业务副作用。
console.log(result.method, result.status, delivery, source)
}
})
// 由 H5 上的用户操作触发;原生页自动执行,无需再点“执行”和“返回”。
const scan = await bridge.scanCode({ scanType: ['qrCode', 'barCode'] })
const position = await bridge.getLocation()
// position.type 明确标识坐标系:浏览器默认 WGS84,小程序默认 GCJ-02。
if (await bridge.ready() === 'native') {
const { code } = await bridge.login()
// 将 code 提交给业务后端;不要把 AppSecret 放在 H5。
}上述调用是顺序示例;根据实际按钮分别触发。页面卸载 / 组件卸载时调用 bridge.dispose()。它移除监听并拒绝当前 Promise,原生模式保留请求记录以支持文档重建。
自动识别
const bridge = createWechatBridge() // 等同于 { mode: 'auto' }
const environment = await bridge.ready() // 'native' | 'browser' | 'mock'
console.log(bridge.environment, bridge.isMock)
const location = await bridge.getLocation() // 调用本身也会等待识别,无需手动 readyauto 结合小程序标记、User-Agent、wx.miniProgram.getEnv 和 WeixinJSBridgeReady 识别。普通浏览器使用 browser,即使网页加载了微信 JSSDK 也不会被误判为小程序。微信容器仍在初始化时,默认最多等待 2000 ms;可用 environmentTimeoutMs 调整为 100–30000 ms。无法确认时抛出 ENVIRONMENT_TIMEOUT,加载完成后可重试 ready() / 调用,不把未知环境当成模拟成功。
自动识别完成后,本实例固定使用选定模式。真实调用的权限拒绝、导航失败、超时等不会退回 mock。已识别为小程序但缺少 JSSDK 时抛出 JSSDK_NOT_READY。mode: 'native' 强制小程序调用,在普通浏览器报 NOT_IN_MINIPROGRAM;mode: 'browser' 强制 Web API;mode: 'mock' 强制模拟。isInMiniProgram() 检测实际环境,不会因强制模式返回假值。检测未完成时 environment 为 undefined,应等待 ready()。
浏览器真实能力
| 能力 | 默认浏览器实现 |
| --- | --- |
| getLocation | 请求定位权限,使用 Geolocation 获取 WGS84 真实坐标;成功、超时或销毁时停止监听 |
| scanCode | 弹出扫码窗口,摄像头或本地图片识别;onlyFromCamera 隐藏选图;支持二维码、常见条码、Data Matrix、PDF417 |
| openLocation | 在新窗口打开高德地图网页,支持显式 type: wgs84 / gcj02,默认 gcj02 |
| makePhoneCall | 发起 tel: 系统拨号请求 |
| login / checkSession / chooseAddress / requestPayment | 返回 UNSUPPORTED;可以接入自己的业务处理器 |
| openEmbeddedMiniProgram / navigateToMiniProgram | 返回 UNSUPPORTED;浏览器没有微信小程序跳转 API |
定位和扫码要求 HTTPS 或 localhost。浏览器地理坐标采用 WGS84,默认 getLocation() 返回 type: 'wgs84';显式要求 gcj02 会返回 UNSUPPORTED_COORDINATE_SYSTEM,不会把 WGS84 假标成 GCJ-02。需要转换时通过业务适配器接入地图服务。小程序定位默认值保持 gcj02。
地图使用高德 URI API。把浏览器定位用于地图时传入 type: position.type,地图会处理对应坐标;微信地图仅接受 GCJ-02。浏览器地图暂不使用 scale,地图和 tel: 的 { ok: true } 仅代表已发起打开请求,不代表地图已加载或电话已接通。应由用户点击触发;无用户操作或窗口被拦截时返回 USER_GESTURE_REQUIRED / POPUP_BLOCKED。
扫码使用本地 canvas 与按需加载的 @zxing/library 解码,不上传摄像头画面或图片。图片上限 20 MB。用户可点击取消或按 Escape;成功、取消、超时、销毁后会停止摄像头并移除窗口,即使权限响应迟到也会释放媒体流。浏览器模式的 source / trigger 为 browser、delivery 为 live,不消费 URL 或原生 pending 记录,也不模拟 Query 重载。
业务适配器具有类型关联,并收到可响应超时/销毁的 signal。例如选择业务收货地址:
const bridge = createWechatBridge({
browser: {
handlers: {
chooseAddress: async (_params, { signal }) => {
// 应用实现此函数,返回 AddressData;取消可抛 BridgeError('CANCELLED', '用户取消')。
return await openYourAddressPicker({ signal })
}
}
}
})仅配置 mock.handlers 不会启用模拟。浏览器登录处理器不能凭空产生有效的微信小程序 code;H5 登录与支付需接入业务后端和相应平台流程。自定义处理器仍遵守现有参数与结果类型,不能用业务 token 冒充微信 code。
显式 Mock
10 项能力均内置模拟实现:固定模拟坐标、门店码、登录资料弹窗、虚构地址及成功标记。可覆盖任意方法,其余保持默认:
import { createWechatBridge, BridgeError } from '@spopc/wechat-miniprogram'
const bridge = createWechatBridge({
mode: 'mock',
mock: {
delayMs: 500, // 默认 300;0–600000 ms,计入调用超时
handlers: {
getLocation: params => ({
latitude: 22.5431, longitude: 114.0579,
accuracy: 10, type: params.type ?? 'gcj02'
}),
scanCode: async (_params, { signal, requestId }) => {
// 可按业务场景返回自定义扫码数据;signal 在超时/销毁/完成时终止。
return { result: 'tea-store://demo?table=08', scanType: 'QR_CODE' }
},
chooseAddress: () => { throw new BridgeError('CANCELLED', '模拟用户取消') },
checkSession: () => { throw new BridgeError('SESSION_EXPIRED', '模拟登录过期') }
}
}
})mock 与真实调用共用参数/结果校验、Promise 类型、单次并发限制和调用超时。CANCELLED 产生 cancel 事件;其他 BridgeError 保留错误码;普通异常变成 MOCK_FAILED,不合法/超大的返回值变成 INVALID_MOCK_RESULT。超时或 dispose 后的迟到结果被丢弃,自定义异步工作可响应 signal 提前结束。
模拟登录弹窗
从 0.3.0 起,显式 mode: 'mock' 下,await bridge.login() 默认弹出“模拟微信登录”,填写 userId、nickName 和可选的 phoneNumber、avatarUrl 后确认。资料仅用于这次调用,不写入浏览器存储;头像 URL 不会被 SDK 请求。取消、Escape 或关闭弹窗返回 CANCELLED,超时 / dispose 自动关闭弹窗。需要支持原生 HTML dialog 的浏览器;不支持时可用自定义 handler 或显式无交互模式。
返回结构与原生登录一致,只有 { code: string }。模拟 code 使用 MOCK_LOGIN_V1. 前缀,携带资料、独立 requestId 和时间戳;微信 wx.login 本身不返回用户资料。相同 userId 可用于测试后端关联同一会员,每次调用的 code 不同。取消的调用不返回资料。
const bridge = createWechatBridge({
mode: 'mock',
mock: {
login: {
profile: { userId: 'member-001', nickName: '测试茶友' }
// interactive: false // 自动化测试时跳过弹窗,直接使用上述资料
}
}
})
const { code } = await bridge.login()
// 与真实模式一样,交给业务后端处理 code。前端可以从包根目录导入 parseMockLoginCode 做纯页面测试;Node 测试后端推荐使用无 DOM 依赖的子入口:
import { parseMockLoginCode } from '@spopc/wechat-miniprogram/mock-login'
// 此开关必须由服务端控制,不能根据请求中的 code 前缀自动开启。
if (process.env.MP_BRIDGE_MODE !== 'mock' || process.env.NODE_ENV === 'production') {
throw new Error('Mock login is disabled')
}
const { profile, requestId } = parseMockLoginCode(code)
// 在测试会员库中用 `mock:${profile.userId}` 查找或创建会员,再签发业务会话。
// profile 包含 nickName 以及填写的 phoneNumber / avatarUrl;手机号未经验证。
// 若测试一次性登录语义,后端还需记录 requestId 并拒绝重复使用。parseMockLoginCode 校验格式和 5 分钟有效期,抛错时应按无效测试 code 处理。模拟 code 是可由客户端构造的未签名测试资料,不是身份凭证;仅在隔离的测试环境使用,不能交给微信 code2Session,也不能用于正式账号登录。 SDK 不调用会员接口或创建用户,测试后端需显式接入上述分支。
mock.handlers.login 优先于 mock.login。现有自定义 handler 继续工作;原本依赖默认 login 自动成功的无人值守测试,需要增加 mock.login.interactive: false。也可用 createMockLoginCode(profile, requestId) 在自定义 mock handler 中生成同格式的测试 code。
mock 的 onResult.source、trigger 均为 mock,delivery 固定为 live;只在当前内存中返回数据,不跳页面、不读写原生 pending 记录、不消费或修改 URL。即使传入调用参数 mode: 'query',也不模拟重载,因此不能用来验证 WebView 的 Hash / Query 传输和文档重建。模拟登录 code 不能交给微信换登录态,模拟支付不会产生订单或真实支付;业务后端联调需配套测试数据。
测试页直接打开 http://127.0.0.1:13334/ 自动使用浏览器能力。?mode=browser、?mode=native、?mode=mock 强制模式,mock 下可选成功/取消/失败,旧 ?mock=1 仍可用。这些 URL 开关只属于测试页面,SDK 本身不读取它们。
方法与参数
所有快捷方法接受 mode?: 'hash' | 'query'、timeoutMs?: number。这里的 mode 指返回 URL 格式,与创建 SDK 时的运行模式不同。默认 Hash、120000 毫秒;超时可设 1000–600000 毫秒。login、chooseAddress、requestPayment 只允许 Hash。
| 方法 | 原生参数 | 成功结果 |
| --- | --- | --- |
| getLocation(options?) | type: 小程序/mock 默认 gcj02;browser 默认且仅内置支持 wgs84 | latitude、longitude、accuracy、type |
| scanCode(options?) | onlyFromCamera?: boolean;scanType?: qrCode / barCode / datamatrix / pdf417 数组 | result、scanType;可选 charSet、path、rawData |
| login(options?) | timeout?: 1000–60000,微信接口自身超时 | code |
| checkSession(options?) | 无 | valid: true |
| openLocation(options) | latitude、longitude;type 默认 gcj02,浏览器也支持 wgs84;可选 name、address、scale(5–18) | ok: true |
| chooseAddress(options?) | 无 | userName、telNumber、provinceName、cityName、countyName、detailInfo,以及平台返回的可选地址字段 |
| makePhoneCall(options) | phoneNumber | ok: true |
| requestPayment(options) | timeStamp、nonceStr、package、signType、paySign | ok: true |
| openEmbeddedMiniProgram(options) | appId;可选 path、envVersion、extraData | ok: true,仅确认打开 |
| navigateToMiniProgram(options) | appId;可选 path、envVersion、extraData | ok: true,仅确认打开 |
底层通用入口也有方法与参数、结果的类型关联:
const result = await bridge.invoke('scanCode', { onlyFromCamera: true }, { mode: 'hash' })
await bridge.openLocation({ latitude: 31.2, longitude: 121.4, name: '门店', scale: 16 })
// 实际支付参数必须由业务后端签发:
// await bridge.requestPayment(paymentParamsFromYourServer)requestPayment.package 使用 prepay_id=... 格式,signType 明确传 RSA / MD5 / HMAC-SHA256。支付没有自动重试;最终订单状态以业务后端的支付通知或查单结果为准。makePhoneCall 成功只表示原生接口调用成功,不表示电话已接通。
半屏与全屏打开小程序(0.4.0 起)
H5 升级 SDK 并重新构建,同时部署支持这两个方法的小程序壳:
await bridge.openEmbeddedMiniProgram({
appId: 'wx0d121e2a0bd96e51',
path: cashierPathFromServer, // 保留后端返回的页面路径与 query,不再次编码整个 path
envVersion: 'release',
extraData: { orderId }, // 可选,仅 JSON 数据;不要放商户密钥
timeoutMs: 600000,
})
// 只确认打开过收银台,继续通过业务后端查单。
// 全屏入口:bridge.navigateToMiniProgram({ appId, path, envVersion, extraData })
// 通用入口:bridge.invoke('openEmbeddedMiniProgram', params, { timeoutMs: 600000 })appId 必填,为 wx 加 16 位十六进制字符;path 最多 4096 字符,extraData 是最多 8192 字符的 JSON 对象,整体请求仍受 16 KiB 限制。envVersion 为 develop / trial / release,缺省 release;正式版壳只能打开正式版目标。业务 URL 编码由后端负责,桥接只编码传输信封,不改写 path 或 extraData。
参考壳只允许 wx0d121e2a0bd96e51,新增目标请修改 src/mini-programs.json 并发布壳;否则返回 APP_ID_NOT_ALLOWED。半屏还需微信后台绑定经目标同意,目标非个人主体且宿主竖屏;条件不符时微信可能自行转为全屏,成功不保证半屏形态。见 微信半屏接入指引。
半屏与全屏均需用户点击原生页“继续打开”,随后由微信执行跳转。开发者工具实测,半屏在页面 ready 时自动调用会返回 can only be invoked by user TAP gesture;H5 点击经过 navigateTo 后不保留原生手势。全屏限制也见 微信跳转文档。SDK 不自动改用另一种方法,也不自动重试;尤其不要因用户取消、超时或查单未支付就再次自动拉起。
{ ok: true } 仅表示微信打开接口成功,不包含支付状态,也不代表用户在目标中完成操作。壳记录打开结果,待前后台返回后回传 H5,不会在成功回调中立刻销毁半屏承载页。默认仍为 120 秒超时,较长操作请显式设置超时(最多 600 秒);H5 若重建,通过 onResult 恢复,超时或任何返回均需业务查单。开发者工具不一定真实跳转,可手动点击承载页“返回点单页面”;实际半屏形态和回调需真机验收。普通浏览器返回 UNSUPPORTED;显式 mock 返回模拟 { ok: true },不会打开收银台或发起支付。
返回与错误
同一网页上下文存活时,成功 resolve 对应能力的数据,失败或取消 reject BridgeError。onResult 同时收到结构化事件:
{
result: {
v: 1, id, method, mode, completedAt,
status: 'success', data // 或 status: 'cancel' | 'error', error: { code, message }
},
delivery: 'live', // 或 'recovered'
source: 'native', // 或 'browser' / 'mock'
trigger: 'hashchange' // 或 startup / pageshow / visible / focus / poll / invoke / browser / mock
}网页重建时旧 Promise 无法继续,必须在新页面重新创建 SDK 并使用 onResult 恢复。回传按 id、method、mode 同时关联,消费后清理 URL 和 sessionStorage,一次调用最多交付一次。
从 0.4.1 起,提前划回 / 关闭原生功能页会通过壳回传 CANCELLED,结束该次 Promise 并释放调用状态,可以立即再次调用。SDK 在等待期间补查 URL,并在下一次调用前先处理已到达的回传和过期状态;Hash 路由先改写地址、WebView 漏发 URL 事件、迟到的旧导航失败回调均不会锁住后续调用。请同时更新小程序壳和 H5 依赖。仅切换前后台或关闭权限弹窗不视为取消,也不会自动重试原生操作。支付 / 收银台提前退出后仍应由业务后端查单。
常见错误:CANCELLED、PERMISSION_DENIED、NATIVE_FAILED、SESSION_EXPIRED、UNSUPPORTED、TIMEOUT、RESULT_TOO_LARGE、INVALID_NATIVE_RESULT。H5 侧还会产生 BUSY、NOT_IN_MINIPROGRAM、ENVIRONMENT_TIMEOUT、JSSDK_NOT_READY、INVALID_PARAMS、STORAGE_UNAVAILABLE、NAVIGATE_FAILED、DISPOSED、MOCK_FAILED、INVALID_MOCK_RESULT。微信错误原文保留在 message,不依赖它处理分支。H5 本地校验、环境识别、导航失败和本地等待超时通过 Promise 拒绝;它们没有原生回传,因此不产生 onResult。
浏览器另外可能返回 SECURE_CONTEXT_REQUIRED、UNSUPPORTED_COORDINATE_SYSTEM、POSITION_UNAVAILABLE、CAMERA_UNAVAILABLE、CODE_NOT_FOUND、SCAN_FAILED、USER_GESTURE_REQUIRED、POPUP_BLOCKED、BROWSER_FAILED、INVALID_BROWSER_RESULT。权限被拒绝会保留为 PERMISSION_DENIED,不会自动降级到模拟。
checkSession 仅检查微信 session_key,不验证业务服务自己的 token。login 不获取手机号、头像或昵称;手机号授权需要原生按钮交互,不属于本版静默桥接范围。
Extended Bridge:原生订单确认页(0.5.0)
@spopc/wechat-miniprogram/extended 复用已有 bridge 实例。H5 先通过业务后端创建订单,再调用 openPaymentPreview:显示原生订单页 → 用户点击原生“确认支付” → 调用 openEmbeddedMiniProgram → 从收银台返回后回到 H5。原生页面本身是全屏订单确认页,收银台使用半屏 API 打开;最终展示形态仍受微信限制。
import { createWechatBridge } from '@spopc/wechat-miniprogram'
import { createExtendedBridge } from '@spopc/wechat-miniprogram/extended'
const bridge = createWechatBridge({
onResult({ result, delivery }) {
if (result.method === 'payment.preview' && delivery === 'recovered') {
// 文档重建后,在这里恢复业务订单并向后端查单。
// 不要把 result.status === 'success' 当作已支付。
}
}
})
const extended = createExtendedBridge(bridge)
// 由 H5 按钮触发。示例只打开目标首页,没有创建实际支付订单。
const receipt = await extended.openPaymentPreview({
templateId: 'order-list-v1',
order: {
orderId: 'demo-001',
merchantName: '茶饮测试门店',
items: [
{ name: '茉莉鲜奶茶', specification: '大杯 / 少冰', quantity: 2, unitPrice: 1800 }
],
discountAmount: 600,
payableAmount: 3000,
note: '展示示例,请勿付款'
},
appearance: {
primaryColor: '#17634D',
backgroundColor: '#F3F5F1',
showItemImages: true,
density: 'comfortable'
},
payment: {
kind: 'embeddedMiniProgram',
appId: 'wx0d121e2a0bd96e51',
envVersion: 'release'
// 实际业务填入后端生成的 path / extraData,不自行拼造支付签名。
}
}, { timeoutMs: 600000 })
// receipt = { orderId: 'demo-001', outcome: 'returned', paymentStatus: 'unknown' }
// 使用 receipt.orderId 向业务后端查单,再更新 H5 的订单状态。首版仅提供 order-list-v1,适合茶饮、零售商品明细。可设置品牌色、页面背景色、HTTPS 商户 logo、是否显示商品图片和 comfortable / compact 密度。颜色仅接受 #RRGGBB;布局由内置模板控制,不接受 HTML、CSS 或脚本。每项商品可传 HTTPS imageUrl。不同结构的行业页面后续新增模板 ID,新增模板需同时更新 SDK 和壳。
金额全部使用整数分(CNY);商品 1–40 项,数量 1–999,金额最大 100,000,000 分,应付金额大于 0。必须满足 sum(unitPrice * quantity) - discountAmount === payableAmount,无优惠时省略 discountAmount。订单号最多 100 字符,商户/商品名称最多 80,规格最多 160,备注最多 300;图片 URL 最多 1024 字符。整个请求仍受 16,384 字符限制,图片应传 URL,不传图片内容。
订单数据和支付跳转信息应来自同一笔后端订单。预览参数只用于展示,不创建订单、不修改实际扣款金额,也不能替代后端对订单归属、金额和签名的验证。SDK 不保存商户密钥或承接支付回调。
返回值始终是 paymentStatus: 'unknown':成功只代表微信接受打开请求且承载流程返回。取消、超时或页面退出也不能断言订单未支付,应按业务需要查单。提前返回产生 CANCELLED 并释放单次调用限制;重复点击不会重复拉起,失败不自动切换全屏或重试支付。默认等待 600 秒,只支持 Hash 回传;可以通过 options.timeoutMs 调整(1000–600000 ms)。与基础能力共享 BUSY、超时、取消、onResult 和文档重建恢复。
普通浏览器默认返回 UNSUPPORTED,可以用 browser.handlers['payment.preview'] 接入自己的网页确认流程。显式 mock 模式自动返回同格式的 unknown 回执,不显示原生订单页、不拉起收银台、不模拟支付成功;可用 mock.handlers['payment.preview'] 覆盖。所有模式遵守相同参数和返回校验。
默认路由 /extended/payment-preview,可在 createWechatBridge 中设置 paymentPreviewPath;nativePath 仍只控制基础能力。宿主必须包含该路由和允许的目标 AppID,旧壳无法使用新增页面。BRIDGE_METHODS 保持 10 个基础方法,协议另外导出 EXTENDED_BRIDGE_METHODS 和合并的 ALL_BRIDGE_METHODS,扩展方法名为 payment.preview。宿主可从 /payment-preview 子入口复用无 DOM 的参数类型和校验函数。
宿主契约与扩展
默认原生路由 /native/invoke,通过 request URL 参数携带 JSON:v、id、method、params、mode、returnUrl、createdAt、expiresAt。可用 nativePath 更改路由,原生宿主须实现相同协议。旧的 /native/location 在示例宿主保留兼容。
普通能力在原生页 ready 时调用注册的 handler,完成后自动 navigateBack。跨小程序打开成功后等待用户返回;半屏和全屏跳转由原生按钮触发。宿主把结果添加到 WebView src 的 __mp_bridge 字段。JS 协议模块同时导出于 @spopc/wechat-miniprogram/protocol,可供小程序端使用,不依赖 DOM、URL、Node API。
当前支持的方法采用明确注册表,拒绝未知方法和额外参数,不开放任意 wx 方法执行。扩展能力时同步修改协议类型与校验、宿主 handler、SDK 快捷方法和测试。
默认只适配示例中允许的业务域名。请求与结果 JSON 的应用上限为 16,384 字符,宿主/微信版本可能有更低 URL 限制;大内容应走业务后端引用。Hash 路由需兼容临时的 __mp_bridge 字段。超时后原生操作本身不一定可撤销,尤其支付不得仅因超时直接重试。
普通能力的中间页无需用户操作;半屏及全屏打开其他小程序按微信要求需点击按钮。扫码、地图、收货地址、拨号、支付和权限提示由微信展示,不能承诺无感或没有路由动画。扫码 UI 及支付参数约定见 Taro 扫码文档、Taro 支付文档。
已验证范围
2026-10-15,SDK 0.5.0:94 项自动测试通过,新增 Extended Bridge 参数、金额、路由、结果关联、提前返回、超时和收银台生命周期测试。开发者工具通过 Bridge Lab 的实际 H5 按钮验证原生订单页、系统返回取消、微信打开确认取消,以及打开成功后返回 H5 的 live Hash 回执和原 Promise resolve;连续三次调用保持同一网页实例。默认及 compact 主题已目视检查。仅打开目标首页,没有创建支付订单;外部茶饮 H5 尚需接入新方法,真机半屏和实际支付尚未验证。
2026-10-14,SDK 0.4.1:83 项自动测试通过,包含取消回传事件丢失 / 延迟、Hash 路由先处理事件、旧导航回调迟到、前后台超时及原生 unload / onShow 顺序。开发者工具通过测试 H5 连续两次进入半屏承载页后提前返回,均收到 live CANCELLED 并结束 Promise,随后 checkSession 成功。退出通过程序导航及原生返回按钮验证;iOS / Android 真机侧滑仍需验收。
2026-10-14,SDK 0.4.0:开发者工具中使用真实 openEmbeddedMiniProgram / navigateToMiniProgram API,点击原生按钮及微信确认框,验证打开成功、返回后 Hash 成功结果,以及半屏取消的 CANCELLED 回传。成功时保留承载页,返回后自动回到 H5。目标 AppID 为 wx0d121e2a0bd96e51,微信确认框显示名称“旺铺管家一”。开发者工具只显示“跳转成功”占位页,不代表目标真机半屏形态、参数接收或支付已验证;茶饮 H5 还需升级 SDK 并部署。
2026-10-13,Windows 微信开发者工具 Stable 2.02.2608070 / 基础库 3.17.4:自动 login、getLocation、checkSession、scanCode 成功及扫码取消均完成往返,通过 Hash 在同一页面收到 live 结果。扫码使用开发者工具选择测试二维码图片,不代表真机相机扫描已测试。初版定位页另验证过 Query 重载与 recovered 恢复。iOS / Android 真机、真实支付、拨号、地图、个人地址尚未实测。
在源码仓库根目录构建:npm run build:sdk;打包检查:npm run pack:sdk -- --dry-run。这些命令会从 sdks/wechat-miniprogram/VERSION 同步版本,包只包含 dist、README 和 package.json。发布新版本时修改 VERSION 并推送到 main,CI 会检查、发布 npm 并同步 npmmirror。
