From befe205bf968443ce7013a165d7408df1e12a294 Mon Sep 17 00:00:00 2001 From: joywayer Date: Sat, 27 Jun 2026 21:46:43 +0800 Subject: [PATCH] =?UTF-8?q?IPA=20=E5=8D=87=E7=BA=A7=20URL=20=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=8C=85=E6=88=90=20itms-services=EF=BC=9A=E8=B7=B3?= =?UTF-8?q?=E8=BF=87=20Safari=E3=80=81=E7=9B=B4=E6=8E=A5=E5=BC=B9=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E5=AE=89=E8=A3=85=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【UX 目标】 点「确定」→ 直接弹系统安装确认窗(不跳 Safari)→ 用户点「安装」→ App 自然切后台、用户看到桌面图标下载进度,App 进程留在内存不退出。 【方案】 makeInstallURL 规范化 appDownload: - itms-services://... → 原样 - https?://...*.plist (mfst) → 包成 itms-services://?action=download-manifest&url=... - 其它(网页 / 短链) → 原样跳 Safari(后台需把 URL 改成上面两种之一才能跳过 Safari) 不再需要 exit(0);iOS 处理 itms-services 时本来就会把 App 切后台,自动满足用户 "回到桌面但 App 不退出"的需求。 文案改为"开始升级,系统会自动下载并安装"匹配新流程。 BuildProject 通过。 Co-Authored-By: Claude Opus 4.7 --- .../WebView/WebContainerViewController.swift | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/ylgamehall/Source/WebView/WebContainerViewController.swift b/ylgamehall/Source/WebView/WebContainerViewController.swift index b0eba0b..60c3fd9 100644 --- a/ylgamehall/Source/WebView/WebContainerViewController.swift +++ b/ylgamehall/Source/WebView/WebContainerViewController.swift @@ -554,27 +554,48 @@ public final class WebContainerViewController: UIViewController { } private func showIPAUpgradeAlert(downloadURL: String) { - // ⚠️ 不要在跳 Safari 后自动 exit(0): - // iOS 的 itms-services:// 系统安装确认弹窗依赖 source app 仍在内存中 - // 才能弹出(系统安全机制);提前 exit 会让 Safari 收到 URL 但确认窗 - // 不显示,整个安装流程被悄悄中断。 + // 行为目标:点「确定」直接弹系统安装窗(不跳 Safari),用户点「安装」后 + // App 自然切后台、用户看到桌面图标下载进度,App 进程留在内存,无需主动 exit。 // - // 正确做法:跳 Safari 后让 App 自然留在后台。用户在 Safari 点「安装」 - // 后,iOS 开始下载 → 替换 IPA 时会自动结束旧 App 进程(或要求用户上滑), - // 无需主动介入。 + // 实现依赖:URL 必须是 iOS 可直接接管的安装协议(itms-services 或 manifest plist 直链)。 + // 详见 makeInstallURL 注释。如果远端配的是 https 网页链接,仍会跳 Safari + // 给用户看引导页 —— 这是预期外的情形,需后台把 appDownload 改成 itms-services + // 或 .plist 直链才能跳过 Safari 中转。 let alert = UIAlertController( title: "需要升级", - message: "检测到新版本,点击「确定」前往下载。\n\n安装确认弹窗出现后请点击「安装」,然后从多任务列表上滑退出本 App,更新即可自动完成。", + message: "检测到新版本,点击「确定」开始升级,系统会自动下载并安装。", preferredStyle: .alert ) alert.addAction(UIAlertAction(title: "确定", style: .default) { _ in - if let url = URL(string: downloadURL) { + if let url = Self.makeInstallURL(from: downloadURL) { UIApplication.shared.open(url) } }) present(alert, animated: true) } + /// 把远端 `appDownload` 规范化为 iOS 系统可直接接管的安装协议,避免跳 Safari 中转。 + /// + /// 三种 raw URL 形态: + /// - `itms-services://...` → 原样返回(iOS 直接弹安装窗) + /// - `https?://...*.plist`(企业签 manifest 直链)→ 自动包成 + /// `itms-services://?action=download-manifest&url=`,iOS 直接弹安装窗 + /// - 其它(网页 / 短链等)→ 原样跳转,由 Safari 接管。这种情形下后台需要把 + /// URL 改成上面两种之一才能跳过 Safari 中转 + private static func makeInstallURL(from raw: String) -> URL? { + let trimmed = raw.trimmingCharacters(in: .whitespaces) + let lower = trimmed.lowercased() + if lower.hasPrefix("itms-services://") { + return URL(string: trimmed) + } + if (lower.hasPrefix("https://") || lower.hasPrefix("http://")), + lower.hasSuffix(".plist") { + let encoded = trimmed.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? trimmed + return URL(string: "itms-services://?action=download-manifest&url=\(encoded)") + } + return URL(string: trimmed) + } + /// 启动期错误的精确分类。先看 NWPath.unsatisfiedReason 区分"真断网"和"权限被拒" /// (iOS 14+ 两类都报 NSURLError -1009,但 path 里有 wifiDenied / cellularDenied /// 标记),fallback 看 NSURLError code。