# getInstalledRelatedApps()

> navigator.getInstalledRelatedApps() 如何报告 related_applications 中哪些条目已安装，各平台的验证方式，空数组与 InvalidStateError 的情形。

`navigator.getInstalledRelatedApps()` 兑现为调用方 web 应用 manifest 中 `related_applications` 里已安装在设备上的那部分条目，站点据此可以隐藏自己的安装按钮，或深链接到原生对应应用。Android 上的 Chrome 84 与 Samsung Internet 14 报告 Play 应用与已安装的 PWA；Windows 上的 Chrome 85、Edge 85 与 Opera 71 只报告 UWP 应用，同样的浏览器在 macOS、Linux、ChromeOS 上兑现为空数组；Firefox 与 Safari 均未实现（BCD `api.Navigator.getInstalledRelatedApps`）。

## 语法

```js
const apps = await navigator.getInstalledRelatedApps();
```

该方法带有 `[SecureContext]`，在纯 HTTP 源上不存在；它只定义在 `Navigator` 上，`WorkerNavigator` 上没有。

## 参数

无。Promise 兑现为一个 `RelatedApplication` 字典数组，每个已安装的匹配项一个元素，字段如下。

| 字段 | 类型 | 说明 |
|---|---|---|
| `platform` | `string` | 商店或生态：`"play"`、`"windows"`、`"webapp"`、`"chrome_web_store"`、`"chromeos_play"`、`"f-droid"` 或 `"amazon"`。从 manifest 条目复制而来。 |
| `id` | `string`，可选 | 平台相关的标识符（Android 包名、UWP 包家族名）。 |
| `url` | `string`，可选 | manifest 条目中的 `url`；对 `"webapp"` 而言是相关 PWA 的 manifest URL。 |
| `version` | `string`，可选 | 平台暴露的已安装版本。 |

匹配需要关系的两端同时成立：调用方站点的 manifest 条目，以及另一方应用指回来的声明。Android 应用通过 Digital Asset Links（资源中的 `asset_statements`，与站点的 `/.well-known/assetlinks.json` 相互验证）声明；UWP 应用通过 URI handler 声明；相关 PWA 则通过自己的 `related_applications` 条目声明，若它在调用方 scope 之外，则通过 `assetlinks.json` 声明。

## 异常

- `InvalidStateError`：从非顶层浏览上下文的文档（例如 `<iframe>`）调用，或文档已不再 fully active（规范 "getInstalledRelatedApps()" 第 1、2 步）。
- `TypeError`：Firefox 与 Safari 中 `navigator.getInstalledRelatedApps` 为 `undefined`，同步抛出；在不安全源上，任一浏览器亦是如此。

空数组不是错误。`related_applications` 缺失、列出的应用都未安装、反向引用（asset links 或 URI handler）验证失败，以及 Windows 之外的 Chromium 桌面版本，结果都是空数组。

:::observed
在 macOS 上的 Chrome（英文界面）控制台中执行 `await navigator.getInstalledRelatedApps()`，即使站点 manifest 列出了一个已安装的 `"webapp"` 条目，结果仍是 `[]`，这正是文档记载的非 Windows 桌面行为；Firefox 中同一行抛出 `TypeError: navigator.getInstalledRelatedApps is not a function`，Safari 抛出措辞不同的 `TypeError`。Chrome 只检查 `related_applications` 的前 3 个条目，第 4 个起永远不会被报告（Chrome 能力指南）。
:::

## 示例

两个示例都假定 manifest 的 `related_applications` 列出了 Android 应用 `com.example.app` 与站点自己的 PWA。

### Play 应用已安装时隐藏安装按钮

manifest 声明关系；页面在决定是否显示 web 安装入口前先检查。由于该方法只回答前 3 个条目，最重要的应用要排在前面。

```json
{
  "related_applications": [
    { "platform": "play", "id": "com.example.app",
      "url": "https://play.google.com/store/apps/details?id=com.example.app" },
    { "platform": "webapp", "url": "https://example.com/manifest.json" }
  ],
  "prefer_related_applications": false
}
```

```js
async function decideInstallUi() {
  const apps = await navigator.getInstalledRelatedApps();
  if (apps.some((app) => app.platform === 'play')) {
    installButton.hidden = true;             // 原生应用已在设备上
    openInAppLink.hidden = false;            // 改为提供深链接
  } else if (apps.some((app) => app.platform === 'webapp')) {
    installButton.hidden = true;             // 这个 PWA 已从另一个浏览器或配置文件安装
  }
}
```

除非希望原生应用取代 PWA，否则让 `prefer_related_applications` 保持 `false`：它为 `true` 时，Chrome 的安装界面会转而提供商店页面，而不是安装 web 应用。

### 检测支持并回退到安装提示

该方法不存在或没有结果时，页面得不到来自其他应用的已安装信号，应回退到常规安装流程，并用 `display-mode` 检查判断自身是否已安装。

```js
async function relatedAppInstalled() {
  if (!('getInstalledRelatedApps' in navigator)) return false;   // Firefox、Safari、HTTP
  try {
    const apps = await navigator.getInstalledRelatedApps();
    return apps.length > 0;
  } catch (error) {
    if (error.name === 'InvalidStateError') return false;        // 在 iframe 内被调用
    throw error;
  }
}

if (!(await relatedAppInstalled())) {
  showInstallAffordance();   // beforeinstallprompt 流程，或 iOS 上的分享菜单指引
}
```

`false` 分支是正确的降级行为：无法回答这个问题的浏览器应当表现得像没有相关应用一样，最坏的结果不过是向已经装了原生应用的用户多显示一个安装按钮。

## 另请参阅

- [Get Installed Related Apps API specification](https://wicg.github.io/get-installed-related-apps/spec/)（wicg.github.io）
- [Is your app installed? getInstalledRelatedApps() will tell you!](https://developer.chrome.com/docs/capabilities/get-installed-related-apps)（developer.chrome.com）
- [getInstalledRelatedApps() 浏览器支持](/zh/compatibility/get-installed-related-apps/)
- [`related_applications` manifest 成员](/zh/reference/manifest/related-applications/)
- [beforeinstallprompt 事件](/zh/reference/installation/install-prompt/)
- [N+1 安装问题](/zh/reference/installation/n-plus-one/)