mcpField
M
mobile-design

mobile-design

github.com/superwall设计与 UI3010 次安装今天更新
代码仓库

关于 mobile-design

这是一份实用指南,帮助开发者按设计参考和原生平台惯例构建移动网页界面,适用于付费墙和引导页面。内容涵盖布局、触控、表单和动效,并涉及 iOS、Android 与网页环境。

主要功能

  1. 01按设计参考还原布局
  2. 02构建原生风格移动页面
  3. 03应用平台特定交互模式
  4. 04处理触控目标与反馈
  5. 05设计表单和键盘行为
  6. 06按交互目的选择动效

适用场景

  1. 01在手机应用内构建网页付费墙
  2. 02实现移动端引导页面
  3. 03检查触控和键盘行为
  4. 04交付前核对页面还原度

MCP 相关

这是一个 skill,并非 MCP 服务或客户端;输入未说明其具备 MCP 功能。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/superwall/skills --skill mobile-design

安装后在 Claude Code 中输入/mobile-design确认已加载。

附带文件references/responsive.md

详细介绍

移动端设计

手机应用中的网页屏幕,要与周围的原生屏幕比较,而不是与其他网页比较。决定它是否合格的有两点:精确还原设计,以及遵循用户能感受到却说不出来的平台惯例。这些是实践经验,不是硬性规定——设计参考始终优先于这里的任何规则——但每一条都源于某个已发布屏幕曾经出现的问题。

每个屏幕都要完整阅读本文。每次交付前,都要浏览文末的检查清单。

设计参考就是规范

  • 1:1 还原。 间距、尺寸、字重、颜色和效果都以设计参考为准,而不是凭习惯决定。请在逻辑尺寸下测量设计参考(即设备宽度下的截图),不要凭目测;完成前,将实现效果与参考并排比较。
  • 不要添加设计中没有的内容。 不要增加额外链接、徽章、脚注或操作入口,无论初衷多好。如果觉得缺少某些内容(例如恢复购买入口或法律链接),请提出讨论——绝不要擅自将其添加到 UI 中。
  • 效果是设计决策,不是默认设置。 阴影、渐变、边框、模糊和圆角都应符合正在构建的付费墙所用的设计系统。参考是扁平风格,就做成扁平风格;参考柔和且有层次,就照样还原。只有参考中展示了某种效果时,才使用它。
  • 以某个尺寸绘制的参考适用于所有尺寸。 Figma 画板可能是 393×852 左右;付费墙还要适配宽度为 320 的手机、高度为 667 的手机、平板,有时还要适配横屏。参考没有说明的地方,按响应式规则处理;参考明确说明的地方,遵循说明,并围绕它调整其余内容。
  • 没有参考,不代表可以随意发挥。 如果提示词只有文字(“为我的冥想应用做一个付费墙”),那么本文中的规范就是设计:使用系统字体,并根据尺寸调整字距;设置一个实色 CTA;每个控件都要有按压反馈;遵循 Motion 中规定的曲线和时长。每项设计决策都要一次定好并说明;绝不要用用户未要求的装饰来填补空白(例如渐变、光晕或弹跳徽章)。

每个屏幕共有的骨架

原生屏幕有固定的结构。在应用任何颜色之前,遵循这一结构就能让屏幕看起来像原生界面:顶部状态栏的安全区域内边距(属于宿主,而非你);紧贴其下的小型界面元素(关闭或返回);可滚动的内容在渐隐效果下滑动;一个固定在 home indicator 上方的主要操作按钮;以及其下方颜色较浅的小型链接。页面会滚动,CTA 不会——CTA 随文案一起滚走,是网页屏幕表现不如原生屏幕最常见的原因。固定意味着将 position: sticky; bottom: 0 作为页面的最后一个子元素,并使用从透明到页面背景色的渐变,让内容在其后方逐渐淡出。

安全区域由宿主负责。在 Superwall 界面中,框架会根据设备安全区域为整个屏幕添加内边距,你只需设置常规内边距(不要使用 env(),也不要使用 position: fixed)。在普通 WebView 中,viewport-fit=cover 和应用于界面元素的 env(safe-area-inset-*) 能达到相同效果。无论哪种情况,界面元素的位置都应是安全区域内边距加上间距,而不是只放在安全区域边缘:安全区域内边距是最低限度,真实手机的状态栏往往更高。

平台惯例

确认屏幕所在的平台(Superwall 界面可读取 <html> 上的 data-sw-platform;普通 WebView 则由应用告知一次,或在启动时读取 user agent)。针对各个平台分别设计;不要只针对 iOS 设计,再让 Android 直接沿用。

iOS
  • 关闭是位于右上角的小型圆形按钮(视觉尺寸约为 30–32px,点击区域为 44px);如果设计如此,则放在左上角;工作表(presentation: modal)带有系统拖动条,通常没有关闭按钮。
  • 返回以左上角的箭头形式放在布局中,并弹出当前堆栈;没有硬件返回键。
  • 按钮采用圆角(12–16px)或完整胶囊形,宽度占满,高 50–56px;文字为 17px 半粗体。主要 CTA 是屏幕上唯一的实心按钮。
  • 系统字体(-apple-system, BlinkMacSystemFont, "SF Pro Text")搭配较大字号下紧凑的负字距,呈现出原生观感。
  • 分段控件、开关和单选行应与对应的 UIKit 控件外观一致;如果设计展示了自定义样式,则按设计实现。
  • 恢复、条款和隐私链接放在 CTA 下方,使用小号、低调的文字(13px),不要做成按钮。
Android
  • 按照 Material 风格,关闭按钮为左上角的 × 或 ←,也可以放在设计指定的位置;硬件返回键/手势返回会通过 SDK 关闭付费墙,因此绝不要依赖自定义返回控件作为唯一的退出方式。
  • 全屏付费墙上的状态栏绘制在付费墙上方(由框架的顶部内边距处理);导航栏则不然——SDK 会让 WebView 保持在导航栏上方,因此底部内边距为 0,固定的 CTA 需要自行设置底部填充(12–16px),而不能依靠内边距留出间距。
  • 按钮采用完整圆角(Material 3 胶囊形)或 12px 圆角,高 48–56px;标签为 16px 中等字重;使用系统字体栈中的 Roboto(system-ui, Roboto, sans-serif)。
  • 涟漪是原生的按压反馈;缩小的按压状态可作为 Web 端替代方案,且幅度应比 iOS 更轻微(0.98)。
  • 文案有所不同:"Restore purchases" 两个平台都适用,但 "Cancel anytime in Settings" 是 iOS 专用表述;如果付费墙同时用于两个平台,应写成 "in Google Play" 或使用不特定于商店的措辞。
Web(Web 转化漏斗或仅限 Web 的付费墙)
  • 没有状态栏、主屏幕指示条或 SDK 界面:所有内边距均为 0,浏览器会在视口周围绘制自己的栏。框架的包装容器使用 100dvh 设置尺寸,因此固定的 CTA 会位于 Safari 工具栏上方,并随着工具栏收起而调整;绝不要使用 100vh 设置任何自有元素的尺寸。
  • 键盘焦点在此处确实存在。输入框和按钮要保留 :focus-visible 样式;这是唯一不应抑制焦点样式的平台。
  • Web 端存在鼠标:可以使用悬停状态;桌面布局应将手机宽度的列(max-width: 28–34rem)居中,而不是让卡片横跨 1440px。
  • 链接仍可通过 openUrl 打开;在 Web 端它只是普通导航。保留这一次调用,以便同一页面也能原生运行。

触控

  • 点击目标在 iOS 上至少为 44×44pt,在 Android 上至少为 48×48dp。若设计要求如此,视觉上较矮的控件(例如纤细的分段控件)可以牺牲高度;但必须通过宽度和间距补偿,也可以用内边距或伪元素扩展点击区域。
  • 每次有意义的点击都要触发触觉反馈,通过宿主的桥接实现(在 Superwall 表面中使用 useHaptics();在其他地方调用原生方法;纯网页上则不触发):导航和 CTA 使用 light,在选项间选择时使用 selection,在 transaction_complete 时使用 success,失败时谨慎使用 error。iOS 在 WebView 内不会自行触发触觉反馈。将触觉反馈和对应的视觉变化放在同一个处理器中触发,使二者出现在同一帧;如果触觉反馈晚于动画,就会显得毫不相关。
  • 在原生付费墙中,隐藏由点击触发的控件的焦点环——:focus-visible 的判断逻辑在 WebView 和预览中容易误判,绘制出设计中并不存在的轮廓。仅在键盘可用的场景(网页)保留键盘焦点样式。
  • 对控件使用:-webkit-tap-highlight-color: transparent、touch-action: manipulation、user-select: none;对页面使用 -webkit-user-select: none,但用户可能想要选中的内容(例如法律文本)除外。为控件和装饰性图片添加 -webkit-touch-callout: none,否则长按主视觉图片会在 iOS 的付费墙上方弹出保存图片菜单。
  • **按下时就提供反馈,而不是等到松开时。**为样式设置 :active;如果控件需要 JavaScript,则响应 pointerdown,而不是 click。按钮只有在手指抬起后才发生变化,即使没有任何延迟,也会让人觉得卡顿。
  • 每条 :hover 规则都必须置于 @media (hover: hover) and (pointer: fine) **之下。**WebView 会在首次点击时模拟悬停状态,并一直保持到下次点击;因此,未加条件限制的悬停样式会让方案卡片在选中后仍保持高亮。Tailwind v4 的 hover: 已会编译为此查询;v3 需要设置 future.hoverOnlyWhenSupported。应根据设备能力进行限制,绝不要根据平台属性或宽度判断:带触控板的 iPad 也支持悬停。
  • 不要通过禁用控件来显示“正在加载”;商店界面就是反馈(usePurchase().isPurchasing 可用于确实需要这种反馈的少数情况——购买按钮不属于这种情况)。
  • 整个选项行都应是点击目标,而不只是单选按钮;整个页脚链接都应是点击目标,而不只是其中的文字。
  • **水平轮播只处理一个轴向。**优先使用原生滚动:在轨道上设置 overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain,在幻灯片上设置 scroll-snap-align: start;平台自带的滚动效果胜过手动实现的弹簧效果。由 JS 驱动的滑动应设置 touch-action: pan-y,以便页面保留纵向滚动。绝不要在用户需要滚动经过的元素上设置 touch-action: none。

表单与键盘

引导流程会提问,网页转化漏斗会收集电子邮件,因此输入框很常见,也是 WebView 最容易露馅的地方。

  • 输入框字体至少为 16px。 iOS 在焦点落到文字较小的输入框时会缩放整个页面,失焦后也不会缩放回来,导致用户看到被裁切、偏移的付费墙。解决方法是调整字体大小,绝不要设置 maximum-scale=1 或 user-scalable=no,因为这会妨碍有需要的用户缩放页面。
  • 选择合适的键盘。 电子邮件使用 type="email",电话号码使用 type="tel",验证码使用 inputmode="numeric",金额使用 inputmode="decimal";设置 autocomplete(email、given-name、one-time-code),让系统提供已知信息;电子邮件和验证码使用 autocapitalize="none" 和 autocorrect="off";设置 enterkeyhint="next" / "done" / "go",让回车键标明其功能。
  • 键盘会遮住屏幕底部。 最常见的问题是固定在焦点字段下方的 CTA:在小屏手机上打开键盘检查页面,并确保字段及其对应操作都能触及(responsive.md)。
  • 在用户输入时或失焦时进行行内验证,绝不要只在提交时验证,并在提示信息中说明如何修正(从消息目录获取,绝不要使用字面值)。

动效

任何元素动起来之前,都必须明确其目的:反馈(界面响应了点击)、空间(元素从何处来或去往何处)、状态(选择发生了变化)或衔接(内容不会凭空跳转)。对于用户在一个流程中会点击十次的控件,“看起来不错”并不是目的。如果说不出目的,就不要添加动画。

  • 只为功能性移动添加动画——也就是在不同状态间实际移动的元素:分段控件的滑块、弹出的面板、填充中的进度条、展开的手风琴。仅发生变化的内容(文本、列表行、价格)应在原位更新;除非设计明确要求,否则不要淡入淡出、滑动或错开出现。
  • 按压反馈是基础交互:可点击元素应有缩小的 :active 状态(iOS 约为 0.96,Android 约为 0.98;约 80ms 快速缩小,约 200ms 回弹),并配合触觉反馈。大多数控件只需这些。scale() 会连同标签和图标一起缩放,因此能呈现出真实的按压感。
  • 入场动效是发挥愉悦感预算的地方。 付费墙或引导页面每天只会被看到一次,而不是一百次,因此这里是适度编排动效最值得的地方。有参考时就照着做。没有参考时,默认采用克制的效果:标题和主视觉上移 8–12px 并淡入,列表行每隔 40–60ms 依次出现一次,而且动画播放时不能阻止点击。未经要求,绝不要做得更多。
  • 所有入场动效都应在屏幕显示时触发,而不是在挂载时触发。 宿主会预加载:Superwall SDK 会在展示表面之前很久就将其挂载并保持隐藏(useSuperwallSnapshot().paywall !== undefined 是判断信号),应用也可能提前创建 WebView。任何在挂载时运行的动效都会在有人看到之前结束。这也包括 CSS:@starting-style、渲染时已存在类上的 animation,以及 useEffect(() => setMounted(true)) 都会在预加载期间触发。应通过宿主的“已显示”信号切换类或 animate 值,从而触发入场动效。
  • 页面转场应由唯一的所有者——路由器负责,而不是页面负责(在 Superwall 表面中:push、slide、fade、shift,或在 [data-sw-route] 上使用自定义转场);导航时绝不要为页面自身的根元素添加动画,否则两者会互相冲突。
这些值

内置 CSS 缓动效果太弱,无法体现出有意设计的感觉。将以下值定义为令牌,并且只使用这些值:

:root {
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);      /* entering, exiting, press, most UI */
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);  /* something moving across the screen: a thumb, an indicator */
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);   /* iOS sheet / drawer */
}
用途时长缓动效果
按压反馈进入时 80ms,退出时约 200ms--ease-out
选项变更(方案卡片边框、勾选标记、切换开关)150–200ms--ease-out
分段控件滑块、标签指示器、进度填充200–300ms--ease-in-out
面板/抽屉/弹出窗口呈现300–500ms--ease-drawer
打开时的进入动画300–450ms--ease-out
仅颜色或不透明度变化150–200msease
  • UI 中绝不使用 ease-in。 它会在用户正注视的时刻缓慢开始;在 200ms 下,ease-out 感觉比 ease-in 更快。任何需要用户等待的动画都应控制在 300ms 以内。
  • 只使用 transform 和 opacity。 它们不会触发布局和绘制,因此即使付费墙仍在加载图片,动画在旧手机上也能保持流畅。为 height、width、top 或 margin 添加动画会导致掉帧;手风琴组件是唯一可以容忍 height 动画的例外。
  • 页面繁忙时,进入动画仍会运行——页面打开时,字体、主视觉图片和商店价格都还在加载。进入动画优先使用 CSS 转场:它们在主线程之外运行,而基于 JS 的动画在这种负载下会卡顿。使用 Motion 时,应为完整的 transform 字符串添加动画({ transform: "translateY(0px)" }),而不是使用会在主线程运行的 x/y/scale 简写属性。
  • 让动画与产品风格相符。 平静的冥想应用应采用较慢、较柔和的进入动画,且不使用弹跳;游戏可以更活泼;金融应用则应保持利落。为每个界面选择一种风格,并统一所有曲线和时长。
  • 在每个转场中明确指定属性(transition: transform 160ms var(--ease-out));绝不使用 transition: all,因为它会为下一次编辑中恰好发生变化的属性添加动画。
  • 绝不从 scale(0) 开始。 真实事物不会凭空出现:从 scale(0.95) 和 opacity: 0 开始。
  • 对用户可能在一秒内触发两次的操作(例如选择方案、切换开关),使用转场而不是关键帧: 转场会从当前位置重新调整目标;关键帧动画会从头重播并产生跳变。
  • 退出动画应与进入动画方向一致,并且更快。 从底部升起的面板应从底部离开;弹出框应从其触发器位置缩放(将 transform-origin 设在触发器处),居中的弹窗则应从中心缩放。
  • 手指驱动的交互使用弹簧动画。 对于拖动关闭的面板、滑动切换幻灯片,使用弹簧动画完成停靠(默认 bounce: 0,仅在快速滑动后使用 ≤ 0.2),从元素当前的屏幕位置和速度开始,并允许在动画过程中随时打断。固定时长动画无法被抓取并反向操作。越过边缘时应逐渐增加阻力,而不是突然停止。示例使用 Motion(motion/react)库。
  • 减少动态效果时,应更柔和,而非完全取消。 在 prefers-reduced-motion: reduce 下,将位移(滑动、升起、弹簧、视差)替换为短暂的不透明度交叉淡化,同时保留能够说明变化结果的颜色和状态变化(Superwall 界面的路由器已为其自身转场实现此行为)。

字体与渲染

  • 除非设计指定了品牌字体,否则默认使用系统字体栈——这样 Web 视图才会显得原生。-apple-system, BlinkMacSystemFont, system-ui, "Segoe UI", Roboto, sans-serif 一条声明即可覆盖所有平台。
  • 在 html 上设置 -webkit-text-size-adjust: 100%;启用抗锯齿平滑;正文使用 15–17px(17 对应 iOS 正文字号;16 对应 Android);显示字号使用 clamp(),使其在 320px 屏幕上缩小,并在平板上停止增大。
  • 行长:手机上为 45–65 个字符;在平板和桌面 Web 上限制栏宽,不要让行宽无限延伸。
  • 自定义字体会增加每次打开页面都要加载的字节数:发布前先做子集化(仅含拉丁字符的 Manrope 约为 24 kB,而整个字体家族约为 90 kB),只发布 woff2,并将一个字体家族加一种等宽字体作为预算。出于同样的原因,要针对手机屏幕压缩并调整图片尺寸。
  • 在设计允许的范围内尊重用户的文字大小:字体和与之相关的间距使用 rem,细线、圆角和图标框使用 px。如果设计需要在极端情况下限制大小,宿主会提供 fontScale/preferredContentSizeCategory。
  • 字距和行距会随字号变化;总有某个值不合适。 显示字体应收紧(letter-spacing: -0.02em 到 -0.03em,line-height: 1.05–1.15);正文设为 0 和 1.4–1.5;小型大写风格的标签略微加宽(+0.01em 到 +0.04em)。综合字号、字重和行距构建层级,并优先调整字重而不是字号:它能在不占用 320px 屏幕空间的情况下增强视觉分量。
  • 会变化或需要对齐的数字使用等宽数字 (font-variant-numeric: tabular-nums):优惠倒计时、动画价格、套餐卡片中纵向排列的价格。比例数字会让计时器跳动。

最坏情况内容

如果付费墙只用英文的 "Pro · $59.99/year" 进行设计,放到第一台真实设备上就会出问题。将页面视为完成前,应使用它实际可能遇到的最坏值进行渲染,并通过与真实场景相同的输入传入这些值(切换地区设置、设备预设、没有价格的商品),绝不要通过编辑标记来实现:

  • 最长的价格。 ₹1,299.00、CHF 129.00、1.299,99 €,以及完全没有价格的商品。价格由商店格式化提供;绝不要用硬编码的 $ 或分隔符,根据 rawPrice 重新拼接价格。
  • 每个标签、徽章和按钮的最长地区语言(关于哪些内容应换行、哪些应保持不动,请参阅 responsive.md)。
  • 数量为 1 时——"1 days free"、"1 weeks"。目录不支持复数规则,因此应绕开数量措辞("Free trial: 1 week"),或自行根据数量分成两个键,并使用 Intl.PluralRules 按当前地区语言选择;绝不要直接拼接 s。
  • 用户输入的电子邮件或姓名:对任何回显这些内容的元素设置 overflow-wrap: anywhere,否则内容会把整行挤出屏幕。
  • 功能行中的图标、勾选标记和头像设置 flex-shrink: 0;旁边的文字设置 min-width: 0。

以上每种情况都是真实用户可能遇到的情形,而不是压力测试。如果某个值看起来不现实,它就不属于本列表。

颜色和深色模式

  • 深色模式跟随宿主,而非浏览器。SDK 会在 Superwall 界面的 <html> 上添加 dark 类;原生 WebView 则应由应用告知。将样式绑定到你控制的类,而不要只依赖 prefers-color-scheme,因为宿主可能不会反映该设置。即使参考图只展示一种配色,也要设计两套配色并分别检查。
  • 告知宿主页面在两种模式下的背景色(Superwall 界面:在 config.ts 中设置 background);它会绘制原生背景和加载状态,让加载过程无缝衔接。
  • 使用语义化令牌,组件中不要直接写十六进制色值:--bg、--fg、--surface、--accent,再用 color-mix() 派生弱化色、边框色和底色,这样深色配色只需设置基础值。
  • 对比度:两种模式下,正文均需达到 ≥ 4.5:1,大号展示文字需达到 ≥ 3:1。弱化文字通常最容易出问题;在浅色背景上,前景色不透明度约 55% 是下限。
  • 深色模式下,除非设计刻意采用 OLED 纯黑,否则不要在内容后使用纯 #000;原生深色屏幕通常使用 #0d0f12–#1c1b19。

图片和媒体

  • Hero 图片应以实际显示逻辑尺寸的 2 倍提供,经过压缩,并采用现代格式;对于宽度为 393 的 Hero,使用宽度为 1290 的 PNG 并不合适。
  • Hero 图片若延伸至顶部边缘,就应有意置于状态栏下方——在 Superwall 界面中,于配置里设置 insets: { top: "none" },并根据 --sw-safe-area-inset-top 定位关闭按钮;在普通 WebView 中,使用 viewport-fit=cover 和 env(safe-area-inset-top)——同时在图片上加遮罩,确保两种模式下状态栏文字都清晰可读。
  • 视频和 Lottie 自动播放时应静音;仅在设计要求循环时循环播放,并在页面被遮挡时暂停(Superwall 界面:useIsFocused())。

发布前检查

在每种设备尺寸和两种模式下都运行检查;所有项目均通过后,页面才算完成。

  • 在带 Home 键的手机、灵动岛手机、Pixel 和 iPad 上,关闭/返回按钮都位于状态栏下方;应用允许横屏时,在横屏状态下也不得与缺口重叠。
  • 主要 CTA 固定放置、宽度铺满,并位于 iOS 主屏幕指示条上方,以及 Android 底部 12px 以上;最后一行内容滚动时不得被其遮挡。
  • 在 320px 宽度下没有水平溢出;在高度为 667px 的屏幕上,使用最长本地化文案时也没有内容被裁切。
  • 已设计并检查两种模式;宿主已获知两种模式下的页面背景(滚动回弹时不会闪白)。
  • 点击目标 ≥ 44px;每次有意义的点击都有触觉反馈;原生点击控件没有焦点环;图标按钮设有 aria-label。
  • 每个可点击元素都有 :active 状态;每个 :hover 都放在 @media (hover: hover) and (pointer: fine) 内。
  • 输入框字号为 16px 或更大,且使用正确的 type / inputmode / autocomplete;在小屏手机上键盘打开时,输入框及其操作仍可访问。
  • 动效:不使用 transition: all、ease-in 或 scale(0);只对 transform/opacity 做动画;UI 变化在 300ms 内完成;进入动画由宿主的“shown”信号触发,绝不在挂载时触发;提供减少动态效果的版本,以交叉淡入淡出代替移动。
  • 最坏情况下的内容也能整洁呈现:最长价格、最长本地化文案、数量为 1,以及完全没有价格。
  • 所有面向用户的字符串均来自消息目录,包括 aria-label;价格使用插值并经过保护处理。
  • 自定义字体经过子集化并采用 woff2;图片尺寸适合手机。
  • 至少在真机上打开过一次。点击高亮、点击后悬停状态残留、输入框缩放、键盘表现和按压手感都无法在桌面浏览器中复现;请说明哪些项目未能检查。

将其作为 Superwall Surface 发布

这项技能适用的每个屏幕,都是团队发布后还会想要修改的屏幕:价格测试、新功能行、重新排序的问题、不同的主视觉图——这些都不应该等到应用发布并通过审核后才能修改。这正是 Superwall Surface:在用户的代码仓库中作为一个小型 React 应用的屏幕(与应用并列放在 superwall/ 中),可在 superwall dev 中通过每种设备预设进行预览,以不可变版本推送,并从仪表板切换上线;产品、购买、语言本地化、触觉反馈、内边距和深色模式均由宿主提供——因此,上述大多数规则已经为你处理好,其余部分交给 CSS。

如果你正在构建的屏幕还不是 Surface(而是原生屏幕或手工制作的 Web 视图),请用一行说明,并提出迁移方案——新建 Surface 用 superwall create,将现有原生屏幕迁移为 Surface 用 superwall migrate --screen <path>——然后阅读 superwall-framework 技能了解具体操作;由用户决定。如果尚未安装,请安装:

npx skills add https://github.com/superwall/skills --skill superwall-framework --global --yes --agent claude-code universal --full-depth

即使没有它,这项技能也完整适用:上述所有内容都适用于手机上的任何 Web 屏幕。

评论

支持 Markdown