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

WKWebView оценивает возвращаемое значение JavaScript

Мне нужно изменить функцию для оценки JavaScript с UIWebView на WKWebView. Мне нужно вернуть результат оценки в этой функции.

Теперь я звоню:

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

Но мне нужно получить результат, как возвращаемое значение, как в UIWebView. Можете ли вы предложить решение?

4b9b3361

Ответ 1

Обновление: это больше не работает на iOS 12+.


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

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

Вот исходный код расширения категории, который я сейчас использую:

@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

Пример кода:

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

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

Ответ 2

Это решение также работает, если код javascript вызывает 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;
}

Ответ 3

Я просто наткнулся на ту же проблему и написал для нее небольшой Swift (3.0) расширение WKWebView, подумал, что могу поделиться им:

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

Ответ 4

Я обнаружил, что значение конечного оператора в вашем вложенном javascript - это возвращаемое значение, переданное как аргумент id функции завершения, если исключений нет. Итак, например:

[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);
    }
}];