iOS tutorial – Intercettare e gestire inapp i click sui link di una UIWebView

ELbuild sviluppo applicazioni iOS

ELbuild sviluppo applicazioni iOSLo sviluppo di applicazioni mobili, sia Android che iOS, fa largo uso delle webview ovvero componenti specializzate che consentono di caricare una porzione di una pagina web ed inserirla all’interno della nostra applicazione. I vantaggi di una scelta di design che include una webview sono la possibilità di riusare codice esistente e la sostanziale platform independence di questo meccanismo. D’altra parte a prima vista risulta complesso gestire click su elementi della pagina e tradurli in chiamate a metodi nel codice nativo. Vediamo in questo breve tutorial come invocare metodi nel codice iOS al click di un determinato link su una UIWebView.

La struttura dell’applicazione

La struttura è quella classica, supponiamo di aver una View, con sopra una UIWebView, entrambe che delegano una classe che implementa UIViewController, di cui sotto vediamo il .h.

//
// MyViewController.h
// TutorialAPP
//
// Created by Luca Adamo on 07/07/12.
// Copyright 2012 ELbuild. All rights reserved.
//

#import <UIKit/UIKit.h>

CGFloat animatedDistance;

@interface UserViewController : UIViewController <UIWebViewDelegate>{
 IBOutlet UIView *mainView;
 IBOutlet UIWebView *myWebView;
 IBOutlet UIActivityIndicatorView *loader;
}

@end

Il punto sta proprio nell’utilizzare il meccanismo della delegation, di fatto assegnando alla classe MyViewController il compito di gestire alcuni aspetti del caricamento delle richieste provenienti dalla UIWebView stessa.

Struttura della pagina

Prima di vedere il resto del codice, ovvero l’implementazione di MyViewController, vediamo che modifiche è necessario apportare ai link della pagina caricata attraverso la webview.

L’unica modifica da fare è quella di strutturare i link da gestire come sotto:

<a href="inapp://my_action">
 My Custom content
</a>

Questo link ha la differenza di avere uno schema non gestito direttamente dalla UIWebView e che quindi può essere intercettato ed interpretato da uno dei metodi dell’interfaccia UIWebViewDelegate.

Implementazione MyViewController

Sotto l’implementazione di MyViewController. Il “segreto” sta nel metodo shouldStartLoadWithRequest che viene invocato prima del load di ogni richiesta con il contract di ritornare un boolean indicante se far gestire o meno la richiesta alla webview delegante. In questo caso un semplice controllo sullo schema ci permette di NON passare la richiesta alla UIWebView e reagire chiamando codice nativo. Ideale ad esempio per chiudere UIWebView che occupano tutto lo schermo.

Sotto il codice commentato:


//
// MyViewController.m
// TutorialAPP
//
// Created by Luca Adamo on 07/07/12.
// Copyright 2012 ELbuild. All rights reserved.
//
#import "NSString+MD5.h"
#import "UserViewController.h"
#import "APPSession.h"

@implementation UserViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
 self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
 if (self) {
 // Custom initialization
 }
 return self;
}

- (void)didReceiveMemoryWarning
{
 // Releases the view if it doesn't have a superview.
 [super didReceiveMemoryWarning];

 // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

/*
 // Implement loadView to create a view hierarchy programmatically, without using a nib.
 - (void)loadView
 {
 }
 */

/*
 // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
 - (void)viewDidLoad
 {
 [super viewDidLoad];
 }
 */

- (void)viewDidUnload
{
 [super viewDidUnload];
 // Release any retained subviews of the main view.
 // e.g. self.myOutlet = nil;
 self.mainView = nil;
 self.myWebView = nil;
}

- (void)viewDidLoad
{
 mainView.delegate = self;
 myWebView.delegate = self;
}

-(void)viewWillAppear:(BOOL)animated{

}

// UIWebViewDelegate stuff here

// Animating a loader during load. Stop
- (void)webViewDidFinishLoad:(UIWebView *)webView {
 loader.hidden= TRUE;
 [loader stopAnimating];
}

// Animating a loader during load. Start
- (void)webViewDidStartLoad:(UIWebView *)webView {
 loader.hidden= FALSE;
 [loader startAnimating];
}

// Handle events coming from click on links inside the delegating webview. We return YES for anything different than "inapp"
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {

 // check if schema match the reserved schema intended for inapp actions
 if ([request.URL.scheme isEqualToString:@"inapp"]) {
 // we can handle multiple actions so we can check if the click comes from inapp://my_action
 if ([request.URL.host isEqualToString:@"my_action"]) {
 // put custom native code here!

 // end of native code
 }
 return NO;
 }
 return YES;
}

@end

Conclusioni

Abbiamo visto come, utilizzando uno schema alternativo nei propri link, si può invocare un’azione od un metodo nel codice nativo, a partire da un qualsiasi elemento HTML di una UIWebView. Anche Android dispone di un sistema simile, che poggia sul concetto di Intent ma per questo ci sarà un altro post.

Autore: Luca Adamo

Luca Adamo si è laureato con lode in Ingegneria delle Telecomunicazioni all'Università degli studi di Firenze ed è dottorando in Ingegneria Informatica, Multimedialità e Telecomunicazioni, sempre nella stessa facoltà. Le sue competenze tecniche includono lo sviluppo software, sia orientato al web che desktop, in C/C++ e Java (J2EE, J2SE, J2ME), l'amministrazione di macchine Unix-based, la gestione di reti di telecomunicazioni, ed il design di database relazionali.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *