2013-01-16 1 views
9

Ho un UIWebView e devo fare qualcosa quando l'utente tocca un collegamento. C'è un callback delegato che può essere utilizzato per rilevare i rubinetti:Come posso rilevare in modo affidabile un clic del collegamento in UIWebView?

- (BOOL) webView: (UIWebView*) webView 
    shouldStartLoadWithRequest: (NSURLRequest*) request 
    navigationType: (UIWebViewNavigationType) navigationType 
{ 
    if (navigationType == UIWebViewNavigationTypeLinkClicked) { 
     … 
    } 
} 

Il problema è che questo codice non gestisce tutti i clic sui link. A titolo di esempio, una pagina di Google pianura Risultati della ricerca fa qualcosa di strano con il link:

<a href="http://example.com/" class="l" onmousedown="return rwt(…)"> 
    <em>Link Text</em> 
</a> 

I risultati rwt funzione nei collegamenti non scatenanti l'evento UIWebViewNavigationTypeLinkClicked quando selezionati. C'è un modo per rilevare in modo affidabile tutti gli eventi che rientrano nel bucket "navigate verso un'altra pagina"?

risposta

6

Finora ho arrivati ​​alla seguente soluzione. In primo luogo, ho iniettare del codice JS nella pagina quando caricato:

function reportBackToObjectiveC(string) 
{ 
    var iframe = document.createElement("iframe"); 
    iframe.setAttribute("src", "callback://" + string); 
    document.documentElement.appendChild(iframe); 
    iframe.parentNode.removeChild(iframe); 
    iframe = null; 
} 

var links = document.getElementsByTagName("a"); 
for (var i=0; i<links.length; i++) { 
    links[i].addEventListener("click", function() { 
     reportBackToObjectiveC("link-clicked"); 
    }, true); 
} 

Quando utente tocca un collegamento, lo so in anticipo grazie alla chiamata webView:shouldStartLoadWithRequest: navigationType: delegato:

if ([[[request URL] scheme] isEqualToString:@"callback"]) { 
    [self setNavigationLeavingCurrentPage:YES]; 
    return NO; 
} 

Poi se un altro richiesta arriva e _navigationLeavingCurrentPage è vero, so che l'utente ha fatto clic su un collegamento anche se il flag del tipo di navigazione è UIWebViewNavigationTypeOther. Devo ancora testare la soluzione ampiamente, perché temo che porterà a dei falsi positivi.

1

Credo che ciò possa essere fatto incorporando nel codice HTML del sito Web un JavaScript personalizzato che monitorerà gli eventi e, in base all'evento che si desidera monitorare, potrebbe attivare un reindirizzamento della pagina con uno schema URL personalizzato , che puoi intercettare in shouldStartLoadWithRequest.

Qualcosa di simile a questo:

<script> 
// Function to capture events 
function captureEvent(el) { 
    window.location.href="callback://"+el.href; 
} 

var elms = document.getElementsByTagName("a"); 
for (var i=0; i<elms.length; i++) { 
    elms[i].addEventListener("onmousedown", function(){captureEvent(el)}, true); 

} 
</script> 

Poi nel shouldStartLoadWithRequest, è possibile cercare di NSURLRequest che hanno un callback: // URL regime, e fare quello che vuoi.

Questo non è stato testato, ma qualcosa di simile potrebbe portarti nella giusta direzione.

Inoltre, dal momento che questo è stato menzionato, sì, si può aggiungere lo script personalizzato a qualsiasi pagina web, utilizzando questo:

- (void)webViewDidFinishLoad:(UIWebView *)webView 
{ 
    [super webViewDidFinishLoad:webView];  
    [webView stringByEvaluatingJavaScriptFromString:@"document.body.insertAdjacentHTML('BeforeEnd','<script>....</script>');"]; 
} 
+0

Non penso che l'OP abbia il controllo della pagina Web che viene visualizzata in UIWebView. Pertanto non possono aggiungere il javascript personalizzato. –

+1

È possibile aggiungere facilmente lo script personalizzato dopo aver caricato la pagina. Vedi la mia modifica su come fare questo – Lefteris

+0

Molto bello aggiungere come aggiungere javascript personalizzato a qualsiasi pagina. –

0

Ho avuto un sacco di problemi nel farlo funzionare. L'utilizzo di un UITapGestureRecognizer funziona, tranne che riceverà sempre i tocchi, anche per i collegamenti. Sfortunatamente, i link hanno un ritardo di circa 300 ms prima di essere riconosciuti, il che significa che il riconoscimento dei gesti ottiene i tocchi prima che il collegamento venga riconosciuto, il che crea un problema di temporizzazione (anche peggio perché non si dovrebbe programmare un tempo per aspettare nel caso Apple lo cambia). Inoltre, attendere 300+ ms per il tocco offre un'esperienza utente scarsa per la mia app.

Quindi quello che ho finito è stato sovrapporre un div trasparente in cima a tutto ciò che ottiene i tocchi senza collegamento. Quindi, inserisci i collegamenti a un livello z più alto. Infine, assicurati che tutto usi ontouchend="javascript:window.location.href='...';". ontouchend agirà solo su una versione tap, che è ciò che gli utenti si aspettano. L'impostazione window.location.href carica una nuova pagina, assicurando che tutti i tocchi chiamino -webView:shouldStartLoadWithRequest:navigationType: e io possa controllare l'URL per vedere quale devo fare.

L'HTML è simile a: ... ... ... ...

(io non sono del tutto sicuro se "position: relative" pone sempre le cose nella stessa posizione altrimenti, ma ha funzionato bene per la mia pagina semplice, la tua situazione potrebbe essere diversa Tuttavia. , sarà bisogno di posizione: qualcosa al fine di ottenere z-index per lavorare)

1

È necessario aggiungere questa linea

webView.dataDetectorTypes = UIDataDetectorTypeAll;.

poi

  • (BOOL) WebView: (UIWebView *) inWeb shouldStartLoadWithRequest: (NSURLRequest *) inRequest navigationType: (UIWebViewNavigationType) Intype

metodo otterrà chiamata .