WKWebView评估JavaScript返回值
WKWebView evaluate JavaScript return value
我需要将一个函数从UIWebView更改为WKWebView来评估JavaScript。我需要返回此函数中的求值结果。
现在,我打电话给:
[wkWebView evaluateJavaScript:call completionHandler:^(NSString *result, NSError *error)
{
NSLog(@"Error %@",error);
NSLog(@"Result %@",result);
}];
但我需要得到像返回值一样的结果,就像在UIWebView
中一样。你能提出一个解决方案吗?
更新:这在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);
如果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;
}
我刚刚偶然发现了同样的问题,并为它写了一个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)
}
}
}
基于@mort3m的回答,这里有一个与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)
}
}
}
我发现,如果没有异常,那么注入的javascript中final语句的值就是作为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);
}
}];
基于@mort3m的注释。这是工作的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
Swift 5.7
你只需要
webView.evaluateJavaScript("your js code") { res, err in
// TODO
}
完整的代码片段示例是
let js = """
function add(x, y) {
return x + y
}
add(1, 2)
"""
webView.evaluateJavaScript(js) { res, err in
print("res : '(res)")
}
如果您喜欢异步/等待:
let js = """
function add(x, y) {
return x + y
}
add(1, 2)
"""
Task {
let res = try? await webView.evaluate(javascript: js)
print("res : '(res)")
}
extension WKWebView {
@discardableResult
func evaluate(javascript: String) async throws -> Any {
return try await withCheckedThrowingContinuation({ continuation in
evaluateJavaScript(javascript, in: nil, in: .page) { result in
switch result {
case .success(let output):
continuation.resume(returning: output)
case .failure(let error):
continuation.resume(throwing: error)
}
}
})
}
}
只有这一点有效,以上答案对我无效。
- (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;
}
可以使用调度信号量。它适用于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.
相关文章:
- Javascript返回值只在循环中返回一次
- Javascript中带有返回值的嵌套函数
- JavaScript生成器中收益率返回值的解析
- HTML如何根据javascript函数的返回值限制文本输入
- 使用在函数外部声明的变量的 Javascript 返回值 + undefined
- 如何在Android中将Javascript返回值转换为String
- PHP 函数不会向 JavaScript 变量返回值
- 单击按钮时,使用Javascript调用并返回值
- 使用Javascript数组或JSON来存储AJAX请求的返回值,以备将来使用
- Javascript只返回键,不返回值
- 从php返回值到javascript
- Scala提升了如何运行javascript函数并将返回值存储在变量中
- Javascript 意外返回值,带有特定的缩进
- 如何在 Python 中获取此 JavaScript 函数的返回值
- 并非所有代码路径都返回值 (JavaScript)
- 难以分割数组并从其中返回值;Javascript
- 从嵌套函数返回值(Javascript)
- 为什么我得到逗号在我的返回值?JavaScript名人姓名揭示器
- 为什么我没有得到返回值JavaScript
- google maps -从嵌套函数返回值- JavaScript