2

我想知道如何在 iOS 中使用turbolinks-ios框架打开链接的 pdf 文件。

目前,我遇到的问题是,当 turbolinks 页面链接到 pdf 或其他文件时,链接将在 safari 而不是嵌入式视图中打开。

背景

turbolinks-5库与turbolinks-ios 框架一起提供了一种将 Web 应用程序连接到相应移动应用程序的本机导航控制器的方法。

截屏

截图取自turbolinks README

期望的行为

当单击指向 pdf 的链接时,应将单独的视图控制器推送到当前导航控制器,以便用户可以阅读 pdf 并轻松导航回文档索引。

观察到的行为

链接的 pdf 在 safari 中打开,而不是在应用程序中打开。不幸的是,Safari 再次要求进行身份验证。此外,用户必须离开应用程序。

4

1 回答 1

3

截取pdf链接的点击

对于 pdf 文件的链接,不会为会话委托触发该didProposeVisitToURL机制。因此,无法从那里决定如何处理链接的 pdf。

相反,可以通过成为 turbolinks 的 web 视图的导航委托来拦截单击链接,如README 所示

extension NavigationController: SessionDelegate {
  // ...

  func sessionDidLoadWebView(session: Session) {
    session.webView.navigationDelegate = self
  }
}

extension NavigationController: WKNavigationDelegate {
  func webView(webView: WKWebView, 
      decidePolicyForNavigationAction navigationAction: WKNavigationAction, 
      decisionHandler: (WKNavigationActionPolicy) -> ()) {

    // This method is called whenever the webView within the
    // visitableView attempts a navigation action. By default, the
    // navigation has to be cancelled, since when clicking a
    // turbolinks link, the content is shown in a **new**
    // visitableView.
    //
    // But there are exceptions: When clicking on a PDF, which
    // is not handled by turbolinks, we have to handle showing
    // the pdf manually.
    //
    // We can't just allow the navigation since this would not
    // create a new visitable controller, i.e. there would be
    // no back button to the documents index. Therefore, we have
    // to create a new view controller manually.

    let url = navigationAction.request.URL!

    if url.pathExtension == "pdf" {
      presentPdfViewController(url)
    }

    decisionHandler(WKNavigationActionPolicy.Cancel)    
  }
}

呈现 pdf 视图控制器

与显示 turbolinks-ios 演示应用程序中所示的可访问视图类似,显示pdf 视图控制器:

extension NavigationController {
  func presentPdfViewController(url: NSURL) {
    let pdfViewController = PdfViewController(URL: url)
    pushViewController(pdfViewController, animated: true)
  }
}

或者,如果您还想显示其他文件类型,请调用它fileViewController而不是pdfViewController.

PdfViewController

新的视图控制器继承自 turbolinks 的VisitableViewController以利用 url 的初始化。

class PdfViewController: FileViewController {
}

class FileViewController: Turbolinks.VisitableViewController {
  lazy var fileView: WKWebView = {
    return WKWebView(frame: CGRectZero)
  }()

  lazy var filename: String? = {
    return self.visitableURL?.pathComponents?.last
  }()

  override func viewDidLoad() {
    view.addSubview(fileView)
    fileView.bindFrameToSuperviewBounds()  // https://stackoverflow.com/a/32824659/2066546
    self.title = filename  // https://stackoverflow.com/a/39022302/2066546
    fileView.loadRequest(NSURLRequest(URL: visitableURL))
  }
}

为了使 web 视图的大小正确,我使用bindFrameToSuperviewBounds了这个 stackoverflow 答案中所示的方法,但我确信还有其他方法。

可选:共享 cookie

如果加载 pdf 需要身份验证,则可以方便地与 turbolinks-ios webview 共享 cookie,如README 中所述

例如,创建一个webViewConfiguration可以传递给的pdfViewController

extension NavigationController {
  let webViewProcessPool = WKProcessPool()

  lazy var webViewConfiguration: WKWebViewConfiguration = {
    let configuration = WKWebViewConfiguration()
    configuration.processPool = self.webViewProcessPool
    // ...
    return configuration
  }()

  lazy var session: Session = {
    let session = Session(webViewConfiguration: self.webViewConfiguration)
    session.delegate = self
    return session
  }()
}

同样webViewConfiguration需要传递给session(如上所示)以及新的 pdf 视图控制器。

extension NavigationController {
  func presentPdfViewController(url: NSURL) {
    let pdfViewController = PdfViewController(URL: url)
    pdfViewController.webViewConfiguration = self.webViewConfiguration
    pushViewController(pdfViewController, animated: true)
  }
}

class FileViewController: Turbolinks.VisitableViewController {
  var webViewConfiguration: WKWebViewConfiguration

  lazy var fileView: WKWebView = {
    return WKWebView(frame: CGRectZero, configuration: self.webViewConfiguration)
  }()

  // ...
}

演示

截屏

于 2016-08-18T17:39:16.703 回答