> 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/unity/build/loading-screen-customization.md).

# 加载页面自定义

说明如何按需更改 Unity WebGL 加载期间看到的画面。

### 加载画面文件

加载画面存在于两个地方。

| 路径                                        | 作用           |
| ----------------------------------------- | ------------ |
| `WebGLTemplates/AITTemplate/loading.html` | SDK 默认模板（原始） |
| `Assets/AppsInToss/loading.html`          | 按项目定制的加载画面   |

`AITPackageInitializer`为 `[InitializeOnLoad]`在编辑器启动时执行， `Assets/AppsInToss/loading.html`如果没有它，就复制 SDK 模板。修改此文件后会应用自定义加载画面。

SDK 模板搜索顺序：

1. `Packages/im.toss.apps-in-toss-unity-sdk/WebGLTemplates/AITTemplate/loading.html`
2. `Packages/com.appsintoss.miniapp/WebGLTemplates/AITTemplate/loading.html`
3. 基于 Assembly 路径

#### 构建时插入顺序

构建的 `CopyWebGLToPublic()` 阶段 `index.html`的 `%AIT_LOADING_SCREEN%` 占位符会被替换为整个加载画面的内容。

```
1. 是否存在 Assets/AppsInToss/loading.html？
   → 是：使用项目自定义加载画面
   → 否：回退到 SDK 默认模板

2. 如果连 SDK 模板也没有？
   → Debug.LogWarning("找不到加载画面文件。将使用空白加载画面。")
   → 替换为空字符串
```

也就是说，加载画面会被 **在构建时内联到 index.html 中**。因为不会作为单独文件加载，所以相对路径引用会按最终 `index.html` 作为基准来解析。

#### 恢复为默认模板

`AIT > Reset Loading Screen`运行后会弹出确认对话框，并将 SDK 模板 `Assets/AppsInToss/loading.html`再次复制过去。自定义内容会丢失，必要时请先备份。

#### 文件结构

```
Assets/
└── AppsInToss/
    ├── Editor/
    │   └── AITConfig.asset
    └── loading.html    ← 自定义加载画面（存在时自动应用）
```

### 应用信息

加载画面中显示的应用信息按以下顺序决定。

1. **原生应用环境** （toss 应用内）— SDK 会 `getAppsInTossGlobals`通过它获取应用信息并覆盖
2. **回退** （Web 浏览器等）— 使用在 AIT Configuration 中设置的值

| 设置                   | 说明               |
| -------------------- | ---------------- |
| 应用名称（`displayName`)  | 加载画面中显示的应用名称     |
| 应用图标（`iconUrl`)      | 加载画面中显示的应用图标 URL |
| 默认颜色（`primaryColor`) | 进度条颜色            |

> **参考**：在实际 toss 应用环境中，原生值优先，因此以上设置主要会在开发·测试环境中看到。

### 可自定义范围

`loading.html`的 HTML、CSS、JavaScript 可自由修改。进度可以从 `AITLoading` API 获取，然后按你想要的方式呈现。

* **UI 设计** — 进度条、饼图、圆形加载等
* **动画** — CSS 动画、JavaScript 动画、GIF、Lottie
* **品牌元素** — 吉祥物角色、Logo 动画
* **交互元素** — 小游戏、提示滑块

#### 使用外部资源

**StreamingAssets** （推荐）— `Assets/StreamingAssets`放在其中会自动包含到构建中。

```html
<img src="StreamingAssets/loading-character.gif" />
<link rel="stylesheet" href="StreamingAssets/loading-fonts.css" />
```

```
Assets/
└── StreamingAssets/
    ├── loading-character.gif
    └── loading-fonts.css
```

**Data URI** — 小于数 KB 的小图片会以内联 Base64 方式嵌入。

```html
<img src="data:image/png;base64,iVBORw0KGgo..." />
```

**CDN** — 通过外部 URL 加载。会产生网络依赖，并且加载画面本身可能出现得更晚。

```html
<img src="https://your-cdn.com/loading-character.gif" />
```

### AITLoading API

`window.AITLoading`是 `index.html`中定义，公开表面只有以下六项。 `_`以此开头的成员是内部实现，请不要依赖。

| 成员                     | 说明                                       |
| ---------------------- | ---------------------------------------- |
| `appInfo`              | `{ iconUrl, displayName, primaryColor }` |
| `onReady(callback)`    | 应用信息准备完成                                 |
| `onProgress(callback)` | 进度更新                                     |
| `onComplete(callback)` | 加载完成                                     |
| `onError(callback)`    | 发生错误                                     |
| `hide()`               | 隐藏加载画面                                   |

#### appInfo

```javascript
console.log(AITLoading.appInfo.iconUrl);       // 应用图标 URL
console.log(AITLoading.appInfo.displayName);   // 应用显示名称
console.log(AITLoading.appInfo.primaryColor);  // 默认颜色
```

初始值是构建时替换的 Configuration 值，等原生应用信息到达后会更新为该值。

#### onReady

在应用信息准备好时调用。用于 UI 初始化。

```javascript
AITLoading.onReady(function(appInfo) {
    document.getElementById('app-icon').src = appInfo.iconUrl;
    document.getElementById('app-name').textContent = appInfo.displayName;
});
```

> **重要**: `onReady` 回调 **不应假设只会调用一次。** 初始化时会调用一次，若原生应用信息稍后到达，则更新后的 `appInfo`会再次调用。请将回调写成即使执行多次也安全（幂等）。如果在已完成初始化后再注册，会立即调用一次。

#### onProgress

`0.0`到 `1.0` 之间的进度。

```javascript
AITLoading.onProgress(function(progress) {
    console.log('加载进度：', Math.round(progress * 100) + '%');
});
```

#### onComplete

加载结束时调用。如果在已完成后再注册，会立即调用。

```javascript
AITLoading.onComplete(function() {
    AITLoading.hide();
});
```

#### onError

`{ message }` 形式的对象。

```javascript
AITLoading.onError(function(error) {
    console.error('加载失败：', error.message);
});
```

> **参考**: WebGL 上下文创建失败（`GLctx`, `WebGL context`, `Unable to create` 等系列）由 SDK 通过专用路径处理，因此不会出现在此回调中。如果你不是要直接处理设备无法打开 WebGL 的情况，就不用在意。

#### hide

`#ait-loading-wrapper` 元素 `display: none`隐藏。

```javascript
AITLoading.hide();
```

### 示例

下面是我直接写的示例。SDK 实际提供的默认模板（暗色主题）请在 `Assets/AppsInToss/loading.html`中查看。

#### 进度条

```html
<style>
    /* ===== 可自定义的 CSS 变量 ===== */
    :root {
        --loading-bg: #ffffff;
        --title-color: #191f28;
        --app-name-color: #333d4b;
        --progress-bg: #e5e8eb;
        --icon-size: 30px;
        --progress-height: 5px;
    }

    .loading-container {
        position: fixed;
        inset: 0;
        background: var(--loading-bg);
        display: flex;
        flex-direction: column;
        padding: 120px 20px 0;
        font-family: -apple-system, BlinkMacSystemFont, sans-serif;
    }

    .loading-title {
        font-size: 22px;
        font-weight: 600;
        color: var(--title-color);
        line-height: 1.4;
        margin-bottom: 44px;
    }

    .loading-card {
        padding: 16px;
        border: 1px solid #e5e8eb;
        border-radius: 16px;
    }

    .loading-header {
        display: flex;
        align-items: center;
        margin-bottom: 12px;
    }

    .loading-icon {
        width: var(--icon-size);
        height: var(--icon-size);
        border-radius: 8px;
        background: rgba(2, 32, 71, 0.05);
        overflow: hidden;
    }

    .loading-icon img { width: 100%; height: 100%; object-fit: cover; }

    .loading-app-name {
        margin-left: 12px;
        font-size: 15px;
        font-weight: 500;
        color: var(--app-name-color);
    }

    .loading-progress {
        height: var(--progress-height);
        background: var(--progress-bg);
        border-radius: 2.5px;
        overflow: hidden;
    }

    .loading-progress-bar {
        height: 100%;
        width: 0%;
        transition: width 0.3s ease;
    }
</style>

<div class="loading-container" id="ait-loading">
    <div class="loading-title" id="loading-title"></div>
    <div class="loading-card">
        <div class="loading-header">
            <div class="loading-icon"><img id="app-icon" src="" alt="" /></div>
            <div class="loading-app-name" id="app-name"></div>
        </div>
        <div class="loading-progress">
            <div class="loading-progress-bar" id="progress-bar"></div>
        </div>
    </div>
</div>

<script>
(function() {
    // 使用应用信息初始化 UI（原生信息到达时可能再次调用）
    AITLoading.onReady(function(appInfo) {
        document.getElementById('app-icon').src = appInfo.iconUrl || '';
        document.getElementById('app-name').textContent = appInfo.displayName || '';
        document.getElementById('progress-bar').style.background =
            appInfo.primaryColor || '#3182f6';
    });

    // 更新进度
    AITLoading.onProgress(function(progress) {
        document.getElementById('progress-bar').style.width = (progress * 100) + '%';
    });

    // 加载完成后隐藏画面
    AITLoading.onComplete(function() {
        AITLoading.hide();
    });
})();
</script>
```

#### 百分比显示和错误处理

```html
<style>
    :root {
        --loading-bg: #ffffff;
        --text-color: #191f28;
        --sub-text-color: #6b7684;
    }

    .loading-container {
        position: fixed;
        inset: 0;
        background: var(--loading-bg);
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        font-family: -apple-system, BlinkMacSystemFont, sans-serif;
    }

    .loading-icon { width: 80px; height: 80px; border-radius: 20px; margin-bottom: 24px; }
    .loading-name { font-size: 18px; font-weight: 600; color: var(--text-color); }
    .loading-progress { width: 200px; height: 6px; background: #e5e8eb; border-radius: 3px; margin-top: 24px; overflow: hidden; }
    .loading-progress-bar { height: 100%; width: 0%; transition: width 0.3s ease; }
    .loading-percent { margin-top: 12px; font-size: 14px; color: var(--sub-text-color); }
</style>

<div class="loading-container" id="ait-loading">
    <img class="loading-icon" id="app-icon" alt="" />
    <div class="loading-name" id="app-name"></div>
    <div class="loading-progress"><div class="loading-progress-bar" id="progress-bar"></div></div>
    <div class="loading-percent" id="percent-text">0%</div>
</div>

<script>
(function() {
    AITLoading.onReady(function(appInfo) {
        document.getElementById('app-icon').src = appInfo.iconUrl || '';
        document.getElementById('app-name').textContent = appInfo.displayName || '';
        document.getElementById('progress-bar').style.background = appInfo.primaryColor || '#3182f6';
    });

    AITLoading.onProgress(function(progress) {
        var percent = Math.round(progress * 100);
        document.getElementById('progress-bar').style.width = percent + '%';
        document.getElementById('percent-text').textContent = percent + '%';
    });

    AITLoading.onComplete(function() {
        AITLoading.hide();
    });

    AITLoading.onError(function(error) {
        document.getElementById('percent-text').textContent = '加载失败';
        document.getElementById('percent-text').style.color = '#f04452';
    });
})();
</script>
```

### 故障排查

#### 图标未显示

1. 检查 AIT Configuration 中是否设置了图标 URL
2. 外部图片可能会被 CORS 策略阻止——建议使用同一域名下的图片
3. 在原生应用环境中，应用图标会自动加载，因此可能看不到回退值

#### 未应用自定义加载画面

1. 文件是否在 `Assets/AppsInToss/loading.html`中——不识别其他路径
2. 加载画面会在构建时内联，因此如果只修改文件而不重新构建，就不会生效

#### 进度未更新

1. `AITLoading.onProgress()`是否已注册
2. 回调必须在页面加载早期注册——如果在加载已经进行后才注册，将无法获得之前的进度

#### appInfo 为空

`AITLoading.appInfo`不要直接读取 `onReady` ，请在回调中使用。脚本执行时，应用信息初始化可能尚未完成。

### 相关文档

* [构建流水线](https://developers-apps-in-toss.toss.im/documentation/unity/build/build-process) — `%AIT_LOADING_SCREEN%` 发生替换的位置
* [构建自定义](https://developers-apps-in-toss.toss.im/documentation/unity/build/build-customization) — 修改加载画面之外的网页入口点
* [开始使用](https://developers-apps-in-toss.toss.im/documentation/unity/first-steps/getting-started) — 设置应用信息
* [问题排查](https://developers-apps-in-toss.toss.im/documentation/unity/first-steps/faq) — 构建·运行时全局


---

# 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/unity/build/loading-screen-customization.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.
