Как предотвратить сбой объекта WKWebView? - PullRequest
0 голосов
/ 13 октября 2018

Сценарий

Я создаю приложение для iOS в Swift.Одной из особенностей является подача живого видео в качестве фона приложения.Видеопоток исходит от Raspberry Pi в локальной сети с использованием sudo motion.Motion успешно размещает фид на порту по умолчанию 8081.

Приложение Swift имеет объект WKWebView, источник которого указывает на порт движения моего Raspberry Pi.

Подозреваемый вопрос

Веб-страница в порту 8081 постоянно обновляется для загрузки самого последнего кадра с камеры.

Неисправность

При работеприложение, канал успешно подключается и загружает первый кадр, а иногда и второй, но затем отключается.

Несколько раз я получал в терминале следующую ошибку: [ProcessSuspension] 0x282022a80 - ProcessAssertion() Unable to acquire assertion for process with PID 0, заставляя меня поверить, что это проблема управления памятью, связанная с постоянно обновляющейся природой веб-страницы.

Текущая конфигурация

В настоящее время мой вызов .load () объекта WKWebView находится в ViewController.swift> override func viewDidLoad().

Предлагаемое разрешение

Нужно ли мне создавать некую форму структуры цикла, в которой я загружаю кадр, приостанавливаю выполнение, а затем вызываю WKWebView, чтобы через несколько секунд перезагрузить новый кадр.

I 'Я очень новичок в Swift, поэтому терпение в формате моего вопроса высоко ценится.

1 Ответ

0 голосов
/ 25 октября 2018

WkWebView и загрузка движений работали в Xcode 9 с версиями iOS 11, но, похоже, больше не работают с iOS 12. Вы правы, что webkit падает на втором изображении.

В связи с тем, что вы новичок в Swift, я бы посоветовал прочитать эту ссылку для делегатов, потому что это решение, которое я предоставляю, будет иметь для вас больше смысла. Swift Delegates В итоге, «Делегаты - это шаблон проектирования, который позволяет одному объекту отправлять сообщения другому объекту, когда происходит определенное событие».

С этим решением / хаком мы будем использоватьнекоторые из WKNavigationDelegates сообщают нам, когда WkWebView выполняет конкретные задачи, и предлагают решение проблемы.Вы можете узнать всех делегатов, которые есть у WKWebKit WKNavigationDelegates .

Следующий код можно использовать в новом проекте iOS и заменить код в ViewController.swift.Это не требует никакого построителя интерфейса или соединений IBOutlet.Это создаст единый веб-вид на представление и укажет на адрес 192.168.2.75:6789.Я включил встроенные комментарии, чтобы попытаться объяснить, что делает код.

  1. Мы загружаем HTTP-ответ дважды с движения в делегате definePolicyFor navigationResponse и отслеживаем со счетчиком.Я оставил несколько печатных заявлений, чтобы вы могли увидеть ответ.Первый - это заголовок, а второй - информация об изображении.
  2. Когда наш счетчик получает 3 элемента (т. Е. Второе изображение), мы заставляем wkWebView отменить всю навигацию (т. Е. Прекратить загрузку) в делегате definePolicyFor navigationResponse.Смотрите строку с решениемHandler (.cancel).Это то, что останавливает аварию.
  3. Это приводит нас к получению обратного вызова от навигации WebView didFail делегата wkwebview.В этот момент мы хотим снова загрузить наш motion / pi url и снова начать процесс загрузки.
  4. Затем мы должны сбросить счетчик, чтобы мы могли повторять этот процесс до тех пор, пока кто-то другой не найдет лучшего решения.

    import UIKit
    import WebKit
    
    class ViewController: UIViewController, WKNavigationDelegate  {
    
        // Memeber variables
        var m_responseCount = 0; /* Counter to keep track of how many loads the webview has done.
                        this is a complete hack to get around the webkit crashing on
                        the second image load */
        let m_urlRequest = URLRequest(url: URL(string: "http://192.168.2.75:6789")!) //Enter your pi ip:motionPort
        var m_webView:WKWebView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            m_webView = WKWebView(frame: self.view.frame)  // Create our webview the same size as the viewcontroller
            m_webView.navigationDelegate = self            // Subscribe to the webview navigation delegate
        }
    
        override func viewDidAppear(_ animated: Bool) {
            m_webView.load(m_urlRequest)                    // Load our first request
            self.view.addSubview(m_webView)                 // Add our webview to the view controller view so we can see it
        }
    
        // MARK: - WKNavigation Delegates
        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
            print("decidePolicyFor navigationAction")
            print(navigationAction.request) //This is the request to connect to the motion/pi server http::/192.168.2.75:6789
            decisionHandler(.allow)
        }
    
        func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
            print("decidePolicyFor navigationResponse")
            print(navigationResponse.response) // This is HTML from the motion/rpi
    
        /* We only want to load the html header and the first image
           Loading the second image is causing the crash
             m_responseCount = 0 - Header
             m_responseCount = 1 - First Image
             m_responseCount >= 2 - Second Image
        */
            if(m_responseCount < 2)
            {
                decisionHandler(.allow)
            }
            else{
                decisionHandler(.cancel) // This leads to webView::didFail Navigation Delegate to be called
            }
    
            m_responseCount += 1;  // Incriment our counter
    
        }
    
        func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        /*
         We have forced this failure in webView decidePolicyFor navigationResponse
         by setting decisionHandler(.cancel)
         */
            print("didFail navigation")
    
            m_webView.load(m_urlRequest) //Lets load our webview again
            m_responseCount = 0     /*  We need to reset our counter so we can load the next header and image again
                                    repeating the process forever
                                */
        }
    
        func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
        // If you find your wkwebview is still crashing break here for
        // a stack trace
            print("webViewWebContentProcessDidTerminate")
    
        }
    }
    

Примечание. Вам также необходимо добавить следующее в файл info.plist, поскольку ответ сервера движения / pi равен http, а не https

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoadsInWebContent</key>
    <true/>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Я рекомендую вам использовать этот базовый пример и изменить его в соответствии с требованиями вашего приложения.Я также призываю вас публиковать любые собственные выводы, потому что у меня точно такая же проблема, когда используется то же самое оборудование, что и у вас, и это скорее взлом, чем решение.

...