# 开始使用 Connect 嵌入式组件 了解如何在您的网站中嵌入管理平台功能。 使用 Connect 嵌入式组件向您的网站添加关联账户管理平台功能。这些库及其支持的 API 允许您直接在您的管理平台和移动应用中为用户提供对 Stripe 产品的访问权限。 有关本指南的沉浸式版本,请参见 [Connect 嵌入式组件集成快速指南](https://docs.stripe.com/connect/connect-embedded-components/quickstart.md)。您也可以从那里下载一个示例集成。若要自定义 Connect 嵌入式组件的外观,请在初始化 `StripeConnectInstance` 时使用 `appearance` 选项。查看[外观参数完整列表](https://docs.stripe.com/connect/customize-connect-embedded-components.md)。 ## Initialize Connect.js [客户端] [服务器端] Stripe 使用 [AccountSession](https://docs.stripe.com/api/account_sessions.md) 来表达您将 API 访问权限授予 Connect 子账户的意图。 AccountSessions API 返回一个*客户端密钥* (The client secret is a unique string returned from Stripe as part of an AccountSession. This string lets the client access a specific Stripe account with Connect embedded components),允许嵌入式组件访问关联账户的资源,就像您在为它们进行 API 调用一样。 ### 创建 AccountSession (Server) 在单页面应用程序中,您的客户端向您的服务器发起获取账户会话的请求。您可以在服务器上创建新的端点,将客户端私钥返回到浏览器: #### Ruby ```ruby require 'sinatra' require 'stripe' # This is a placeholder - it should be replaced with your secret API key. # Sign in to see your own test API key embedded in code samples. # Don’t submit any personally identifiable information in requests made with this key. Stripe.api_key = '<>' post '/account_session' do content_type 'application/json' # Create an AccountSession begin account_session = Stripe::AccountSession.create({ account: {{CONNECTED_ACCOUNT_ID}}, components: { payments: { enabled: true, features: { refund_management: true, dispute_management: true, capture_payments: true } } } }) { client_secret: account_session[:client_secret] }.to_json rescue => error puts "An error occurred when calling the Stripe API to create an account session: #{error.message}"; return [500, { error: error.message }.to_json] end end ``` ### 创建 Account Session API [创建账户会话 API](https://docs.stripe.com/api/account_sessions/create.md) 决定 Connect 嵌入组件的组件和功能访问权限。Stripe 会对与该账户会话对应的任何组件强制执行这些参数。如果您的网站支持多个用户角色,请确保为该账户会话启用的组件和功能与当前用户的角色对应。例如,您可以仅为网站管理员启用[退款管理](https://docs.stripe.com/api/account_sessions/create.md#create_account_session-components-payments-features-refund_management)功能,而不允许其他用户访问。为了确保用户角色访问控制得到强制执行,您必须将网站的用户角色映射到账户会话组件上。 ### 设置 Connect.js (Client) 我们建议用 npm 设置 Connect.js,如以下示例所示,但也可以[不使用 npm](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#without-npm)。 #### HTML + JS 安装 [npm 包](https://github.com/stripe/connect-js),以便以模块形式使用 Connect.js。 ```bash npm install --save @stripe/connect-js ``` #### React 从 [npm 公共注册表](https://www.npmjs.com/package/@stripe/react-connect-js)中安装 Connect.js 和 React Connect.js 库。 ```bash npm install --save @stripe/connect-js @stripe/react-connect-js ``` ### 加载并初始化 Connect.js (Client) 通过调用您在服务器上创建的新端点,使用您的公钥和一个检索客户端私钥的函数调用 `loadConnectAndInitialize`。使用返回的 `StripeConnectInstance` 创建嵌入式组件。初始化 Connect.js 后,您可以随时在 DOM 中挂载或卸载组件。这包括 React 或 Vue 门户中呈现的任何元素。 #### HTML + JS 若要创建组件,调用您在上边创建的 `StripeConnectInstance` 上的 `create`,然后传入组件名称。这将返回一个[自定义元素](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements),Connect.js 注册并使用该元素自动将 DOM 连接到 Stripe。然后可以将该元素 `append` 附加到 DOM 中。 用 `payments` 调用 `create`,然后将结果添加到您的 DOM 中以呈现支付 UI。 #### React 若要将 Connect 嵌入式组件与 React 包装器一起使用,请将您的应用程序包装在 `ConnectComponentsProvider` 中,然后传入您之前创建的 `StripeConnectInstance`。 在您的页面上使用 `ConnectPayments` 来呈现支付 UI。 #### HTML + JS ```html

Payments

``` ```javascript import {loadConnectAndInitialize} from '@stripe/connect-js'; const fetchClientSecret = async () => { // Fetch the AccountSession client secret const response = await fetch('/account_session', { method: "POST" }); if (!response.ok) { // Handle errors on the client side here const {error} = await response.json(); console.error('An error occurred: ', error); document.querySelector('#error').removeAttribute('hidden'); return undefined; } else { const {client_secret: clientSecret} = await response.json(); document.querySelector('#error').setAttribute('hidden', ''); return clientSecret; } } const stripeConnectInstance = loadConnectAndInitialize({ // This is a placeholder - it should be replaced with your publishable API key. // Sign in to see your own test API key embedded in code samples. // Don’t submit any personally identifiable information in requests made with this key. publishableKey: "<>", fetchClientSecret: fetchClientSecret, }); const paymentComponent = stripeConnectInstance.create("payments"); const container = document.getElementById("container"); container.appendChild(paymentComponent); ``` [查看支持的嵌入式组件的完整列表 →](https://docs.stripe.com/connect/supported-embedded-components.md) ## Configure Connect.js [客户端] 客户端上 `loadConnectAndInitialize` 方法采用几个不同的选项来配置 Connect.js。 | 期权 | 描述 | | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -- | | `publishableKey` | 您的[集成](https://docs.stripe.com/keys.md)的公钥。 | 必填 | | `fetchClientSecret` | 该函数检索 `/v1/account_sessions` 返回的*客户端私钥* (The client secret is a unique string returned from Stripe as part of an AccountSession. This string lets the client access a specific Stripe account with Connect embedded components)。这将告诉 `StripeConnectInstance` 授权访问哪个账户。此函数还用于检索客户端私钥函数,以在会话到期时刷新会话。`fetchClientSecret` 应始终创建一个新的账户会话并返回一个新的 `client_secret`。 | 必填 | | `appearance` | 一个用来自定义 Connect 嵌入式组件外观的对象。 | 可选 | | `locale` | 该参数用于指定 Connect 嵌入式组件所使用的[区域](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#localization)。区域设置默认为浏览器的语言。如果不直接支持指定的区域设置,则使用一个合理的替代方案(例如,`fr-be` 可能回退到 `fr-fr`)。查看[本地化](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#localization),获取受支持区域的列表。 | 可选 | | `fonts` | 一组自定义字体,可供从 `StripeConnectInstance` 创建的任何嵌入组件使用。可以将字体指定为 [CssFontSource](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#css-font-source) 或 [CustomFontSource](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#custom-font-source) 对象。 | 可选 | ### 自定义 Connect 嵌入式组件的外观 [嵌入式组件 Figma UI 工具包](https://www.figma.com/community/file/1438614134095442934)包含每个组件、常见模式和一个示例应用程序。您可以使用它来可视化和设计网站中的嵌入式用户界面。 我们提供了[一组选项](https://docs.stripe.com/connect/embedded-appearance-options.md)来定制 Connect 嵌入式组件的外观。这些定制会影响我们设计系统中的按钮、图标和其他元素。 > #### 必要的弹出窗口 > > 嵌入式组件中的某些行为,如[用户身份验证](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#user-authentication-in-connect-embedded-components),必须以弹出窗口的形式呈现。您无法自定义嵌入式组件来消除此类弹窗。 在初始化 `StripeConnectInstance` 时,可以通过向 `appearance` 对象传递一个 Appearance 来设置这些选项。您只能用 [Connect.js 选项](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#configuring-connect)来修改 Connect 嵌入式组件中的样式。Connect 嵌入式组件的字体系列和背景颜色继承自父级 HTML 容器。您必须显式设置所有其他选项。 ```javascript const stripeConnectInstance = loadConnectAndInitialize({ publishableKey: "<>", fetchClientSecret: fetchClientSecret, fonts: [ { cssSrc: "https://myfonts.example.com/mycssfile.css", }, { src: `url(https://my-domain.com/assets/my-font-2.woff)`, family: 'My Font' } ], appearance: { // See all possible variables below overlays: "dialog", variables: { fontFamily: 'My Font', colorPrimary: "#FF0000", }, }, }); ``` 请参见[外观变量的完整列表](https://docs.stripe.com/connect/embedded-appearance-options.md)。 ### 字体对象 `stripeConnect.initialize` 中的 `fonts` 对象接受一个由 [CssFontSource](https://docs.stripe.com/js/appendix/css_font_source_object) 或 [CustomFontSource](https://docs.stripe.com/js/appendix/custom_font_source_object) 对象组成的数组。 如果您在页面中使用自定义字体(例如 `.woff` 或 `.tff` 文件),则必须在初始化 Connect 嵌入式组件时指定这些文件。这样做可以使 Connect 嵌入式组件正确呈现这些字体。您可以将它们指定为: #### CssFontSource 创建 `StripeConnectInstance` 时,使用此对象传递定义自定义字体的样式表 URL。对于 `CssFontSource` 对象,您的 [CSP 配置](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#csp-and-http-header-requirements)必须允许提取与指定为 CssFontSource 的 CSS 文件 URL 相关联的域名。 | 姓名 | 类型 | 示例值 | | -------- | -------------- | --------------------------------------------------- | | `cssSrc` | 字符串 `required` | `https://fonts.googleapis.com/css?family=Open+Sans` | 一个指向具有 [@font-face](https://developer.mozilla.org/en/docs/Web/CSS/@font-face) 定义的 CSS 文件的相对或绝对 URL。该文件必须托管在 https 上。如果您使用[内容安全策略 (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy),则文件可能需要[其他指令](https://docs.stripe.com/security/guide.md#content-security-policy)。 | #### CustomFontSource 创建 `StripeConnectInstance` 时,使用此对象传递定义自定义字体的样式。 | 姓名 | 类型 | 示例值 | | -------------- | -------------- | ----------------------------------------------- | | `family` | 字符串 `required` | `Avenir` | 字体的名称。 | | `src` | 字符串 `required` | `url(https://my-domain.com/assets/avenir.woff)` | 一个指向您自定义字体文件的有效 [src](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src) 取值。该值通常(但非绝对)是后缀为 `.woff`、`.otf` 或 `.svg` 的文件链接,且文件必须通过 https 协议托管。 | | `display` | 字符串 `optional` | `auto` | 一个有效的 [font-display](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display) 值。 | | `style` | 字符串 `optional` | `normal` | `normal`、`italic`、`oblique` 中的一个。 | | `unicodeRange` | 字符串 `optional` | `U+0-7F` | 有效的 [unicode-range](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range) 值。 | | `weight` | 字符串 `optional` | `400` | 有效的[字体粗细](https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight)。这是一个字符串,而不是数字。 | ### 初始化后更新 Connect 嵌入式组件 `update` 方法支持在初始化后更新 Connect 嵌入式组件。您可以使用它在运行时切换外观选项(无需刷新页面)。为此,请使用您用 `initialize` 创建的同一个 `stripeConnectInstance` 对象,并对其调用 `update` 方法: ```javascript stripeConnectInstance.update({ appearance: { variables: { colorPrimary: "#FF0000", }, }, locale: 'en-US', }); ``` > 并非所有选项(例如 `fonts`)都可更新。该方法支持的选项是 `initialize` 中提供的选项的子集。这支持更新 `appearance` 和 `locale`。 ### 宽度和高度 Connect 嵌入式组件的行为类似于常规的 `block` HTML 元素。默认情况下,它们采用其父级 HTML 元素的 100% 宽度,并根据内部呈现的内容增加高度。您可以通过指定 HTML 父级的 `width` 来控制 Connect 嵌入式组件的 `width`。您不能直接控制 `height`,因为这取决于呈现的内容,但是,您可以使用 `maxHeight` 和 `overflow: scroll` 来限制高度,和使用其他 HTML `block` 元素一样。 ## 验证 我们提供了一组 API 来管理 Connect 嵌入式组件中的账户会话和用户凭证。 ### 刷新客户端私钥 在长时间运行的会话中,来自最初提供的*客户端私钥* (The client secret is a unique string returned from Stripe as part of an AccountSession. This string lets the client access a specific Stripe account with Connect embedded components)的会话可能会过期。当它过期时,我们会自动用 `fetchClientSecret` 检索新的客户端私钥并刷新会话。您不需要传入任何额外参数。 ```javascript import { loadConnectAndInitialize } from "@stripe/connect-js"; // Example method to retrieve the client secret from your server const fetchClientSecret = async () => { const response = await fetch('/account_session', { method: "POST" }); const {client_secret: clientSecret} = await response.json(); return clientSecret; } const stripeConnectInstance = loadConnectAndInitialize({ publishableKey: "{{PUBLISHABLE_KEY}}", fetchClientSecret: fetchClientSecret, }); ``` ### 退出 我们建议您在用户注销您的应用程序后调用 `stripeConnectInstance` 上的 `logout` 来销毁关联的账户会话对象。这将禁用链接到该 `stripeConnectInstance` 的所有 Connect 嵌入式组件。 > #### 必要的弹出窗口 > > 仅在用户从您的应用中登出时调用 `logout`。当组件卸载(例如导航至其他页面或关闭页面时)或加载其他组件时,请勿调用 logout,因为此方法会使当前账户会话和 [Stripe 用户会话](https://docs.stripe.com/connect/get-started-connect-embedded-components.md?platform=web#user-authentication-in-connect-embedded-components)完全失效。调用 `logout` 后,与 `stripeConnectInstance` 关联的组件将不再渲染。 ```javascript // Call this when your user logs out stripeConnectInstance.logout(); ``` ## CSP 和 HTTP 头的要求 如果您的网站实施了*内容安全政策* (Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross-Site Scripting (XSS) and data injection attacks),您需要通过添加以下规则来更新该策略: - `frame-src` `https://connect-js.stripe.com` `https://js.stripe.com` - `img-src` `https://*.stripe.com` - `script-src` `https://connect-js.stripe.com` `https://js.stripe.com` - `style-src` `sha256-0hAheEzaMe6uXIKV4EehS9pu1am1lj/KnnzrOYqckXk=` (SHA of empty style element) 如果您使用 CSS 文件加载 [Web 字体](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#fonts-object)以用于 Connect 嵌入式组件,其 URL 必须被您的 [connect-src](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/connect-src) CSP 指令允许。 设置某些 [HTTP 响应头](https://developer.mozilla.org/en-US/docs/Glossary/Response_header) 可启用 Connect 嵌入式组件的全部功能: - [Cross-Origin-Opener-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy), `unsafe-none`。此 (`unsafe-none`) 是标头的默认值,因此不设置此标头也可以。在 Connect 嵌入式组件中,其他值如 `same-origin` 会破坏[用户身份验证](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#user-authentication-in-connect-embedded-components)。 ## 支持的浏览器 我们支持 [Stripe 管理平台当前支持](https://docs.stripe.com/dashboard/basics.md)的相同浏览器。 - 最近 20 个主要版本的 Chrome 和 Firefox - 最近两个主要版本的 Safari 和 Edge - 移动 iOS 系统上最近两个主要版本的 Safari 您不能在移动端或桌面应用的嵌入式网页视图中使用 Connect 嵌入式组件。如需在移动应用中使用 Connect 嵌入式组件,请使用 [iOS](https://docs.stripe.com/connect/get-started-connect-embedded-components.md?platform=ios)、[Android](https://docs.stripe.com/connect/get-started-connect-embedded-components.md?platform=android) 或 [React Native](https://docs.stripe.com/connect/get-started-connect-embedded-components.md?platform=react-native) SDK。 如果我们的移动 SDK 尚不支持嵌入式组件,我们建议链接到可以渲染嵌入式组件的网页浏览器。 ## 本地化 初始化 [Connect.js](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#account-sessions) 时,可以传递一个 `locale` 参数。要将嵌入式组件的区域设置与您网站的区域设置进行匹配,请在 `locale` 参数中传递您的网站呈现用户界面的区域设置。 `locale` 参数的默认值由浏览器配置的区域设置确定。如果不直接支持指定的区域设置,则使用一个合理的替代方案(例如,`fr-be` 可能回退到 `fr-fr`)。 Connect 嵌入式组件支持以下地区: | 语言 | 区域代码 | | -------------- | ------------ | | 保加利亚语(保加利亚) | `bg-BG` | | 中文(简体) | `zh-Hans` | | 中文(繁体 - 香港) | `zh-Hant-HK` | | 中文(繁体 - 台湾) | `zh-Hant-TW` | | 克罗地亚语(克罗地亚) | `hr-HR` | | 捷克语(捷克) | `cs-CZ` | | 丹麦语(丹麦) | `da-DK` | | 荷兰语(荷兰) | `nl-NL` | | 英语(澳大利亚) | `en-AU` | | 英语(印度) | `en-IN` | | 英语(爱尔兰) | `en-IE` | | 英语(新西兰) | `en-NZ` | | 英语(新加坡) | `en-SG` | | 英语(英国) | `en-GB` | | 英语(美国) | `en-US` | | 爱沙尼亚语(爱沙尼亚) | `et-EE` | | 菲律宾语(菲律宾) | `fil-PH` | | 芬兰语(芬兰) | `fi-FI` | | 法语(加拿大) | `fr-CA` | | 法语(法国) | `fr-FR` | | 德语(德国) | `de-DE` | | 希腊语(希腊) | `el-GR` | | 匈牙利语(匈牙利) | `hu-HU` | | 印度尼西亚语(印度尼西亚) | `id-ID` | | 意大利语(意大利) | `it-IT` | | 日语(日本) | `ja-JP` | | 朝鲜语(韩国) | `ko-KR` | | 拉脱维亚语(拉脱维亚) | `lv-LV` | | 立陶宛语(立陶宛) | `lt-LT` | | 马来语(马来西亚) | `ms-MY` | | 马耳他语(马耳他) | `mt-MT` | | 挪威语(波克默尔语)(挪威) | `nb-NO` | | 波兰语(波兰) | `pl-PL` | | 葡萄牙语(巴西) | `pt-BR` | | 葡萄牙语(葡萄牙) | `pt-PT` | | 罗马尼亚语(罗马尼亚) | `ro-RO` | | 斯洛伐克语(斯洛伐克) | `sk-SK` | | 斯洛文尼亚语(斯洛文尼亚) | `sl-SI` | | 西班牙语(阿根廷) | `es-AR` | | 西班牙语(巴西) | `es-BR` | | 西班牙语(拉丁美洲) | `es-419` | | 西班牙语(墨西哥) | `es-MX` | | 西班牙语(西班牙) | `es-ES` | | 瑞典语(瑞典) | `sv-SE` | | 泰语(泰国) | `th-TH` | | 土耳其语(土耳其) | `tr-TR` | | 越南语(越南) | `vi-VN` | ## 处理加载错误 如果某个组件加载失败,可以通过向任意嵌入式组件提供一个加载错误处理程序来对该失败做出反应。根据失败原因的不同,可以多次调用加载错误处理程序。加载错误处理程序触发的任何逻辑都必须是幂等的。 #### HTML + JS ```js // Load errors are emitted by all components. We use Balances as an example here. const balances = stripeConnectInstance.create('balances'); balances.setOnLoadError((loadError) => { const componentName = loadError.elementTagName const error = loadError.error console.log(componentName + " failed to load") console.log(`${error.type}: ${error.message}`); }); container.appendChild(balances); ``` #### HTML + JS | 方式 | 描述 | 变量 | | ---------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `setOnLoadError` | 当加载失败发生时,组件将执行此回调函数。 | - `loadError.error`:参见[加载错误对象](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#the-load-object) - `loadError.elementTagName`:用于在浏览器中呈现组件的 HTML 标记的名称 | #### React | React 属性 | 描述 | 变量 | | ------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `onLoadError` | 当加载失败发生时,组件将执行此回调函数。 | - `loadError.error`:参见[加载错误对象](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#the-load-object) - `loadError.elementTagName`:用于在浏览器中呈现组件的 HTML 标记的名称 | #### 加载 `error` 对象 每次加载失败时,都会向具有以下属性的加载错误处理程序传递一个 `error` 对象。 | 姓名 | 类型 | 示例值 | | --------- | -------------------------------------------------------------------------------------------------------- | --------------------------------- | | `type` | 请参见[加载失败的类型](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#the-load-object) | `authentication_error` | 错误类型 | | `message` | 字符串 | 未定义 | `Failed to fetch account session` | 有关该错误的进一步描述 | #### 负载故障类型 当某个组件加载失败时,我们会检测失败类型,并将其归类为以下类型之一。如果无法确定加载错误类型,则将其标记为 `api_error`。 | 类型 | 描述 | | ------------------------------ | --------------------------------------- | | `api_connection_error` | 未能连接 Stripe 的 API | | `authentication_error` | 无法在 Connect 嵌入式组件中执行验证流程 | | `account_session_create_error` | 账户会话创建失败 | | `invalid_request_error` | 请求失败,显示 4xx 状态码,通常由平台配置问题引起 | | `rate_limit_error` | 因检测到异常请求速率,请求失败 | | `render_error` | 组件渲染失败,通常由浏览器扩展程序或网络问题引起 | | `api_error` | 涵盖任何其他类型的问题的 API 错误,例如 Stripe 服务器的临时性问题 | #### 加载错误的用户界面 在大多数情况下,嵌入式组件加载失败时会显示错误消息,因此您无需额外处理。您可以使用加载错误处理器来统计分析数据,或处理加载错误可能影响到的网站其他元素。 不过,对于在调用 [onLoaderStart](https://docs.stripe.com/connect/get-started-connect-embedded-components.md?platform=web#reacting-to-component-display) 回调函数之前发生的错误,嵌入式组件不会显示任何消息,因为这意味着组件尚未渲染任何用户界面。这种情况下,应由您的代码来渲染错误界面。 ## 检测嵌入式组件的显示情况 创建组件后,只有在浏览器中加载并解析了该组件的 javascript 才会向用户显示任何用户界面。这可能会导致组件在完成加载后显示为弹出式页面。为避免这种情况,请在创建组件之前显示您自己的加载用户界面,并在显示组件后隐藏用户界面。所有嵌入式组件都可以接受回调函数,当任何用户界面(包括加载指示器)向用户显示时,该回调函数会立即触发。 #### HTML + JS ```html
``` ```js // Loader start events are emitted by all components. We use Balances as an example here. const container = document.getElementById('balances-container'); const balances = stripeConnectInstance.create('balances'); balances.setOnLoaderStart((event) => { container.getElementById("spinner").style.display = "none"; console.log(`${event.elementTagName} is visible to users`) }); container.appendChild(balances); ``` #### HTML + JS | 方式 | 描述 | 变量 | | ------------------ | ---------------------------------- | ------------------------------------------------ | | `setOnLoaderStart` | 当向用户显示任何用户界面(包括加载指示器)时,组件将执行此回调函数。 | - `event.elementTagName`:用于在浏览器中呈现组件的 HTML 标记的名称 | #### React | React 属性 | 描述 | 变量 | | --------------- | ---------------------------------- | ------------------------------------------------ | | `onLoaderStart` | 当向用户显示任何用户界面(包括加载指示器)时,组件将执行此回调函数。 | - `event.elementTagName`:用于在浏览器中呈现组件的 HTML 标记的名称 | ## 在没有 npm 的情况下使用 Connect.js 我们建议与我们的 [javascript](https://github.com/stripe/connect-js) 和 [React 封装组件](https://github.com/stripe/react-connect-js)进行集成,它们简化了 Connect 嵌入式组件的加载并为我们支持的接口提供了 TypeScript 定义。如果您的构建系统当前不支持依赖工具包,则可以在没有这些工具包的情况下集成。 手动将 Connect.js 脚本标记添加到您的网站上每个页面的 ``。 ```html ``` Connect.js 加载完成后,会初始化全局 window 变量 `StripeConnect`,并调用 `StripeConnect.onLoad`(如果已定义)。您可以通过设置 `onload` 函数并传入与 `loadConnectAndInitialize` 相同的 [Connect.js 选项](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#configuring-connect) 来调用 `StripeConnect.init`,从而安全地初始化 Connect.js。您可以像使用 `loadConnectAndInitialize` 返回的实例一样,使用 `init` 返回的 Connect 实例,在 [HTML + JS 集成](https://docs.stripe.com/connect/get-started-connect-embedded-components.md?client=js&platform=web#load-and-initialize-connectjs) 中创建嵌入式组件。 ```javascript window.StripeConnect = window.StripeConnect || {}; StripeConnect.onLoad = () => { const stripeConnectInstance = StripeConnect.init({ // This is a placeholder - it should be replaced with your publishable API key. // Sign in to see your own test API key embedded in code samples. // Don't submit any personally identifiable information in requests made with this key. publishableKey: "<>", fetchClientSecret: fetchClientSecret, }); const payments = stripeConnectInstance.create('payments'); document.body.appendChild(payments); }; ``` ## Connect 嵌入式组件中的用户身份验证 Connect 嵌入式组件通常不需要用户验证。在某些场景中,Connect 嵌入式组件要求关联账户在访问组件以提供必要功能之前使用其 Stripe 账户登录(例如,在[账户注册](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md)组件中向账户法律实体写入信息的情况)。其他组件可能在首次呈现后需要在组件内进行验证。 当要求变更时,若由 Stripe 负责收集更新后的信息,则关联账户需要进行验证。对于要求到期或变更时由您负责收集更新后的信息的关联账户(如 Custom 账户),Stripe 验证由 [disable_stripe_user_authentication](https://docs.stripe.com/api/account_sessions/create.md#create_account_session-components-account_onboarding-features-disable_stripe_user_authentication) 账户会话功能控制。我们建议将实施双重验证 (2FA) 或等效安全措施作为[最佳实践](https://docs.stripe.com/connect/risk-management/best-practices.md#prevent-account-take-overs)。对于支持此功能的账户配置(如 Custom 账户),如果关联账户无法偿还[负余额](https://docs.stripe.com/connect/risk-management/best-practices.md#decide-your-approach-to-negative-balance-liability),则由您承担责任。 ### 需要验证的组件 验证过程中会弹出一个 Stripe 拥有的窗口。Connect 子账户必须先验证后才能继续他们的流程。 以下组件要求关联账户在特定场景下进行验证: - [账户入驻](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md) - [账户管理](https://docs.stripe.com/connect/supported-embedded-components/account-management.md) - [余额](https://docs.stripe.com/connect/supported-embedded-components/balances.md) - [提现](https://docs.stripe.com/connect/supported-embedded-components/payouts.md) - [通知横幅](https://docs.stripe.com/connect/supported-embedded-components/notification-banner.md) - [金融账户](https://docs.stripe.com/connect/supported-embedded-components/financial-account.md) - [发卡列表](https://docs.stripe.com/connect/supported-embedded-components/issuing-cards-list.md) ## 性能最佳做法 为确保 Connect 嵌入式组件的加载时间尽可能短,请遵循以下建议: - **尽早在流程中调用 `loadConnectAndInitialize`**。 - **创建单个关联实例**:每个会话只需调用一次 `loadConnectAndInitialize` 来创建单个关联实例,然后重用该实例以创建和管理多个组件。常见错误是为每个组件创建单个关联实例,或在一个会话中创建多个关联实例,这会导致额外的资源消耗和 API 请求。如果您使用 React,可以使用状态管理库或 React 上下文来管理该实例。 - **使用适用 SDK 的最新版本**:使用 [connect-js](https://www.npmjs.com/package/@stripe/connect-js) 或 [react-connect-js](https://www.npmjs.com/package/@stripe/react-connect-js) npm 工具包 SDK 的最新版本。这些 SDK 以最大限度提高性能的方式对嵌入式组件进行初始化。SDK 中增加了性能改进,因此我们建议对旧版本进行升级。 - **尽快在流程中加载 `connect.js` 脚本**:最先加载此脚本的地方是将其包含在 HTML `head` 中。您还可以使用我们的 npm 工具包 SDK 的默认行为,它会在您的页面 JavaScript 首次加载时加载它。 ## 设置 StripeConnect [客户端] [服务器端] Stripe 使用 [AccountSession](https://docs.stripe.com/api/account_sessions.md) 来表达您将 API 访问权限授予 Connect 子账户的意图。 AccountSessions API 返回一个*客户端密钥* (The client secret is a unique string returned from Stripe as part of an AccountSession. This string lets the client access a specific Stripe account with Connect embedded components),允许嵌入式组件访问关联账户的资源,就像您在为它们进行 API 调用一样。 ### 创建 AccountSession (Server) 您的应用必须向服务器发起请求以获取账户会话。您可以在服务器上创建一个新端点,将客户端私钥返回给应用: #### Ruby ```ruby require 'sinatra' require 'stripe' # This is a placeholder - it should be replaced with your secret API key. # Sign in to see your own test API key embedded in code samples. # Don’t submit any personally identifiable information in requests made with this key. Stripe.api_key = '<>' post '/account_session' do content_type 'application/json' # Create an AccountSession begin account_session = Stripe::AccountSession.create({ account: {{CONNECTED_ACCOUNT_ID}}, components: { account_onboarding: { enabled: true, features: { # We recommend disabling authentication for a better user experience when possible disable_stripe_user_authentication: true, } } } }) { client_secret: account_session[:client_secret] }.to_json rescue => error puts "An error occurred when calling the Stripe API to create an account session: #{error.message}"; return [500, { error: error.message }.to_json] end end ``` ### 创建 Account Session API [创建账户会话 API](https://docs.stripe.com/api/account_sessions/create.md) 决定 Connect 嵌入组件的组件和功能访问权限。Stripe 会对与该账户会话对应的任何组件强制执行这些参数。如果您的应用支持多个用户角色,请确保该账户会话启用的组件和功能与当前用户的角色对应。例如,您可以仅为网站管理员启用[退款管理](https://docs.stripe.com/api/account_sessions/create.md#create_account_session-components-payments-features-refund_management)功能,而不允许其他用户访问。为了确保用户角色访问控制得到强制执行,您必须将网站的用户角色映射到账户会话组件上。 ### 安装 StripeConnect SDK (Client) [Stripe iOS SDK](https://github.com/stripe/stripe-ios) 是开源的,[有完整的文档](https://stripe.dev/stripe-ios/index.html),并且与支持 iOS 15 或更高版本操作系统的应用程序兼容。 #### Swift Package Manager 要安装 SDK,按这些步骤进行: 1. 在 Xcode 中,选择**文件** > **添加工具包依赖…**并输入 `https://github.com/stripe/stripe-ios-spm` 作为仓库 URL。 1. 从我们的[发布页面](https://github.com/stripe/stripe-ios/releases)选择最新的版本号。 1. 将 **StripeConnect** 产品添加到[您的目标应用程序](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app)。 #### CocoaPods 1. 如果您还没有[CocoaPods](https://guides.cocoapods.org/using/getting-started.html),请安装其最新版本。 1. 如果您目前没有 [Podfile](https://guides.cocoapods.org/syntax/podfile.html),请运行以下命令创建一个: ```bash pod init ``` 1. 将这一行代码添加到您的 `Podfile`: ```podfile pod 'StripeConnect' ``` 1. 运行以下命令: ```bash pod install ``` 1. 今后,一定记得用 `.xcworkspace` 文件来打开您在 Xcode 中的项目,不要使用 `.xcodeproj` 文件。 1. 将来,要更新到 SDK 的最新版本,运行: ```bash pod update StripeConnect ``` #### Carthage 1. 如果您还没有[Carthage](https://github.com/Carthage/Carthage#installing-carthage),请安装其最新版本。 1. 将这一行代码添加到您的 `Cartfile`。 ```cartfile github "stripe/stripe-ios" ``` 1. 按照 [Carthage 安装说明](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos)进行。确保嵌入[这里](https://github.com/stripe/stripe-ios/tree/master/StripeConnect#manual-linking)所列的所有必要框架。 1. 将来,要更新到 SDK 的最新版本,运行以下命令即可: ```bash carthage update stripe-ios --platform ios ``` #### 手动框架 1. 前往我们的 [GitHub 发布页面](https://github.com/stripe/stripe-ios/releases/latest),下载并解压缩 **Stripe.xcframework.zip**。 1. 将 **StripeConnect.xcframework** 拖拽到您的 Xcode 项目中 **General**(常规)设置的 **Embedded Binaries**(嵌入式二进制文件)部分。一定要选择 **Copy items if needed**(需要时复制项目)。 1. 为[这里](https://github.com/stripe/stripe-ios/tree/master/StripeConnect#manual-linking)所列的所有必要框架重复第 2 步。 1. 将来,要更新到 SDK 的最新版本,重复第 1-3 步。 > 有关最新 SDK 发布及过往版本的详细信息,请查看 GitHub 上的[发布](https://github.com/stripe/stripe-ios/releases)页面。要想在新版本发布时接收通知,请[查看仓库的发布](https://help.github.com/en/articles/watching-and-unwatching-releases-for-a-repository#watching-releases-for-a-repository)。 ### 设置相机授权 (Client-side) Stripe Connect iOS SDK 要求访问设备的摄像头来捕捉身份文件。要使您的应用能够请求相机访问权限,请执行以下操作: 1. 在 Xcode 中打开您项目的 **Info.plist**。 1. 添加 `NSCameraUsageDescription` 密钥。 1. 添加一个字符串值,向用户解释为什么您的应用程序需要相机访问权限,例如: > 该应用程序将使用相机拍摄您的身份证件照片。 查看 [Apple 文档](https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/requesting_authorization_for_media_capture_on_ios),了解有关请求相机授权的更多信息。 ### 初始化 EmbeddedComponentManager (Client) 使用 `StripeAPI.shared` 设置您的可发布密钥,并使用一个闭包来实例化 [EmbeddedComponentManager](https://stripe.dev/stripe-ios/stripeconnect/documentation/stripeconnect/embeddedcomponentmanager),该闭包通过调用您在服务器上创建的新端点来检索客户端私钥。要创建组件,请在您上面实例化的 `EmbeddedComponentManager` 上调用相应的创建方法。 [账户入驻](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md)会返回一个控制器,用于管理其自身的展示。其他组件(如 [Payments](https://docs.stripe.com/connect/supported-embedded-components/payments.md))会返回一个 [UIViewController](https://developer.apple.com/documentation/uikit/uiviewcontroller),您可以应用程序中更灵活地展示该组件。 #### UIKit ```swift import StripeConnect import UIKit class MyViewController: UIViewController { let errorView: UIView func fetchClientSecret() async -> String? { let url = URL(string: "https://{{YOUR_SERVER}}/account_session")! var request = URLRequest(url: url) request.httpMethod = "POST" do { // Fetch the AccountSession client secret let (data, _) = try await URLSession.shared.data(for: request) let json = try JSONSerialization.jsonObject(with: data) as? [String : Any] errorView.isHidden = true return json?["client_secret"] as? String } catch let error { // Handle errors on the client side here print("An error occurred: \(error)") errorView.isHidden = false return nil } } override func viewDidLoad() { super.viewDidLoad() // This is your test publishable API key. STPAPIClient.shared.publishableKey = "{{PUBLISHABLE_KEY}}", let embeddedComponentManager = EmbeddedComponentManager( fetchClientSecret: fetchClientSecret ) // Account onboarding presents modally and fullscreen let controller = embeddedComponentManager.createAccountOnboardingController() controller.title = "Onboard with Stripe" controller.present(from: self) // All other components can be flexibly presented let paymentsViewController = embeddedComponentManager.createPaymentsViewController() present(paymentsViewController) } } ``` ## Configure the Embedded Component Manager [客户端] [查看参考文档:external:](https://stripe.dev/stripe-ios/stripeconnect/documentation/stripeconnect/embeddedcomponentmanager/init\(apiClient:appearance:fonts:fetchClientSecret:\))。 ### 自定义 Connect 嵌入式组件的外观 [嵌入式组件 Figma UI 工具包](https://www.figma.com/community/file/1438614134095442934)包含每个组件、常见模式和一个示例应用程序。您可以使用它来可视化和设计网站中的嵌入式用户界面。 我们提供了[一组选项](https://docs.stripe.com/connect/embedded-appearance-options.md)来定制 Connect 嵌入式组件的外观。这些定制会影响我们设计系统中的按钮、图标和其他元素。 > #### 必要的弹出窗口 > > 嵌入式组件中的某些行为(例如[用户验证](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#user-authentication-in-connect-embedded-components))必须在经过验证的 WebView 中呈现。您无法定制嵌入式组件以消除此类 WebView。 您可以在初始化 `EmbeddedComponentManager` 时,使用 [EmbeddedComponentManager.Appearance](https://stripe.dev/stripe-ios/stripeconnect/documentation/stripeconnect/embeddedcomponentmanager/appearance) 设置这些选项。 ```swift func fetchClientSecret() async -> String? { let url = URL(string: "https://{{YOUR_SERVER}}/account_session")! var request = URLRequest(url: url) request.httpMethod = "POST" do { let (data, _) = try await URLSession.shared.data(for: request) let json = try JSONSerialization.jsonObject(with: data) as? [String : Any] return json?["client_secret"] as? String } catch { return nil } } // Specify custom fonts var customFonts: [CustomFontSource] = [] let myFont = UIFont(name: "My Font", size: 16)! let fontUrl = Bundle.main.url(forResource: "my-font-2", withExtension: "woff")! do { let customFontSource = try CustomFontSource(font: myFont, fileUrl: fontUrl) customFonts.append(customFontSource) } catch { print("Error loading custom font: \(error)") } // Customize appearance var appearance = EmbeddedComponentManager.Appearance() appearance.typography.font.base = myFont appearance.typography.fontSizeBase = 16 // Unscaled font size appearance.colors.primary = UIColor { traitCollection in if traitCollection.userInterfaceStyle == .dark { return UIColor(red: 0.455, green: 0.424, blue: 1.000, alpha: 1.0) } else { return UIColor(red: 0.404, green: 0.365, blue: 1.000, alpha: 1.0) } } STPAPIClient.shared.publishableKey = "{{PUBLISHABLE_KEY}}", let embeddedComponentManager = EmbeddedComponentManager( appearance: appearance, fonts: customFonts, fetchClientSecret: fetchClientSecret ) ``` 当 Connect 嵌入式组件的 [UITraitCollection](https://developer.apple.com/documentation/uikit/uitraitcollection) 被更新时,使用[动态提供程序](https://developer.apple.com/documentation/uikit/uicolor/3238041-init)的外观颜色会自动应用于 Connect 嵌入式组件,包括[暗色模式](https://developer.apple.com/design/human-interface-guidelines/dark-mode)和[辅助功能对比度](https://developer.apple.com/documentation/uikit/uiaccessibilitycontrast)。默认外观不包括暗色模式颜色,因此您必须为 `EmbeddedComponentManager` 指定具有动态颜色的外观,才能在您的应用中支持暗色模式。 指定字体大小时,请使用针对设备的默认大小等级显示的未缩放字体大小。嵌入式组件会根据它的 [UITraitCollection](https://developer.apple.com/documentation/uikit/uitraitcollection) 自动缩放字号。 请参阅 iOS 上的 [外观选项完整列表](https://docs.stripe.com/connect/embedded-appearance-options.md)。 ### 使用自定义字体 如果您的应用中使用自定义字体(例如,来自嵌入应用二进制文件的 `.otf` 或 `.tff` 文件),则必须在初始化 `EmbeddedComponentManager` 时,在传递给 `fonts` 参数的 [CustomFontSource](https://stripe.dev/stripe-ios/stripeconnect/documentation/stripeconnect/embeddedcomponentmanager/customfontsource) 中指定字体文件。这使 Connect 嵌入式组件能够访问字体文件,从而正确渲染字体。 在 `appearance` 中指定的字体必须使用 [支持的系统字体](https://developer.apple.com/fonts/system-fonts/),或在初始化时传递给 `EmbeddedComponentManager` 的 [CustomFontSource](https://stripe.dev/stripe-ios/stripeconnect/documentation/stripeconnect/embeddedcomponentmanager/customfontsource),才能正确渲染。 [查看参考文档:external:](https://stripe.dev/stripe-ios/stripeconnect/documentation/stripeconnect/embeddedcomponentmanager/customfontsource)。 ### 初始化后更新 Connect 嵌入式组件 调用 `update` 方法,更改初始化后嵌入式组件的外观: ```swift var appearance = EmbeddedComponentManager.Appearance() appearance.colors.primary = UIColor.red manager.update(appearance: appearance) ``` ## 验证 我们提供了一组 API 来管理 Connect 嵌入式组件中的账户会话和用户凭证。 ### 刷新客户端私钥 在长时间运行的会话中,来自最初提供的*客户端私钥* (The client secret is a unique string returned from Stripe as part of an AccountSession. This string lets the client access a specific Stripe account with Connect embedded components)的会话可能会过期。当它过期时,我们会自动用 `fetchClientSecret` 检索新的客户端私钥并刷新会话。您不需要传入任何额外参数。 ```swift func fetchClientSecret() async -> String? { var request = URLRequest(url: URL(string: "https://{{YOUR_SERVER}}/account_session")!) request.httpMethod = "POST" do { let (data, _) = try await URLSession.shared.data(for: request) let json = try JSONSerialization.jsonObject(with: data) as? [String : Any] return json?["client_secret"] as? String } catch let error { return nil } } STPAPIClient.shared.publishableKey = "{{PUBLISHABLE_KEY}}", let embeddedComponentManager = EmbeddedComponentManager( fetchClientSecret: fetchClientSecret ) ``` ## 本地化 Connect 嵌入式组件支持以下地区: | 语言 | 区域代码 | | -------------- | ------------ | | 保加利亚语(保加利亚) | `bg-BG` | | 中文(简体) | `zh-Hans` | | 中文(繁体 - 香港) | `zh-Hant-HK` | | 中文(繁体 - 台湾) | `zh-Hant-TW` | | 克罗地亚语(克罗地亚) | `hr-HR` | | 捷克语(捷克) | `cs-CZ` | | 丹麦语(丹麦) | `da-DK` | | 荷兰语(荷兰) | `nl-NL` | | 英语(澳大利亚) | `en-AU` | | 英语(印度) | `en-IN` | | 英语(爱尔兰) | `en-IE` | | 英语(新西兰) | `en-NZ` | | 英语(新加坡) | `en-SG` | | 英语(英国) | `en-GB` | | 英语(美国) | `en-US` | | 爱沙尼亚语(爱沙尼亚) | `et-EE` | | 菲律宾语(菲律宾) | `fil-PH` | | 芬兰语(芬兰) | `fi-FI` | | 法语(加拿大) | `fr-CA` | | 法语(法国) | `fr-FR` | | 德语(德国) | `de-DE` | | 希腊语(希腊) | `el-GR` | | 匈牙利语(匈牙利) | `hu-HU` | | 印度尼西亚语(印度尼西亚) | `id-ID` | | 意大利语(意大利) | `it-IT` | | 日语(日本) | `ja-JP` | | 朝鲜语(韩国) | `ko-KR` | | 拉脱维亚语(拉脱维亚) | `lv-LV` | | 立陶宛语(立陶宛) | `lt-LT` | | 马来语(马来西亚) | `ms-MY` | | 马耳他语(马耳他) | `mt-MT` | | 挪威语(波克默尔语)(挪威) | `nb-NO` | | 波兰语(波兰) | `pl-PL` | | 葡萄牙语(巴西) | `pt-BR` | | 葡萄牙语(葡萄牙) | `pt-PT` | | 罗马尼亚语(罗马尼亚) | `ro-RO` | | 斯洛伐克语(斯洛伐克) | `sk-SK` | | 斯洛文尼亚语(斯洛文尼亚) | `sl-SI` | | 西班牙语(阿根廷) | `es-AR` | | 西班牙语(巴西) | `es-BR` | | 西班牙语(拉丁美洲) | `es-419` | | 西班牙语(墨西哥) | `es-MX` | | 西班牙语(西班牙) | `es-ES` | | 瑞典语(瑞典) | `sv-SE` | | 泰语(泰国) | `th-TH` | | 土耳其语(土耳其) | `tr-TR` | | 越南语(越南) | `vi-VN` | ## Connect 嵌入式组件中的用户身份验证 Connect 嵌入式组件通常不需要用户验证。在某些场景中,Connect 嵌入式组件要求关联账户在访问组件以提供必要功能之前使用其 Stripe 账户登录(例如,在[账户注册](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md)组件中向账户法律实体写入信息的情况)。其他组件可能在首次呈现后需要在组件内进行验证。 当要求变更时,若由 Stripe 负责收集更新后的信息,则关联账户需要进行验证。对于要求到期或变更时由您负责收集更新后的信息的关联账户(如 Custom 账户),Stripe 验证由 [disable_stripe_user_authentication](https://docs.stripe.com/api/account_sessions/create.md#create_account_session-components-account_onboarding-features-disable_stripe_user_authentication) 账户会话功能控制。我们建议将实施双重验证 (2FA) 或等效安全措施作为[最佳实践](https://docs.stripe.com/connect/risk-management/best-practices.md#prevent-account-take-overs)。对于支持此功能的账户配置(如 Custom 账户),如果关联账户无法偿还[负余额](https://docs.stripe.com/connect/risk-management/best-practices.md#decide-your-approach-to-negative-balance-liability),则由您承担责任。 ### 需要验证的组件 关联账户将在您的应用中看到经过验证的 [WebView](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession)。关联账户必须先进行验证,才能在 WebView 中继续其工作流程。 Stripe 托管的验证流程会显示您在 [Connect 设置](https://dashboard.stripe.com/account/applications/settings)中设置的品牌名称、颜色和图标,且在验证完成前不会使用来自[嵌入式组件管理器](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#configuring-connect)的定制外观和字体。 以下组件要求关联账户在特定场景下进行验证: - [账户入驻](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md) - [提现](https://docs.stripe.com/connect/supported-embedded-components/payouts.md) ## 处理加载错误 [客户端] 通过实现组件的 `onLoadError` 监听方法来响应组件加载失败。 由于组件加载失败的原因可能不同,`onLoadError` 方法可能会被多次调用,因此由 `onLoadError` 触发的任何逻辑都必须具备幂等性。 #### Swift ```swift // All components emit load errors. This example uses AccountOnboarding. // All components support didFailLoadWithError. class MyViewController: UIViewController, AccountOnboardingControllerDelegate { func openAccountOnboarding() { let accountOnboardingController = embeddedComponentManager.createAccountOnboardingController(); accountOnboardingController.delegate = self accountOnboardingController.present(from: self) } // MARK: - AccountOnboardingControllerDelegate func accountOnboarding(_ accountOnboarding: AccountOnboardingController, didFailLoadWithError error: Error) { print("Account onboarding failed to load with error '\(error)'") } } ``` ## 设置 StripeConnect [客户端] [服务器端] Stripe 使用 [AccountSession](https://docs.stripe.com/api/account_sessions.md) 来表达您将 API 访问权限授予 Connect 子账户的意图。 AccountSessions API 返回一个*客户端密钥* (The client secret is a unique string returned from Stripe as part of an AccountSession. This string lets the client access a specific Stripe account with Connect embedded components),允许嵌入式组件访问关联账户的资源,就像您在为它们进行 API 调用一样。 ### 创建 AccountSession (Server) 您的应用必须向服务器发起请求以获取账户会话。您可以在服务器上创建一个新端点,将客户端私钥返回给应用: #### Ruby ```ruby require 'sinatra' require 'stripe' # This is a placeholder - it should be replaced with your secret API key. # Sign in to see your own test API key embedded in code samples. # Don’t submit any personally identifiable information in requests made with this key. Stripe.api_key = '<>' post '/account_session' do content_type 'application/json' # Create an AccountSession begin account_session = Stripe::AccountSession.create({ account: {{CONNECTED_ACCOUNT_ID}}, components: { account_onboarding: { enabled: true, features: { # We recommend disabling authentication for a better user experience when possible disable_stripe_user_authentication: true, } } } }) { client_secret: account_session[:client_secret] }.to_json rescue => error puts "An error occurred when calling the Stripe API to create an account session: #{error.message}"; return [500, { error: error.message }.to_json] end end ``` ### 创建 Account Session API [创建账户会话 API](https://docs.stripe.com/api/account_sessions/create.md) 决定 Connect 嵌入组件的组件和功能访问权限。Stripe 会对与该账户会话对应的任何组件强制执行这些参数。如果您的应用支持多个用户角色,请确保该账户会话启用的组件和功能与当前用户的角色对应。例如,您可以仅为网站管理员启用[退款管理](https://docs.stripe.com/api/account_sessions/create.md#create_account_session-components-payments-features-refund_management)功能,而不允许其他用户访问。为了确保用户角色访问控制得到强制执行,您必须将网站的用户角色映射到账户会话组件上。 ### 安装 StripeConnect SDK (Client) [Stripe Android SDK](https://github.com/stripe/stripe-android) 是开源的,且[有完整的文档](https://stripe.dev/stripe-android/)。 安装 SDK 时,将 `connect` 添加到您的 [app/build.gradle](https://developer.android.com/studio/build/dependencies) 文件的 `dependencies` 块中: #### Kotlin ```kotlin plugins { id("com.android.application") } android { ... } dependencies { // ... // Connect Android SDK implementation("com.stripe:connect:23.1.0") } ``` > 有关最新 SDK 发布及过往版本的详细信息,请查看 GitHub 上的[发布](https://github.com/stripe/stripe-android/releases)页面。要想在新版本发布时接收通知,请[查看仓库的发布情况](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository)。 ### 初始化 EmbeddedComponentManager (Client) 使用您的公钥实例化 [EmbeddedComponentManager](https://stripe.dev/stripe-android/connect/com.stripe.android.connect/-embedded-component-manager/index.html),并通过调用您在服务器上创建的新端点来检索客户端私钥的 lambda。要处理配置更改,请将 `EmbeddedComponentManager` 实例保留在 Activity 或 Fragment `ViewModel` 中。 #### Kotlin ```kotlin class MyActivityViewModel : ViewModel() { val embeddedComponentManager: EmbeddedComponentManager = EmbeddedComponentManager( // This is a placeholder - it should be replaced with your publishable API key. // Sign in to see your own test API key embedded in code samples. // Don't submit any personally identifiable information in requests made with this key. publishableKey = "<>", fetchClientSecret = ::fetchClientSecret, ) private suspend fun fetchClientSecret(): String? = try { // Fetch the AccountSession client secret Fuel.post("https://{{YOUR_SERVER_BASE_URL}}/account_session") .awaitString() .let { JSONObject(it).getString("client_secret") } } catch (error: CancellationException) { throw error } catch (error: Exception) { // Handle errors on the client side here println("Error fetching client secret: ${error.message}") null } } ``` 要创建组件,首先在您的 Activity 的 `onCreate` 方法中调用 `EmbeddedComponentManager.onActivityCreate()`。然后,在您上面实例化的 `EmbeddedComponentManager` 上调用相应的创建方法。 [账户入驻](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md)会返回一个控制器,用于管理其自身的展示。其他组件(如 [Payments](https://docs.stripe.com/connect/supported-embedded-components/payments.md))会返回一个 [View](https://developer.android.com/reference/android/view/View),您可以更灵活地在应用程序中展示该组件。 #### 渲染控制器 #### Kotlin ```kotlin class MyActivity : FragmentActivity() { private val viewModel: MyActivityViewModel by viewModels() private lateinit var accountOnboardingController: AccountOnboardingController override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) EmbeddedComponentManager.onActivityCreate(this) setContentView(R.layout.my_activity) accountOnboardingController = viewModel.embeddedComponentManager.createAccountOnboardingController(this) } private fun openAccountOnboarding() { accountOnboardingController.show() } } ``` #### 渲染`视图` #### Kotlin ```kotlin class MyActivity : FragmentActivity() { private val viewModel: MyActivityViewModel by viewModels() private lateinit var paymentsView: View override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) EmbeddedComponentManager.onActivityCreate(this) setContentView(R.layout.my_activity) paymentsView = viewModel.embeddedComponentManager.createPaymentsView(this) // Add the view to your layout val container = findViewById(R.id.payments_container) container.addView(paymentsView) } } ``` ## Configure the Embedded Component Manager [客户端] [查看参考文档:external:](https://stripe.dev/stripe-android/connect/com.stripe.android.connect/-embedded-component-manager/index.html)。 ### 自定义 Connect 嵌入式组件的外观 [嵌入式组件 Figma UI 工具包](https://www.figma.com/community/file/1438614134095442934)包含每个组件、常见模式和一个示例应用程序。您可以使用它来可视化和设计网站中的嵌入式用户界面。 我们提供了[一组选项](https://docs.stripe.com/connect/embedded-appearance-options.md)来定制 Connect 嵌入式组件的外观。这些定制会影响我们设计系统中的按钮、图标和其他元素。 > #### 必要的弹出窗口 > > 嵌入式组件中的某些行为(例如[用户验证](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#user-authentication-in-connect-embedded-components))必须在经过验证的 WebView 中呈现。您无法定制嵌入式组件以消除此类 WebView。 初始化 `EmbeddedComponentManager` 时,可以使用 [Appearance](https://stripe.dev/stripe-android/connect/com.stripe.android.connect.appearance/-appearance/index.html) 设置这些选项。 #### Kotlin ```kotlin // Specify custom fonts val customFonts = listOf( CustomFontSource( // Font file located in `assets/` folder assetsFilePath = "fonts/myCustomFont.ttf", name = "myCustomFont", weight = 1000, ) ) // Customize appearance val appearance = Appearance.Builder() .typography( Typography.Builder() .fontFamily("myCustomFont") // Same name as the custom font above .fontSizeBase(16f) // Unscaled font size .build() ) .colors( Colors.Builder() .primary(Color.RED) .build() ) .build() val embeddedComponentManager = EmbeddedComponentManager( publishableKey = "<>", fetchClientSecret = ::fetchClientSecret, appearance = appearance, customFonts = customFonts, ) ``` 指定字体大小时,请使用针对设备的默认大小等级显示的未缩放字体大小。嵌入式组件会根据用户的[辅助功能字体设置](https://support.google.com/accessibility/android/answer/11183305?sjid=3094445894544346025-NA#fontsize)自动缩放字号。 查看 Android 上的[外观选项完整列表](https://docs.stripe.com/connect/embedded-appearance-options.md?platform=android)。 ### 使用自定义字体 如果您在应用程序中使用自定义字体(例如,从应用程序二进制文件中嵌入的 `.otf` 或 `.tff` 文件中),则必须在初始化 `EmbeddedComponentManager` 时指定传入 `customFonts` 参数的 [CustomFontSource](https://stripe.dev/stripe-android/connect/com.stripe.android.connect.appearance.fonts/-custom-font-source/index.html) 中的字体文件。这样 Connect 嵌入式组件便可以访问字体文件,从而正确呈现这些字体。 `appearance` 中指定的字体必须使用在初始化时传递给 `EmbeddedComponentManager` 的 [CustomFontSource](https://stripe.dev/stripe-android/connect/com.stripe.android.connect.appearance.fonts/-custom-font-source/index.html) 才能正确呈现。 [参见参考文档:external:](https://stripe.dev/stripe-android/connect/com.stripe.android.connect.appearance.fonts/-custom-font-source/index.html)。 ### 初始化后更新 Connect 嵌入式组件 调用 `update` 方法,更改初始化后嵌入式组件的外观: #### Kotlin ```kotlin val appearance = Appearance.Builder() .colors( Colors.Builder() .primary(ContextCompat.getColor(context, R.color.primary)) .build() ) .build() embeddedComponentManager.update(appearance = appearance) ``` ## 验证 我们提供了一组 API 来管理 Connect 嵌入式组件中的账户会话和用户凭证。 ### 刷新客户端私钥 在长时间运行的会话中,来自最初提供的*客户端私钥* (The client secret is a unique string returned from Stripe as part of an AccountSession. This string lets the client access a specific Stripe account with Connect embedded components)的会话可能会过期。当它过期时,我们会自动用 `fetchClientSecret` 检索新的客户端私钥并刷新会话。您不需要传入任何额外参数。 #### Kotlin ```kotlin val embeddedComponentManager: EmbeddedComponentManager = EmbeddedComponentManager( publishableKey = "<>", fetchClientSecret = ::fetchClientSecret, ) private suspend fun fetchClientSecret(): String? = try { Fuel.post("https://{{YOUR_SERVER_BASE_URL}}/account_session") .awaitString() .let { JSONObject(it).getString("client_secret") } } catch (error: CancellationException) { throw error } catch (error: Exception) { null } ``` ## 本地化 Connect 嵌入式组件支持以下地区: | 语言 | 区域代码 | | -------------- | ------------ | | 保加利亚语(保加利亚) | `bg-BG` | | 中文(简体) | `zh-Hans` | | 中文(繁体 - 香港) | `zh-Hant-HK` | | 中文(繁体 - 台湾) | `zh-Hant-TW` | | 克罗地亚语(克罗地亚) | `hr-HR` | | 捷克语(捷克) | `cs-CZ` | | 丹麦语(丹麦) | `da-DK` | | 荷兰语(荷兰) | `nl-NL` | | 英语(澳大利亚) | `en-AU` | | 英语(印度) | `en-IN` | | 英语(爱尔兰) | `en-IE` | | 英语(新西兰) | `en-NZ` | | 英语(新加坡) | `en-SG` | | 英语(英国) | `en-GB` | | 英语(美国) | `en-US` | | 爱沙尼亚语(爱沙尼亚) | `et-EE` | | 菲律宾语(菲律宾) | `fil-PH` | | 芬兰语(芬兰) | `fi-FI` | | 法语(加拿大) | `fr-CA` | | 法语(法国) | `fr-FR` | | 德语(德国) | `de-DE` | | 希腊语(希腊) | `el-GR` | | 匈牙利语(匈牙利) | `hu-HU` | | 印度尼西亚语(印度尼西亚) | `id-ID` | | 意大利语(意大利) | `it-IT` | | 日语(日本) | `ja-JP` | | 朝鲜语(韩国) | `ko-KR` | | 拉脱维亚语(拉脱维亚) | `lv-LV` | | 立陶宛语(立陶宛) | `lt-LT` | | 马来语(马来西亚) | `ms-MY` | | 马耳他语(马耳他) | `mt-MT` | | 挪威语(波克默尔语)(挪威) | `nb-NO` | | 波兰语(波兰) | `pl-PL` | | 葡萄牙语(巴西) | `pt-BR` | | 葡萄牙语(葡萄牙) | `pt-PT` | | 罗马尼亚语(罗马尼亚) | `ro-RO` | | 斯洛伐克语(斯洛伐克) | `sk-SK` | | 斯洛文尼亚语(斯洛文尼亚) | `sl-SI` | | 西班牙语(阿根廷) | `es-AR` | | 西班牙语(巴西) | `es-BR` | | 西班牙语(拉丁美洲) | `es-419` | | 西班牙语(墨西哥) | `es-MX` | | 西班牙语(西班牙) | `es-ES` | | 瑞典语(瑞典) | `sv-SE` | | 泰语(泰国) | `th-TH` | | 土耳其语(土耳其) | `tr-TR` | | 越南语(越南) | `vi-VN` | ## Connect 嵌入式组件中的用户身份验证 Connect 嵌入式组件通常不需要用户验证。在某些场景中,Connect 嵌入式组件要求关联账户在访问组件以提供必要功能之前使用其 Stripe 账户登录(例如,在[账户注册](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md)组件中向账户法律实体写入信息的情况)。其他组件可能在首次呈现后需要在组件内进行验证。 当要求变更时,若由 Stripe 负责收集更新后的信息,则关联账户需要进行验证。对于要求到期或变更时由您负责收集更新后的信息的关联账户(如 Custom 账户),Stripe 验证由 [disable_stripe_user_authentication](https://docs.stripe.com/api/account_sessions/create.md#create_account_session-components-account_onboarding-features-disable_stripe_user_authentication) 账户会话功能控制。我们建议将实施双重验证 (2FA) 或等效安全措施作为[最佳实践](https://docs.stripe.com/connect/risk-management/best-practices.md#prevent-account-take-overs)。对于支持此功能的账户配置(如 Custom 账户),如果关联账户无法偿还[负余额](https://docs.stripe.com/connect/risk-management/best-practices.md#decide-your-approach-to-negative-balance-liability),则由您承担责任。 ### 需要验证的组件 关联账户将在您的应用中看到经过验证的 [WebView](https://developer.chrome.com/docs/android/custom-tabs)。关联账户必须先进行验证,才能在 WebView 中继续其工作流程。 Stripe 托管的验证流程会显示您在 [Connect 设置](https://dashboard.stripe.com/account/applications/settings)中设置的品牌名称、颜色和图标,且在验证完成前不会使用来自[嵌入式组件管理器](https://docs.stripe.com/connect/get-started-connect-embedded-components.md#configuring-connect)的定制外观和字体。 > #### Android 限制 > > 由于 Android API 的限制,嵌入式组件无法在已验证的 WebView 中使用定制字体,即使验证完成后也是如此。 以下组件要求关联账户在特定场景下进行验证: - [账户入驻](https://docs.stripe.com/connect/supported-embedded-components/account-onboarding.md) - [提现](https://docs.stripe.com/connect/supported-embedded-components/payouts.md) ## 处理加载错误 [客户端] 通过实现组件的 `onLoadError` 监听方法来响应组件加载失败。 由于组件加载失败的原因可能不同,`onLoadError` 方法可能会被多次调用,因此由 `onLoadError` 触发的任何逻辑都必须具备幂等性。 #### Kotlin ```kotlin // All components emit load errors. This example uses AccountOnboarding. // All components support onLoadError. class MyActivity : FragmentActivity() { private lateinit var accountOnboardingController: AccountOnboardingController override fun onCreate(savedInstanceState: Bundle?) { accountOnboardingController = embeddedComponentManager.createAccountOnboardingController(this) accountOnboardingController.listener = MyAccountOnboardingListener() } private fun openAccountOnboarding() { accountOnboardingController.show() } private inner class MyAccountOnboardingListener : AccountOnboardingListener { override fun onLoadError(error: Throwable) { println("Error loading account onboarding: ${error.message}") } } } ``` ## 设置 StripeConnect [客户端] [服务器端] Stripe 使用 [AccountSession](https://docs.stripe.com/api/account_sessions.md) 来表达您将 API 访问权限授予 Connect 子账户的意图。 AccountSessions API 返回一个*客户端密钥* (The client secret is a unique string returned from Stripe as part of an AccountSession. This string lets the client access a specific Stripe account with Connect embedded components),允许嵌入式组件访问关联账户的资源,就像您在为它们进行 API 调用一样。 ### 创建 AccountSession (Server) 您的应用必须向服务器发起请求以获取账户会话。您可以在服务器上创建一个新端点,将客户端私钥返回给应用: #### Ruby ```ruby require 'sinatra' require 'stripe' # This is a placeholder - it should be replaced with your secret API key. # Sign in to see your own test API key embedded in code samples. # Don’t submit any personally identifiable information in requests made with this key. Stripe.api_key = '<>' post '/account_session' do content_type 'application/json' # Create an AccountSession begin account_session = Stripe::AccountSession.create({ account: {{CONNECTED_ACCOUNT_ID}}, components: { account_onboarding: { enabled: true, features: { # We recommend disabling authentication for a better user experience when possible disable_stripe_user_authentication: true, } } } }) { client_secret: account_session[:client_secret] }.to_json rescue => error puts "An error occurred when calling the Stripe API to create an account session: #{error.message}"; return [500, { error: error.message }.to_json] end end ``` ### 创建 Account Session API [创建账户会话 API](https://docs.stripe.com/api/account_sessions/create.md) 决定 Connect 嵌入组件的组件和功能访问权限。Stripe 会对与该账户会话对应的任何组件强制执行这些参数。如果您的应用支持多个用户角色,请确保该账户会话启用的组件和功能与当前用户的角色对应。例如,您可以仅为网站管理员启用[退款管理](https://docs.stripe.com/api/account_sessions/create.md#create_account_session-components-payments-features-refund_management)功能,而不允许其他用户访问。为了确保用户角色访问控制得到强制执行,您必须将网站的用户角色映射到账户会话组件上。 ### 安装 Stripe React Native SDK (Client) 使用 npm 或 yarn 安装 Stripe React Native SDK: ```bash npm install @stripe/stripe-react-native react-native-webview # or yarn add @stripe/stripe-react-native react-native-webview ``` ### 初始化 StripeConnectProvider (Client) 使用 `ConnectComponentsProvider` 包裹您的应用,并提供您的可发布密钥,以及一个通过调用您在服务器上创建的新端点来获取客户端私钥的函数。 ```javascript import { useState } from 'react'; import { ConnectComponentsProvider } from '@stripe/stripe-react-native'; const fetchClientSecret = async (): Promise => { const response = await fetch('https://{{YOUR_SERVER}}/account_session', { method: 'POST', }); const { client_secret: clientSecret } = await response.json(); return clientSecret; }; export default function App() { const [stripeConnectInstance] = useState(() => { return loadConnectAndInitialize({ // This is a placeholder - it should be replaced with your publishable API key. // Sign in to see your own test API key embedded in code samples. // Don't submit any personally identifiable information in requests made with this key. publishableKey: "<>", fetchClientSecret: fetchClientSecret, }) }); return ( ); } ``` 要使用嵌入式组件,请先导入它,并在 `ConnectComponentsProvider` 内部渲染: ```javascript import { ConnectAccountOnboarding } from '@stripe/stripe-react-native'; import { useState } from 'react'; import { View } from 'react-native'; import Button from '../components/Button'; export default function AccountOnboardingScreen() { const [visible, setVisible] = useState(false); return (