WKWebView评估JavaScript返回值
我需要将一个函数从UIWebView更改为WKWebView来评估JavaScript。我需要返回这个函数中的求值结果 现在,我打电话:WKWebView评估JavaScript返回值,javascript,ios,objective-c,wkwebview,Javascript,Ios,Objective C,Wkwebview,我需要将一个函数从UIWebView更改为WKWebView来评估JavaScript。我需要返回这个函数中的求值结果 现在,我打电话: [wkWebView evaluateJavaScript:call completionHandler:^(NSString *result, NSError *error) { NSLog(@"Error %@",error); NSLog(@"Result %@",result); }]; 但我需要得到返回值这样的结果,比如在UIWeb
[wkWebView evaluateJavaScript:call completionHandler:^(NSString *result, NSError *error)
{
NSLog(@"Error %@",error);
NSLog(@"Result %@",result);
}];
但我需要得到返回值这样的结果,比如在UIWebView
中。
您能提出解决方案吗?更新:这在iOS 12+上不再有效。
我通过等待结果直到返回结果值来解决这个问题 我使用nsrunlop等待,但我不确定这是否是最好的方式 下面是我现在使用的类别扩展源代码:
@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代码出现N错误,此解决方案也可以工作:
- (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)
}
}
}
我发现注入的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);
}
}];
可以使用调度信号量。它在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.
根据@mort3m的回答,这里是一个使用Swift 5的WKWebView扩展 扩展WKWebView{ func求值(脚本:字符串,完成:@escaping(Any?,Error?)->Void){ var finished=false evaluateJavaScript(脚本,completionHandler:{(结果,错误)在 如果错误==nil{ 如果结果为!=nil{ 完成(结果为零) } }否则{ 完成(无,错误) } 完成=正确 }) 一会儿!完成了{ RunLoop.current.run(模式:RunLoop.mode(rawValue:“NSDefaultRunLoopMode”),在:NSDate.distantFuture之前) } } }
NSString*returnVal=[self.webView stringByEvaluatingJavaScriptFromString:@“func(\“arg\”)”代码>这个功能不工作吗?不,这个功能在UIWebView中并且正在工作,我需要将它更改为WKWebView。我可以通过一些回调来解决它,但是在我的项目中它太复杂了。。。奇怪,控制台输出什么?NSLOGS之后,这段代码的问题是,如果出现JS错误,您的本机函数将无限运行!解决方案是检查块安全布尔值,而不是结果字符串。在使用多个wkwebview时,查看下方将导致崩溃;这个解决方案不再有效了。回调现在从主线程调用,如果将主线程锁定在while
循环中(如本解决方案中),则永远不会调用回调处理程序evaluateJavaScript
等待主线程释放,但它从未发生,因为它锁定在循环中。对iOS 12或iOS 13有什么想法吗?此解决方案在iOS 13中不起作用。有人有iOS 13的工作解决方案吗?我不能使用你的代码,因为运行循环。我的编译器找不到RunLoop变量。我确实导入了WKWebKIT和基金会…当我使用NSRunLoop.currentRunLoop().run()时,它会一直运行,我不能说要运行多长时间。我做错了什么?我使用了:NSRunLoop.currentRunLoop().runMode(“NSDefaultRunLoopMode”,beforeDate:NSDate.distantFuture())这有效!谢谢你的回答!!!抱歉,如果您使用回调,这有什么意义?@Shizam您可能愿意确保首先加载WKWebview。当您试图检查文档是否准备好时,这种方法实际上不起作用,同时,它只适合于提取一些内部HTML。文档中说:“完成处理程序总是在主线程上运行。”因此,如果在主线程上调用此代码,它将永远阻塞。在典型的webView.evaluateJavaScript(jsCode){(值,错误)中如何使用此代码在
语句中?你必须使用这个新函数evaluate
,而不是evaluateJavaScript
。我完全没有意识到它只是evaluate
。我想是深夜吧。代码工作得很好,顺便说一句!嘿@Nicolas,我在这段代码中遇到了新的崩溃错误(我相信是由Swift 5引入的)@JustinBush我和Swift 5合作得很好。你的错误是什么?