尧图精选

iOS Lynx Explorer 集成 Sparkling 容器:路由协调器、LaunchDescriptor 与双构建模式实战指南

🕒 发布时间:2026/9/15 12:52:43 📁 来源:尧图网络
iOS Lynx Explorer 集成 Sparkling 容器路由协调器、LaunchDescriptor 与双构建模式实战指南【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynx导读本文以 iOS Lynx Explorer 的 Sparkling 容器集成方案为主线系统讲解第一阶段的完整落地路径一个RouteCoordinator如何把所有 URL 入口解析为不可变的LaunchDescriptor如何在保持 Legacy 容器默认行为不变的前提下通过Sparkling Go显式扩展路由暴露完整 Sparkling 容器能力。读完本文你将掌握 iOS Explorer 的路由契约、Legacy 参数兼容映射、全局 props 与能力保留、失败契约、模拟器冒烟验收以及sparkling双构建模式的完整工程实践并能在本地复现bundle_install.sh的构建与所有权校验流程。架构总览容器集成而非二次 Lynx 集成第一阶段为 iOS Lynx Explorer 提供了一条显式的全量 Sparkling 启动路径但不改变普通 bundle 的默认容器。核心设计只有一个RouteCoordinator它将每一个 URL 入口解析成一个不可变的LaunchDescriptor再根据解析结果呈现选中的容器。关键边界在于这是容器集成不是第二次 Lynx 集成。无论在哪种构建模式下Lynx、LynxBase、LynxServiceAPI、LynxService、LynxDevtool、BaseDevtool、XElement都继续来自当前 Lynx checkout由生成得到的LynxLibraryRegistrypod 同样是源码自持的来自 Explorer 工作区中的generated/lynx-library。源码级证据可参见 explorer/darwin/ios/lynx_explorer/bundle_install.shCocoaPods 安装后随即执行verify_sparkling_ownership.py做所有权校验确保八个源码自持 pod 各自解析到预期位置。用户可见的路由契约Explorer 保留通用首页并把 Sparkling Go 作为可选扩展暴露。普通打开动作与扩展路由刻意承载不同语义Open原始 bundle 与 Legacy bundle URL 仍然落在 Legacy Explorer 容器上Sparkling Go只有当宿主声明了 Sparkling 容器能力时首页才出现这一紧凑的扩展行其内嵌的根 bundle 请求一个完整 Sparkling 容器并继续打开后续的 Sparkling 页面。无论请求来自首页、扫码器、应用代理还是页内路由协调器都统一执行以下规则输入Open显式 Sparkling 路由原始 HTTP/HTTPS bundleLegacySparklingfile://lynx?local://bundle_pathbundleLegacySparkling包裹原始/Legacy bundle 的lynx://open?urlencoded_url解包后 Legacy语义映射后 Sparklinghybrid://lynxview_page?bundlebundle_pathSparklingSparklinghybrid://lynxview_page?urlencoded_urlSparklingSparkling包裹规范 Sparkling scheme 的 Legacy 包装解包后 Sparkling解包后 SparklingRecorder URLRecorder/Legacyrecorder_unsupported_in_sparkling畸形或不受支持的 URL类型化路由错误类型化路由错误两个要点值得强调规范 Sparkling scheme 拥有其请求普通Open无法把它强行压入 Legacy第一阶段绝不擅自升级原始 bundle 只有在调用方显式进入Sparkling Go、或从扫码器选择 Sparkling 时才会被提升为 Sparkling。规范 scheme 由官方 Sparkling 解析器校验包装解包是有界的通常要求恰好一个url目标。解析器还保留了 Explorer 历史遗留的未转义urlhttps://......尾部形式——此时剩余 query 属于该单一目标而非包装层且原始编码 URL 会被保留。LaunchDescriptorURL 语法与容器创建的 SDK 中立边界LaunchDescriptor是介于 URL 语法与容器创建之间的 SDK 类型中立边界其源码定义位于 explorer/darwin/ios/lynx_explorer/LynxExplorer/routing/LaunchDescriptor.swift记录了原始输入以及适用时的原始规范 scheme本地 bundle、远程 bundle 或 Recorder 资源对应LaunchResource枚举的localBundle/remote/recorder三种 case初始数据、公共 props、页面 props、页面名与无损 query 项LaunchQueryItem为name 可空valueviewport、背景/透明度、导航与呈现选项ViewportOptions精确到物理像素AppearanceOptions与NavigationOptions结构化承载缓存与 Node-API/调试选项请求的与解析后的容器类型外加路由来源RouteSource枚举覆盖 manualInput、scanner、startup、externalURL、universalLink、debugBridge、nativeModule、sparklingRouter、recorder 等入口。两个启动器职责分明Legacy 启动器是唯一把类型化模型还原为既有字符串键 Explorer 参数的地方Sparkling 启动器构建SPKContext并调用SPKRouter.create(withURL:context:frame:)绝不用普通LynxView代替。相关实现见 explorer/darwin/ios/lynx_explorer/LynxExplorer/routing/SparklingContainerLauncher.swift其中对 Recorder 资源会直接抛出recorderUnsupportedInSparkling。Legacy 参数兼容映射类型化的已知值采用 query 名称的最后一个有值出现。布尔参数保持 Legacy shell 的NSString.boolValue兼容无法识别的值继续保留在无损 query/extra 视图中而不是让一个本来合法的 Legacy URL 失败。完整映射如下Legacy 参数解析类型描述符字段Legacy 消费方Sparkling 映射无效值行为animatedFoundation 兼容 Boolean默认truepresentation.animatedNavigationHost转场同一协调器转场也保留在 query/页面 props 中无值项不抹掉先前值未识别的有值拼写遵循NSString.boolValue且被无损保留hidden_navFoundation 兼容 Boolean默认falsenavigation.navigationHiddenLegacy shell 导航可见性规范hide_nav_bar保留为hiddenNav页面 prop未识别值遵循NSString.boolValue且被无损保留fullscreenFoundation 兼容 Boolean默认falsenavigation.fullScreen、导航隐藏、透明外观Legacy 全屏布局fullscreen、hide_nav_bar、hide_status_bar与透明状态栏上下文未识别值遵循NSString.boolValue且被无损保留titleStringnavigation.titleLegacy 导航标题规范/上下文title与title页面 prop无值项被保留但不提升到类型化字段不抹掉先前的有值项title_colorStringnavigation.titleColorLegacy 标题颜色规范/上下文title_color与titleColor页面 prop作为字符串保留不支持的色彩由渲染属主忽略bar_colorStringnavigation.barColorLegacy 导航背景规范nav_bar_color与barColor页面 prop作为字符串保留不支持的色彩由渲染属主忽略back_button_styleStringnavigation.backButtonStyleLegacy 返回图与前端主题保留在规范 query、SPKContext.queryItems与backButtonStyle页面 prop为前向兼容保留活动容器决定其支持哪些样式widthheight物理像素下的正 Legacy 整数前缀值NSString.intValue/ Int32 语义两者都必须viewportLegacy 屏幕/视口尺寸显示比例换算后SPKRouterframe同样的显示比例换算后不完整、非正或越界的配对使类型化 viewport 不设置同时保留原始值orientationportrait或landscapenavigation.orientationLegacy 支持方向掩码未知拼写保持未类型化且被无损保留钉住的 Sparkling API 没有安全的按容器等价物任何携带orientation项的非规范路由被显式强制进入 Sparkling 时返回sparkling_option_unsupported包括未知拼写规范输入仍由官方解析器拥有原始值总是保留只有被强制的非规范 Sparkling 转换会拒绝enable_napi_addon窄 Legacy truthy 集合1、true或yes默认falsedebugOptions.enableNAPIAddonLegacy 后台运行时、生命周期监听器与模块页面自持后台运行时与监听器由SPKContext配置保留Explorer 模块在 builder 上注册其他值禁用 addon 且被无损保留initial_page直通字符串pageName、extras、queryItems与initialPage页面 propLegacy 全局 prop规范 query 与SPKContext.queryItems无额外类型化校验无值项不提升为 prop未知 query 键直通有序queryItemsextras与 camelCase 页面 props 中取最后值Legacy 参数/全局 prop 兼容规范 query 加SPKContext.extra/queryItems与 camelCase 页面 prop无类型化拒绝重复编码项保持有序字典视图取最后值解析器还识别container_bg_color与trans_status_bar。无法被安全表示的字段会显式失败而不是悄悄改变容器语义。两条优先级规则规范hide_nav_bar与nav_bar_color独立于 query 顺序优先于其 Legacy 别名hide_status_bar与 fullscreen 分开建模规范页面可以隐藏状态栏而不改变其呈现模式。解析实现可参见 explorer/darwin/ios/lynx_explorer/LynxExplorer/routing/LaunchDescriptorParser.swift其单元测试覆盖于 explorer/darwin/ios/lynx_explorer/LynxExplorerTests/LaunchDescriptorParserTests.swift。全局 props 与能力保留普通 Sparkling 页面 props 遵循以下优先级Explorer common props Sparkling stable/container props launch/page props公共层不会遮蔽钉住的 SDK 的稳定设备、viewport、安全区、URL、SPK_version、lynxSdkVersion、sparklingVersion、containerInitTime字段。以下归一化身份/能力名称在每个不可信边界被保留containerIDcontainerTypeexplorerSupportsExplicitRouteOwnershipexplorerSupportsSparklingContainersparklingAvailablesparklingNavigationspkContainerIDspkPipe完整 Sparkling 页面会收到SDK 拥有的容器身份、MethodPipe、router、生命周期、稳定 props、Explorer 资源/图片提供器、XElement 注册、原生模块以及本地 Lynx DevTool 配置。语义上需要注意sparklingNavigationtrue表示当前页面具备该能力不代表 App 二进制只是链接了 SparklingLegacy 页面不注册spkPipe也不宣告 Sparkling 导航explorerSupportsExplicitRouteOwnership描述的是已安装的 iOS 协调器在纯 Legacy 构建中也保持为 true独立的explorerSupportsSparklingContainer构建能力控制首页是否提供Sparkling Go扩展。nav-basic运行时夹具暴露 SDK 拥有的lynxSdkVersion值。Sparkling 验收检查会拒绝空值以及absent、unknown、unavailable哨兵值并要求夹具的nav-xelement-input探针恰好映射到一个可见的原生XCUIElementTypeTextField。每次 Chrome DevTools ProtocolCDP读取通过匹配锚文本与 frame 坐标把可见原生 LynxView 绑定到一个 DevTool 会话——这些检查防止另一个页面或过期会话满足能力断言。失败契约一旦描述符解析为 Sparkling行为是确定的容器创建或呈现失败返回给调用方Sparkling 生命周期错误视图展示异步加载失败router.open报告协调器的实际接受结果或类型化错误router.close接受缺失/空目标为当前容器非空 ID 仅在与该容器匹配时接受未知 ID 被拒绝且不会关闭其他页面请求绝不通过 Legacy 重试Explorer 绝不创建普通LynxView作为 Sparkling 回退。最近历史仅在路由被接受后更新。原生模块回调以稳定 code 与 message恰好完成一次。Router 服务条目在读取 UIKit 状态前会先把完整操作编组到主线程——包括 MethodPipe 请求当前线程执行的情况。被审计的路由入口当前所有 iOS 入口都终止于同一个协调器入口来源/策略lynx_initial_url环境值最高优先级启动路由UIApplicationLaunchOptionsURLKey冷启动自定义 URLapplication:openURL:options:热启动 app 专属lynx://open?url百分号编码目标传输原始编码包装被保留application:continueUserActivity:restorationHandler:来自webpageURL的 Universal Link 路由首页手动Open/Sparkling Go扩展自动或显式 Sparkling 意图的 push首页最近行自动Open历史仅在接受后变化首页 showcase/导航辅助协调器支撑的 Legacy 路由Sparkling 之外完整 Sparkling 页面内是 Sparkling router扫码器选择表暴露 LegacyOpen与Open with Sparkling取消或失败后恢复扫描DebugBridge 本地路由replaceTop策略DebugBridge 远程路由resetAndPush策略ExplorerModule.openSchema向后兼容的单参数 Legacy/自动适配器ExplorerModule.openRoute/navigateBack能力探测、回调驱动的容器适配器SparklingRouterServiceopen/close带显式 Sparkling 意图的原始 scheme 与实际协调器结果无 Legacy 转换原生导航按钮与完成的边缘返回手势协调器拥有的关闭Sparkling 系统手势与 Legacy 自定义手势保留同一栈Legacy 提交是原子的SDK 回退 pop 总是被消费Recorder 回调支持的 Legacy Recorder 路由当前 iOS Explorer没有Scene manifest、SceneDelegate或startFromUrl入口。未来若新增任何此类入口必须调用同一个协调器而不是另起一套 URL 解析器。Explorer 有意不认领通用的hybridURL scheme。第三方使用普通 LaunchServices 时应把规范 Sparkling URL 包裹在注册的 app 专属lynx://open?url...传输中或使用 universal link解包后仍会把规范目标强制进入 Sparkling。Appium 套件通过其定向 deep-link API 把同样的 app 专属包装投递给 Explorer 的 bundle ID不注册也不直接投递通用hybrid传输。模拟器冒烟验收run_sparkling_smoke.sh见 explorer/darwin/ios/lynx_explorer/scripts/run_sparkling_smoke.sh的流程是安装选定 App 一次用lynx_initial_url启动然后不重新启动、不终止通过真实 LaunchServices 路径用simctl openurl投递两次热 URL。第一次热 URL 是畸形规范路由第二次是有效规范路由两者都通过已注册的 app 专属lynx://open包装传输。脚本随后在限定进程日志中检查初始容器、畸形路由的类型化失败、有效路由的预期结果。它还要求非空本地 Lynx 版本、让 App 在两次热投递期间保持存活、拒绝新的重复类诊断并在检查失败路由没有回退到其他容器之前等待一段时间。sparkling模式期望两次 Sparkling 成功零Legacy 成功无sparkling模式期望一次 Legacy 成功以及显式的sparkling_unavailable失败。核心断言模式来自脚本源码包括LEGACY_SUCCESS_PATTERNLynxExplorer route_success containerlegacy([[:space:]]|$) SPARKLING_SUCCESS_PATTERNLynxExplorer route_success containersparkling([[:space:]]|$) SPARKLING_VERSIONED_SUCCESS_PATTERNLynxExplorer route_success containersparkling lynx_sourcelocal lynx_version[^[:space:]] MALFORMED_MARKERLynxExplorer route_failure code$EXPECTED_MALFORMED_CODE模式匹配通过轮询日志实现wait_for_pattern_count与openurl_until_pattern_count按超时窗口递增计数assert_known_lynx_version拒绝unknown/unavailable版本assert_single_application_process则确保热 URL 投递没有重新拉起进程。冒烟测试覆盖 LaunchServices 投递、路由结果、本地 Lynx 版本日志与 no-fallback 契约DevTool 会话与原生 XElement 运行时证据由 Appium 套件补充。依赖模式与所有权Sparkling 是显式构建模式默认不带sparklingcd explorer/darwin/ios/lynx_explorer ./bundle_install.sh --sparkling-mode disable_sparkling ./bundle_install.sh --sparkling-mode enable_sparklingsparkling模式会在被忽略的生成目录中实例化官方 Sparkling 仓库钉在指定 commit并仅从源码构建Sparkling、SparklingMacro、SparklingMethod、Sparkling-Router四个 pod与本地 Lynx pods 一起编译无sparkling模式不含任何 Sparkling pod。Sparkling-DebugTool、Sparkling-Media、Sparkling-Storage不在此阶段依赖图内。sparkling模式同时打包官方 playground 构建产物入口 bundle 位于Resource/extensions/sparkling-go/main.lynx.bundle兄弟页面 bundle 共享该命名空间。Explorer 不维护 Sparkling Go UI 的 fork。官方 playground 虽含 Media 与 Storage 页面但第一阶段未链接其原生 pods因此那些方法调用不可用。无sparkling构建会移除生成资源防止旧的sparkling构建把扩展泄漏进纯通用产物。本地sparkling构建要求 Node 22 与 pnpm 10.26.0先同步钉住的源码、构建官方 playground再运行bundle_install.shpython3 ../../../scripts/sync_sparkling_source.py \ --manifest ../../../sparkling-source.json \ --source-root ../../../generated/sparkling-source pnpm --dir ../../../generated/sparkling-source install --frozen-lockfile pnpm --dir ../../../generated/sparkling-source --filter sparkling-playground build bash bundle_install.sh --sparkling-mode enable_sparkling源码同步脚本 explorer/scripts/sync_sparkling_source.py 会先在临时目录完成浅克隆与 detached checkout校验通过后用原子替换落位到目标目录并且拒绝覆盖已存在的源码路径manifest 定义于 explorer/sparkling-source.json其中记录了 repository、commit、removal_condition 与四个 pod 的源码路径。CI 的sparklingaction 执行相同序列无sparkling路径不安装 Node、不构建 Sparkling Go。在钉住的 revision 上选定的Sparkling、SparklingMethod、Sparkling-Routerpodspec 不约束 Lynx 版本但Sparkling-DebugTool仍把Lynx、LynxService/Devtool、LynxDevtool/Framework约束到~ 3.9.0因此所有权校验器会拒绝该 subspec避免引入已发布的 Lynx 依赖。bundle_install.sh在 CocoaPods 安装后运行所有权校验器verify_sparkling_ownership.py脚本位于 explorer/darwin/ios/lynx_explorer/scripts/verify_sparkling_ownership.py检查八个源码自持 podLynxLibraryRegistry必须解析到generated/lynx-library其余七个必须解析到当前 checkout 根目录。校验器拒绝不匹配或脏的 pin、包管理器或 CocoaPods 缓存目标、非本地源码自持的 Lynx pod、被禁止的 Sparkling pod、或第二个 Lynx 属主。它永不修改node_modules、下载的 podspec 或 CocoaPods 缓存。Explorer 钉住官方 AnimaX 1.1.0 可用版本。该版本打包的 FMLThreadConfig声明与当前 Lynx checkout ABI 不兼容因此 Podfile 仅对 AnimaX target 在HEADER_SEARCH_PATHS前置当前 Lynx 根目录让 AnimaX 与 LynxBase 编译到同一个规范base/include/fml/thread.h其他 target 不变。构件校验器在 AnimaX 依赖文件证明该头文件属主之前失败关闭并拒绝 link map 中的不兼容构造函数。在 AnimaX 停止打包重复 FML 头后应移除这一窄覆盖并重跑两种构建模式与构件矩阵。源码覆盖可在满足以下条件后移除官方 Sparkling 发布已包含相关 API、对源码自持 Lynx pods 无版本约束、无需修改即可针对当前 checkout 解析并通过依赖、Debug/Release 链接与运行时所有权矩阵。CI 构建矩阵与发布构件CI 与发布只构建实际发布或被下游任务消费的内容因此没有未经构建检查就发布或执行的.app。publish-release.yml发布四个iOS Explorer App——arm64/x86_64×{无 sparkling, sparkling}全部为 Debug 模拟器构件架构模式LynxExplorer-arm64.app.tar.gzarm64无sparkling原始LynxExplorer-x86_64.app.tar.gzx86_64无sparkling原始LynxExplorer-arm64-sparkling.app.tar.gzarm64sparklingLynxExplorer-x86_64-sparkling.app.tar.gzx86_64sparklingci.yml的ios-explorer-build构建同样的四个Debug 模拟器保证每个发布的 App 都必然可编译、可链接。为什么是四个、为什么sparkling不能取代原始版路由用#if canImport(Sparkling)门控。sparkling构建编译#if分支无sparkling构建编译#else分支而sparkling构建永远看不到#else分支。因此无sparkling构建并非冗余——它是唯一对#else路径做类型检查的构建也是仍然发布的原始.appios-e2e-test只下载 arm64 Debugsparkling构建。LegacyContainerLauncher无条件编译因此单一sparkling构建在运行时也能覆盖 Legacy 路由路径——这正是 e2e 只需一个构建而非每模式一个的原因。CI 恰好构建这四个——没有 Release-only 或真机任务——以把共享 macOS runner 预算控制在最低每个任务要么发布构件要么被 e2e 消费。上游 API 依赖与移除条件钉住的 revision 暴露了提案中的四个永久集成点SPKHybridSchemeParam.buildLynxPageScheme拥有规范 URL 构造SPKContext.navigationBarBackHandler让宿主协调器在 Sparkling 发出页面返回与结束返回事件后拥有其栈SPKContext.interactivePopGestureDelegate让同一协调器序列化可取消的系统边缘返回手势而不替换 UIKit 转场SPKContext.failedViewBuilder让 Explorer 提供唯一的加载错误 UI同时 Sparkling 保留失败生命周期与重试所有权。Explorer 直接使用这些公开 API不替换 Sparkling 导航栏、不复刻规范语法、不实现并行的加载错误生命周期/覆盖层。其加载错误视图注册 SDK 提供的刷新块因此 Retry 遵循 Sparkling 的重载契约。当 PR 合入后应把精确 pin 推进到第一个包含该 revision 的官方版本重跑解析器/编码测试、sparklingDebug 与 Release 构建、所有权校验和导航冒烟测试然后优先采用包含该 revision 的第一个发布。在整个升级过程中语义路由模型与协调器保持不变。相关文档本文对应的 Android 侧容器集成方案explorer/docs/android-sparkling-container.mdiOS Explorer 构建入口脚本explorer/darwin/ios/lynx_explorer/bundle_install.sh冒烟验收脚本explorer/darwin/ios/lynx_explorer/scripts/run_sparkling_smoke.shSparkling 源码同步脚本与 manifestexplorer/scripts/sync_sparkling_source.py、explorer/sparkling-source.json【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →