Подтвердить что ты не робот

UIWebView: когда страница действительно заканчивала загрузку?

Мне нужно знать, когда веб-страница полностью загружена UIWebView. Я имею в виду, действительно, полностью, когда все переадресации завершены, и динамически загруженный контент готов. Я попытался ввести javascript (запрос для document.readyState == 'complete'), но это не кажется очень надежным.

Есть ли, возможно, событие из частного api, которое принесет мне результат?

4b9b3361

Ответ 1

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

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

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    if ([[webView stringByEvaluatingJavaScriptFromString:@"document.readyState"] isEqualToString:@"complete"]) {
        // UIWebView object has fully loaded.
    }
}

Ответ 2

Мое решение:

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    if (!webView.isLoading) {
        // Tada
    }
}

Ответ 3

Возможность UIWebView выполнять Javascript не зависит от того, загружена ли страница или нет. Его возможное использование stringByEvaluatingJavaScriptFromString: выполнить Javascript, прежде чем вы даже сделаете вызов для загрузки страницы в UIWebView в первую очередь или без загрузки страницы вообще.

Поэтому я не могу понять, как принимается ответ в этой ссылке: webViewDidFinishLoad: стрельба слишком скоро? потому что вызов любого Javascript вообще не говорит вам (если они называют какой-то интересный Javascript, который контролирует dom, например, они не упоминают об этом, и если бы они были, это было бы потому, что это важно).

Вы можете вызвать некоторый Javascript, который, например, проверяет состояние dom или состояние загруженной страницы и сообщает, что обратно к вызывающему коду, однако, если он сообщает, что страница еще не загружена, то что вы делаете делать? - вам придется называть это снова немного позже, но сколько позже, когда, где, как, как часто... Опрос обычно никогда не является хорошим решением для чего-либо.

Единственный способ узнать, когда страница полностью загружена, быть точным и контролировать то, что именно она делает, - подключить прослушиватели событий JavaScript на загружаемую страницу и заставить их вызвать ваш shouldStartLoadWithRequest: с некоторым проприетарным URL. Например, вы можете создать JS-функцию для прослушивания загрузки окна или события, подготовленного dom, и т.д. В зависимости от того, нужно ли вам знать, когда загружена страница, или только что загрузили дом и т.д. В зависимости от ваших потребностей.

Если веб-страница не принадлежит вам, вы можете поместить этот javascript в файл и ввести его на каждую загружаемую страницу.

Как создать javascript-прослушиватели событий является стандартным javascript, ничего особенного для iOS, например, здесь JavaScript, чтобы определить, когда dom загрузился в форму, которая может быть введена на страницу загрузки из UIWebView и затем вызывается вызов toStartLoadWithRequest: (это вызовет shouldStartLoadWithRequestwhen: dom завершил загрузку, которая до отображения полного содержимого страницы, чтобы обнаружить это, просто измените прослушиватель событий).

var script = document.createElement('script');  
script.type = 'text/javascript';  
script.text = function DOMReady() {
    document.location.href = "mydomain://DOMIsReady";
}

function addScript()
{        
    document.getElementsByTagName('head')[0].appendChild(script);
    document.addEventListener('DOMContentLoaded', DOMReady, false);
}
addScript();

Ответ 4

Ответ Мартина H на правильном пути, но он все равно может срабатывать несколько раз.

Что вам нужно сделать, это добавить слушателя Javascript onLoad на страницу и следить за тем, добавили ли вы слушателя:

#define kPageLoadedFunction @"page_loaded"
#define kPageLoadedStatusVar @"page_status"
#define kPageLoadedScheme @"pageloaded"

- (NSString*) javascriptOnLoadCompletionHandler {
    return [NSString stringWithFormat:@"var %[email protected] = function() {window.location.href = '%[email protected]:' + window.location.href; window.%[email protected] = 'loaded'}; \
    \
    if (window.attachEvent) {window.attachEvent('onload', %[email protected]);} \
    else if (window.addEventListener) {window.addEventListener('load', %[email protected], false);} \
    else {document.addEventListener('load', %[email protected], false);}",kPageLoadedFunction,kPageLoadedScheme,kPageLoadedStatusVar];
}

- (BOOL) javascriptPageLoaded:(UIWebView*)browser {
    NSString* page_status = [browser stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.%@",kPageLoadedStatusVar]];
    return [page_status isEqualToString:@"loaded"];
}


- (void)webViewDidFinishLoad:(UIWebView *)browser {

    if(!_js_load_indicator_inserted && ![self javascriptPageLoaded:browser]) {
        _js_load_indicator_inserted = YES;
        [browser stringByEvaluatingJavaScriptFromString:[self javascriptOnLoadCompletionHandler]];
    } else
        _js_load_indicator_inserted = NO;
}

Когда страница будет завершена, слушатель Javascript будет запускать новую загрузку страницы URL pageloaded:<URL that actually finished>. Затем вам просто нужно обновить shouldStartLoadWithRequest, чтобы найти эту схему URL:

- (BOOL)webView:(UIWebView *)browser shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if([request.URL.scheme isEqualToString:kPageLoadedScheme]){
        _js_load_indicator_inserted = NO;
        NSString* loaded_url = [request.URL absoluteString];
        loaded_url = [loaded_url substringFromIndex:[loaded_url rangeOfString:@":"].location+1];

        <DO STUFF THAT SHOULD HAPPEN WHEN THE PAGE LOAD FINISHES.>

        return NO;
    }
}

Ответ 5

Вы также можете использовать принятый ответ здесь: UIWebView - как идентифицировать "last" Сообщение webViewDidFinishLoad?...

В принципе, используйте свойство valuProgress, и когда это достигает 100, страница закончила загрузку... Обратитесь это руководство для справки.

Хотя он использует частную структуру, в соответствии с руководство, в App Store есть несколько приложений...

Ответ 6

Сделайте свой контроллер просмотра делегатом UIWebView. (Вы можете сделать это в Interface Builder или с помощью этого кода в методе viewDidLoad:

[self.myWebView setDelegate:self];

Затем используйте метод, описанный в принятом ответе здесь: webViewDidFinishLoad: слишком скоро стрелять?.

Код:

-(void) webViewDidFinishLoad:(UIWebView *)webView
{
    NSString *javaScript = @"function myFunction(){return 1+1;}";
    [webView stringByEvaluatingJavaScriptFromString:javaScript];

    //Has fully loaded, do whatever you want here
}

Ответ 7

WKWebView вызывает делегат didFinish, когда DOM readyState interactive, что слишком рано для веб-страниц, загруженных javascripts. Нам нужно подождать состояния complete. Я создал такой код:

func waitUntilFullyLoaded(_ completionHandler: @escaping () -> Void) {
    webView.evaluateJavaScript("document.readyState === 'complete'") { (evaluation, _) in
        if let fullyLoaded = evaluation as? Bool {
            if !fullyLoaded {
                DDLogInfo("Webview not fully loaded yet...")
                DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
                    self.waitUntilFullyLoaded(completionHandler)
                })
            } else {
                DDLogInfo("Webview fully loaded!")
                completionHandler()
            }
        }
    }
}

а затем:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    DDLogInfo("Webview claims that is fully loaded")

    waitUntilFullyLoaded { [weak self] in
        guard let unwrappedSelf = self else { return }

        unwrappedSelf.activityIndicator?.stopAnimating()
        unwrappedSelf.isFullLoaded = true
    }
}

Ответ 8

Здесь приведена упрощенная версия @jasonjwwilliams.

#define JAVASCRIPT_TEST_VARIBLE @"window.IOSVariable"
#define JAVASCRIPT_TEST_FUNCTION @"IOSFunction"
#define LOAD_COMPLETED @"loaded"

// Put this in your init method
// In Javascript, first define the function, then attach it as a listener.
_javascriptListener = [NSString stringWithFormat:
    @"function %@() {\
         %@ = '%@';\
    };\
    window.addEventListener(\"load\", %@, false);",
        JAVASCRIPT_TEST_FUNCTION, JAVASCRIPT_TEST_VARIBLE, LOAD_COMPLETED, JAVASCRIPT_TEST_FUNCTION];

// Then use this:

- (void)webViewDidFinishLoad:(UIWebView *)webView;
{
    // Only want to attach the listener and function once.
    if (_javascriptListener) {
        [_webView stringByEvaluatingJavaScriptFromString:_javascriptListener];
        _javascriptListener = nil;
    }

    if ([[webView stringByEvaluatingJavaScriptFromString:JAVASCRIPT_TEST_VARIBLE] isEqualToString:LOAD_COMPLETED]) {
        NSLog(@"UIWebView object has fully loaded.");
    }
}

Ответ 9

Благодаря JavaScript новые ресурсы и новая графика могут быть загружены навсегда - определение того, когда загрузка "сделана", для страницы с достаточной степенью извращения, будет означать решение проблема с остановкой. Вы действительно не можете знать, когда страница загружена.

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

Ответ 10

Поскольку все эти ответы webViewDidFinishLoad а webViewDidFinishLoad, а многие головные боли позже позвольте мне объяснить, как точно узнать, когда страница закончила загрузку в веб-комплекте (webview) с помощью swift 4.2.

class ViewController: UIViewController, WKNavigationDelegate {

    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!

    override func viewDidLoad() {

        webView.navigationDelegate = self

    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

    // it is done loading, do something!

    }

}

Конечно, мне не хватает другого кода по умолчанию, поэтому вы добавляете в свои существующие функции.