mcpField
I
iphone-duo-capacitor

iphone-duo-capacitor

github.com/mirzaaghazadeh开发250353 次安装今天更新
代码仓库

关于 iphone-duo-capacitor

iphone-duo-capacitor 是一项面向在 iPhone Duo 上运行的 Capacitor 应用的适配指南,供处理折叠屏布局的开发者参考。它说明 WebView 的能力限制,并结合安全区域、尺寸类别和现有插件介绍分层适配方法。

主要功能

  1. 01说明 WebView 折叠感知限制
  2. 02处理不对称安全区域
  3. 03按动态尺寸调整布局
  4. 04使用尺寸类别而非设备判断
  5. 05介绍原生折叠屏桥接插件

适用场景

  1. 01适配 iPhone Duo 的 Capacitor 应用
  2. 02排查安全区域导致的布局问题
  3. 03应对折叠、旋转和分屏尺寸变化
  4. 04通过原生插件获取折叠状态

安装

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

$npx skills add https://github.com/mirzaaghazadeh/iphone-duo-skills --skill iphone-duo-capacitor

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

详细介绍

iPhone Duo 上的 Capacitor

先看这里,否则这件事会耗掉你整个下午:

WebKit 27.1 实现了 Device Posture 和 Viewport Segments,但两者都受一个只有 Safari 才能设置的实验性标志控制。

Capacitor 应用运行在一个无法控制其标志的 WKWebView 中,因此其中没有 navigator.devicePosture、device-posture 媒体查询和 env(viewport-segment-*) 变量;而同一设备上的 Safari 却能在同一页面中读取这些信息。请进行功能检测,不要想当然,并做好这些功能都不可用的准备。

因此,在这台设备上,Web 平台开箱即不支持折叠感知。不过,它确实提供了大部分重要功能。请分两个层级处理。

第 1 层——现已可用,无需原生代码

信任安全区域,绝不要假设它们对称

这是最容易造成实际问题的一点。iOS 会把系统栏移到显示屏的一侧,具体在哪一侧取决于设备姿态和阅读方向。

系统栏会体现为真实的安全区域插入值:在 27.1 模拟器上测得,env(safe-area-inset-right) 为 84px;如果应用选择不使用垂直系统栏,则会变为 env(safe-area-inset-top) 的 82px,实时生效且无需重新加载。因此,大多数布局只需在四边使用合适的 env(safe-area-inset-*) 内边距即可。

任何形式为 width - env(safe-area-inset-left) * 2 的表达式在这台设备上都是缺陷。

正确处理尺寸变化

窗口尺寸会不断变化:打开、关闭、折叠、旋转、分屏视图。需要时再读取尺寸,不要缓存;优先使用容器查询和 %/fr 布局,而不是存储像素值。任何在 useEffect 或 ngOnInit 中测量并保存下来的值,几秒内就会过时。

根据尺寸类别处理,而不是检查设备

iOS 使用尺寸类别来判断这台设备的状态:外屏为紧凑宽度,内屏为常规宽度。请根据系统提供的尺寸类别分支,而不要使用用户代理字符串或屏幕方向,因为内屏不会遵循支持的屏幕方向设置。

在模拟器上测得:内屏横向时为 951×669,外屏为 466×678。

在宽屏上将导航移到侧边

当 iOS 将自己的标签栏和工具栏移到垂直侧栏时,固定在底部的 HTML 标签栏与所有原生应用相比都会显得格格不入。内屏使用侧栏、外屏使用底部栏,是 Web 端对应的做法,而且只需一个断点。

第 2 层——需要原生端支持

在原生端将信息传递给 Web 视图之前,所有真正与 iPhone Duo 相关的内容对它来说都是不可见的。

原生 API(iOS 27.1)在 Web 视图中使用它的原因
UIView 上的 reservedRegions(kind:options:)获取折叠区域和摄像头的位置,以便布局避开它们
UIHingeInteraction获取连续的铰链角度,用于特效和姿态判断
trait collection 上的 verticalBarEdge获取 iOS 将系统栏移到哪一侧,以便让应用界面与之匹配
traitCollection 中的尺寸类别获取 iOS 实际使用的信号,而不是猜测断点

在自己编写这些功能之前,有两个细节值得了解。平放手机的折叠区域会被报告为非活动,因此读取时需要使用 options: .includeInactive,否则你会误以为设备没有铰链。而且 UIHinge.status 是延迟更新的,因此在折叠过程中会与角度不一致;两者都可用时,请以角度为准。

使用现有桥接

@erkamyaman/capacitor-foldable 是一个 MIT 插件,已经实现了这些功能,还补全了 Device Posture 和 Viewport Segments,让标准 CSS 如今就能在应用中正常使用:

npm install @erkamyaman/capacitor-foldable
npx cap sync
import { Foldable, installFoldablePolyfill } from '@erkamyaman/capacitor-foldable';

await installFoldablePolyfill();

const fold = await Foldable.getFoldState();
await Foldable.addListener('foldStateChange', (state) => layout(state));

该 polyfill 会在 <html> 上设置 --fold-left、--fold-width 等变量,因此网格可以将间隔精确地放在折痕处,而不用猜测。相同的构建也通过 androidx.window 支持 Android 折叠屏设备。

更多深入资料请参阅 iphone-duo-capacitor-skills: 其中介绍了 CSS 模式、完整 API、Ionic 细节,以及如何在模拟器和 Android 模拟器上测试。

Ionic 应用

Ionic 的 ion-tabs 属于 HTML,因此原生栏移动时,它仍会留在底部。有两种方案:使用样式表,将标签栏变成位于 iOS 所选边缘的侧边胶囊;或者使用 @rdlabo/capacitor-native-ui,通过 UIKit 和 SwiftUI 渲染现有的 ion-buttons、ion-button、ion-back-button 和 ion-tab-bar,而原始元素及其状态和处理程序仍保留在 Web 视图中。它以设备状态作为输入,因此两者可以组合使用,而不会相互冲突;其安装说明中也列出了该插件。可选的 @rdlabo/ionic-theme-ios27 还可在此基础上添加 iOS 27 样式。

操作步骤

  1. 检查所有安全区域表达式,找出其中假定两侧对称的地方。大多数问题都能在这一步解决。
  2. 停止缓存尺寸,并根据传入的尺寸进行分支处理。
  3. 为宽屏设计真正适用的布局,而不是拉伸手机布局。
  4. 添加插件,并对标准 API 进行功能检测,这样同一构建仍能在支持这些 API 的浏览器中运行。
  5. 只有完成以上步骤后,再考虑铰链角度效果;它在良好移植工作中所占比重最小。

步骤 1 到 3 无需原生代码,同时也能改善应用在平板电脑上的体验。步骤 4 是唯一针对 iPhone Duo 的部分,而且必须使用 Xcode 27.1 模拟器才能测试。

要了解原生 API 的作用及其原因,请阅读 ../iphone-duo-adaptive-layout/SKILL.md 和 ../iphone-duo-vertical-bars/SKILL.md——尽管代码无法直接移用,设计思路却完全适用。

评论

支持 Markdown