WKWebView évalue la valeur de retour JavaScript

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

maintenant, j'appelle:

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

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

25
demandé sur pkamb 2014-11-06 14:58:58

4 réponses

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

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

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);
29
répondu UnknownStack 2016-07-03 14:08:32

Cette solution fonctionne aussi si le code javascript augmente 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;
}
16
répondu Brams 2015-10-26 12:43:15

j'ai juste trébuché 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 la 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)
        }
    }
}
11
répondu mort3m 2016-06-17 01:06:35

j'ai trouvé que la valeur de la déclaration finale dans votre JavaScript injecté est la valeur de retour transmise comme argument id à la fonction completion, 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);
    }
}];
2
répondu Steve Yost 2017-03-21 18:50:26