Swift 4.1:如何检测App是否由外部PDF文件启动
检测外部PDF打开的启动方式并自动加载PDFViewController
嘿,我明白你的需求——已经把应用注册成了外部PDF查看器,能拿到Inbox目录里的文件,但没法判断是不是通过“外部打开”的方式启动应用,对吧?下面给你一套具体的实现方案,分iOS和Android两种常见平台来说:
核心思路
本质上,我们需要在应用启动/唤醒时捕获外部文件触发的Intent/URL事件,通过这个事件标记启动类型,再在应用主流程中根据标记去打开PDFViewController。
第一步:捕获外部打开的触发事件
这是判断启动类型的关键,不同平台的处理入口不一样:
对于iOS
如果你的应用用了SceneDelegate,就在scene(_:openURLContexts:)里处理;如果是旧版的AppDelegate,就用application(_:open:options:):
// SceneDelegate.swift func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { guard let fileURL = URLContexts.first?.url else { return } // 校验是不是PDF文件 if fileURL.pathExtension.lowercased() == "pdf" { // 用UserDefaults标记是外部打开启动 UserDefaults.standard.set(true, forKey: "isLaunchedFromExternalPDF") // 保存文件路径,后续用来加载 UserDefaults.standard.set(fileURL.path, forKey: "externalPDFPath") } }
对于Android
你已经在Manifest里注册了PDF的Intent Filter,接下来在接收的Activity里处理Intent——注意要同时处理onCreate(冷启动)和onNewIntent(热启动,应用在后台时被唤醒):
// 你的主Activity或者专门处理文件的Activity override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) handleExternalPDFIntent(intent) } override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) handleExternalPDFIntent(intent) } private fun handleExternalPDFIntent(intent: Intent?) { intent?.takeIf { it.action == Intent.ACTION_VIEW && it.type == "application/pdf" }?.let { val fileUri = it.data fileUri?.let { uri -> // 这里替换成你把Uri转成Inbox目录文件路径的逻辑(你已经能读取Inbox,应该有现成代码) val inboxFilePath = convertUriToInboxPath(uri) // 用SharedPreferences标记启动类型 val prefs = getSharedPreferences("AppSettings", MODE_PRIVATE) prefs.edit() .putBoolean("isLaunchedFromExternalPDF", true) .putString("externalPDFPath", inboxFilePath) .apply() } } }
第二步:启动后判断并打开PDFViewController
在应用的主页面(比如首页ViewController/Activity)的合适生命周期里,读取之前的标记,触发PDFViewController的跳转:
iOS示例(首页ViewController)
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let isExternalLaunch = UserDefaults.standard.bool(forKey: "isLaunchedFromExternalPDF") if isExternalLaunch { if let pdfPath = UserDefaults.standard.string(forKey: "externalPDFPath"), let pdfURL = URL(fileURLWithPath: pdfPath) { // 初始化你的PDFViewController并跳转 let pdfVC = PDFViewController(pdfURL: pdfURL) navigationController?.pushViewController(pdfVC, animated: true) } // 用完记得清除标记,避免下次启动误触发 UserDefaults.standard.set(false, forKey: "isLaunchedFromExternalPDF") UserDefaults.standard.removeObject(forKey: "externalPDFPath") } }
Android示例(首页Activity)
override fun onResume() { super.onResume() val prefs = getSharedPreferences("AppSettings", MODE_PRIVATE) val isExternalLaunch = prefs.getBoolean("isLaunchedFromExternalPDF", false) if (isExternalLaunch) { val pdfPath = prefs.getString("externalPDFPath", "") if (!pdfPath.isNullOrEmpty()) { val pdfFile = File(pdfPath) if (pdfFile.exists()) { // 启动PDF查看页面 val intent = Intent(this, PDFViewController::class.java) intent.putExtra("PDF_FILE_PATH", pdfPath) startActivity(intent) } } // 清除标记 prefs.edit() .putBoolean("isLaunchedFromExternalPDF", false) .remove("externalPDFPath") .apply() } }
几个额外提醒
- 文件异步复制的问题:如果文件是后台异步复制到Inbox的,直接读取可能拿到空文件,建议加个监听(比如文件变化的观察者),等复制完成再打开PDFViewController。
- 权限校验:Android要确保申请了
READ_EXTERNAL_STORAGE或者适配了Scoped Storage;iOS要确保配置了UIFileSharingEnabled和对应的文件访问权限。 - 重复触发的避免:一定要在处理完后清除标记,不然下次启动应用会重复打开上次的PDF。
这样就能准确识别外部打开PDF的启动场景,自动加载对应的文件啦~
内容的提问来源于stack exchange,提问作者Puty
相关产品推荐
相关产品推荐

