简体   繁体   English

PDFKit 不能在 iPad 上运行,而在模拟器上运行良好 [iOS, Swift]

[英]PDFKit doesn’t work on iPads while works fine on a simulator [iOS, Swift]

I am learning about how to build a document-based app in iOS.我正在学习如何在 iOS 中构建基于document-based应用程序。

I followed Apple's official example ( https://developer.apple.com/documentation/uikit/view_controllers/building_a_document_browser-based_app#overview ) and tried to revise it to display a PDF viewer.我按照 Apple 的官方示例( https://developer.apple.com/documentation/uikit/view_controllers/building_a_document_browser-based_app#overview )并尝试修改它以显示 PDF 查看器。

I modified the original sample code to create the following code.我修改了原始示例代码以创建以下代码。 It works totally fine with any simulators on my Macbook Pro (2020).它在我的 Macbook Pro(2020)上的任何模拟器上都可以正常工作。 However, when I tested with iPads (ie, iPad Mini & iPad Pro: new generations), I cannot open PDF files.但是,当我使用 iPad(即 iPad Mini 和 iPad Pro:新一代)进行测试时,我无法打开 PDF 文件。

I identified that the following code is not working: let doc = PDFDocument(url: documentURL) .我发现以下代码不起作用: let doc = PDFDocument(url: documentURL) The URL seems to be appropriately obtained.该 URL 似乎是适当获取的。 doc remains to be nil when testing with iPads, while appropriately obtained when testing with simulators.使用 iPad 进行测试时, doc仍然nil ,而在使用模拟器进行测试时适当地获得。

I would really appreciate it if you could let me know what is wrong with my code.如果您能让我知道我的代码有什么问题,我将不胜感激。

DocumentBrowserController.swift DocumentBrowserController.swift

import UIKit
import os.log
import PDFKit

/// - Tag: DocumentBrowserViewController
class DocumentBrowserViewController: UIDocumentBrowserViewController, UIDocumentBrowserViewControllerDelegate {
    
    /// - Tag: viewDidLoad
    override func viewDidLoad() {
        super.viewDidLoad()
        delegate = self
        
        allowsDocumentCreation = true
        allowsPickingMultipleItems = false
    }
    
     //MARK: - UIDocumentBrowserViewControllerDelegate
    
    // UIDocumentBrowserViewController is telling us to open a selected a document.
    func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL]) {
        if let url = documentURLs.first {
            presentDocument(at: url)
        }
    }
    
    // MARK: - Document Presentation
   var transitionController: UIDocumentBrowserTransitionController?
    
    func presentDocument(at documentURL: URL) {
        let storyBoard = UIStoryboard(name: "Main", bundle: nil)

        // Load the document's view controller from the storyboard.
        let instantiatedNavController = storyBoard.instantiateViewController(withIdentifier: "DocNavController")
        guard let docNavController = instantiatedNavController as? UINavigationController else { fatalError() }
        guard let documentViewController = docNavController.topViewController as? TextDocumentViewController else { fatalError() }
        
//        // Load the document view.
//        documentViewController.loadViewIfNeeded()
//
        // In order to get a proper animation when opening and closing documents, the DocumentViewController needs a custom view controller
        // transition. The `UIDocumentBrowserViewController` provides a `transitionController`, which takes care of the zoom animation. Therefore, the
        // `UIDocumentBrowserViewController` is registered as the `transitioningDelegate` of the `DocumentViewController`. Next, obtain the
        // transitionController, and store it for later (see `animationController(forPresented:presenting:source:)` and
        // `animationController(forDismissed:)`).
        docNavController.transitioningDelegate = self
        
        // Get the transition controller.
        transitionController = transitionController(forDocumentAt: documentURL)
        
        let doc = PDFDocument(url: documentURL)

        transitionController!.targetView = documentViewController.pdfView
  
        
        // Present this document (and it's navigation controller) as full screen.
        docNavController.modalPresentationStyle = .fullScreen

        // Set and open the document.
        documentViewController.document = doc
        os_log("==> Document Opened", log: .default, type: .debug)
        self.present(docNavController, animated: true, completion: nil)
    }
    
}

extension DocumentBrowserViewController: UIViewControllerTransitioningDelegate {
    
    func animationController(forPresented presented: UIViewController,
                             presenting: UIViewController,
                             source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        // Since the `UIDocumentBrowserViewController` has been set up to be the transitioning delegate of `DocumentViewController` instances (see
        // implementation of `presentDocument(at:)`), it is being asked for a transition controller.
        // Therefore, return the transition controller, that previously was obtained from the `UIDocumentBrowserViewController` when a
        // `DocumentViewController` instance was presented.
        return transitionController
    }
    
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        // The same zoom transition is needed when closing documents and returning to the `UIDocumentBrowserViewController`, which is why the the
        // existing transition controller is returned here as well.
        return transitionController
    }
    
}

TextDocumentViewController.swift TextDocumentViewController.swift

(I just post this here too, although this code does not seem to be the problem) (我也只是在这里发布这个,虽然这段代码似乎不是问题)

/*
 See LICENSE folder for this sample’s licensing information.
 
 Abstract:
 A view controller for displaying and editing documents.
 */

import UIKit
import os.log
import PDFKit

var currentPage = 0

/// - Tag: textDocumentViewController
class TextDocumentViewController: UIViewController, PDFDocumentDelegate, PDFViewDelegate {
    
    @IBOutlet weak var pdfView: PDFView!
    @IBOutlet weak var doneButton: UIBarButtonItem!
    
    private var keyboardAppearObserver: Any?
    private var keyboardDisappearObserver: Any?
    
    var document: PDFDocument! {
        didSet {
            document.delegate = self
        }
    }
    
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        //        setupNotifications()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        //        setupNotifications()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        pdfView.delegate = self
        doneButton.isEnabled = false
        
        if #available(iOS 13.0, *) {
            /** When turned on, this changes the rendering scale of the text to match the standard text scaling
             and preserves the original font point sizes when the contents of the text view are copied to the pasteboard.
             Apps that show a lot of text content, such as a text viewer or editor, should turn this on and use the standard text scaling.
             
             For more information, refer to the WWDC 2019 video on session 227 "Font Management and Text Scaling"
             https://developer.apple.com/videos/play/wwdc2019/227/
             (from around 30 minutes in, and to the end)
             */
        }
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        pdfView.document = document!
        pdfView.autoScales = true
        pdfView.displayMode  = .singlePage
        pdfView.displayDirection = .horizontal
        pdfView.displaysPageBreaks = true
        pdfView.pageBreakMargins = UIEdgeInsets(top: 10, left: 20, bottom: 10, right: 20)
        pdfView.usePageViewController(true)                   
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
    }
    
    
    
}

* I simplified the code trying to illustrate the problem clearly (2020/10/27) * 我简化了代码,试图清楚地说明问题 (2020/10/27)

Hi I think this might be because:您好,我认为这可能是因为:

documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL]) 

Access' items out side of the sandbox.访问沙箱外的项目。

Can you try replacing:你可以尝试更换:

 presentDocument(at: url)

With

let data = try? Data(contentsOf: url)
print(data)

If this prints nil, it's because the URL is failing to load.如果这打印 nil,那是因为 URL 加载失败。

Then replace it with:然后将其替换为:

   let didObtainSecScope = url.startAccessingSecurityScopedResource()
   let data = try? Data(contentsOf: url)
   print(data, didObtainSecScope)
   url.stopAccessingSecurityScopedResource()

If my suspicion is correct, it should print a description data object, followed by 'true'.如果我的怀疑是正确的,它应该打印一个描述数据对象,然后是“true”。 You should be able to replace "Data(contentsOf: url)" with your PDF code.您应该能够用您的 PDF 代码替换“Data(contentsOf: url)”。 You will have to maintain the security scope while you are using the URL, and then call "url.stopAccessingSecurityScopedResource" once you are finished using the document at the URL.您必须在使用 URL 时维护安全范围,然后在使用完 URL 处的文档后调用“url.stopAccessingSecurityScopedResource”。 Otherwise you will leak kernel resources.否则你会泄漏内核资源。

Ensure you don't call "stopAccessingSecurityScopedResource()" too early.确保不要过早调用“stopAccessingSecurityScopedResource()”。

Edit: This is explicitly mentioned in apples documentation here: https://developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories编辑:这里的苹果文档中明确提到了这一点: https : //developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Firebase 在 ios 模拟器上运行良好,但在真实设备上不起作用 - Firebase works fine on ios simulator but it does't work on real device nskeyedarchiver不适用于ios8,但适用于ios7和模拟器 - nskeyedarchiver doesn't work on ios8 but works on ios7 and simulator AVSpeechSynthesizer - iOS 12.3 不工作(在 iOS 12.2 上工作正常) - AVSpeechSynthesizer - iOS 12.3 Doesn't work (it works fine with iOS 12.2) LottieView 在 iOS 模拟器中工作,但在设备上不起作用 -- Expo - LottieView Works in iOS Simulator, but doesn't work on device -- Expo UIButton 在第一次运行时工作正常,但在模拟器上的第二次运行时不起作用 - The UIButton works fine at first run, but doesn't work at the second run on the simulator 代码在iPhone上不起作用,但在模拟器上起作用 - Code doesn't work on iPhone but works on simulator UISearchBar在模拟器上可用,但在设备上不可用 - UISearchBar works on simulator but doesn't work on device iOS应用程序不会在设备上编译,但在模拟器中工作正常 - iOS app won't compile on device but works fine in simulator 应用程序在模拟器中运行良好,但 function 在手机上无法正常运行 - App works fine in simulator but doesn't function correctly on phone IOS 7模拟器根本不起作用 - IOS 7 simulator doesn't work at all
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM