---
title: "外部链接"
description: "通过精确 origin 白名单打开系统浏览器。"
---


> 将白名单中的 HTTP(S) 链接交给系统浏览器，不在 WebView 内直接执行外部页面。

## 模块边界

`shell` 只负责把已经授权的绝对 `http` / `https` URL 交给操作系统浏览器。它不下载内容、不
返回浏览器后续页面，也不校验浏览器重定向后的 URL。

实现入口：

| 入口 | 责任 |
| --- | --- |
| `frontend/src/api/shell.ts` | URL 守卫 |
| `windows/src/platform/ksm_windows_host_services.cpp` | 精确 origin 白名单和 `ShellExecuteW` |
| `android/app/src/main/java/dev/kasumi/app/KSMAndroidHostServices.kt` | 精确 origin 白名单和 `ACTION_VIEW` |

## 平台支持

| 方法 | Windows | Android | 权限 |
| --- | --- | --- | --- |
| `KSM.shell.openExternal` / `shell.openExternal` | 支持 | 支持 | `shell.open` |

## 参数与返回

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `url` | string | 是 | 绝对 `http://` 或 `https://` URL |

返回 `{ opened: boolean }`。`true` 表示宿主已提交打开动作，不代表浏览器窗口已成功显示。

## Origin 白名单

宿主初始化时配置精确 origin 白名单，默认空白名单并拒绝所有调用。比较包含 scheme、host 和
显式端口；默认端口会规范化，例如 `https://example.com:443` 与
`https://example.com` 等价。

以下输入会被拒绝：

- `javascript:`、`file:`、`data:`、`intent:` 和 `content://`。
- 带用户名或密码的 URL。
- 相对 URL、空主机和超长 URL。
- origin 不在宿主白名单中的 URL。

只校验调用时传入的 URL。系统浏览器后续重定向不经过 Kasumi，因此宿主必须信任浏览器自身的
安全边界。

## 示例

```ts
import { KSM } from '@kasumi/bridge';

try {
  const result = await KSM.shell.openExternal({
    url: 'https://example.com/docs'
  });

  if (!result.opened) {
    console.warn('系统没有可用的浏览器处理器');
  }
} catch (error) {
  if (error instanceof Error && error.name === 'PERMISSION_DENIED') {
    console.warn('origin 未加入宿主白名单');
  }
}
```

## 错误行为

| 情况 | 错误 |
| --- | --- |
| 非法 scheme、相对 URL、凭据、空主机 | `INVALID_ARGS` |
| 未授予 `shell.open` | `PERMISSION_DENIED` |
| origin 不在白名单 | `PERMISSION_DENIED` |
| 系统没有浏览器处理器 | 返回 `{ opened: false }` 或 `IO_ERROR` |
| 宿主未配置 shell 服务 | `NOT_SUPPORTED` |

## 平台差异

Windows 使用 `ShellExecuteW`，服务层会再次检查精确 origin；Android 使用 `ACTION_VIEW`，
不会把任意 `content://`、`intent://` 或非 Web scheme 交给系统。两端默认白名单都为空，调用方
必须在宿主初始化时显式配置。

## 排查路径

1. 确认 URL 是绝对 HTTP(S)，且没有用户名密码。
2. 确认宿主白名单包含正确的 scheme、host 和端口。
3. 确认 `capabilities.permissions` 包含 `shell.open`。
4. 返回 `{ opened: false }` 时检查系统浏览器或默认处理器。
5. 不要把浏览器重定向后的地址当作 Kasumi 已验证的 URL。
