mcpField
C
capacitor-ios-resizability

capacitor-ios-resizability

github.com/cap-go开发7355 次安装2 周前更新
代码仓库

关于 capacitor-ios-resizability

帮助 Capacitor iOS 应用适配 iPad 等设备上的可调整窗口。它审查网页布局、原生代码、插件和应用配置,再指导修复与验证。

主要功能

  1. 01审查网页布局假设
  2. 02扫描原生 API 和插件代码
  3. 03检查 Info.plist 与场景设置
  4. 04指导跨应用层的获批修复
  5. 05在模拟器中验证窗口缩放

适用场景

  1. 01为 iPad 多任务处理做准备
  2. 02排查窗口缩放后失效的布局
  3. 03检查分屏中的插件叠加层
  4. 04处理启动屏幕和方向警告

安装

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

$npx skills add https://github.com/cap-go/capgo-skills --skill capacitor-ios-resizability

安装后在 Claude Code 中输入/capacitor-ios-resizability确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

metadata.json
references/
info-plist-and-scenes.md
native-replacements.md
plugin-audit.md
swiftui-in-plugins.md
web-layer.md
scripts/
scan-legacy-apis.sh

详细介绍

Capacitor iOS 应用的可调整大小窗口

Capacitor 应用是在 CAPBridgeViewController 中的全窗口 WKWebView。Web 视图会随窗口变化。我们需要让 Web 布局响应宽度变化,并移除那些假定只有一个全屏窗口的原生代码(应用、自定义代码、插件)。

适用场景

在以下情况触发:

  • 为 iPad 多任务处理、Stage Manager、窗口化 iPad 应用、可折叠 iPhone 或外接显示器准备应用
  • 窗口调整大小时,布局出错或没有更新
  • 分屏视图中的插件原生叠加层(扫描仪、相机预览、自定义面板)尺寸或位置不正确
  • Xcode 或 App Store Connect 警告 UIRequiresFullScreen、缺少 iPad 方向设置或启动屏幕要求
  • 用户要求移除 UIScreen.main、userInterfaceIdiom、interfaceOrientation 或 AppDelegate 生命周期用法

不要用于:

  • 仅设置 CSS env(safe-area-inset-*) 和刘海屏内边距:safe-area-handling
  • 将 AppDelegate 迁移到 SceneDelegate:capacitor-uiscene-migration(Xcode 27 的前置步骤)
  • 键盘遮挡:capacitor-keyboard
  • 仅使用 Tailwind 断点:tailwind-capacitor

制定计划所依据的事实

  • iOS 27 会忽略 UIRequiresFullScreen,并仍会调整场景大小(TN3192)。切勿悄悄删除此键:删除后,应用会立即在当前 iOS 上变为可调整大小。切勿自行添加 UIRequiresFullScreenIgnoredStartingWithVersion:它的值决定哪些版本继续采用旧行为。两者都应由用户在测试后决定。
  • iOS 27 SDK 要求声明启动屏幕。 如果没有声明,上传会因 ITMS-90870 被拒。Capacitor 模板会设置 UILaunchStoryboardName;请保留它。
  • Xcode 27 要求使用场景生命周期。 Capacitor 8.5 模板包含 SceneDelegate.swift。如果没有它,AppDelegate 生命周期方法将是唯一信号,这在多窗口场景下并不正确。如果缺少 UIApplicationSceneManifest,请先运行 capacitor-uiscene-migration。
  • 保留 UIApplicationSupportsMultipleScenes = false。 每个场景都会创建自己的 CAPBridgeViewController,以及第二个 WebView 和一组插件。Capacitor 在 8.5 中添加了场景级通知,供插件做好准备,但模板不支持多窗口。单场景也可以调整大小。
  • CAPBridgeViewController 仅根据 iPhone 键 UISupportedInterfaceOrientations 构建 supportedInterfaceOrientations,不会读取 UISupportedInterfaceOrientations~ipad(Capacitor 8.5 源码)。即使 iPad 声明了全部四种方向,桥接层掩码仍可能将其锁定。请报告此问题;只有在用户希望采用不同的 iPad 行为时,才在桥接子类中重写 supportedInterfaceOrientations。
  • Web 层会自动收到调整大小事件。 WKWebView 会随窗口调整大小并触发 resize。布局出错是因为布局代码读取了设备信息,而非视口信息。
  • 插件属于第三方代码。 安装时对 node_modules 的修改会丢失。请报告插件问题、升级插件、向上游提交问题,或仅在用户批准后将 patch-package 作为临时方案。

参考资料

仅在涉及相应主题时加载参考资料。

文件加载时机
references/info-plist-and-scenes.md检查 Info.plist 键、方向掩码、场景生命周期,以及不再触发的 AppDelegate 方法
references/web-layer.md审查并修复 CSS/JS 布局:视口、单位、设备检测、安全区域在运行时发生变化的情况
references/native-replacements.md在 Swift/ObjC 中替换 UIScreen.main、方向、设备类型、关键窗口、生命周期和硬编码内边距
references/plugin-audit.md扫描 node_modules 中的插件、分类处理,以及插件作者应进行的更改
references/swiftui-in-plugins.md插件或应用展示了必须调整大小的原生 SwiftUI 屏幕;iOS 27 SDK 的 SwiftUI 变更

脚本:scripts/scan-legacy-apis.sh 会扫描 ios/App/App 和所有 node_modules/**/ios 文件夹,并打印与调整大小相关的 Info.plist 键。只读。

工作流

1. 前提检查(只读)

读取 ios/App/App/Info.plist、AppDelegate.swift、SceneDelegate.swift、@capacitor/ios 版本,以及 TARGETED_DEVICE_FAMILY 构建设置(1,2 = iPhone 和 iPad)。报告:

检查项符合条件否则
启动屏幕存在 UILaunchStoryboardName 或 UILaunchScreen报告 ITMS-90870 风险
场景生命周期存在 UIApplicationSceneManifest,且 SceneDelegate.swift 属于该目标先交由 capacitor-uiscene-migration 处理
iPad 方向UISupportedInterfaceOrientations~ipad 列出了全部四种方向,或不存在 iPad 键指出缺少哪些方向。提及上文的 bridge 掩码事实
全屏退出选项不存在 UIRequiresFullScreen报告 iOS 27 会忽略此项。更改前先询问用户
2. 扫描
bash <skill>/scripts/scan-legacy-apis.sh .

同时扫描 Web 代码(references/web-layer.md):

grep -rnE 'screen\.(width|height|availWidth)|window\.orientation|orientationchange|\b100vh\b|navigator\.userAgent.*(iPad|iPhone)|isPlatform\(.(ipad|tablet|iphone)|innerWidth' src --include='*.{ts,tsx,js,jsx,vue,svelte,css,scss}'

创建 TODO 列表,每个文件对应一条。大型项目:每批处理 3 至 5 个文件。列表中的每个文件都必须进行更改,或书面说明无需更改的原因。

3. 报告,然后询问

将发现的问题分类为:应用 Web 代码、应用原生代码、插件(按包分类)、Info.plist。每项都说明修复方法。进行以下更改前先询问用户:

  • 更改 UIRequiresFullScreen、方向键或方向掩码,
  • 更改共享原生代码中的公共方法签名,
  • 修补 node_modules 中的插件。
4. 修复
  • 先处理 Web 层。这通常就是全部修复内容:references/web-layer.md。
  • 应用原生代码:references/native-replacements.md。仅编辑包含目标 API 的行。保留所有 if/else 分支和 #available 守卫。绝不将动态值替换为字面值,也绝不将一个全局对象(UIScreen.main)替换为另一个(UIApplication.shared、UITraitCollection.current、UIDevice.current)。
  • 空的模板桩(例如 applicationDidBecomeActive,只有注释)无害。仅在其中包含代码时才移动。
  • 插件:references/plugin-audit.md。
5. 验证
npx cap sync ios
xcrun simctl list devices available | grep -i ipad
npx cap run ios --target <iPad-simulator-UDID>
  • 在 iPad 模拟器(iPadOS 26+)中,将应用切换到窗口模式并拖动窗口角落。检查窄、中、宽三种尺寸。也尝试与另一个应用使用分屏视图。
  • 在每种尺寸下旋转设备。在窄窗口中打开并关闭键盘。
  • 检查插件提供的原生浮层(扫描仪、相机预览、选择器)在窄窗口中的表现。
  • 将应用切换到后台再切回前台。JS pause / resume 必须触发。
  • 如果 Xcode 提供可折叠 iPhone 模拟器,请以相同方式测试折叠和展开。
  • 重新运行扫描。对每个剩余命中项,都必须书面说明理由(例如相机拍摄方向或分析用途等非布局用途)。

错误处理

症状原因修复方法
调整大小后,布局仍停留在旧尺寸JS 在启动时缓存了 window.innerWidth / screen.width,或 CSS 使用了 100vh在 resize 时读取尺寸,或使用 CSS;将 100vh 替换为 100dvh
仅在某些窗口尺寸下,内容位于状态栏或主屏幕指示器下方安全区域内边距只读取了一次,或将一侧的内边距镜像到了两侧在 CSS 中按边使用 env(safe-area-inset-*);切勿在 JS 中缓存
插件覆盖层在分屏视图中覆盖了错误区域插件根据 UIScreen.main.bounds 调整视图尺寸更新插件,或使用扫描行向上游提交问题
App 已启动,但在 iOS 26 上无法调整大小UIRequiresFullScreen = true在用户测试后将其移除之前,这属于预期行为
上传因 ITMS-90870 被拒绝缺少启动屏幕键恢复 UILaunchStoryboardName,并设置为 LaunchScreen.storyboard
添加 SceneDelegate 后,pause / resume 不再触发AppDelegate 生命周期方法中的自定义代码将代码移至场景方法,或监听通知(参考资料)

相关技能

  • safe-area-handling:CSS env() 变量和状态栏覆盖层
  • capacitor-uiscene-migration:采用 SceneDelegate,这是进行场景感知修复的前提
  • tailwind-capacitor:Tailwind 中的响应式断点
  • capacitor-testing:模拟器和设备验证流程
  • capacitor-plugin-upgrade-v8-to-v9:插件修复需要新主版本时

评论

支持 Markdown