You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:27:38