@ ait- kit/ sdk
Toss 小型应用程序Apps的前端SDK适配器:共享合同加 每跑一次的入站点.
npm install @ait-kit/sdk
入境点
| 条目 | 用它来 |
|---|---|
@ait-kit/sdk (基层) | 运行时间中立的共享合同:广告+IAP类型, SdkError. 任何地方都可以被导入——平地节点,网络,回放原生——没有正式安装SDK. |
@ait-kit/sdk/rn | 反应原生适配器(全屏广告,IAP). 需要官员 @apps-in-toss/framework,宣布为 选项对等点 和懒惰地进口。 从不要求网络SDK. |
@ait-kit/sdk/webview | WebView 适配器用于广告,横幅,购买,身份,存储,通知,共享,评论,和促销. 需要官员 @apps-in-toss/web-framework,宣布为 选项对等点 和懒惰地进口。 从不要求反应原生SDK. |
两个平台条目共用一个内部引擎,但完全保留
单独的 SDK 连接 — 在 JavaScript 和运出的类型
声明——如此 /rn 消费者从不安装网页软件包和副产品
反之为相.
应用程序购买(RN + WebView)
两个条目都暴露出相同的IAP表面;只有加载器不同:
import { createReactNativeIap } from "@ait-kit/sdk/rn"; // or:
import { createWebViewIap } from "@ait-kit/sdk/webview";
const iap = createReactNativeIap({
// The ONLY place product delivery happens. Resolve only after YOUR
// server verified the order with the provider and persisted the grant
// (see @ait-kit/api-core's iapOrderStatus for server-side verification).
grant: async ({ orderId, sku }) => {
const response = await fetch("/api/iap/grant", {
method: "POST",
body: JSON.stringify({ orderId, sku })
});
if (!response.ok) {
// Resolve-only-on-success is part of the contract: never report a
// grant your server did not verify and persist.
throw new Error(`grant request failed: HTTP ${response.status}`);
}
}
});
// 1. Start a purchase.
const result = await iap.purchaseOneTime("SKU_100_COINS");
// result.status: "completed" | "canceled" | "failed"
// | "grant_failed" | "unknown"
// 2. Subscriptions work the same way.
await iap.purchaseSubscription("SKU_PREMIUM", offerId);
completed 需求 两者 该平台的成功活动和你的赠款
已解析 顺序相同: 仅一个成功事件永远不会
完成购买,对不同订单的赠款结束于
failed编号 :ORDER_MISMATCH,而失败的服务器授权结束为 grant_failed
从来没有像购买成功. unknown (如超时)指补助金可能
仍在进行中;客户端超时不会取消.
复制赠款控制(客户方,范围为一个适配器)
- 同一订单的并行赠款共用一次飞行中呼叫——仅用于
相同目标(相同)
orderId财务报告和审定财务报表sku;不熟悉subscriptionId和待决命令一样,可以加入缓存 订阅补助金)。 明显相冲突的重复拒绝. - 在适配器范围内对成功发出的订单进行再利用 同一目标(以后恢复或重复成功不会重运行) 服务器呼叫).
- 失败的赠款不是缓存的——下一次尝试是真实的.
- 这只会减少重复的客户端工作: 服务器侧赠款 仍然是强制性的 (核实命令,坚持一次).
待发命令收回(从未自动收回)
const { orders } = await iap.getPendingOrders();
for (const order of orders) {
// Runs (or reuses) the server grant FIRST; the platform's
// completeProductGrant notification is sent only after it confirms.
const outcome = await iap.recoverPendingOrder(order);
// outcome.status: "completed" | "grant_failed" | "notify_failed"
}
SDK初始化不会自行给予或完成待批订单.
特性矩阵
| 能力 | /rn | /webview | 页:1 |
|---|---|---|---|
| 产品列表 | ✅ | ✅ | 一次性+共同订阅 |
| 一次性购买 | ✅ | ✅ | 适用补助金召回合同 |
| 订阅购买 | ✅ | ✅ | offerId 可选; subscriptionId 完成时浮出水面 |
| 订阅信息 | ✅ | ✅ | 仅读提供者状态和访问快照 |
| 已完成/重新供资的订单 | qq 光标 | 仅首页 | 只读; 没有自动恢复或退款动作 |
| 待决命令 | ✅ | ✅ | 恢复由消费者驱动 |
| 赠款完成通知 | ✅ | ✅ | 仅在服务器授权确认后发送 |
| 全屏/奖励广告 | ✅ | ✅ | 只奖励事件; 每次显示后重新加载 |
| Banner 生命周期 | ➖ | ✅ | 初始化、附加、取消和销毁自有控件 |
| 通知协议 | ✅ | ✅ | 基于事件,每个请求一个模板 |
| 共享链接/ 共享工作表 | ✅ | ✅ | intoss:// 路径; completed 共享 |
| 不支持的应用程序版本 | SdkError("UNSUPPORTED") | 不变 | 每个职务 isSupported 门 |
在两个条目中通知并共享适配器船(见下文).
登录、匿名身份和存储(RN + WebView)
import { createReactNativeIdentity, createReactNativeStorage } from "@ait-kit/sdk/rn";
// or: import { createWebViewIdentity, createWebViewStorage } from "@ait-kit/sdk/webview";
const identity = createReactNativeIdentity();
// 1. Login: the adapter validates and preserves authorizationCode/referrer.
const login = await identity.login();
// Forward BOTH values to YOUR server for the token exchange
// (@ait-kit/api-core exposes the server-side endpoint) and create the
// application session there. The adapter never performs the exchange.
// 2. Anonymous key: { type: "HASH", hash } or a typed error — never a
// fabricated key.
const anon = await identity.getAnonymousKey();
// 3. Storage: string values, verbatim keys.
const storage = createReactNativeStorage();
await storage.set("cart:items", "[]");
const raw = await storage.get("cart:items"); // string | null
await storage.remove("cart:items");
合同:
- 登录 验证结果(
authorizationCode非空无物,referrer”并逐字保留。 错误的结果 拒绝SdkError("INVALID_LOGIN_RESULT"); 不支持的环境 与UNSUPPORTED;SDK拒绝宣传不变. - 匿名密钥 成果必须记录在案
{ type: "HASH", hash }形状。 其他一切(包括官方SDK)"ERROR"(哨号) 拒绝方式SdkError("INVALID_ANONYMOUS_KEY")——适配器从不 发明一键. 一个例外:官方在React Industrial上getAnonymousKey()决定undefined当安装的应用程序在下面时 该特性的最小版本,该版本以SdkError("UNSUPPORTED")相反,一个没有支持的环境,而不是一个 变形的密钥 . - 存储 键和字符串值通过字节换字节:没有
名称空间前缀,没有密钥转换 。 编写名称空格密钥
自己(例如:.
cart:items) (中文(简体) ).get决定null缺少密钥;set编号 :remove拒绝的传播使得失败是显而易见的. - 没有环境猜测: 默认从不替换假登录
或基于运行时间的存储。 对于发展,注入一个明确的
通过
framework选项. - 当匿名标识符更改时, 会话无效 以前存储的钥匙, 和靴子的顺序 留在消费者.
通知协议和共享(RN + WebView)
import {
createReactNativeNotification,
createReactNativeShare
} from "@ait-kit/sdk/rn";
// or: import { createWebViewNotification, createWebViewShare } from "@ait-kit/sdk/webview";
// 1. Notification agreement: one template, one request.
const notification = createReactNativeNotification();
const result = await notification.requestAgreement("TEMPLATE_CODE");
// result.status: "agreed" (newAgreement | alreadyAgreed) | "rejected"
// | "failed" | "timeout"
// result.templateCode and result.sourceEvent are preserved verbatim. The
// outcome describes ONLY this request — it is not the user's global
// notification setting, nor any server-persisted consent state. Syncing
// consent to your server (and any smart-message sending) is your job.
// 2. Share links: intoss:// deeplink paths, optional OG image.
const share = createReactNativeShare();
const link = await share.createLink("intoss://my-app/about", "https://cdn/og.png");
// 3. Share sheet: "completed" means the SDK share call finished — nothing more.
const uiResult = await share.sendMessage(`check this out ${link}`);
// uiResult.status: "completed" | "failed" — completed does NOT prove the
// user shared and never grants share-reward eligibility.
合同:
- 协议 运行在共享事件流程基数上:一次结算、重复/
晚事豁免、单一错误吞咽清理、登记-投掷
回收,总期限
timeoutMs,默认为60s). SDK 错误保留 他们的code编号 :reason; 超时报告timeout带有模板. - 共享链接 验证文件
intoss://路径合同 (单位:千美元)INVALID_SHARE_PATH和通过 逐字记录。 OG图像生成是消费者的关注. - 共享表 解析为
completed,仅指SDK共享 调用完成——基础SDK不报告工作表是否打开, 关闭, 或者用户实际共享 。 奖励赠款和完成跟踪 和消费者呆在一起。 (从closed0.3.0;见Migrating。 ) - 不支持的表面/ 应用程序版本拒绝使用
SdkError("UNSUPPORTED")。 。 。 .
反应原生和Webview全屏广告
import { createReactNativeAds } from "@ait-kit/sdk/rn";
// WebView: import { createWebViewAds } from "@ait-kit/sdk/webview";
const ads = createReactNativeAds();
await ads.loadFullScreenAd("AD_GROUP_ID"); // joins an in-flight duplicate load
const result = await ads.showFullScreenAd("AD_GROUP_ID");
if (result.status === "rewarded") {
// result.reward came from the provider's userEarnedReward event — nothing
// else (load success, show success, dismissal) ever grants a reward.
// Verify against YOUR server before crediting anything.
}
行为:
- 负载状态按广告类型+广告单位跟踪. 同时重复负载 共享一个注册; 负载失败可清除空档, 因此下次尝试 重试而不是被屏蔽.
- 显示需要完成的负载( S)
AD_NOT_LOADED(否则) 同样的广告 无法同时显示组( e)AD_ALREADY_SHOWING) (中文(简体) ). 全屏广告 被单用:在显示流程结束(奖励、解职、失败)后, 超时),需要再加载. - 整个节目流程有一个期限(
showTimeoutMs,默认为60;loadTimeoutMs(默认 30s) 约束负载 。 最后期限是单一的 包含 SDK 装入和提供者事件流的预算:装入器 消耗了大部分,只留下剩下的 活动等待,a 完全消耗的预算从未向提供者登记。 超时结果 从活动流的 自己的期限, 所以订阅清理 在暂停之前 —— 没有孤儿能活过电话. - Slot 更新了返回承诺的和解范围内的土地:失败
在呼叫者之前装入空档
catch恢复(即刻) 重新尝试开始新的注册, 并推广成功的负载 在打电话之前await简历(即时表演作品). - 缺少或未实现进口框架
SdkError("SDK_UNAVAILABLE")· ; 不支持的应用程序版本 →SdkError("UNSUPPORTED")。负载失败 从未永久缓存——后来的呼叫重试导入. - 默认情况下,适配器从不编造成功或奖励结果: 结果只来自提供者的活动.
责任分离
SDK提供广告行为和结果. 您的应用程序拥有服务器侧 ad奖励请求、用户会话检查、付款限额和分类账更新. 两个条目中还提供身份、存储、通知和共享适配器.
版本
@ait-kit/sdk 独立于服务器 API 软件包
(单位:千美元)@ait-kit/api-*),它们互相锁上锁放出.
已验证的官方 SDK 版本
适配器的开发与不断对照这些精确度
正式发布(见 scripts/test-package-tarballs.mjs:
| 正式软件包 | 经核实的版本 | 同伴范围 |
|---|---|---|
@apps-in-toss/framework (韩文) | 2.10.10 国家 | >=2.10.10 |
@apps-in-toss/web-framework (网易新闻) | 3.4.0 (中文(简体) ) | >=3.4.0 |
运行时间表面匹配的旧版本(每种能力)可能会起作用
选中每个函数, 缺失的则拒绝 UNSUPPORTED不过
仅对上述版本进行校验。 新的版本有望奏效
通过相同的结构检查;如果官方出口形状发生变化,则
操作错误会浮出水面 而不是沉默的不当行为.
移动
0.3.0——共享表结果 closed → completed
sendMessage 现在决定 { status: "completed" } 改为
{ status: "closed" }。含义也得到了精确: completed 状态
只分享 SDK 共享 调用 结束了。 没有证明股份
工作表打开或关闭,用户共享,或任何奖励
获得资格。 更新任何 status === "closed" 检查; 失败
成果(status: "failed" 与 code编号 :reason)不变.
0.3.0 — RN 适配器调用官方导出形状
React 本地默认加载器现在转换正式的平面输出
(单位:千美元)appLogin, (中文(简体) ), getAnonymousKey, (中文(简体) ), requestNotificationAgreement, (中文(简体) ),
getTossShareLink, (中文(简体) ), share)纳入共享适配器合同。 此前
正确安装的官方 RN SDK 仍在生产
SdkError("UNSUPPORTED") 这五个能力,因为装载器
寻找网络 SDK 的命名空间形状 。 自定义 framework 注射量
使用内部命名空间合同或装载机的工作保持不变.
一个错误的映射改变沿途:官方RN getAnonymousKey()
解决 undefined (安装在功能最小版本以下)
现在拒绝 SdkError("UNSUPPORTED") 改为
INVALID_ANONYMOUS_KEY; 数据 "ERROR" 哨兵仍然拒绝
INVALID_ANONYMOUS_KEY。 。 。 .
审查请求
import { createReactNativeReview } from "@ait-kit/sdk/rn";
// WebView: import { createWebViewReview } from "@ait-kit/sdk/webview";
const review = createReactNativeReview(); // share one instance across screens
if (await review.isSupported()) await review.request();
ReviewAdapter 是运行时中性根类型。 工厂接受 framework
(单位:千美元) Review.request 与现有适配器类似.
RN 翻译官方 requestReview() 导出; WebView 调用 Review.request()。 。 。 .
官方SDK只装入使用. 缺少特性/支持检查器返回
false; 导入失败抛出 SDK_UNAVAILABLE; 推广支持检查例外.
request() 重新检查支持并丢弃 UNSUPPORTED 当无法使用时.
同时提出的一项请求 共享一项承诺,成功后予以批准或
失败。 没有重试或超时.
Promise<void> 补全无法确定UI是否出现或是否检讨
被写。 永远不要给予奖励,解锁功能,或在审查时屏蔽导航
已完成。 完成并坚持核心行动,然后单独启动
在核心流中不等待错误处理的审查请求 。 消费者
拥有请求的时间、会话限制、冷却和存储。 不记录原始 SDK
默认错误.
官方参考: 复议 (Android/iOS Toss 5.253.0+,由SDK检查). 已验证软件包表面 : RN 2.10.10和WebView 3.4.0. 设备UI行为需要单独的人工验证; 单位/tarball测试使用注射式SDK或被接住的土生桥.
明确的直接晋升奖励
import { createReactNativePromotion } from "@ait-kit/sdk/rn";
// WebView: import { createWebViewPromotion } from "@ait-kit/sdk/webview";
const promotion = createReactNativePromotion({ timeoutMs: 15_000 });
const support = await promotion.getSupport();
// RN 2.10.10 exposes no support checker: support is "unknown", not "supported".
// Opt into direct grants explicitly, with app-specific eligibility/budget checks.
PromotionAdapter, (中文(简体) ), PromotionSupport, (中文(简体) ), PromotionGrantInput 财务报告和审定财务报表
PromotionGrantResult 是运行时中性的根类型。 两家工厂都接受
framework (单位:千美元) Promotion.grantReward 合同或自动装载器.
RN 电话 grantPromotionReward({ params: { promotionCode, amount } })· ;
仅WebView 呼叫 Promotion.grantReward({ promotionCode, amount })。 。 。 .
WebView 的回落或回落到/从服务器支付流量中.
getSupport() 报告 unsupported 函数缺失或明显错误
检查, supported 真实的检查,和 unknown 当一个函数没有检查器时.
导入失败抛出 SDK_UNAVAILABLE; 推广支持检查例外.
每笔赠款都会重新检查支持。 RN有记录 undefined 和供应商的
UNSUPPORTED_APP_VERSION 掷出 UNSUPPORTED; 错误的WebView响应仍然未知.
输入出错 INVALID_PROMOTION_INPUT 在装入/调用SDK前:
promotionCode 必须是非空的,而不绕入白空间(从未修剪过)
输入不同的代码),和 amount 必须是正的安全整数。 运动
资格、最高数额和预算仍然是消费者的责任.
结果:
granted无空rewardKey仅仅意味着SDK报告成功.rejected带有明确文件的拒绝代码:4100, (中文(简体) ),4104, (中文(简体) ),4105, (中文(简体) ),4108, (中文(简体) ),4109, (中文(简体) ),4110, (中文(简体) ),4112,或4114。 。 。 .unknown要求确认: SDK 例外/ sentinels, 畸形或 相互矛盾的反应、最后期限、,UNKNOWN_ERROR, (中文(简体) ),4113,或新提供者 密码.4113从来没有变成一个推断的 已经授予的分类账状态.
赠款结果不包括提供人的信息和原始错误。 提供者代码 仅保留为已绑定的大写字母数字/分数符号; 不日志 奖励键,升级代码或整个SDK响应.
共享一个适配器实例 。 同时发放的补助金 PROMOTION_IN_PROGRESS· ;
完成的结果永远不会被缓存为一能支付. timeoutMs 默认为
0(残疾),通过2147483647接受整数,并覆盖装载和SDK
电话 延迟时间在发送前和SDK结算后检查,所以延迟
计时器回调不能启动逾期付款或将延迟结果变为成功.
超时后结果未知, 但实例将一直锁定到
实际操作结算。 超时后完成的加载机从不开始付费.
延迟成功/失败无法改变返回的超时结果 。 没有
取消、自动重试或跨例/设备/启动的保护.
消费者 UI 模式( 所有回调由 app 提供) :
async function grantOnce(input, ui) {
ui.disableGrantAction();
try {
const result = await promotion.grantReward(input);
if (result.status === "unknown") {
ui.showConfirmationRequired(); // keep disabled; never retry automatically
return;
}
ui.showSdkResult(result); // client report only; not a server ledger receipt
} catch {
ui.showConfirmationRequired(); // do not dump raw exceptions or auto-reenable
}
}
将客户端结果张贴到服务器不是独立的支付验证. 需要服务器分类账的消费者必须保留现有的三相服务器 支付路径。 此 API 不需要客户端的 mTLS 证书/ 代理令牌 而不取代TrailBase索赔或自有货币会计.
官方参考: 奖励。 。 。 . 合同对照RN 2.10.10和Webview 3.4.0公布的种类/编码进行核对 合成桥固定装置. 设备检查和正式的测试促进电话仍然存在 手动;测试不会引用真正的升级.
WebView 命名迁移
使用 @ait-kit/sdk/webview 编辑 createWebView* 工厂/ WebView* 类型.
遗产 @ait-kit/sdk/web 条目, createWeb* 工厂,以及 Web* 类型不变
可用作具有相同行为的被贬值的别名。 官方对等软件包
名称 : @apps-in-toss/web-framework。 。 。 .
WebView 广告使用官方平面 loadFullScreenAd 财务报告和审定财务报表 showFullScreenAd 出口.
创建它们与 createWebViewAds() 从 @ait-kit/sdk/webview; 不变
负载/显示截止时间,单用规则,以及上述奖励事件语义适用.
订阅状态查询
两个IP适配器都曝光 getSubscriptionInfo(orderId) 返回时 { subscription }
与提供者 catalogId, (中文(简体) ), status, (中文(简体) ), expiresAt, (中文(简体) ), isAutoRenew, (中文(简体) ),
gracePeriodExpiresAt,以及 isAccessible 字段。 保留未来状态字符串;
访问从不从状态字符串推断。 把这当成一个提供者的快照,
不是服务器侧权限验证 。 查询从不调用 grant 或改变应享权利.
缺少能力, 不支持主机版本, 和 RN 不支持 undefined
响应投出 SdkError("UNSUPPORTED")空的身份证 INVALID_IAP_INPUT· ;
投出不良有效载荷 INVALID_IAP_RESULT。其他提供者的错误仍然可见.
已完成并退还定单历史
iap.getCompletedOrRefundedOrders() 返回时 { orders, hasNext, nextKey?, pagination }。 。 。 .
每一订单都保留其提供者 orderId, (中文(简体) ), sku, (中文(简体) ), status (单位:千美元)COMPLETED 或者说 REFUNDED, (中文(简体) ),
财务报告和审定财务报表 date。这个只读查询从来不给予货物或取消应享权利.
RN页面有 pagination: "cursor"; 通过 { key: page.nextKey } 明确
当 hasNext 是真实的,并存在光标。 网页
有过 pagination: "first_page_only": 当前的官方 WebView SDK 接受不
光标. hasNext 可能仍然是真实的,但通过一个非无键键抛出 UNSUPPORTED
在供应商发送之前。 不要循环WebView的一页呼叫或把它们当作一个完全恢复.
缺少/不支持的能力抛出 UNSUPPORTED,输入错误
INVALID_IAP_INPUT,且页面格式错误 INVALID_IAP_RESULT其他提供者
错误不自动重复传播 .
WebView 横幅广告
import { createWebViewBannerAds } from "@ait-kit/sdk/webview";
const ads = createWebViewBannerAds();
const controller = new AbortController();
const banner = await ads.attachBanner("AD_GROUP_ID", "#banner", {
theme: "auto", tone: "grey", variant: "card", signal: controller.signal,
callbacks: { onNoFill: () => console.log("No banner available") }
});
// On unmount: controller.abort() also cancels a pending attachment.
banner.destroy(); // idempotent; only this handle is destroyed
初始化是懒惰的,在适配器内共享,并以 initializeTimeoutMs
(默认为15秒;整数毫秒从1到2,147,483,647). 失败的初始化可以重试 .
附件在提供者返回其手柄时解决;它不声称是
广告或得到的奖励。 渲染/视图/点击/印象/失败/不填写回调
被传送到一个微型任务中,并在销毁后被压制。 同步附件
失败拒绝方式 BANNER_ATTACH_FAILED。 。 。 .
每个活的附着物必须拥有独特的DOM元素. SDK 实例拒绝重复
目标为 BANNER_TARGET_IN_USE 直到前一个手柄被销毁。 不组合
同一元素上的原始提供者附件和适配器附件。 无全局
TossAds.destroyAll() 打电话了。 使用一个 AbortSignal 当目标可能卸载时
初始化待决; 初始化后拒绝等待的呼叫
永远不要附着在被中止的目标上.
如果提供商进行清理,手柄仍会在当地被摧毁,并释放
目标要求; 提供者的例外仍然可以观察到。 合并附件失败
与清理失败拒绝 AggregateError 保留两个错误.
匿名服务器认证
官方WebView SDK 3. 6.0 或更新:
import { createWebViewIdentity } from "@ait-kit/sdk/webview";
const identity = createWebViewIdentity();
const { code } = await identity.createAnonymousKeyAuthCode();
// Send immediately to your server; use @ait-kit/api-core exchangeAnonAuthCode there.
每通电话向SDK询问一个新鲜代码;代码不被缓存或存储. 失踪
方法和不支持的运行时间以 UNSUPPORTED无效的响应
形状拒绝 INVALID_ANONYMOUS_AUTH_CODE 没有回音代码。 这个
方法永远不会回到登录或客户端提供的散列。 现有 API 仍然
与现有的对等版本一起工作;只有这种方法需要SDK 3.6+.