
# 社区分享预置

`share.showShareMenu()` 和 `share.screenshot()` 可以给客户端的“转发到社区”流程预置分区与话题。预置内容进入发帖页后仍可由用户修改，SDK 不会直接发布内容。

## 普通分享

普通分享的落地页固定为当前小程序的 `common_share`，不接受自定义 `url`。普通分享只支持一个默认分区，并且配置 `post` 时不要同时指定站外 `channel`。

```ts
import { share } from '@heybox/hb-sdk'

await share.showShareMenu({
  title: '本局战绩',
  desc: '查看我的完整战绩',
  post: {
    topicIds: [235709],
    topics: ['无畏契约战绩'],
  },
})
```

## 截图分享

截图分享可以预置多个分区，客户端发帖页负责最终选择与确认。进入社区发帖流程后，客户端会自动把帖子关联到当前小程序，开发者无需配置额外来源字段。

SDK 在每次调用截图时输出行为变更 warning，提醒版本门槛、底部预留区域和明暗配色。这是 SDK 侧的升级提示，日志输出失败不影响截图调用；Runtime 只负责按版本选择水印行为，不输出兼容警告。

**升级注意：正式 SDK `0.9.1` 起默认添加截图水印。** 新 Runtime 使用已校验的 SDK 版本记录判断：低于 `0.9.1`（包括 `0.9.1-alpha.*`）时，Runtime 静默跳过水印，产物不加水印；版本记录缺失的兼容模式同样不加水印。`0.9.1` 及以上保持默认水印行为。升级 SDK 时必须同时检查下述预留区域与配色要求。

启用水印后，调用 `share.screenshot()` 时，Runtime 自动在目标截图区域底部居中添加「小黑盒 + 搜索图标 + 当前小程序名称」胶囊，下方为灰色「小黑盒工坊小程序」。水印进入截图后随图片用于预览、保存、站外分享及社区发帖，开发者无需自行绘制。

**布局要求：在目标截图区域底部预留至少 57 个逻辑像素的空白背景**，不要放置成绩、正文、按钮等重要内容；背景应与所选水印配色保持足够对比度。使用自定义 `rect` 时，预留区域以该矩形底部为准。水印叠加在区域内，不会额外增加图片高度；正常浏览时不常驻，仅在 SDK 截图期间展示，完成或失败后移除。系统按键截图暂不支持添加此水印。

可通过 `watermarkTheme` 按截图背景选择配色：`light` 适合浅色背景，使用黑色图标、边框和名称；`dark` 适合深色背景，使用白色图标、边框和名称。说明文字分别为 40% 黑色或白色。默认 `dark`，保持现有白色水印效果，不自动跟随 App 或系统主题；旧 Runtime 可能忽略此字段。

```ts
await share.screenshot({
  watermarkTheme: 'light', // 浅色截图背景使用黑色水印
  delay: 100,
  saveToAlbum: true,
  post: {
    topicIds: [235709, 66739],
    topics: ['无畏契约战绩'],
  },
})
```

截图等待不受 SDK 普通请求的固定超时限制。排队和 `delay` 期间会响应会话终止；移动端从投递原生截图起最多等待 15 秒成图回调，已投递的截图无法保证撤回。结果为不透明值，不要根据返回值的真假判断用户是否分享成功。

调用前需声明并启用 [`share` 权限](../guide/permissions.md)。Android、iOS、OHOS 的移动 Host 提供真实截图分享；当前新 PC 的 Windows/macOS Host 未开放，应处理 `METHOD_FORBIDDEN`。Browser Dev Host 仅展示参数确认，仍需真机验收。完整参数与平台边界见 [`share.screenshot()`](../reference/sdk/share/screenshot.md)。

## 恢复分享页面状态

通过固定通用分享链接分享时，可以使用 `extra` 携带由小程序自行定义的页面状态。分享方只负责写入状态，接收方负责决定如何使用：

```ts
await share.showShareMenu({
  title: '排行榜',
  desc: '查看当前排名',
  extra: { page: 'ranking', options: [1, 2, 3] },
})
```

需要由业务按钮复制链接时，传入同样的状态即可：

```ts
const shareUrl = await share.copyLink({
  extra: { page: 'ranking', options: [1, 2, 3] },
})
```

`copyLink()` 完成时链接已写入系统剪贴板，并返回同一个完整链接。它不会自动弹出提示，建议在用户点击后调用并自行展示成功反馈。

小程序被分享链接打开后，用同步的 `getExtra()` 读取状态，再交给自己的路由：

```ts
const sharedState = share.getExtra()
const routeMap = { ranking: '#/ranking', profile: '#/profile' } as const

if (sharedState && typeof sharedState === 'object' && !Array.isArray(sharedState)) {
  const page = sharedState.page
  const target = typeof page === 'string' ? routeMap[page as keyof typeof routeMap] : undefined
  if (target) window.location.hash = target
}
```

`getExtra()` 不依赖异步请求；没有有效数据时返回 `undefined`，业务应回退到默认首页。`extra` 只支持 JSON-compatible 数据，最多 8 层，单个数组或对象最多 64 项，内容不超过 128 字节，也不要存放 token、个人信息等敏感数据。`copyLink()` 不会继承当前启动链接中的 `extra`，只携带本次显式传入的数据。

## 参数边界

- `topicIds` 接受正整数或非空字符串，按首次出现顺序去重。
- `topics` 只传话题内容，不要添加首尾 `#`；字符串会先 trim 再去重。
- `post: null` 等同于不配置社区发帖预置，`post: {}` 是无效配置。
- 本地 Mock、App Dev Shell 和开发 Runtime 会对无效配置返回 `INVALID_PARAMS`。
- 生产 Runtime 会过滤无效项；普通分享只使用第一个有效分区，配置冲突时保留站外 `channel`，不会阻断原分享流程。

调用方不能通过该 API 传客户端协议、回调、自定义按钮或发布指令。
