概述

AppsInToss SDK 是为了在 Toss 应用内快速构建 Mini App 而提供的 WebView 和 React Native 运行时框架。 SDK 的核心是 Granite,负责与应用运行环境进行通信的通用运行时框架。 目前提供 WebView SDK 和 React Native SDK 两种形式。 本文档介绍 Granite 的 AppsInToss 组件以及由原生端传递的初始数据(InitialProps)。这是技术指南。

查看示例项目 ↗ 查看示例合集 ↗

签名

AppsInToss

AppsInToss: { registerApp( AppContainer: ComponentType>, { appName, context, router }: BedrockProps ): (initialProps: InitialProps) => JSX.Element; readonly appName: string; }

InitialProps type InitialProps = AndroidInitialProps | IOSInitialProps;

AppsInToss

AppsInToss.registerApp 用于设置服务的基本环境,帮助开发者在无需复杂初始配置的情况下快速启动开发。 只需传入 appName,即可立即使用基于文件的路由、查询参数处理、返回操作、屏幕可见性检测等核心功能。

提供功能 基于文件的路由:像 Next.js 一样,路径与 URL 自动映射。 /my-service/pages/home.ts → intoss://my-service/home 查询参数处理:可直接使用 URL Scheme 参数(如 referrer 等) 返回操作控制:可拦截返回事件并进行对话框显示或关闭页面等处理 *屏幕可见性检测:可根据页面显示或隐藏事件进行行为控制

属性

registerApp 必填 · RegisterService 初始化应用并启用路由/参数/返回操作/可见性控制功能。

示例:注册应用 import { AppsInToss } from '@apps-in-toss/framework'; import { PropsWithChildren } from 'react'; import { InitialProps } from '@granite-js/react-native'; import { context } from '../require.context';

function AppContainer({ children }: PropsWithChildren) { return <>{children}</>; }

// 只需传入应用名称和 context,即可完成基本配置。 export default AppsInToss.registerApp(AppContainer, { context });

InitialProps 在 React Native 应用中,当用户进入特定页面时,原生端(Android/iOS)传递给应用的初始数据类型。 各平台结构不同,包含初始渲染和状态设置所需的核心信息。 Android: AndroidInitialProps iOS: IOSInitialProps

Property platform必填 · 'ios' | 'android' 当前应用正在运行的平台。

initialColorPreference必填 · ColorPreference 初始颜色主题,表示用户设置的颜色主题。

networkStatus必填 · NetworkStatus 当前设备的网络连接状态及连接的网络类型

schemestring 进入当前页面时使用的 URL Scheme。

initialFontSize必填 · xSmall | Small | Medium | Large | xLarge | xxLarge | xxxLarge | A11y_Medium | A11y_Large | A11y_xLarge | A11y_xxLarge | A11y_xxxLarge (仅 iOS)iOS 系统字体大小,默认值为 Large。

isVisible必填 · boolean (仅 iOS)当前页面是否可见,初始值为 true。

initialFontScale必填 · string (仅 Android)反映 Android 辅助功能设置的系统字体缩放比例。

示例:使用初始数据 import { AppsInToss } from '@apps-in-toss/framework'; import { PropsWithChildren } from 'react'; import { InitialProps } from '@granite-js/react-native'; import { context } from '../require.context';

function AppContainer({ children, ...initialProps }: PropsWithChildren) { // 可以在页面进入时使用原生端传递下来的初始值。 console.log({ initialProps }); return <>{children}</>; }

export default AppsInToss.registerApp(AppContainer, { context });

Environment Variables

支持环境:React Native 运行环境:Toss App/Sandbox App

plugin-env 是一个用于向项目注入环境变量的插件, 可以通过 import.meta.env 方便地访问这些变量。 该插件仅可在 React Native 环境中使用, 并在基于 @granite-js/react-native 的配置文件(granite.config.ts)中进行应用。

安装

根据所使用的包管理器,可以使用以下命令之一进行安装:

使用 npm 的情况下

npm install '@granite-js/plugin-env';

使用 yarn 的情况下

yarn add '@granite-js/plugin-env';

使用 pnpm 的情况下

pnpm add '@granite-js/plugin-env';

示例:注册和使用环境变量 是使用 plugin-env 在 React Native 项目中注册并使用环境变量的示例。 // granite config import { appsInToss } from '@apps-in-toss/framework/plugins'; import { defineConfig } from '@granite-js/react-native/config'; import { env } from '@granite-js/plugin-env';

export default defineConfig({ scheme: 'intoss', appName: 'my-granite-app', plugins: [ appsInToss({ brand: { displayName: 'my-granite-app', // 请将其更改为在界面上显示的应用中文名称 primaryColor: '#3182F6', // 请将其更改为在界面上显示的应用主色 icon: "", // 请将其更改为在界面上显示的应用图标图片地址 bridgeColorMode: 'basic', }, permissions: [], }), env({ MY_ENV_VAR: 'Hello, World!' }), ], });

// service import.meta.env.MY_ENV_VAR; // 'Hello, World!'

通用设置

支持环境: React Native,WebView 运行环境:Toss App,Sandbox App

在 Mini App 中,可在一处统一管理品牌、主机、权限、构建选项等全局配置。下面的示例展示了可分别用于 WebView 和 React Native 环境的基本配置模板。

进行基本配置后,Bridge View 和导航栏将自动显示。通过导航栏的“更多”按钮,可以使用分享、举报等功能。

游戏服务设置 如果是游戏服务,需要进行如下配置。. WebView webViewProps.type = 'game' brand.bridgeColorMode = 'inverted' ReactNative appType: "game"

导航栏的关闭按钮(X 按钮)位置 import { SafeAreaInsets } from '@apps-in-toss/web-framework'; import { useEffect, useState } from 'react';

interface SafeAreaInsets { top: number; bottom: number; left: number; right: number; }

function Page() { const [safeAreaInsetsValue, setSafeAreaInsetsValue] = useState(() => SafeAreaInsets.get()) // 导航栏顶部间距: safeAreaInsetsValue.top // 导航栏顶部间距: safeAreaInsetsValue.right + 10

useEffect(() => { const cleanup = SafeAreaInsets.subscribe({ onEvent: (insets) => { setSafeAreaInsetsValue(insets); } }); return () => cleanup(); }, []);

// ... }

*详细使用方法请参考权限指南和 WebView 属性控制指南

Bridge View

导航栏:非游戏

导航栏:游戏

WebView interface defineConfig { appName: string, // 在控制台注册的应用 ID brand: { displayName: string, // 向用户显示的应用名称 primaryColor: string, // 品牌主色 (hex) icon: string, // 应用图标(图片 Web URL) bridgeColorMode: 'basic' | 'inverted', // 基础模式 | 暗黑模式 }, web: { host: string, // 开发服务器主机 port: number, // 开发服务器端口 commands: { dev: string, // 启动命令 build: string, // 构建命令 }, }, permissions: Permission[], // 运行时权限(可根据需要扩展) outdir: string, // 构建产物路径 webViewProps: WebViewProps // 额外属性 }

ReactNative

interface defineConfig({ scheme: string, // 应用路由 Scheme (intoss) appName: string, // 在控制台注册的应用 ID plugins: [ appsInToss({ brand: { displayName: string, // 向用户显示的应用名称 primaryColor: string, // 品牌主色 (hex) icon: string, // 应用图标(图片 Web URL) bridgeColorMode: 'basic' | 'inverted', // 基础模式 | 暗黑模式 }, permissions: Permission[], // 运行时权限(可根据需要扩展) }), ], });

示例 import { defineConfig } from '@apps-in-toss/web-framework/config';

export default defineConfig({ appName: 'webview-template', brand: { displayName: WebView 模板', // 请更改为在界面上显示的应用中文名称. primaryColor: '#3182F6', // 请更改为在界面上显示的应用主色 icon: "https://static.toss.im/icons/png/4x/icon-person-man.png", //请更改为在界面上显示的应用图标图片地址 bridgeColorMode: 'inverted', // 暗黑模式(游戏) }, web: { host: 'localhost', port: 5173, commands: { dev: 'vite', build: 'tsc -b && vite build', }, }, permissions: [ { name: "clipboard", access: "read", }, { name: "clipboard", access: "write", }, { name: "camera", access: "access", }, { name: "photos", access: "read", }, ], outdir: 'dist', webViewProps: { type: 'partner' | 'game' | 'extenral'
} });

认证

Toss 认证登录

支持环境: React Native,WebView 运行环境: Toss App, Sandbox App

appLogin appLogin 函数通过 Toss 认证进行登录。登录完成后会返回到 Toss 应用。

签名 function appLogin(): Promise<{ authorizationCode: string; referrer: "DEFAULT" | "SANDBOX"; }>;

示例 通过 Toss 认证进行登录的示例。

import { appLogin } from '@apps-in-toss/web-framework'; import { Button } from '@toss/tds-mobile';

function Page() { async function handleLogin() { const { authorizationCode, referrer } = await appLogin();

// 획득한 인가 코드(`authorizationCode`)와 `referrer`를 서버로 전달해요.

}

return ; }

体验示例应用 请从 apps-in-toss-examples 仓库下载 with-app-login 代码进行体验。

游戏登录

支持环境:React Native,WebView 运行环境:Toss App,Sandbox App

getUserKeyForGame getUserKeyForGame getUserKeyForGame 函数用于获取游戏 Mini App 中可识别用户的键值。 无需额外服务器联动,也能像 Toss 登录功能一样区分用户。

通过此函数返回的用户标识符(hash)在每个 Mini App 中都是唯一的,并可用于促销(Toss Points)功能。

注意事项

该函数仅可在游戏类 Mini App 中使用,在非游戏类调用会报错。 支持 Toss App 5.232.0 及以上版本,低于该版本会返回 undefined。 为了可靠获取所有用户的标识符,Toss App 的最低支持版本已提升至 5.232.0。 在低于支持版本的环境中,进入 Mini App 时会显示更新提示。 游戏用户标识符仅用于游戏公司内部的用户识别,不能用该键直接向 Toss 服务器发起请求。 在 Sandbox 环境中返回的是 mock 数据,请通过 QR 码进行测试。

签名 function getUserKeyForGame(): Promise;

返回值 Promise

返回用户键值查询结果:

GetUserKeyForGameSuccessResponse: 사용자 키 조회에 성공했어요. { type: 'HASH', hash: string } 형태로 반환돼요. 'INVALID_CATEGORY': 게임 카테고리가 아닌 미니앱에서 호출했어요. 'ERROR': 알 수 없는 오류가 발생했어요. undefined: 앱 버전이 최소 지원 버전보다 낮아요.

示例

// webview import { getUserKeyForGame } from '@apps-in-toss/web-framework';

function GameUserKeyButton() { async function handleClick() { const result = await getUserKeyForGame();

  if (!result) {
    console.warn('지원하지 않는 앱 버전이에요.');
    return;
  }

  if (result === 'INVALID_CATEGORY') {
    console.error('게임 카테고리가 아닌 미니앱이에요.');
    return;
  }

  if (result === 'ERROR') {
    console.error('사용자 키 조회 중 오류가 발생했어요.');
    return;
  }

  if (result.type === 'HASH') {
    console.log('사용자 키:', result.hash);
    // 여기에서 사용자 키를 사용해 게임 데이터를 관리할 수 있어요.
  }

}

return ( ); }

TOSS 认证

认证页面调用

支持环境:React Native,WebView 运行环境: Toss App 通过在实名认证请求 API 响应中获取的 txId,调用 appsInTossSignTossCert。

一键认证及应用版本提示 使用一键认证方式(USER_NONE)时,设置 skipConfirmDoc 为 true 可以跳过认证证书确认文档步骤。

Toss 认证(requestType: USER_PERSONAL):支持 Toss App 5.233.0 及以上版本 Toss 一键认证(requestType: USER_NONE):支持 Toss App 5.236.0 及以上版本 可使用 getTossAppVersion 函数检查 Toss App 版本。

Import { appsInTossSignTossCert } from '@apps-in-toss/web-framework';

interface AppsInTossSignTossCertParams { txId: string; // 본인확인 요청 시 발급받은 txId skipConfirmDoc?: boolean; // 원터치 인증 시 true로 설정 }

/**

  • Toss 인증서 화면을 txId 기반으로 호출합니다. *
  • 참고:
  • response는 인증 완료 확정 용도가 아닙니다.
  • 서버에서 txId 기준으로 결과조회 API를 호출해 최종 상태를 판별하세요. */ export async function openTossCertWithTxId( txId: string, skipConfirmDoc = false ): Promise { try { const params: AppsInTossSignTossCertParams = { txId, skipConfirmDoc }; const response = await appsInTossSignTossCert(params); return response; } catch (e: unknown) { // 호출 실패 처리 (사용자 취소/앱 미설치/스킴 실패 등) throw e; } }

响应 onSuccess 无参数 onError Error { code: string; message: string }(例如:用户取消、应用未安装、Scheme 调用失败等)

// 错误类型示例 type AppsInTossSignTossCertError = { code: string; message: string; };

// try/catch로 onSuccess/onError 处理方式 try { await appsInTossSignTossCert({ params: { txId: "bb8bead6-0957-4be7-b937-f554911d7a87", skipConfirmDoc: true, // 一键认证设置 }, }); // onSuccess: 无参数 } catch (e: any) { const err: AppsInTossSignTossCertError = { code: e?.code ?? 'UNKNOWN', message: e?.message ?? String(e), }; // onError: 错误处理 }

个人信息加解密

支持环境:React Native,WebView 运行环境: Toss App

Toss 认证 API 的部分请求可能包含客户的个人信息。为了安全,客户服务器与 Toss 服务器之间仅传输加密数据。如需明文,请将数据解密后查看。.

*在认证请求中传递客户姓名、出生日期、手机号时进行加密

电子签名服务原文中包含客户个人信息时,进行原文加密 在认证结果中,Toss 服务器提供包含 CI、DI 等个人信息时,进行加密

원터치 본인 인증 由于客户服务器不会向 Toss 认证服务器传递客户信息,因此无需加密过程。但在用户认证完成后调用结果查询 API 时,需要在请求中包含会话密钥。

会话密钥生成及加密示例

package im.toss.cert.sdk;

import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test;

class TossCertSessionTest {

@Test
public void test() {

    // 1. 请提前仅生成一次会话密钥        TossCertSessionGenerator tossCertSessionGenerator = new TossCertSessionGenerator();

    // 2. 在调用包含个人信息的认证请求 API 之前,请先生成会话密钥
    TossCertSession tossCertSession = tossCertSessionGenerator.generate();

    // 3. 请对包含个人信息的数据进行加密
    String userName = "김토스";
    String encryptedUserName = tossCertSession.encrypt(userName);
    System.out.println("encryptedUserName: " + encryptedUserName);

    // 4. 请调用认证请求 API
    // 在认证请求 API 的 body 参数中添加已生成的 sessionKey
    String sessionKey = tossCertSession.getSessionKey();
    String userName = encryptedUserName;

    // 5. 在用户认证完成后,调用结果查询 API 之前,请生成新的会话密钥
    TossCertSession tossCertSession = tossCertSessionGenerator.generate();

    // 6. 请调用结果查询 API
    // 请在结果查询 API 的 body 参数中添加已生成的 sessionKey
    String sessionKey = tossCertSession.getSessionKey();
    String txId = "a39c84d9-458d-47e4-acf7-c481e851f79b";

    // 7. 要进行解密,需要持有在结果查询请求中生成的 tossCertSession다.
    // response.userName 假设 response.userName 是返回的加密用户名
    // decryptedUserName  已完成完整性验证
    String decryptedUserName = tossCertSession.decrypt(response.userName);
}

}

注意事项

在 Toss 测试环境中,提供的并非真实用户的个人信息,而是 Toss 生成的虚拟固定个人信息。

可查看提供的语言示例

建议使用 SDK,但也提供了多种语言的代码示例: https://github.com/toss/toss-cert-examples

results matching ""

    No results matching ""