web-dev-qa-db-fra.com

UIWebView: Quand une page a-t-elle vraiment été chargée?

J'ai besoin de savoir quand une page Web a été complètement chargée par UIWebView. Je veux dire, vraiment complètement, lorsque toutes les redirections sont effectuées et que le contenu chargé dynamiquement est prêt ..__ J'ai essayé d'injecter du javascript (interrogation de document.readyState == 'complete'), mais cela ne semble pas très fiable.

Y at-il, peut-être, un événement de l’API privée qui m’apportera le résultat?

28
Sebastian

Je cherchais la réponse, et j'ai eu cette idée de la question de Sebastian. D'une certaine manière, cela fonctionne pour moi, peut-être que cela fonctionnera pour ceux qui rencontrent ce problème.

Je règle un délégué sur UIWebView et dans le webViewDidFinishLoad, je détecte si le chargement de la vue Web est vraiment terminé en exécutant un Javascript.

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

Ma solution:

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

La capacité de UIWebView à exécuter Javascript est indépendante du fait qu'une page ait été chargée ou non. Son utilisation possible stringByEvaluatingJavaScriptFromString: exécuter le code Javascript avant même d'avoir appelé pour charger une page dans UIWebView ou ne pas charger de page. 

Par conséquent, je ne comprends pas comment la réponse de ce lien est acceptée: webViewDidFinishLoad: Vous déclenchez-vous trop tôt? car appeler any Javascript ne vous dit rien du tout (s’ils appellent un Javascript intéressant, qui surveille le dom par exemple, ils ne font aucune mention de cela et s’il existe étaient-ils parce que c'est important).

Vous pouvez appeler du code Javascript qui, par exemple, examine l’état du dom ou de la page chargée et le signale au code appelant. Toutefois, s’il signale que la page n’a pas encore été chargée, que faites-vous? - vous devrez le rappeler un peu plus tard, mais combien de temps plus tard, quand, où, comment, combien de fois, .... .__ Les sondages ne sont généralement jamais une solution intéressante pour rien.

Le seul moyen de savoir quand la page est totalement chargée et précise et en contrôle le contenu exact est de le faire vous-même - attachez des écouteurs d'événements JavaScript à la page en cours de chargement et demandez-leur d'appeler votre shouldStartLoadWithRequest: avec des url. Vous pouvez, par exemple, créer une fonction JS pour écouter un événement de chargement de fenêtre ou de préparation de dom, etc. selon que vous avez besoin de savoir quand la page a été chargée, ou si seul le dom a été chargé, etc. En fonction de vos besoins.

Si la page Web ne vous appartient pas, vous pouvez insérer ce code dans un fichier et l'injecter dans toutes les pages que vous chargez.

Comment créer les écouteurs d'événements javascript est un script javascript standard, rien de spécial à faire avec iOS, par exemple, voici le code JavaScript à détecter lorsque le dom est chargé dans un formulaire pouvant être injecté dans la page de chargement à partir de UIWebView, puis générer un appel à shouldStartLoadWithRequest: (cela invoquerait devraitStartLoadWithRequestquand: le dom a fini de se charger, avant que le contenu de la page ne soit affiché, pour le détecter, changez simplement l'écouteur d'événements).

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();
10
Gruntcakes

La réponse de Martin H est sur la bonne voie, mais elle peut toujours être renvoyée plusieurs fois.

Ce que vous devez faire, c'est ajouter un écouteur Javascript onLoad à la page et savoir si vous avez déjà inséré l'écouteur:

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

- (NSString*) javascriptOnLoadCompletionHandler {
    return [NSString stringWithFormat:@"var %1$@ = function() {window.location.href = '%2$@:' + window.location.href; window.%3$@ = 'loaded'}; \
    \
    if (window.attachEvent) {window.attachEvent('onload', %1$@);} \
    else if (window.addEventListener) {window.addEventListener('load', %1$@, false);} \
    else {document.addEventListener('load', %1$@, 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;
}

Une fois le chargement de la page terminé, l’écouteur Javascript déclenche un nouveau chargement de page de l’URL pageloaded:<URL that actually finished>. Ensuite, il vous suffit de mettre à jour shouldStartLoadWithRequest pour rechercher ce schéma d'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;
    }
}
4
jasonjwwilliams

Vous pouvez également utiliser la réponse acceptée ici: UIWebView - Comment identifier le "dernier" message webViewDidFinishLoad? ...

Fondamentalement, utilisez la propriété ratedProgress et lorsque le nombre atteint 100, le chargement de la page est terminé ... Voir ce guide pour obtenir de l'aide.

Bien qu'il utilise un cadre privé, d'après the guide , certaines applications de l'App Store l'utilisent ...

3
gtmtg

WKWebView appelle le délégué didFinish lorsque l'état readyState de DOM est interactive, ce qui est trop tôt pour les pages Web chargées de javascripts. Nous devons attendre l'état complete. J'ai créé un tel code:

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()
            }
        }
    }
}

et alors:

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
    }
}
2
konradowy

Faites de votre contrôleur de vue un délégué de UIWebView. (Vous pouvez le faire dans Interface Builder ou en utilisant ce code dans la méthode viewDidLoad:

[self.myWebView setDelegate:self];

Utilisez ensuite la méthode décrite dans la réponse acceptée ici: webViewDidFinishLoad: Vous déclenchez-vous trop tôt? .

Le code:

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

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

Voici une version simplifiée de la réponse de @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.");
    }
}
0
Chris Prince

Puisque toutes ces réponses sont anciennes et que webViewDidFinishLoad a été amorti et que de nombreux maux de tête ont été laissés plus tard, laissez-moi vous expliquer comment exactement savoir quand une page a fini de se charger dans un webkit (webview) avec 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!

    }

}

Bien sûr, il me manque une partie de l’autre code par défaut, ce qui vous permet d’ajouter à vos fonctions existantes.

0
Cesar Bielich

Grâce à JavaScript, de nouvelles ressources et de nouveaux graphiques peuvent être chargés à tout jamais. Déterminer à quel moment le chargement est "terminé", pour une page de perversité suffisante, équivaut à résoudre le problème en arrêt . Vous ne pouvez vraiment pas savoir quand la page est chargée. 

Si vous le pouvez, affichez simplement la page ou une image de celle-ci et utilisez webViewDidLoad pour mettre à jour l'image, puis laissez l'utilisateur choisir à quel moment couper ou non. 

0
Neal