2014-11-06 17 views
22

UIWebView ile WKWebView arasında JavaScript'i değerlendirmek için bir işlevi değiştirmem gerekiyor. Bu fonksiyonda değerlendirme sonucunu geri vermem gerekiyor.WKWebView, JavaScript dönüş değerini değerlendiriyor

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

Ama UIWebView olduğu gibi dönüş değeri gibi sonuç almak gerekir:

Şimdi, arıyorum. Bir çözüm önerebilir misiniz?

+0

'NSString * returnVal = [self.webView stringByEvaluatingJavaScriptFromString: "işlev (\" Arg \ ")" @];' olup bu iş? – l0gg3r

+0

Bu işlev UIWebView'da çalışmıyor ve çalışıyor, WKWebView'a değiştirmem gerekiyor. Bazı geri bildirimle çözebilirim ama projemde çok karmaşık. – redak105

+0

hm ... garip, konsol çıkışı nedir? NSLogs – l0gg3r

cevap

25

Bu değeri, sonuç değeri döndürülene kadar sonuç bekleyerek çözdüm.

Beklemekten için NSRunLoop kullanılan, ancak burada

şimdi kullanıyorum kategori uzatma kaynak kodu ... bu en iyi yol ya da değil emin değilim.

@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 

Örnek kodu) Bu çözüm aynı zamanda çalışır

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

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

'dan sonra mevcut UIWebView kodunuza dokunulmadan bırakmak için stringByEvaluatingJavaScriptFromString: name işlevini kullanın. –

+3

Bu kodla ilgili sorun, bir JS hatası ortaya çıkarsa, yerel işlevinizin sonsuza kadar koşacağıdır! Çözüm sonuçString yerine blok güvenli bir boolean kontrol etmek olacaktır. Aşağıya bakın – Brams

+0

Bunu ilk olarak işaretleyin (ve WTF'nin tüm sabahını bitirin). 5 yıldız için aşağıda belirtilen BOOL isFinished kontrolünü kullanmak için lütfen bu cevabı güncelleyin. Birden çok wkwebview kullanılırken – eGanges

16

javascript kodu NSError yükseltirseniz: (3.0 Sadece aynı sorun hakkında tökezledi ve biraz Swift yazdığı

- (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

) Bunun için WKWebView eklentisi, paylaşabilir miyim düşündüm:

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

Kodunuzu RunLoop nedeniyle kullanamıyorum. Derleyicim RunLoop değişkenini bulamıyor. WKWebKit ve Foundation'ı aldım ... NSRunLoop.currentRunLoop(). Run() işlevini kullandığımda çalışmaya devam ediyor ve ne kadar süreyle çalışacağımı söyleyemem. Neyi yanlış yapıyorum? –

+0

Kullanılan: NSRunLoop.currentRunLoop() runMode ("NSDefaultRunLoopMode", beforeDate: NSDate.distantFuture()) bu işe yaradı! Cevabınız için teşekkürler!!! –

2

Enjekte edilen javascript'teki son ifadenin değerinin, herhangi bir istisna yoksa, tamamlanma işlevi için id argümanı olarak iletilen dönüş değeri olduğunu buldum. Bu nedenle, örneğin:

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