更新记录

0.2.0(2026-09-25) 下载此版本

  • 新增按 shareId 管理的多记录本地收件箱,默认保留最近 20 条,最多可配置 100 条。
  • 新增 SharedRecord、SharedItemFailure、接收状态和平台能力数据结构。
  • 新增完整记录监听、历史读取、单条确认、全部清理、主动修剪、能力查询和状态查询接口。
  • 新增附件数量、单文件大小、单次总大小、MIME 类型白名单和保留时长配置。
  • Android 与 iOS 支持完整、部分成功和失败三种记录状态,并返回逐项失败原因。
  • Android Cache 与 iOS App Group 均加入历史淘汰、过期清理和孤立附件清理。
  • 保留 0.1.x 的四个接口;旧读取与监听映射到最新一条记录,旧清理接口映射为清空全部记录。
  • 示例页升级为白色中文收件箱界面,可查看状态、历史、失败项目,并按条确认清理。
  • 同步更新插件版本、iOS Extension 版本和 0.2.0 接入、存储、测试及验证文档。
  • 本次按开发安排只完成编码与文档收口,未启动模拟器或执行最新页面、Extension 的运行调试。

0.1.0(2026-08-24) 下载此版本

  • 实现 Android ACTION_SEND / ACTION_SEND_MULTIPLE 系统分享入口。
  • 支持文字、链接、单图、多图和普通文件,附件复制到应用私有缓存。
  • 完成冷启动、运行中回调、最近结果持久化、重复回放与显式清理。
  • 完成 iOS App Group 宿主桥接和 Share Extension 可编译源码模板。
  • 新增交互式收件箱示例页、API 文档、iOS 集成指南与双端测试清单。
  • 通过 Android、iOS 插件模块及 uni-app x 整项目编译。

平台兼容性

uni-app x(4.0)

Chrome Safari Android Android插件版本 iOS iOS插件版本 鸿蒙 微信小程序
× × 5.0 0.2.0 12 0.2.0 × ×

其他

多语言 暗黑模式 宽屏模式 蒸汽模式
× × × √

接收系统分享文字图片与文件

xs-share-receiver 是面向 uni-app x App 的系统分享接收 UTS 插件。它把 Android 系统分享 Intent 与 iOS Share Extension 统一为本地收件记录,可接收其他应用主动分享的文字、网页链接、单图、多图和普通文件。

当前版本:0.2.0

0.2.0 源码已完成。当前版本新增历史、失败明细、限制、确认和清理能力;本轮按项目安排未启动模拟器,也未完成 0.2.0 最新代码的真机端到端验收。Android 必须使用包含插件原生清单的自定义基座或正式安装包;iOS 必须使用自己的 Bundle ID、App Group 和描述文件构建签名 Share Extension。

这个插件解决什么问题

普通页面代码不能直接把 Android 分享 Intent 和 iOS NSItemProvider 当作稳定业务数据使用。来源 URI 可能只有短暂读取权限,系统分享入口也属于原生安装包能力。本插件负责:

  1. 把应用注册到系统分享面板。
  2. 在临时授权有效时读取并复制附件。
  3. 把双端内容统一为 SharedRecord。
  4. 保存多条本地收件记录并回放最新一条。
  5. 记录每个未接收附件的失败原因。
  6. 按业务策略限制数量、大小、类型和保留时间。
  7. 在业务处理完成后按 shareId 确认并清理。

插件不负责“从本应用分享出去”,也不包含上传、云同步、文件预览、解压、OCR、病毒扫描或业务入库。

适用场景

  • 从微信、浏览器、相册或文件管理器把内容送入业务 App。
  • 制作“保存到应用”“发送到工作台”“导入到项目”等系统入口。
  • 接收图片、合同、报表、音视频或其他业务附件。
  • 将临时 URI 转换为后续可读取的本地文件路径。
  • 给离线采集、资料归档和待处理收件箱提供入口层。

0.2.0 新能力

能力 说明
多记录收件箱 默认保留最近 20 条,可配置 1~100 条
唯一分享编号 每次分享生成 shareId,用于业务幂等和确认
结果完整度 返回 complete、partial 或 failed
失败明细 返回失败项索引、名称、MIME 和稳定原因码
可配置限制 历史数、附件数、单文件大小、单次总大小、类型白名单、保留时长
消费确认 可按 shareId 移除记录并选择是否删除附件
自动修剪 清理过期、超容量记录和孤立附件
运行状态 查询平台就绪、监听状态、记录数、文件数和占用字节
能力查询 查询当前平台公开能力和最低系统版本
向后兼容 保留 0.1.x 的读取、监听、停止和清理接口

平台支持

项目 Android iOS
最低版本 Android 5.0 / API 21 iOS 12.0
uni-app x 支持 支持
网页、小程序、鸿蒙 不支持 不支持
系统入口 透明接收 Activity 独立 Share Extension
附件位置 应用 Cache App Group 容器
记录索引 应用私有偏好 App Group 共享偏好
拉起主应用 接收后尝试回到主应用 系统不保证自动拉起主应用
来源应用 尽力返回包名 当前返回 null
网络与公共存储权限 不需要 不需要照片库权限

开发环境要求:HBuilderX 5.0 及以上、uni-app x 4.0 及以上。

使用前必须了解

  1. 标准基座不能验证新增的 Android Activity 或 iOS Extension。
  2. iOS .appex 不能跨开发者账号通用分发,必须由集成方签名。
  3. 插件路径是临时接收区,不是业务永久文件库。
  4. 启动监听会回放最新记录,业务要用 shareId 幂等。
  5. 限制项会产生失败明细,不应只检查 files.length。
  6. iOS 分享完成后通常需要用户手动返回主应用。

安装与导入

将本目录放到业务工程:

uni_modules/xs-share-receiver/

推荐导入:

import {
  acknowledgeSharedRecord,
  clearSharedRecords,
  configureShareReceiver,
  getSharedRecords,
  getShareReceiverCapabilities,
  getShareReceiverStatus,
  pruneSharedRecords,
  ShareReceiverStatus,
  SharedRecord,
  startShareRecordReceiver,
  stopShareReceiver
} from '@/uni_modules/xs-share-receiver'

不要从 utssdk 或平台子目录导入内部实现。

推荐接入示例

export default {
  data() {
    return {
      records: [] as SharedRecord[],
      ready: false,
      message: ''
    }
  },
  onLoad() {
    configureShareReceiver({
      maxHistoryCount: 20,
      maxFileCount: 32,
      maxFileSizeBytes: 104857600,
      maxTotalSizeBytes: 314572800,
      allowedMimeTypes: [] as string[],
      retentionHours: 72
    })

    pruneSharedRecords()
    this.reloadInbox()

    startShareRecordReceiver((record : SharedRecord) => {
      this.reloadInbox()
    })
  },
  onUnload() {
    stopShareReceiver()
  },
  methods: {
    reloadInbox() {
      this.records = getSharedRecords(20)
      const status : ShareReceiverStatus = getShareReceiverStatus()
      this.ready = status.ready
      this.message = status.message ?? ''
    },
    finishRecord(record : SharedRecord) {
      // 先完成业务复制、上传或入库,再删除插件附件。
      const removed = acknowledgeSharedRecord(record.shareId, true)
      if (removed) this.reloadInbox()
    },
    clearInbox() {
      clearSharedRecords(true)
      this.reloadInbox()
    }
  }
}

Android 进程刚启动时建议先调用 configureShareReceiver(),让原生层取得应用上下文,再读取状态和历史。

接收流程

Android

来源应用选择分享
        ↓
系统匹配接收 Activity
        ↓
读取文字与临时授权 URI
        ↓
应用接收策略并复制附件到 Cache
        ↓
保存 SharedRecord 历史
        ↓
回到主应用并通知当前监听者

iOS

来源应用打开系统分享面板
        ↓
用户选择已签名 Share Extension
        ↓
扩展读取 Provider、校验并复制附件
        ↓
记录写入 App Group
        ↓
用户打开或返回主应用
        ↓
宿主桥接检查变化并通知当前监听者

接口总览

接口 说明
configureShareReceiver(options) 保存接收和保留策略
getSharedRecords(limit) 倒序读取最多指定条数
getLatestSharedRecord() 读取最新一条,不消费
startShareRecordReceiver(callback) 监听完整记录并回放最新记录
stopShareReceiver() 停止当前回调,保留数据
acknowledgeSharedRecord(shareId, deleteFiles) 确认并移除指定记录
clearSharedRecords(deleteFiles) 清空全部记录,返回移除数量
pruneSharedRecords() 应用过期、数量和孤立文件清理
getShareReceiverCapabilities() 查询平台能力
getShareReceiverStatus() 查询就绪、监听和缓存状态

完整签名见 ../../docs/API.md。

记录结构

type SharedRecord = {
  shareId: string
  text: string | null
  url: string | null
  files: SharedFile[]
  sourceApp: string | null
  receivedAt: number
  status: string
  requestedCount: number
  successCount: number
  failedCount: number
  failures: SharedItemFailure[]
}

典型部分成功结果:

{
  "shareId": "4c468d19-8db1-4eec-a76d-5cb874c83620",
  "text": "资料请查收",
  "url": null,
  "files": [
    {
      "name": "photo.jpg",
      "path": "/private/path/xs-share-receiver/uuid-photo.jpg",
      "mimeType": "image/jpeg",
      "size": 286720
    }
  ],
  "sourceApp": null,
  "receivedAt": 1788710400000,
  "status": "partial",
  "requestedCount": 2,
  "successCount": 1,
  "failedCount": 1,
  "failures": [
    {
      "index": 1,
      "name": "video.mp4",
      "mimeType": "video/mp4",
      "reason": "FILE_TOO_LARGE"
    }
  ]
}

示例路径只说明数据结构,不能硬编码或跨设备复用。

接收策略

type ShareReceiverOptions = {
  maxHistoryCount: number
  maxFileCount: number
  maxFileSizeBytes: number
  maxTotalSizeBytes: number
  allowedMimeTypes: string[]
  retentionHours: number
}
参数 默认值 说明
maxHistoryCount 20 配置范围 1~100
maxFileCount 32 配置范围 1~32
maxFileSizeBytes 0 0 表示不设置插件级限制
maxTotalSizeBytes 0 0 表示不设置插件级限制
allowedMimeTypes 空数组 空数组允许所有类型
retentionHours 0 0 表示不过期,最大 8760 小时

白名单支持 image/* 这类类型族,也支持 application/pdf 这类精确值。限制只减少插件愿意复制的内容,不代替业务端的文件安全检查。

失败原因

原因码 建议提示
FILE_COUNT_EXCEEDED 超过单次附件数量上限
MIME_NOT_ALLOWED 文件类型不在允许范围
FILE_TOO_LARGE 文件超过单文件大小限制
TOTAL_SIZE_EXCEEDED 本次附件总量超过限制
READ_PERMISSION_DENIED 来源未授予有效读取权限
SOURCE_UNAVAILABLE 来源内容已不可读取
CACHE_DIRECTORY_UNAVAILABLE 无法创建插件缓存目录
COPY_FAILED 复制文件时发生其他错误

原因码用于程序判断;用户提示应根据业务语境翻译,不建议直接展示英文码。

回放、幂等与监听

  • 只存在一个活动监听者;新旧监听接口会相互替换。
  • 开始监听时会回放最新一条现有记录。
  • 页面重建后可能再次收到同一条记录。
  • 使用 shareId 做幂等,而不是文件名、接收时间或来源应用。
  • stopShareReceiver() 不影响系统继续写入本地收件箱。
  • 停止期间收到的内容,可在下次读取历史或开始监听时取得。

确认与清理

推荐业务顺序:

  1. 收到 SharedRecord。
  2. 检查状态和 failures,决定是否接受部分成功。
  3. 校验文件是否存在、大小和类型是否符合业务要求。
  4. 复制到业务持久目录,或完成上传与数据库提交。
  5. 使用同一个 shareId 防止重复入库。
  6. 成功后调用 acknowledgeSharedRecord(shareId, true)。

deleteFiles = false 只是在当前调用中不删除附件。记录被移除后,这些文件失去引用,未来 pruneSharedRecords() 仍可能把它们视为孤立文件删除。需要长期保存必须先复制到插件目录之外。

Android 接入

插件 Manifest 已注册:

  • android.intent.action.SEND
  • android.intent.action.SEND_MULTIPLE
  • MIME */*

必须使用重新制作的自定义基座或正式安装包。若分享面板没有入口,先检查最终合并 Manifest 是否包含 ShareReceiverActivity,再检查来源应用实际提供的 Intent 类型。

Android 会读取 EXTRA_TEXT、EXTRA_STREAM、ClipData 和文件型 data URI,对 URI 去重并在临时授权有效期间复制。透明 Activity 完成后会尝试通过宿主启动 Intent 返回主应用。厂商后台限制和任务栈差异需要真机验证。

iOS 接入

iOS 需要独立签名 Share Extension。发布者必须:

  1. 创建主应用和 Extension 两个 Bundle ID。
  2. 给两个 App ID 分配同一个 App Group。
  3. 重新生成两份包含 App Group 的描述文件。
  4. 用仓库 Swift 源码构建并签名 .appex。
  5. 将产物放入 utssdk/app-ios/Plugins/。
  6. 在业务工程配置 nativeResources/ios/ios-extension.json。
  7. 检查最终 .app/PlugIns/、嵌套签名和两端 entitlement。

完整步骤见 ios-extension-source/README.md 和 ../../docs/IOS_EXTENSION.md。

缓存与保留

场景 0.2.0 行为
新分享写入 追加到历史顶部,并按策略修剪
超过历史上限 移除最旧记录并删除其插件附件
超过保留时间 修剪时移除过期记录和附件
按条确认 移除指定记录,可同时删除附件
清空全部 移除全部记录,可同时删除附件
孤立文件 主动修剪时删除不被任何记录引用的插件附件
系统回收 Android Cache 仍可能由系统主动回收
应用卸载 应用私有数据通常随应用删除

历史记录不等于永久归档。业务仍需对重要文件建立自己的持久化、校验、备份和删除流程。

0.1.x 升级说明

以下接口继续可用:

getInitialSharedPayload()
startShareReceiver(callback)
stopShareReceiver()
clearSharedPayload()

兼容读取和监听映射到最新一条记录。旧结构看不到 shareId、状态和失败明细。为了避免历史残留,0.2.0 的 clearSharedPayload() 会清空全部记录及插件附件。需要按条消费的新项目应迁移到 SharedRecord 接口。

常见问题

为什么监听一启动就收到已有内容?

这是冷启动回放。使用 shareId 判断业务是否已经处理;不要依赖回调次数。

为什么记录状态是“部分接收”?

本次至少有一个附件成功,也至少有一个失败。查看 failures 决定继续处理成功项,还是要求用户重新分享。

为什么记录状态是“接收失败”但仍保留?

0.2.0 会保存失败记录,便于页面给出明确原因和后续排错,而不是静默丢失。

为什么 sourceApp 为空?

来源标识不是稳定系统承诺。Android 仅在系统提供 calling package 或 referrer 时返回;iOS 当前为 null。它不能作为可信身份或权限依据。

路径能永久保存吗?

不能。Android Cache 可能被系统回收,iOS App Group 也受插件保留规则管理。需要长期使用时先复制到业务目录。

插件会上传内容吗?

不会。插件不联网、不上传、不内置广告、统计、账号或云服务。集成应用自己的网络行为需要单独说明。

更多排错见 ../../docs/FAQ.md。

当前限制

  • 单次候选附件硬上限为 32 个。
  • 不提供字节级复制进度、单项取消和超时接口。
  • Android sourceApp 不保证存在,iOS 当前固定为 null。
  • iOS 分享完成后不保证自动拉起主应用。
  • iOS .appex 必须使用集成应用自己的签名资产制作。
  • 不提供分享发送、业务归档、文件预览、上传、同步、扫描或加密存储。
  • 0.2.0 最新源码尚未完成当前轮次的模拟器、自定义基座和真机回归。

发布前验证

至少覆盖:

  1. Android 和 iOS 的冷启动、后台、前台路径。
  2. 文字、链接、中文、换行和表情符号。
  3. 单图、多图、PDF、文本、音频、视频和无扩展名文件。
  4. 1、配置上限和 33 个候选附件。
  5. 单文件大小、单次总量和 MIME 白名单边界。
  6. 完整、部分和失败三种状态及每个原因码。
  7. 连续分享、回放幂等、按条确认、全部清理和过期修剪。
  8. 不同 Android 厂商系统和至少一台 iPhone 真机。

完整矩阵见 ../../docs/TESTING.md,证据边界见 ../../docs/VERIFICATION.md。

隐私与安全

  • 只处理用户通过系统分享面板主动发送给应用的内容。
  • 插件本身不联网、不上传、不收集账号和设备标识。
  • Android 不申请公共存储权限,iOS 不因分享接收申请照片库权限。
  • 文件名、MIME 和来源应用都属于不可信元数据,不能直接用于鉴权或命令拼接。
  • 插件限制不是内容安全检查;调用方仍应做扩展名、MIME、文件头、容量、恶意内容和访问控制校验。
  • 调用方应在隐私政策中说明内容用途、保存期限、上传对象和删除方式。

插件不联网只代表插件实现本身不发送数据,不代表集成它的业务应用一定不上传。

更多文档

文档 内容
../../docs/API.md 完整接口和字段语义
../../docs/IOS_EXTENSION.md iOS 标识、App Group、签名、打包和排错
../../docs/STORAGE_AND_PRIVACY.md 存储生命周期、清理和隐私责任
../../docs/FAQ.md 接入问题与故障排查
../../docs/TESTING.md 双端 0.2.0 验收矩阵
../../docs/VERIFICATION.md 已完成和待完成的验证证据

隐私、权限声明

1. 本插件需要申请的系统权限列表:

Android 无需运行时权限但必须使用含插件 Manifest 的自定义基座;iOS 需配置 App Group、Share Extension 与对应描述文件

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

仅在本机读取用户主动分享给 APP 的内容;附件复制到应用私有目录,插件不联网、不上传

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

许可协议

MIT协议

暂无用户评论。