web-dev-qa-db-fra.com

WKWebView évalue la valeur de retour JavaScript

J'ai besoin de changer une fonction pour évaluer JavaScript de UIWebView à WKWebView. J'ai besoin de retourner le résultat de l'évaluation dans cette fonction.

Maintenant, j'appelle:

[wkWebView evaluateJavaScript:call completionHandler:^(NSString *result, NSError *error)
{
    NSLog(@"Error %@",error);
    NSLog(@"Result %@",result);
}];

Mais j'ai besoin d'un résultat comme la valeur de retour, comme dans UIWebView. Pouvez-vous proposer une solution?

29
redak105

Mise à jour: cela ne fonctionne plus sur iOS 12+.


J'ai résolu ce problème en attendant le résultat jusqu'à ce que la valeur du résultat soit renvoyée.

J'ai utilisé NSRunLoop pour attendre, mais je ne suis pas sûr que ce soit le meilleur moyen ou non ...

Voici le code source de l'extension de catégorie que j'utilise maintenant:

@interface WKWebView(SynchronousEvaluateJavaScript)
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
@end

@implementation WKWebView(SynchronousEvaluateJavaScript)

- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
{
    __block NSString *resultString = nil;
    __block BOOL finished = NO;

    [self evaluateJavaScript:script completionHandler:^(id result, NSError *error) {
        if (error == nil) {
            if (result != nil) {
                resultString = [NSString stringWithFormat:@"%@", result];
            }
        } else {
            NSLog(@"evaluateJavaScript error : %@", error.localizedDescription);
        }
        finished = YES;
    }];

    while (!finished)
    {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }

    return resultString;
}
@end

Exemple de code:

NSString *userAgent = [_webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];

NSLog(@"userAgent: %@", userAgent);
30
UnknownStack

Cette solution fonctionne également si le code du javascript déclenche NSError:

- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script {
    __block NSString *resultString = nil;
    __block BOOL finished = NO;

    [self evaluateJavaScript:script completionHandler:^(id result, NSError *error) {
        if (error == nil) {
            if (result != nil) {
                resultString = [NSString stringWithFormat:@"%@", result];
            }
        } else {
            NSLog(@"evaluateJavaScript error : %@", error.localizedDescription);
        }
        finished = YES;
    }];

    while (!finished)
    {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }

    return resultString;
}
18
Brams

Je suis juste tombé sur le même problème et j'ai écrit une petite extension Swift (3.0) WKWebView pour cela, j'ai pensé que je pourrais le partager:

extension WKWebView {
    func evaluate(script: String, completion: (result: AnyObject?, error: NSError?) -> Void) {
        var finished = false

        evaluateJavaScript(script) { (result, error) in
            if error == nil {
                if result != nil {
                    completion(result: result, error: nil)
                }
            } else {
                completion(result: nil, error: error)
            }
            finished = true
        }

        while !finished {
            RunLoop.current().run(mode: .defaultRunLoopMode, before: Date.distantFuture)
        }
    }
}
12
mort3m

J'ai trouvé que la valeur de la déclaration finale dans votre javascript injecté est la valeur de retour passée comme argument id à la fonction d'achèvement, s'il n'y a pas d'exceptions. Ainsi, par exemple:

[self.webview evaluateJavaScript:@"var foo = 1; foo + 1;" completionHandler:^(id result, NSError *error) {
    if (error == nil)
    {
        if (result != nil)
        {
            NSInteger integerResult = [result integerValue]; // 2
            NSLog(@"result: %d", integerResult);
        }
    }
    else
    {
        NSLog(@"evaluateJavaScript error : %@", error.localizedDescription);
    }
}];
3
Steve Yost