2014-11-06 14 views
22

Tôi cần thay đổi một hàm để đánh giá JavaScript từ UIWebView đến WKWebView. Tôi cần trả lại kết quả đánh giá trong hàm này.WKWebView đánh giá giá trị trả về JavaScript

Bây giờ, tôi kêu gọi:

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

Nhưng tôi cần phải có được kết quả như giá trị trả về, như trong UIWebView. Bạn có thể đề xuất giải pháp không?

+0

'NSString * returnVal = [self.webXem chuỗiByEvaluatingJavaScriptFromString: @" func (\ "arg \") "];' không làm việc này? – l0gg3r

+0

Không có chức năng này trong UIWebView và đang hoạt động, tôi cần thay đổi nó thành WKWebView. Tôi có thể giải quyết nó với một số cuộc gọi lại, nhưng nó quá phức tạp trong dự án của tôi. – redak105

+0

hm ... lạ, đầu ra của bàn điều khiển là gì? sau NSLogs – l0gg3r

Trả lời

25

Tôi đã giải quyết vấn đề này bằng cách đợi kết quả cho đến khi giá trị kết quả được trả về.

tôi đã sử dụng NSRunLoop chờ đợi, nhưng tôi không chắc chắn đó là cách tốt nhất hay không ...

Đây là mã nguồn mở rộng chủng loại mà tôi đang sử dụng bây giờ.

@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 

Ví dụ mã)

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

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

Sử dụng stringByEvaluatingJavaScriptFromString: name để thay thế mã UIWebView hiện tại của bạn bị ảnh hưởng. –

+3

Vấn đề với mã này là nếu một lỗi JS được nâng lên, hàm gốc của bạn sẽ chạy vô hạn! Giải pháp sẽ là kiểm tra khối boolean an toàn thay vì resultString. Nhìn bên dưới – Brams

+0

Đánh dấu cái này lên lần đầu tiên (và kết thúc một buổi sáng đầy đủ của WTF). Vui lòng cập nhật câu trả lời này để sử dụng BOOL là séc đã hoàn thành được ghi chú bên dưới cho 5 sao. – eGanges

16

Giải pháp này cũng làm việc nếu mã của javascript nâng 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; 
} 
10

Tôi chỉ cần stumbled về cùng một vấn đề và viết một chút Swift (3.0) Tiện ích mở rộng WKWebView cho nó, nghĩ rằng tôi có thể chia sẻ nó:

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

Tôi không thể sử dụng mã của bạn vì RunLoop. Trình biên dịch của tôi không thể tìm thấy biến RunLoop. Tôi đã nhập WKWebKit và Foundation ... Khi tôi sử dụng NSRunLoop.currentRunLoop(). Run() nó tiếp tục chạy, và tôi không thể nói trong bao lâu để chạy. Tôi đang làm gì sai? –

+0

Tôi đã sử dụng: NSRunLoop.currentRunLoop(). RunMode ("NSDefaultRunLoopMode", beforeDate: NSDate.distantFuture()) làm việc này! Cảm ơn câu trả lời của bạn!!! –

2

Tôi đã tìm thấy rằng giá trị của câu lệnh cuối cùng trong javascript được chèn của bạn là giá trị trả về được chuyển thành đối số id cho hàm hoàn thành, nếu không có ngoại lệ. Vì vậy, ví dụ:

[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); 
    } 
}]; 
Các vấn đề liên quan