Skip to main content
Ayrshare Connect 小组件把我们的关联按钮放进你自己的控制台。你加载一个脚本,在布局中每个网络 所属的位置放一个插槽(slot),我们就会在那里渲染一个按钮,并且它已经显示该账号是否已关联。你的 用户点击它,无需离开你的页面即可关联账号——最多出现一个弹窗,也就是社交网络自己的弹窗。 你不需要编写任何弹窗处理、OAuth 回调、会话刷新或按网络区分的逻辑。当某个网络在它那一侧做出变更 时,修复会在我们部署的那一刻通过我们的框架发布;你无需重新部署任何东西。

你需要哪种界面

一个客户控制台,卡片中嵌入了 Instagram、TikTok 和 LinkedIn 的 Ayrshare Connect 卡片

嵌入式框架:我们的卡片渲染在你自己的布局内,每个网络一个插槽,或一个插槽容纳多个网络。

一个带有自有 Connect 按钮的客户控制台,以及显示 Facebook 交接屏幕的 Ayrshare 弹窗

你自己的按钮:按钮由你渲染,我们的一个短暂弹窗处理社交网络。

显示所有可用网络的托管社交关联页面

托管关联页面:我们托管的页面,带有你的 logo 和颜色,你的用户要离开你的应用去使用它。

两个小组件行是同一个集成,而不是两个。一次 init 同时给你两者:在需要我们按钮的地方挂载 框架,在其他任何地方从你自己的按钮调用 popup()。它们共享同一个会话,并在同一组处理器上报告 结果。直连模式(Direct Mode)是不带我们脚本的同一个弹窗—— 适用于带有严格 Content-Security-Policy 的页面、服务器端渲染的页面或原生应用。在那里由你自己 打开并监视弹窗。

添加脚本

固定(pin)一个版本及其哈希,或不带哈希地跟随一个渠道。两者绝不要同时使用——在会变动的 URL 上 添加 integrity 属性会在我们下一次发布时失效,因为它指向的文件已经合理地发生了变化。
Pinned version
Tracking v1
v1 是值得推荐的渠道。 它会获得修复,但绝不会跨越破坏性变更。latest 从定义上就会跨越 主版本,因此它终究会把一个你尚未审阅过其行为的版本交给你的页面。 每个版本的哈希都发布在 manifest.json 中,其中还标明了 每个渠道当前提供的版本:
manifest.json
每个 bundle 的开头还有一条注明自身版本的注释,这是告诉我们某个页面实际运行的版本的最快方式:

Content-Security-Policy

如果你的页面发送 Content-Security-Policy,它需要两条条目,都指向你加载脚本的主机:
这就是全部清单。你不需要为我们添加 connect-src 条目——我们的框架从其内部访问我们的 API, 而不是从你的页面——也不需要为弹窗添加条目,弹窗是顶层窗口,不受你的策略约束。这两条条目都 经过实际验证:移除 script-src 会阻止脚本,移除 frame-src 会阻止框架。

启动一个实例

session 是唯一必需的选项。它每个实例调用一次,而不是每次 mount 调用一次,并且必须把你的 后端对带 mode: "connect" 的创建 Link Session 调用的响应 ——{ sessionId, token, expiresAt }——原样返回。
Your page
Your backend
小组件会话不指定 network——它授权你的账户允许的所有网络,具体显示哪些由每次 mount 在你的 页面中决定。它确实携带一个 origin,而这正是让框架得以渲染的唯一条件:框架会将嵌入它的页面与 该值进行比对,在其他任何地方都拒绝渲染。
请在你的服务器上创建会话。该调用需要你的 API Key,而它返回的 token 会让你的用户登录其 User Profile——请像对待密码一样对待它。
我们会在 token 过期之前再次调用 session,因此在一个整天开着的页面上小组件也能持续工作。如果 调用被拒绝或未返回 token,会再重试两次——分别在 0.5 秒和 1 秒之后——然后我们放弃并发出 error。因此一次刷新最多花费三次对你端点的调用。

挂载插槽

每个插槽一次 mount。可以请求一个网络、多个网络,或会话允许的所有网络——粒度由你决定,因此 一个插槽可以是现有表格中的一行,也可以是容纳所有内容的一个面板。
mount 接受 CSS 选择器或元素,并返回 { unmount, element }。如果目标没有匹配到任何内容,它会 抛出异常——这几乎总是因为插槽还不存在,所以请在你的标记进入文档之后再 mount。 每次 mount 都是一个 iframe。它会向我们报告自身高度,我们据此调整其大小,因此你的布局会随我们 内容的变化而重排;超过 maxHeight 时,框架改为内部滚动,而不会溢出你的页面。我们支持的最窄 插槽是 300px。 网络键名使用 Ayrshare 自己的名称,别名拼写同样有效:instagram 和 instagramapi 都表示 instagramApi,x 表示 twitter。不是网络的键不会渲染任何卡片。

你自己的按钮

宁愿使用自己的按钮而不是我们框架的客户可以改为调用 popup。它运行同样的流程、使用同一个会话, 并在同一组处理器上报告结果。
请直接在点击处理器内调用它,之前不要 await 任何东西。 浏览器只在仍在处理用户点击时才允许 弹窗,而这个许可撑不过一次 await。反正也没有什么需要 await 的——会话在 init 时就已创建。
popup 返回 { close(), network },并且总是返回一个句柄——包括弹窗被拦截之后(此时 close() 什么也不做)——因此你的代码在调用 close() 之前永远不必做空值检查。 所有网络在这里都可用,包括那些在框架自身面板内完成的网络:Facebook 在弹窗中显示其交接说明, Bluesky 和 X 显示它们的凭据表单,而 LinkedIn、Pinterest、YouTube 和 Google Business 会跳转到 网络并返回。 对三种属于编程错误的情况它会同步抛出异常——没有 network、实例已被销毁、或会话尚未解析完成。 弹窗被拦截不是其中之一:那会发出带 reason: "popupBlocked" 的 error,因为你的用户没有 做错任何事。 同一时间最多只有一个弹窗打开。第二次调用会关闭第一个弹窗,并在其上报告带 reason: "superseded" 的 cancelled。我们的框架打开的弹窗是另一回事,绝不会被触及,因此你的按钮无法取消在挂载的 插槽内运行的流程。
会话是否可以关联某个网络由服务器决定,而不是脚本。一个仅限 Bluesky 的会话被要求关联 LinkedIn 时,会在弹窗中渲染拒绝信息并报告为 error。脚本只检查是否指定了网络。

React

脚本不依赖任何框架,因此 React 不需要我们做任何特殊处理——但它的生命周期有四件事值得第一次就 做对。 只加载一次脚本,且在你的组件树之外。在 Next.js 中是根布局里的 next/script;在 Vite 或 Create React App 中是 index.html 里的一个标签。按组件加载会在每次挂载时重新运行它。
ConnectAccounts.jsx
绝不要在 destroy() 之后重用实例。 被销毁的实例会一直保持销毁状态——在其上调用 popup() 会抛出异常,mount() 也无法让它复活。请在下一次 effect 运行中创建新实例,上面的代码正是这样 做的。
这种模式有两个后果,都不是 bug:
  • 在开发环境中你会看到 session 回调触发两次。 React 的 Strict Mode 以 mount → unmount → mount 的顺序运行 effect,因此实例会被创建、销毁、再创建。上面的清理让这一切是安全的;它在 开发环境多花一次对你后端的调用,在生产环境一次也不多。
  • 保持 effect 依赖稳定。 从父级渲染直接传入 mount 的数组字面量每次都是新值,因此依赖它的 effect 会在每次渲染时拆掉并重建小组件。请对它做 memoize,或像上面那样保持常量。

事件

用 on 订阅,它返回一个取消订阅函数。处理器会收到事件负载以及事件来源的 mount;当你更愿意用 具名处理器时,off(name, handler) 完成同样的工作。
十个事件。除 ready 之外每个都携带 network,另有一种与网络完全无关的 error 也不携带—— 参见下方 error 有两个来源。 其中四个是结局——success、unlinked、error 和 cancelled——每次尝试恰好到达一个。 closed 是跟在结局之后的生命周期通知,本身不是结局。 click 在任何关联工作开始之前触发,因此它也会报告那些随后被拦截的弹窗或失效会话拒绝的 点击。它是用于你自己的分析统计的事件;started 才意味着一次尝试真正在运行。

Reason 取值

error 有两个来源

其中只有一个是关联失败,且两者携带的字段不同。
  • 关联错误携带 network、code 以及它来源的 mount。
  • 会话错误——我们无法创建或刷新你的会话——只携带 message,因为当时没有任何东西在被关联。
请防御性地解构:在第二种情况下 code 和 network 为 undefined。

state 让你免于轮询

state 是数据通道,而不是对某次尝试的报告。每个框架在挂载时会为每个网络发出一个 state,携带 该网络的当前状态以及它保持该状态起始的 since 时间戳;每当状态变化时再发出一个——包括源自 我们这一侧的变化,例如 token 失效进入需要重新关联的状态。因此你可以完全由小组件驱动你的 UI, 而无需轮询任何东西。 取值与 GET /profiles 带 include=state 返回的枚举相同: linked、unlinked、identityVerificationRequired、restricted、rateLimited、suspended。

解除关联

我们的卡片既能关联也能解除关联。你的用户点击一个已连接的网络并确认,账号即被移除:
  1. click 触发,带 action: "unlink"。
  2. 移除保存后,unlinked 触发。
失败的解除关联会报告 error,用户在确认步骤退出的会报告 cancelled。没有单独的 “解除关联失败”事件。

外观

客户的样式表无法进入跨源框架,因此样式以数据的形式传输,由我们在框架内应用。将 appearance 作为 CSS 自定义属性传给 init;我们没有收到的每一项都保持默认值。
成对设置颜色。 只设置背景 token 而不设置旁边的前景 token,是让它产生不可读结果的唯一方式: 单独把 --ayr-connect-surface-bg 设为深色,而我们默认的 --ayr-connect-surface-fg 仍是深 海军蓝。没有任何机制能替你推断出另一半。
完全不传 appearance 时,每个 token 都保持默认值,框架看起来是这样:
三个使用默认外观的 Ayrshare Connect 卡片

默认 token:白色表面、深海军蓝文字、靛蓝强调色、8px 圆角。

传入几个 token,同样的框架就会呈现你的配色。下面的示例把表面变为淡蓝色,将文字和强调色加深以 匹配,并把圆角略微加大:
三个 Ayrshare Connect 卡片,重新设计为淡蓝色表面和更深的蓝色强调色

应用上述 token 之后的同样三个卡片。

只有一套配色,没有明暗预设。 没有任何逻辑依赖 prefers-color-scheme,这是有意的——你页面 的主题未必与用户的操作系统一致,而媒体查询会悄悄推翻你选择的颜色。深色控制台通过提供深色取值来 设置主题。 这份 token 列表是我们跨版本保持的受支持契约。

Token 列表

对其 token 而言不是合法 CSS 的值会被忽略,并在你的控制台输出一条警告,而不会被应用。这比 听起来更重要:给 --ayr-connect-spacing 传一个不带单位的 8 是个完全无辜的字符串,但它会使 读取它的所有计算失效并让布局塌陷,而且任何地方都不会报错。请给长度带上单位。

在交接屏幕上显示你自己的名称

在把用户交给社交网络之前,我们会显示一个简短的屏幕,标明他们正通过谁进行连接。两个钩子让你把它 变成自己的,而且两者都跨版本稳定。 --ayr-connect-partner-name 设置标签。它是唯一取值为文本的 token,因此必须作为 CSS 字符串 加引号——不带引号的值是非法的,什么也不会渲染:
logo 不是 token。我们把标志(mark)作为已定位、已设定尺寸的元素提供,你通过 css 用 background-image 来填充它,如上所示——我们不接受能从我们文档内部获取图片的 token,因此该请求 来自你编写的规则,而不是你传给我们的值。
[data-ayr-connect-partner-mark] 和 [data-ayr-connect-partner-name] 是下方自定义 CSS 注意事项的例外:这两个选择器是契约的一部分,我们会跨版本保留它们。

自定义 CSS

css 接受一个应用于每个框架内部的字符串,用于 token 覆盖不到的情况。
自定义 CSS 不跨版本受支持。 它的选择器针对我们的内部标记,而内部标记会在版本之间变化—— 今天有效的规则可能在任何一次更新后悄悄失效。上面的 token 契约才是我们保留的部分。如果你依赖 自定义 CSS,请固定一个版本。
弹窗会和框架一样继承实例的 appearance 和 css,因此你的用户不会在流程进行到一半时看到我们的 中性默认样式。

发布前值得了解的事

用 popup() 打开的弹窗无法被告知 token 被拒绝的原因——要说明原因,它就必须信任一个尚未 验证的来源,而我们的安全模型不允许这样做。因此携带失效 token 的弹窗会关闭,并以带 reason: "popupClosed" 的 cancelled 而非 error 呈现。实践中这种情况很少见:在静默刷新之前打开的弹窗会继续工作,因为它在打开时验证了自己的 token。如果你看到无法解释的 popupClosed 结果,请检查你的 session 端点是否返回了新鲜的 会话。
十四个 mount 共享一个 token,只花费一次对你后端的调用,而不是十四次。如果你想要不同作用域的 插槽——其中一些使用不同的 allowedSocial——请运行第二个带有自己会话的 init,而不要指望 某个 mount 去收窄它。
每个会话都携带你页面运行所在的 origin,框架在渲染任何内容之前会将嵌入它的页面与该值比对。 嵌入在其他地方的框架保持空白且不发送任何事件。没有需要注册的允许列表,也没有需要配置的东西 ——在创建会话时发送正确的 origin 即可。
框架向脚本报告自身高度,脚本据此调整框架大小。你的布局只管重排即可。没有可订阅的 resize 事件,你这一侧也没有任何需要测量的东西。

要求

  • Max Pack。小组件会话是 connect 模式的会话,没有 Max Pack 创建会 返回 code: 504。如果你需要在没有 Max Pack 的账户上启用 connect 模式,请联系支持团队。
  • 每个会话都要有 origin——你页面运行所在的确切 origin。省略它返回 code: 505;不是 https origin、自定义 scheme 或 http://localhost 的值返回 code: 506。
  • 会话上不要有 network。该参数会让会话变成直连模式, 而直连模式会话的 URL 不是脚本所期望的。
上述每个错误码都收录在 Link Session 错误参考中, 包含 API 返回的确切消息以及应对方法。