WKWebView оценивает возвращаемое значение JavaScript
Мне нужно изменить функцию для оценки JavaScript с UIWebView на WKWebView. Мне нужно вернуть результат оценки в этой функции.
Теперь я звоню:
[wkWebView evaluateJavaScript:call completionHandler:^(NSString *result, NSError *error)
{
NSLog(@"Error %@",error);
NSLog(@"Result %@",result);
}];
Но мне нужно получить результат, как возвращаемое значение, как в UIWebView
. Можете ли вы предложить решение?
Ответы
Ответ 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);
}
}];