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。