按 Companion 业务协议中的 opaque ID 打开一个受控附件。
Companion 自己产生并通过业务协议交给页面的附件 ID。SDK 只要求它是长度大于 0 的
string,不 trim、不限制格式或长度;空字符串和非字符串在发送请求前返回 INVALID_PARAMS。
空白字符串虽通过本地结构校验,通常仍会由 Host 按未知 ID 拒绝。
当前 Runtime session 中新注册的冻结 FileHandle direct proxy。kind 固定为
'file',mode 固定衰减为 'read',name 是 Host 提供并经校验的 basename;不返回物理路径、
原生句柄、URL、controller generation 或可持久化的 wire ref。
HbMiniProgramSDKError id 为空或不是 string 时返回 INVALID_PARAMS;Host 找不到
当前 Session 对应的 ID、该 ID 已失效或 Session 没有 attachments capability 时通常返回
COMPANION_ATTACHMENT_NOT_FOUND。
HbMiniProgramSDKError 当前 proxy 已知 Session 已退出时返回
COMPANION_SESSION_EXITED;controller 已转移给其他 Runtime generation 时返回
COMPANION_SESSION_OWNERSHIP_LOST。本地检查与 Host 打开之间存在竞态,Host 会用未公开的
controller generation 再次校验当前调用。
HbMiniProgramSDKError 当前运行快照缺少或未启用 companion 权限时返回
PERMISSION_NOT_IN_SNAPSHOT / PERMISSION_DENIED;Host 未开放 companion.openAttachment 时返回
METHOD_FORBIDDEN,旧 Runtime 可返回 METHOD_NOT_FOUND。Host 不支持 Companion 或附件描述符
暂不可用时还可能返回 COMPANION_UNSUPPORTED / COMPANION_DESCRIPTOR_UNAVAILABLE。
HbMiniProgramSDKError 当前 Runtime session 的 direct handles 已达到 1024 上限时
返回 FILE_QUOTA_EXCEEDED。Host 返回的对象不是完整 File capability、名称/mode/ref 非法、不是
精确 direct File,或 Runtime 无法注册安全 opaque handle 时返回 FILE_IO_FAILED;其他未知 Host
失败会脱敏为 COMPANION_HOST_FAILED。SDK/Runtime 终止或请求超时还可能返回
SDK_DESTROYED、RUNTIME_UNAVAILABLE、REQUEST_TIMEOUT。
id 是当前 Companion 业务协议的不透明标识,不是路径、文件名、URL、下载地址或系统 bookmark。
页面不能用 ../、绝对路径或自己拼接的字符串访问任意文件,也不应解析 ID 推断物理位置。Host
将 ID 解析为当前 Session 明确暴露的一个附件,并只把对应 File capability 交给 Runtime。
open() 本身不读取内容,也不根据扩展名推断格式。
session.attachments 仅在 Session 快照的 capability 集合包含 'attachments' 时存在;调用前应按
属性是否存在分支。打开动作需要当前 Runtime 持有 Session controller,但不要求新的可信用户手势。
session.state === 'running' 不能证明仍有控制权;有 Session event source 时应监听
onOwnershipLost() 并停止新的 open()。自定义 Host 缺少
event source 时本地状态可能不会主动更新,但 Host 仍必须拒绝旧 generation,不能把事件监听当作授权边界。
成功后附件 provenance 保存在 Runtime 文件 registry 中,不进入公开 proxy。返回句柄是独立的当前
Runtime session 能力:SDK 不会仅因随后收到 ownership-lost 或 exit 事件就在本地删除它,但 Host 可随
Session、授权或底层附件生命周期撤销访问,后续读取会以 FILE_ACCESS_REVOKED 等错误失败。因此不能
序列化、跨页面保存或假定它在 controller 转移/进程退出后仍可读;需要新句柄时先明确取得当前 controller
并重新按业务 ID 打开。
每次成功 open() 都注册一个新的 direct handle,即使 ID 相同也不缓存或复用 proxy,并与
files.pickFiles()、files.pickDirectory()、files.saveFile() 共享当前 Runtime session 的 1024
handle 上限。页面应复用已经返回的 FileHandle,避免循环重复打开同一 ID;Runtime session 结束时
registry 会统一失效。
返回句柄始终只读,即使底层 Host File 原本可写:create()、writeText()、writeBytes() 和
remove() 都会以 FILE_ACCESS_DENIED 拒绝,也不能从中派生父目录或兄弟文件。已启用的
companion 权限只为 registry 证明 provenance 的附件开放 readText()、
readBytes() 和 stat();这三项不要求另行声明
filesystem。其他 FileHandle operation 不因 attachment provenance 获得通用 filesystem 权限。
readText() / readBytes() 都会把完整附件载入内存,没有公开 stream、range read 或自动分段 API。
open() 不受文件内容大小影响,但后续读取仍受实际 PC Host 的单次 I/O 与内存限制,可能返回
FILE_TOO_LARGE;新 PC Host 没有公开沿用 Android/iOS 的固定 8 MiB 上限。可先用 stat() 做业务
大小门槛,但附件可能在两次异步调用之间变化,stat 与 read 不是原子操作。
V1 真实 attachments 仅支持实现该 capability 的新 PC Host(Windows x64 / macOS arm64);
Browser Dev Host 只提供 ID 为 'report' 的确定性 Fake 文件,用于验证 UI 与读取流程,不访问本机
任意路径。其他平台、旧 Host 或 operation 缺失时 fail closed,不提供浏览器 File / Blob、URL fetch
或内存 fallback。
import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
const session = await hbSDK.companion.getActiveSession('runner')
const attachments = session?.attachments
if (session && attachments) {
let ownsController = true
const stopOwnership = session.onOwnershipLost(() => {
ownsController = false
})
try {
const attachmentId = readAttachmentIdFromBusinessFrame()
if (!ownsController) return
const file = await attachments.open(attachmentId)
const stat = await file.stat()
if (stat.size > 4 * 1024 * 1024) throw new Error('附件超过业务读取上限')
const bytes = await file.readBytes()
consumeAttachment(file.name, bytes)
} catch (error) {
if (
error instanceof HbMiniProgramSDKError &&
(error.code === 'COMPANION_ATTACHMENT_NOT_FOUND' ||
error.code === 'COMPANION_SESSION_OWNERSHIP_LOST')
) {
showAttachmentUnavailable()
} else {
throw error
}
} finally {
stopOwnership()
}
}
Companion 产生的受控附件访问能力。
id是 Companion 业务协议中的不透明标识,不是路径、URL 或文件句柄;返回的文件只能按 当前FileHandle权限读取。