Safe Haven 中文文档 下载 App

Safe Haven 社区投稿和自动发现,GitHub Top 50 也会被抓进来

三种"非开发者"来源

Safe Haven 的目录里不是所有应用都是开发者自己提交的。有三种来源会把应用先抓进来,再等开发者认领:

  1. 社区投稿:用户主动提交一个源码仓库地址
  2. 自动化发现:Safe Haven 后台自动去 GitHub / OpenHub 抓热门开源安卓项目
  3. 上游仓库同步:F-Droid / IzzyOnDroid 索引同步(另一个话题,详见同步那一页)

这三种来源的共同特点是:条目标记为 unverified,打上 Unverified Listings 标志。

社区投稿

用户怎么提交

在 Safe Haven 的 GitHub Discussions 上有一个专门的 App Suggestions 分类(discussions/categories/app-suggestions),用户可以发帖推荐想在 Safe Haven 上看到的应用,附上源码仓库地址。

或者直接在 store.colourswift.com 的 Web 门户上提交仓库 URL(GitHub / GitLab / Codeberg)。

提交后发生什么

  1. 条目进数据库,trustLevel 设为 unverified
  2. 如果包名还不知道,系统用 {owner}-{repo} 格式生成一个临时占位符(比如 phsycologicalFudge-SafeHaven-Store)
  3. Poller 检查上游仓库的 Release,找到最新 APK
  4. APK 下载进 staging 目录
  5. 扫描管线跑——扫描时从 manifest 里提取真实包名,覆盖临时占位符
  6. 通过扫描 → 进 pending_review → 自动批准 → 进公开目录(带 unverified 标志)

提交被拒绝的可能原因

自动化发现

GitHub Top 50 抓取

Safe Haven 的后端定期调用 GitHub Search API,搜索star 数最高的开源安卓项目(Top 50)。条件:

发现一个不重复的项目就拉进来,走和社区投稿一样的管线。

OpenHub 次级来源

除了 GitHub,Safe Haven 的 bootstrap(初始化)流程也查 OpenHub 做补充。OpenHub 收录了很多较老的开源项目,一些 GitHub 上 star 不多但在 OpenHub 上活跃的项目可能会被发现。

自动发现的局限

自动发现依赖可访问的公开仓库和 GitHub Search API 的结果:

管理员直接导入

管理员可以在后台给任意支持的仓库 URL手动导入应用。除了社区投稿和自动发现,管理员还能指定:

这个通道通常用于:自动发现漏掉了但管理员知道值得收录的项目、或需要手动触发一次同步测试。

为什么要标记 unverified

Safe Haven 对未验证条目的处理不是"删掉",而是"保留但明确标记"——原因是:

  1. 信息透明:让用户知道这个条目不是作者自己提交的
  2. 开发者发现:开发者可能还不知道自己的应用在 Safe Haven 上,标记了他就知道"这个条目可以认领"
  3. 社区贡献激励:用户主动推荐的应用有价值,不应该因为作者还没来认领就挡在门外
  4. 安全底线:扫描管线对未验证条目一视同仁——过不了扫描就进不了公开目录

认领流程(claim)

原始开发者发现自己的应用在 Safe Haven 上但没被认领,可以去 store.colourswift.com 的开发者门户认领:

  1. 找到自己应用的条目
  2. 在源码仓库根目录放 .safehaven 文件完成握手验证(和新应用注册一样)
  3. Safe Haven 后台抓取比对 token
  4. 验证成功 → trustLevel 从 unverified 变成 verified_source
  5. 如果来源是 F-Droid:额外需要提供新的签名哈希(因为 F-Droid 的 APK 用 F-Droid 签名,认领后切成开发者原生签名),系统会清除旧的 F-Droid 版本记录

认领成功后,这个应用就变成了"标准的开发者所有条目",后续的自动同步会从开发者自己的仓库抓,不再从 F-Droid 或其他上游。

社区投稿质量

社区投稿的质量参差不齐——有的用户推荐的是主流应用,有的是小众实验项目。Safe Haven 扫描管线统一处理所有投稿,不做质量筛选。但有一个自动过滤:扫描没过的不会进公开目录。所以最终在客户端能看到的社区投稿条目,至少都通过了扫描管线。

临时占位符怎么解决

社区贡献的条目如果提交时没给包名,系统会用 {owner}-{repo} 格式生成一个临时包名。这个临时包名只在数据库内部使用,用户不会在客户端看到。扫描管线跑通后,从 APK manifest 里提取真实包名,自动替换掉临时占位符。