2

Since the ios13 update, overriding the PDFView class’s method canPerformAction(_ action: Selector, withSender sender: Any?) no longer detects or controls the "look up", "share" and "forward" menu items and I can't figure out a way to disable them. Previously overriding it in this manner blocked all menu items:

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
}

However this only blocks cut, copy, paste from ios13. Has anyone figured this out? If so I would very much appreciate your help!

shochu_king
  • 136
  • 2
  • 10

3 Answers3

1

Figure out what class the elements you are selecting belong to (UITextField, UITextView, UIWebView, etc.), and method swizzle its canPerformAction:withSender:.

The_Falcon
  • 287
  • 1
  • 2
  • 10
  • Thanks for taking time to write an answer. The method and class are mentioned in the question. The above override of canPerformAction() worked for pdfview in ios 11 and 12 and has stopped working properly in ios 13 – shochu_king Nov 06 '19 at 06:07
1

I faced the same issue. Looks like in iOS13 some actions (menu and touches) are delegated to PDFView's property documentView. So, method swizzling for that view class worked for me, but it looks like a working but "dirty" hack. In my PDFView subclass I've added:

private func swizzleDocumentView() {
    guard let d = documentView, let documentViewClass = object_getClass(d) else { return }

    let sel = #selector(swizzled_canPerformAction(_:withSender:))
    let meth = class_getInstanceMethod(object_getClass(self), sel)!
    let imp = method_getImplementation(meth)

    let selOriginal = #selector(canPerformAction(_:withSender:))
    let methOriginal = class_getInstanceMethod(documentViewClass, selOriginal)!

    method_setImplementation(methOriginal, imp)
}

@objc func swizzled_canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
   return false
}
somedev
  • 791
  • 11
  • 29
  • Thanks for your answer. I've tried calling your method from init (using Swift 3) but it never gets the documentView.. where do you call your method from? – shochu_king Apr 24 '20 at 06:36
  • After reading around, I've implemented your method swizzling for documentView, but "lookup", "share" menu items are still being displayed. So, unfortunately, it doesn't work. (ios 13.4.1 simulator, Swift 3.1) – shochu_king Apr 28 '20 at 04:20
  • Oh, I've forgotten to mention that `documentView ` property is not `nil` after filling `document` property of `PDFView` instance. So I've override `document` property in my `PDFView` subclass and in `didSet` closure call `swizzleDocumentView()`. Also you need a flag to prevent multiple swizzling. p.s. sorry for delayed answer – somedev Apr 29 '20 at 08:28
  • Unfortunately it still doesn't work. Perhaps something else is necessary? – shochu_king Apr 30 '20 at 09:40
  • @shochu_king I've updated my sample, now it should work correctly – somedev May 04 '20 at 11:48
  • Thanks for trying again, but it still doesnt work. The first line of your swizzleDocumentView() method always fails on object_getClass(d) and returns. That is with calling it from the didSet() override for document. I have also implemented it without that first line but despite the method swizzling appearing to have worked, the menu items are still being displayed.. :( – shochu_king May 07 '20 at 08:24
  • 1
    This solution works well for me. Looks like lookup and share are handled by the document view. Of course this is not the nicest solution, but I guess that we need to follow this way until apple allows us to handle this nicely in the PDFView subclass. – Eluss Jun 17 '20 at 14:58
1

You can override buildMenu for PDFView subclass

override func buildMenu(with builder: UIMenuBuilder) {
    builder.remove(menu: .share)
    builder.remove(menu: .lookup)
    super.buildMenu(with: builder)
}
john07
  • 562
  • 6
  • 16