2014-09-30 6 views
30

Ich habe ein Modul in meiner iOS 7+ App, die ein UIWebView ist. Die HTML-Seite lädt ein Javascript, das benutzerdefinierte Schaltflächen (mit der Raphaeljs-Bibliothek) erstellt. Mit UIWebView setze ich delegate auf self. Die Delegate-Methode webView: shouldStartLoadWithRequest: navigationType: wird jedes Mal aufgerufen, wenn eine meiner benutzerdefinierten Schaltflächen gedrückt wird. Die Anfragen sollten nicht vom HTML, sondern vom iOS Code bearbeitet werden. Also habe ich eine Anforderungskonvention (hier irgendwo auf stackoverflow) mit "inapp" als Schema meiner Anfragen verwendet. Ich checke dann nach dem Gastgeber und ergreife die entsprechende Aktion.UIWebView Delegate-Methode sollteStartLoadWithRequest: Entsprechung in WKWebView?

Dieser Code funktioniert gut auf iOS 7. Aber die Web-Ansichten erscheinen leer auf iOS 8 (Bug?), So entschied ich mich, WKWebView für iOS 8 Geräte zu verwenden. Die Web-Ansichten werden jetzt gut dargestellt (und unglaublich schneller!), Aber meine Schaltflächen haben keine Wirkung.

Ich versuchte mit - (WKNaviation *)loadRequest:(NSURLRequest *)request, aber es heißt nicht.

Ich kann keine direkte Entsprechung der UIWebView-Delegate-Methode webView: shouldStartLoadWithRequest: navigationType: finden. Was ist der beste Weg, um diese Anfragen mit WKWebView zu bearbeiten?

Antwort

7

Re-Lesen Sie Ihre Beschreibung Es sieht aus, als was Sie tatsächlich wissen müssen ist, wie eine Javascript/Objective-C Brücke mit WKWebView neu zu implementieren.

Ich habe dies selbst gerade getan, nach dem Tutorial http://tetontech.wordpress.com/2014/07/17/objective-c-wkwebview-to-javascript-and-back/ und die Informationen an http://nshipster.com/wkwebkit/

WKWebView hat eine eingebaute Möglichkeit, zwischen Javascript der Kommunikation und Objective-C/Swift: WKScriptMessageHandler.

Zunächst sind die WebKit-Header und WKScriptMessageHandler Protokoll in Ihrem View-Controller-Header:

#import <UIKit/UIKit.h> 
#import <WebKit/WebKit.h> 
@interface ViewController : UIViewController <WKScriptMessageHandler> 

@end 

Die, wenn Ihr WKWebView Initialisierung, müssen Sie es mit einem Skript Message-Handler konfigurieren. Nennen Sie es, was immer Sie wollen, aber für mich scheint es, als würde es für Ihre App einen Sinn ergeben.

WKWebViewConfiguration *theConfiguration = 
      [[WKWebViewConfiguration alloc] init]; 
    [theConfiguration.userContentController 
      addScriptMessageHandler:self name:@"myApp"]; 

    _theWebView = [[WKWebView alloc] initWithFrame:self.view.frame 
         configuration:theConfiguration]; 
    [_theWebView loadRequest:request]; 
    [self.view addSubview:_theWebView]; 

Jetzt implementieren userContentController:didReceiveScriptMessage:. Dies wird ausgelöst, wenn Ihr Webview eine Nachricht empfängt, so dass es die Arbeit erledigt, die Sie zuvor mit webView:shouldStartLoadWithRequest:navigationType: gemacht haben.

- (void)userContentController:(WKUserContentController *)userContentController 
         didReceiveScriptMessage:(WKScriptMessage *)message { 
    NSDictionary *sentData = (NSDictionary *)message.body; 
    NSString *messageString = sentData[@"message"]; 
    NSLog(@"Message received: %@", messageString); 
} 

Sie können jetzt Nachrichten von Javascript empfangen. Die Funktion rufen Sie Ihre Javascript hinzufügen müssen, ist dies:

window.webkit.messageHandlers.myApp.postMessage({"message":"Hello there"}); 
+0

Zuerst entschuldige ich mich für die Verzögerung. Ich habe Ihre Lösung für einen meiner Links getestet und es hat funktioniert. Vielen Dank! Ich werde die Lösung jetzt überall anwenden. Obwohl ich meinen Webinhalt auf dem Simulator sehen kann, kann ich ihn auf meinem Gerät nicht sehen. Auf dem Gerät sehe ich immer noch eine leere Seite. Irgendeine Idee warum? – invalidArgument

+1

@invalidArgument Laden Sie den Web-Content aus dem Internet oder aus Ihrem Bundle? Weil ich seitdem gelernt habe, gibt es einen kleinen Fehler in WKWebView zum Laden von lokalen Inhalten: http://stackoverflow.com/questions/24882834/wkwebview-not-working-in-ios-8-beta-4 – SeanR

+0

Es ist aus meinem Bündel geladen. Ich habe gerade eine Frage gestellt, die ausschließlich dem Problem der leeren Seite gewidmet ist: http://stackoverflow.com/q/26455432/873436. Dieser Link war sehr hilfreich, danke nochmal. Es führte jedoch zu einem anderen Problem. – invalidArgument

57

Ich habe selbst nach einer guten Erklärung gesucht, aber keine gefunden. Ich habe die folgende in meiner Anwendung verwendet und alles scheint zu funktionieren (Edit: auf ccoroom's comment Basis aktualisiert):

UIWebViewDelegate  - webView:shouldStartLoadWithRequest:navigationType: 
WKNavigationDelegate - webView:decidePolicyForNavigationAction:decisionHandler: 

Hier ist die andere UIWebViewDelegate Methoden:

UIWebViewDelegate  - webViewDidStartLoad: 
WKNavigationDelegate - webView:didCommitNavigation: 

UIWebViewDelegate  - webViewDidFinishLoad: 
WKNavigationDelegate - webView:didFinishNavigation: 

UIWebViewDelegate  - webView:didFailLoadWithError: 
WKNavigationDelegate - webView:didFailNavigation:withError: 
         - webView:didFailProvisionalNavigation:withError: 

Ich würde gerne für jemand, der das für mich bestätigt.

Edit: Eigentlich habe ich die Frage beantwortet man im Titel hatte (obwohl ich bin nicht mehr davon überzeugt, dass webView:didCommitNavigation: an dem exakt gleichen Zeitpunkt im Lebenszyklus genannt wird), aber Re-Lektüre Ihre Beschreibung es Es sieht so aus, als ob Sie tatsächlich wissen müssen, wie Sie eine Javascript/Objective-C-Brücke mit WKWebView neu implementieren können. Sehen Sie sich meine andere Antwort an.

+0

Vielleicht vermisse ich etwas, aber ein großer Unterschied zwischen webView: s houldStartLoadWithRequest: navigationType: und webView: didStartProvisionalNavigation: scheint zu sein, dass letzterer NSUrlRequest nicht bekommt. Wie erhalten Sie Informationen über die Anfrage? – ajh158

+0

@ ajh158 Sie können die URL von WkWebView.URL abrufen, aber ich bin mir nicht sicher über andere Anfragedetails. – SeanR

+0

Ich würde nicht sagen, Ihre ersten beiden sind gleich, da Sie die Anfrage nicht auswerten und in WKNavigationDelegate stoppen können. –

0

Sie Observer für Ihren WKWebView hinzufügen

static void* keyValueObservingContext = &keyValueObservingContext; 

[webView addObserver:self forKeyPath:@"URL" options:0 context:keyValueObservingContext]; 


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 

if ([keyPath isEqualToString:@"URL"]){ 
// do something 
    } 
} 

nicht in viewWillDisappear zu entfernen Vergessen

-(void)viewWillDisappear:(BOOL)animated{ 
[super viewWillDisappear:animated]; 
[webView removeObserver:self forKeyPath:@"URL"]; 
} 
59

Um die ursprüngliche Frage zu beantworten, ist das Äquivalent von webView:shouldStartLoadWithRequest:navigationType: in UIWebView webView:decidePolicyForNavigationAction:decisionHandler: in WKWebView. Diese Methoden werden vor jeder Anforderung aufgerufen (einschließlich der ursprünglichen Anforderung) und bieten die Möglichkeit, sie zuzulassen/zu verbieten.

+3

die richtige Antwort meiner Meinung nach –

26

einfach die folgende Methode verwenden, ist es ein Teil von WKNavigationDelegate

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { 

    NSURLRequest *request = navigationAction.request; 
    NSString *url = [[request URL]absoluteString]; 

    decisionHandler(WKNavigationActionPolicyAllow); 
} 
5

In Swift Sie etwas tun können:

func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) { 

    switch navigationAction.request.URLString { 
    case "http://action.is.needed/some-action": 
     self.someFunc() 
     decisionHandler(.Cancel) 
     break 
    default: 
     decisionHandler(.Allow) 
     break 
    } 

} 

Und dies ist der Link in Web-Seite:

<a href="http://action.is.needed/some-action">Hello world!</a>