ios WKWebView评估JavaScript返回值

j13ufse2  于 2022-12-27  发布在  iOS
关注(0)|答案(9)|浏览(204)

我需要更改一个函数来评估JavaScript从UIWebView到WKWebView。我需要返回这个函数的评估结果。
现在,我打电话:

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

但是我需要得到像UIWebView那样的返回值,你能建议一个解决方案吗?

nzkunb0c

nzkunb0c1#

    • 更新:这在iOS 12+上不再有效。**

我通过等待result直到返回result值来解决这个问题。
我使用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);
cs7cruho

cs7cruho2#

如果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;
}
kkbh8khc

kkbh8khc3#

我刚刚遇到了同样的问题,并为它写了一个小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)
        }
    }
}
kmb7vmvb

kmb7vmvb4#

根据mort@3m的回答,下面是一个与Swift 5一起工作的WKWebView扩展。

extension WKWebView {
    func evaluate(script: String, completion: @escaping (Any?, Error?) -> Void) {
        var finished = false

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

        while !finished {
            RunLoop.current.run(mode: RunLoop.Mode(rawValue: "NSDefaultRunLoopMode"), before: NSDate.distantFuture)
        }
    }
}
tyu7yeag

tyu7yeag5#

我发现如果没有异常的话,在你注入的javascript中final语句的值是作为id参数传递给completion函数的返回值。

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

5q4ezhmt6#

基于mort@3m的评论。这是Objective-C的工作版本。

@implementation WKWebView(SynchronousEvaluateJavaScript)

- (void)stringByEvaluatingJavaScriptFromString:(NSString *)script completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler
{
    __block BOOL finished = FALSE;
    [self evaluateJavaScript:script completionHandler:^(id result, NSError *error) {
        if (error == nil) {
            if (result != nil) {
                completionHandler(result, error);
            }
        } else {
            completionHandler(NULL, error);
        }
        finished = TRUE;
    }];

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

@end
np8igboo

np8igboo7#

只有这个工作,上面的答案对我不起作用.

- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
{
    __block NSString *resultString = nil;
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    [self evaluateJavaScript:script completionHandler:^(id result, NSError *error) {
        if (error == nil) {
            if (result != nil) {
                resultString = [NSString stringWithFormat:@"%@", result];
            }
        } else {
            NSLog(@"evaluateJavaScript error : %@", error.localizedDescription);
        }
        dispatch_semaphore_signal(sem);
    }];
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    
    return resultString;
}
jpfvwuh4

jpfvwuh48#

雨燕5.7

let js = """
function add(x, y) {
    return x + y
}

add(1, 2)
"""

webView.evaluateJavaScript(js) { res, err in
    print("res : \(res)") 
}

应该够了
没有必要写任何额外的仪式和样板代码以外的。
目前不推荐,但如果您更喜欢async/await:

(注意,如果js中没有指定返回值,它将由于Swift内部错误而崩溃,我猜是这样。我不确定原因)

let js = """
function add(x, y) {
    return x + y
}

add(1, 2)
"""

Task {
    let res = try? await webView.evaluateJavaScript(js)
    print("res : \(res)")
}
smtd7mpg

smtd7mpg9#

可以使用调度信号量,在**iOS12 +**上工作
示例:

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

    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);

    //process resultString here.

相关问题