2014-11-06 26 views
22

Potrzebuję zmienić funkcję do oceny JavaScript z UIWebView do WKWebView. Muszę zwrócić wynik oceny w tej funkcji.Ocena WKWebView JavaScript wartość zwracana

Teraz Wołam:

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

Ale muszę uzyskać wynik jak zwracanej wartości, jak w UIWebView. Czy możesz zaproponować rozwiązanie?

+0

'NSString * returnVal = [self.webView stringByEvaluatingJavaScriptFromString: @ "func (\" arg \ ")"];' nie ta praca? – l0gg3r

+0

Brak tej funkcji w UIWebView i działa, muszę zmienić ją na WKWebView. Mogę go rozwiązać za pomocą wywołania zwrotnego, ale jest to zbyt skomplikowane w moim projekcie. – redak105

+0

hm ... dziwne, co robi wyjście konsoli? po NSLogs – l0gg3r

Odpowiedz

25

Rozwiązałem ten problem, czekając na wynik, dopóki nie zostanie zwrócona wartość wyniku.

użyłem NSRunLoop oczekiwania, ale nie jestem pewien, że to najlepszy sposób, czy nie ...

Oto kod źródłowy kategoria przedłużenie że używam teraz.

@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 

Przykład kodu)

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

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

Użyj stringByEvaluatingJavaScriptFromString: wpisz zamiast tego pozostawić istniejący kod UIWebView nietknięty. –

+3

Problem z tym kodem polega na tym, że jeśli zostanie zgłoszony błąd JS, twoja natywna funkcja będzie działać bez końca! Rozwiązaniem byłoby sprawdzenie bloku bezpiecznego wartości boolowskiej zamiast metody resultString. Spójrz poniżej: – Brams

+0

Oznacz to jako pierwsze (i kończąc cały poranek WTF). Zaktualizuj tę odpowiedź, aby użyć 5-cio punktowej kontroli BOOL isFinished. – eGanges

16

To rozwiązanie działa także jeśli kod javascript podnoszą 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

Właśnie natknąłem się na ten sam problem i napisałem trochę Swift (3.0) Rozszerzenie WKWebView do tego, myślałem, że mogę się nim podzielić:

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

Nie mogę użyć twojego kodu z powodu RunLoopa. Mój kompilator nie może znaleźć zmiennej RunLoop. Zaimportowałem WKWebKit i Foundation ... Kiedy używam NSRunLoop.currentRunLoop(). Run() to działa i nie mogę powiedzieć, jak długo ma działać. Co ja robię źle? –

+0

Użyłem: NSRunLoop.currentRunLoop(). RunMode ("NSDefaultRunLoopMode", beforeDate: NSDate.distantFuture()) to działało! Dzięki za odpowiedź!!! –

2

Odkryłem, że wartość końcowego oświadczenia w wstrzykniętym javascript jest wartością zwracaną przekazywaną jako argument id do funkcji uzupełniania, jeśli nie ma wyjątków. Tak więc, na przykład:

[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); 
    } 
}]; 
Powiązane problemy