UIWebview vs WKWebview

UIWebview est un composant d’interface permettant d’afficher du contenu HTML directement dans une application. C’est un composant déjà ancien puisqu’il est apparu avec iOS 2. Il est fortement présent au sein de nos applications pour, par exemple, afficher le contenu des FAQ, des CGV, le tunnel de commande, la création de compte et certaines informations comme celles par exemple liées au compte utilisateur.

Avec iOS 8 Apple a mis à disposition un nouveau composant plus complet appelé WKWebview.

La principale différence entre ces deux composants c’est la performance. WKWebview charge les pages web plus rapidement et plus efficacement que UIWebview car il est exécuté dans un processus distinct de l’application en s’appuyant sur les optimisations JavaScript de Safari.

Pourquoi migrer vers WKWebview ?

Début 2020, Apple a signalé par email que le composant UIWebview ne sera plus autorisé dans les applications. Ils refuseront toute publication d’application contenant des UIWebview.

Deprecated API Usage – Apple will stop accepting submissions of apps that use UIWebView APIs starting from December 2020 .

Remplacer le composant dans l’interface

UIWebview étant un composant UIKit, il suffisait de drag & drop le composant dans votre storyboard, définir les contraintes puis le delegate et c’était réglé.

Avec WKWebview, si votre projet est toujours compatible pour les systèmes d’exploitation inférieur à iOS 11 vous ferez face au même problème que nous :

Il vous faudra intégrer votre WKWebview en code.

Importez Webkit

import WebKit
#import <WebKit/WebKit.h>

Ajoutez ce code dans le viewDidLoad

let webConfiguration = WKWebViewConfiguration()
let frame = view.bounds
let webView = WKWebView(frame: frame, configuration: webConfiguration)
webView.navigationDelegate = self
webView.clipsToBounds = true
view.addSubview(webView)

let urlRequest = URLRequest(url: url)
webView.load(urlRequest)
WKWebViewConfiguration *webConfiguration = [[WKWebViewConfiguration alloc] init];
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:webConfiguration];
webView.navigationDelegate = self;
webView.clipsToBounds = true;
[self.view addSubview:webView];

NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];

Définissez les contraintes de votre webview (nous vous conseillons d’utiliser une librairie afin de simplifier l’écriture des contraintes en code, nous utilisons ***Masonry***)

webView.mas_makeConstraints { make in
		_ = make?.edges.equalTo()(self.view)
}
[webView mas_makeConstraints:^(MASConstraintMaker *make) {
		make.edges.equalTo(self.view);
}];

Les delegates

Puisqu’il est parfois compliqué de trouver l’équivalent des méthodes qu’on utilise habituellement avec UIWebview voici une liste qui pourra vous aider.

Méthode permettant de détecter le chargement de la UIWebview.

func webViewDidStartLoad(_ webView: UIWebView)
-(void)webViewDidStartLoad:(UIWebView*)webView;

Devient pour une WKWebview.

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;

Méthode permettant de détecter que la UIWebview a terminé de charger son contenu.

func webViewDidFinishLoad(_ webView: UIWebView)
- (void)webViewDidFinishLoad:(UIWebView*)webView;

Devient pour une WKWebview.

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation;

Méthode permettant de détecter que le chargement a échoué.

func webView(_ webView: UIWebView, didFailLoadWithError error: Error)
-(void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error;

Devient pour une WKWebview

//Invoked when an error occurs during a committed main frame navigation.
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error)
//Invoked when an error occurs while starting to load data for the main frame.
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error)
//Invoked when an error occurs during a committed main frame navigation.
- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;
//Invoked when an error occurs while starting to load data for the main frame.
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error;

Méthode permettant de définir une action en fonction des paramètres présent dans l’url ou d’intercepter des ancres.

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebView.NavigationType) -> Bool {
	return true //or false
}
-(BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
	return true //or false
}

Devient pour une WKWebview

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
		decisionHandler(.allow) //or decisionHandler(.false)
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
		decisionHandler(WKNavigationActionPolicyAllow); //or decisionHandler(WKNavigationActionPolicyCancel);
}

Les requêtes POST

Afin d’appeler une requête en POST avec une WKWebview, il vous faudra préciser les Headers dans votre requête pour ne pas avoir une page blanche.

var request = URLRequest(url: url)
request.httpMethod = "POST"
            
let params = "your_query_params_as_string"
request.httpBody = params.data(using: .utf8)
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.initialUrl];
[request setHTTPMethod:@"POST"];

NSString *params = @"your_query_params_as_string"
[request setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

N’hésitez pas à nous contacter si vous souhaitez en savoir plus ou mettre à profit nos compétences pour réaliser votre projet.