> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/sdk/v3.md).

# v3

`@apps-in-toss/web-framework` 3.0.0 `latest`发布到了。现在 `npm install @apps-in-toss/web-framework`执行后会安装 3.0.0。

3.0.0 是为 Web 迷你应用开发重新整理了 SDK 结构的重大更新。你可以在本文档中查看 2.x 和 3.0.0 的差异。

### 一目了然

* 我们将公开 API 按领域对象重新整理了。按领域归类的原有函数保留为 deprecated，因此无需修改代码也能正常工作。
* 包变轻了。安装体积从约 27MB 缩小到约 660KB。
* 配置文件 `granite.config.ts`从 `apps-in-toss.config.ts`变更了。 `npx ait migrate v3` 可以用该命令自动转换。
* 沙盒应用不支持 3.0。我们计划支持用于模拟 API 的 devtools。在那之前，请使用控制台发放的二维码在 Toss App 中测试。

### 领域对象 API

3.0.0 的公开 API 按功能划分为领域对象。按领域归类的原有单独函数已 deprecated，请使用同一功能的领域成员。

```typescript
// 2.x 方式 — 虽然能工作，但会显示 deprecated 警告。
import { openCamera } from "@apps-in-toss/web-framework";
const image = await openCamera();

// 3.0 方式
import { Device } from "@apps-in-toss/web-framework";
const image = await Device.openCamera();
```

原有函数从函数名到接收值、返回值都与 2.x 完全一致。因此 2.x 代码无需修改即可在 3.0 中编译并运行。不过编辑器中会出现 deprecated 标记，建议新代码使用领域成员来编写。

#### 原有 API 与领域成员对应表

| 领域           | 原有 API (deprecated)                | 新 API                           |
| ------------ | ---------------------------------- | ------------------------------- |
| Clipboard    | `getClipboardText`                 | `Clipboard.getText`             |
| Clipboard    | `setClipboardText`                 | `Clipboard.setText`             |
| Device       | `fetchAlbumItems`                  | `Device.getAlbumItems`          |
| Device       | `fetchAlbumPhotos`                 | `Device.getPhotos`              |
| Device       | `fetchContacts`                    | `Device.getContacts`            |
| Device       | `getCurrentLocation`               | `Device.getLocation`            |
| Device       | `getLocale`                        | `Device.locale`                 |
| Device       | `getPlatformOS`                    | `Device.os`                     |
| Device       | `generateHapticFeedback`           | `Device.triggerHaptic`          |
| Device       | `openCamera`                       | `Device.openCamera`             |
| Device       | `openURL`                          | `Device.openURL`                |
| Device       | `startUpdateLocation`              | `Device.subscribeLocation`      |
| Environment  | `getDeviceId`                      | `Environment.deviceId`          |
| Environment  | `getGroupId`                       | `Environment.groupId`           |
| Environment  | `getOperationalEnvironment`        | `Environment.environment`       |
| Environment  | `getTossAppVersion`                | `Environment.tossAppVersion`    |
| Environment  | `env.getDeploymentId`              | `Environment.deploymentId`      |
| Environment  | `getSchemeUri`                     | `Environment.initialURL`        |
| Environment  | `getNetworkStatus`                 | `Environment.getNetworkStatus`  |
| Environment  | `getServerTime`                    | `Environment.getServerTime`     |
| File         | `saveBase64Data`                   | `File.saveBase64`               |
| File         | `openPDFViewer`                    | `File.openPDFViewer`            |
| Game         | `openGameCenterLeaderboard`        | `Game.openLeaderboard`          |
| Game         | `submitGameCenterLeaderBoardScore` | `Game.setLeaderboardScore`      |
| Game         | `getGameCenterGameProfile`         | `Game.getUserProfile`           |
| Game         | `getUserKeyForGame`                | `User.getAnonymousKey`          |
| Game         | `grantPromotionRewardForGame`      | `Promotion.grantReward`         |
| Notification | `requestNotificationAgreement`     | `Notification.requestAgreement` |
| Promotion    | `grantPromotionReward`             | `Promotion.grantReward`         |
| Review       | `requestReview`                    | `Review.request`                |
| SafeArea     | `getSafeAreaInsets`                | `SafeArea.get`                  |
| SafeArea     | `SafeAreaInsets.subscribe`         | `SafeArea.subscribe`            |
| Screen       | `closeView`                        | `Screen.close`                  |
| Screen       | `setScreenAwakeMode`               | `Screen.setAwakeMode`           |
| Screen       | `setSecureScreen`                  | `Screen.setSecure`              |
| Screen       | `setIosSwipeGestureEnabled`        | `Screen.setIosSwipeBack`        |
| Screen       | `setDeviceOrientation`             | `Screen.setOrientation`         |
| Share        | `getTossShareLink`                 | `Share.createLink`              |
| Share        | `share`                            | `Share.sendMessage`             |
| TossAuth     | `appLogin`                         | `TossAuth.login`                |
| TossAuth     | `getIsTossLoginIntegratedService`  | `TossAuth.isIntegrated`         |
| TossAuth     | `appsInTossSignTossCert`           | `TossAuth.sign`                 |
| TossPay      | `checkoutPayment`                  | `TossPay.authorize`             |
| TossPay      | `requestTossPayPaysBilling`        | `TossPay.authorizeSubscription` |
| User         | `getAnonymousKey`                  | `User.getAnonymousKey`          |
| User         | `getConsentedUserData`             | `User.getConsentedData`         |
| User         | `getDeclaredAgeRange`              | `User.getDeclaredAgeRange`      |

`SafeAreaInsets`是 `SafeArea`与其相同的对象。可以继续沿用原名称。

#### 保持不变的 API

以下 API 不会按领域归类，而是以原有形式提供。无需 deprecated，继续使用即可。

* 对象型 API： `IAP`, `Storage`, `TossAds`, `GoogleAdMob`, `Analytics`, `partner`
* 广告： `loadFullScreenAd`, `showFullScreenAd`
* 权限： `getPermission`, `requestPermission`, `openPermissionDialog`以及权限错误类
* 事件： `appsInTossEvent`, `graniteEvent`, `tdsEvent`
* 环境： `isMinVersionSupported`, `getAppsInTossGlobals`

#### 新增加的 API

* `PermissionError`：权限错误的公共父类已公开。 `error instanceof PermissionError`可以用它一次性处理所有权限错误。
* `TossPay` 领域对象：在 2.x 中 `checkoutPayment` 只有 `TossPay.authorize`, `TossPay.authorizeSubscription`这类单独函数，但在 3.0 中已归类为

#### 原有函数与领域成员的行为差异

不只是名称变更，部分行为约定也进行了改进。迁移时请确认以下差异。

* 常量型 API 不是通过函数调用，而是以属性读取。例如 `getLocale()`是 `Device.locale`， `getDeviceId()`是 `Environment.deviceId`会变为
* 领域成员在不支持的 Toss App 版本中会 `UNSUPPORTED_APP_VERSION` 或 `UNSUPPORTED_OS_VERSION` 代码的错误。原有函数会按照 2.x 约定返回 `undefined`或 `'ERROR'` 等值。例如 `getAnonymousKey`失败时会返回 `'ERROR'`，但 `User.getAnonymousKey`会抛出错误。 `error.code`进行分支，就可以显示“请更新 Toss App”等提示。
* `Share.createLink`接收对象参数。 `getTossShareLink(path, ogImageUrl)`是 `Share.createLink({ path, ogImageUrl })`会变为
* `IAP.createOneTimePurchaseOrder` 响应中的商品标识符使用 `sku`。 `productId` 字段已 deprecated。

### 配置文件变更

配置文件名称变更为 `granite.config.ts`从 `apps-in-toss.config.ts`，部分选项也有变化。

| 2.x (`granite.config.ts`)         | 3.0 (`apps-in-toss.config.ts`) | 说明                                      |
| --------------------------------- | ------------------------------ | --------------------------------------- |
| `web` (host, port, commands)      | 移除                             | 开发服务器和构建执行已从 SDK 移到 `package.json` 脚本中。 |
| `brand.displayName`, `brand.icon` | 移除                             | `brand`中 `primaryColor`只剩下了。            |
| `webViewProps`                    | `webView`                      | 名称变了。下层选项保持不变， `type`只移除了。              |
| `webViewProps.type`               | 移除                             | WebView frame type 选项已消失。               |
| `outdir`                          | `webBundleDir`                 | 只是名称变了。默认值与 `dist`相同。                   |

配置类型名称也从 `AppsInTossWebConfig`从 `变成了 AppsInTossConfig`变更了。

Web 开发服务器和构建现在直接在 `package.json` 脚本中执行。

```json
{
  "scripts": {
    "dev": "vite dev",
    "build": "vite build && ait build",
    "deploy": "ait deploy"
  }
}
```

### 包结构变更

| 项目           | 2.x          | 3.0                                                                   |
| ------------ | ------------ | --------------------------------------------------------------------- |
| 安装体积         | 约 27MB       | 约 660KB                                                               |
| 模块格式         | 仅 ESM        | ESM + CJS 双格式                                                         |
| dependencies | 13 个         | 4 个 (`@apps-in-toss/cli`, `@webview-bridge/web`, `semver`, `valibot`) |
| 许可证          | 仅 LICENSE 文件 | `Apache-2.0` 注明                                                       |

CJS 环境(`require`、旧版打包器）中也能使用了，并且由于依赖减少，安装更快，与其他包的版本冲突担忧也降低了。

### 沙盒与开发环境模拟

沙盒应用不支持 3.0。相反，我们正在准备尽快提供 devtools，以便即使没有沙盒应用，也能在本地开发环境中模拟 API。

在此之前，请使用 Apps in Toss 控制台发放的二维码在 Toss App 中测试用 3.0 制作的迷你应用。

### 迁移到 3.0.0

提供自动迁移命令。配置文件转换和 `package.json` 脚本重构会自动处理。

```bash
npx ait migrate v3
```

此命令会执行以下操作。

* `granite.config.ts`将 `apps-in-toss.config.ts`转换为（`brand`是 `primaryColor`仅保留， `webViewProps`是 `webView`改为， `outdir`是 `webBundleDir`改为， `web` 删除区块）。
* `package.json`的 `dev`, `build` 脚本会重新整理。
* 如果转换前验证失败，会在不修改文件的情况下告知原因和解决方法。

迁移后，请将 bundle 上传到控制台，并通过二维码在 Toss App 中测试。

#### 请务必确认

* 如果发布用 SDK 3.x 构建的 bundle，就无法回滚到 2.x。请在用二维码充分测试后再发布。
* 从 3.0 起，迷你应用将在 `https://<appName>.web.tossmini.com`（正式环境）和 `https://<appName>.private-web.tossmini.com`（QR 测试）Origin 中运行。请把这两个域名注册到 API 服务器的 CORS 白名单中。
* 如果使用 TDS， `@toss/tds-mobile`和 `@toss/tds-mobile-ait`请一起更新到 2.4.1 及以上版本。
* 3.0.0-rc.1 和 rc.2 因依赖问题无法安装。请务必使用 3.0.0 正式版。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/sdk/v3.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
