WKWebview с новым модальным сбоем iOS13 при вызове средства выбора файлов - PullRequest
8 голосов
/ 30 сентября 2019

У меня есть веб-просмотр в контроллере модального представления на iOS13. Когда пользователь пытается загрузить изображение в веб-просмотр, происходит сбой.

Это исключение, которое я получаю:

2019-09-30 17: 50: 10.676940+0900 Engage [988: 157733] * Завершение работы приложения из-за необработанного исключения «NSGenericException», причина: «Ваше приложение представило UIDocumentMenuViewController (). В его текущей среде свойств, modalPresentationStyle UIDocumentMenuViewController с этим стилем является UIModalPresentationPopover. Вы должны предоставить информацию о местонахождении для этого всплывающего окна через popoverPresentationController контроллера представления. Вы должны предоставить либо sourceView и sourceRect, либо barButtonItem. Если эта информация неизвестна при представлении контроллера представления, вы можете предоставить ее в методе UIPopoverPresentationControllerDelegate -prepareForPopoverPresentation. '* стек первых двух вызовов: (0x18926c98c 0x188f950a4 0x18cb898a8 0x18cb939b4 0x18cb914f8 0x18d283b98 0x18d2737c0 0x18d2a3594 0x1891e9c48 0x1891e4b34 0x1891e5100 0x1891e48bc 0x193050328 0x18d27a6d4 0x1002e6de4 0x18906f460) Libc ++ abi.dylib: оканчивающиеся неперехваченного исключением типа NSException

1009

Я не уверен, где я могу установить этот делегат ...

Я сделал пример проекта: https://github.com/ntnmrndn/WKUploadFormCrash И заполнил отчет об ошибке в Apple

Ответы [ 3 ]

3 голосов
/ 21 октября 2019

Как правильно сказано @ jshapy8, вам необходимо переопределить метод present() и вручную установить .sourceView / .sourceFrame / .barButtonItem. Но вы должны иметь в виду, что в случае, если UIViewController, который содержит WkWebView, представлен UINavigationController, UINavigationController отвечает за представление других UIViewController.

Если вы не являетесьна iPad.

Так что на самом деле вам необходимо переопределить метод present() в вашем UINavigationController, а также в UIViewController, который содержит WkWebView.

ВВ приведенном ниже примере UIViewController, который содержит WkWebView, называется WebVC.

. В вашем UINavigationController вам нужно добавить:

  override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
    if let webVC = viewControllers.filter({ $0 is WebVC }).first as? WebVC {
      webVC.setUIDocumentMenuViewControllerSoureViewsIfNeeded(viewControllerToPresent)
    }
    super.present(viewControllerToPresent, animated: flag, completion: completion)
  }

И в вашем WebVCвам нужно добавить:

  override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
    setUIDocumentMenuViewControllerSoureViewsIfNeeded(viewControllerToPresent)
    super.present(viewControllerToPresent, animated: flag, completion: completion)
  }

  func setUIDocumentMenuViewControllerSoureViewsIfNeeded(_ viewControllerToPresent: UIViewController) {
    if #available(iOS 13, *), viewControllerToPresent is UIDocumentMenuViewController && UIDevice.current.userInterfaceIdiom == .phone {
      // Prevent the app from crashing if the WKWebView decides to present a UIDocumentMenuViewController while it self is presented modally.
      viewControllerToPresent.popoverPresentationController?.sourceView = webView
      viewControllerToPresent.popoverPresentationController?.sourceRect = CGRect(x: webView.center.x, y: webView.center.y, width: 1, height: 1)
    }
  }

Таким образом, вы можете использовать новый стиль модальной презентации iOS 13 и загружать файлы без сбоев ?

Редактировать: Такое поведение при сбое, похоже, (другое) iOS 13ошибка, потому что это проблема только на iPhone, а не на iPad (только что проверил это на iPad с iOS 12 и 13. Похоже, что инженеры Apple просто забыли, что в случае, если WKWebView представлен с их новым модальным стилем презентации,UIDocumentMenuViewController представлен в стиле UIModalPresentationPopover, даже на телефонах, который был доOS 13 попросту не подходит.

Я обновил свой код, поэтому теперь он устанавливает .sourceView / .sourceFrame / .barButtonItem только для типов телефонов, потому что типы планшетов будут обрабатываться iOS самостоятельно.

2 голосов
/ 30 сентября 2019

Я также столкнулся с подобной аварией.

Вы можете исправить это, установив modalPresentationStyle в .fullScreen.

1 голос
/ 10 октября 2019

Как говорится в сообщении об ошибке, UIKit решает, что UIDocumentMenuController должен быть поповером, и поэтому он ожидает, что будут установлены либо sourceView и sourceFrame, либо barButtonItem этого поповера (сбойименно потому, что эти не были установлены).

Если вы хотите сохранить модальный стиль представления iOS 13, не возвращаясь к использованию просто .fullScreen, в контроллере представления, который встраиваетWKWebView вы можете переопределить present, чтобы получить ссылку на UIDocumentMenuViewController и установить свойства для его popoverPresentationController:

class WebViewController: UIViewController {
    override open func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
        if #available(iOS 13, *), viewControllerToPresent is UIDocumentMenuViewController {
            viewControllerToPresent.popoverPresentationController?.barButtonItem = // reference to a bar button item you want to present the popover from
            // OR
            viewControllerToPresent.popoverPresentationController?.sourceView = // whatever view you want to present the popover from
            viewControllerToPresent.popoverPresentationController?.sourceFrame = // that view's frame
        }

        super.present(viewControllerToPresent, animated: flag, completion: completion)
    }
}
...