2011-01-24 14 views
52

Ho una visualizzazione Web nella mia applicazione in cui è aperto un sito (sempre uguale, è la mia pagina). Il sito ha un codice JS che carica alcune immagini dall'host remoto.Intercetta e sostituisce le richieste HTTP da WebView

Desidero intercettare le richieste a tali immagini (tramite pattern URL) e restituire il mio contenuto (ad esempio un'altra immagine) oppure lasciare la richiesta non trattata in base alla logica dell'applicazione interna.

È possibile farlo?

EDIT: Lo stato attuale della domanda ...

WebView ha una capacità di impostare un WebViewClient (come notato da Axarydax). WebViewClient avere due metodi utili

  • shouldOverrideUrlLoading
  • onLoadResource

shouldOverrideUrlLoading è in grado di intercettare qualsiasi URL di carico, se il caricamento è innescato da interazioni pagina (per esempio collegamento in una pagina viene cliccato, WebView.loadURL ("") non sta attivando questo metodo). È anche in grado di annullare il caricamento degli URL restituendo false. Questo approccio non è utilizzabile, perche 'non e' in grado di intercettare il caricamento delle risorse della pagina (e le immagini, quello che ho bisogno di intercettare, sono tali risorse di pagina).

onLoadResource si attiva ogni volta che la risorsa della pagina (e le immagini! Thx su jessyjones) si stanno caricando, ma non c'è modo di annullarla. Questo rende questo metodo non adatto anche al mio compito.

risposta

45

Sembra che l'API 11 abbia il supporto per ciò di cui hai bisogno. Vedi WebViewClient.shouldInterceptRequest().

+3

Una parola di ATTENZIONE! Se intercetti un tentativo dal browser per recuperare un'immagine (o probabilmente qualsiasi risorsa) e quindi restituire "null" (ovvero consentire a WebView di continuare a recuperare l'immagine), eventuali richieste future a questa risorsa potrebbero semplicemente andare alla cache e NON attiveranno "shouldInterceptRequest()". vuoi intercettare OGNI richiesta di immagine, devi disabilitare la cache o (cosa ho fatto) chiamare 'WebView.clearCache (true)'. – ADDruid

+2

Sto provando ad aggiungere cookie personalizzati e intestazioni aggiuntive Qualche idea su come si possa fare? – Karoly

+0

Poiché API 24, la versione di 'shouldInterceptRequest' che richiede' String url' è deprecata. Per far fronte a questo, vedere questa domanda: https://stackoverflow.com/q/36484074/56285 (Riguardo alla deprecazione, ' shouldInterceptReque st' è analogo a 'shouldOverrideUrlLoading'.) – Jonik

63

Prova questo, ho usato in un wiki-come app personali:

webView.setWebViewClient(new WebViewClient() { 
    @Override 
    public boolean shouldOverrideUrlLoading(WebView view, String url) { 
     if (url.startsWith("foo://")) { 
      // magic 
      return true; 
     } 
     return false; 
    } 
}); 
+0

Ok, è il modo di intercettare chiamate (a proposito, sarà innescherà se la mia pagina carica un'immagine, non fare una ricarica completa?), Ma come posso fornire una risposta per la chiamata intercettata prodotta dal mio codice Java? – Olegas

+1

è possibile utilizzare il metodo loadData() di WebView per inserire alcuni html in esso. Utilizzo: webView.loadData (" ...", "text/html", "utf-8"); – Axarydax

+0

Non adatto. I contenuti statici caricati tramite loadData non hanno accesso a ulteriori contenuti di caricamento tramite la rete. Come soluzione alternativa è possibile utilizzare loadData ("javascript: ....") (per interagire con un codice "client"). Questo può essere un buon e appropriato aproach se si deve eseguire OverrideUrlLoading per ogni risorsa di pagina (esattamente le immagini del contenuto). Ma non è stato così. – Olegas

10

Per quanto ne so, shouldOverrideUrlLoading non viene chiamato per le immagini, ma piuttosto per i collegamenti ipertestuali ... Penso che l'appropriato metodo è

@Override public void onLoadResource(WebView view, String url)

Questo metodo viene chiamato per ogni risorsa (immagine, styleesheet, sceneggiatura) che è caricato dal WebView, ma dal momento che è un vuoto, non ho trovato un modo per cambiare l'URL e sostituire in modo che carichi una risorsa locale ...

+0

Sì, con questo metodo ho tutti gli URL caricati (uno root e tutte le risorse lì). Ma ancora la domanda è: come sovrascrivere loading = (Ho alcune idee su come sostituire il contenuto dell'immagine, ma ancora non è chiaro come ignorare la chiamata originale. – Olegas

3

Una soluzione definitiva sarebbe incorporare un semplice server http in ascolto sulla porta "segreta" su loopback. Poi si può sostituire l'URL src immagine abbinato con qualcosa di simile http://localhost:123/.../mypic.jpg

4

Tu non parlare della versione API, ma dal momento che API 11 c'è il metodo WebViewClient.shouldInterceptRequest

Forse questo potrebbe aiutare?

+0

e che dire dell'ispezione? (http://stackoverflow.com/questions/24000805/how-to-inspect-http-request-made-by-webviews) –

+2

Ecco un esempio di Schoenobates: https://gist.github.com/kibotu/32313b957cd01258cf67 –

8

Ecco la mia soluzione che utilizzo per la mia app.

Ho diverse cartelle di risorse con file di font css/js/img anf.

L'applicazione ottiene tutti i nomi di file e controlla se è richiesto un file con questo nome. Se sì, lo carica dalla cartella delle risorse.

//get list of files of specific asset folder 
     private ArrayList listAssetFiles(String path) { 

      List myArrayList = new ArrayList(); 
      String [] list; 
      try { 
       list = getAssets().list(path); 
       for(String f1 : list){ 
        myArrayList.add(f1); 
       } 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      return (ArrayList) myArrayList; 
     } 

     //get mime type by url 
     public String getMimeType(String url) { 
      String type = null; 
      String extension = MimeTypeMap.getFileExtensionFromUrl(url); 
      if (extension != null) { 
       if (extension.equals("js")) { 
        return "text/javascript"; 
       } 
       else if (extension.equals("woff")) { 
        return "application/font-woff"; 
       } 
       else if (extension.equals("woff2")) { 
        return "application/font-woff2"; 
       } 
       else if (extension.equals("ttf")) { 
        return "application/x-font-ttf"; 
       } 
       else if (extension.equals("eot")) { 
        return "application/vnd.ms-fontobject"; 
       } 
       else if (extension.equals("svg")) { 
        return "image/svg+xml"; 
       } 
       type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); 
      } 
      return type; 
     } 

     //return webresourceresponse 
     public WebResourceResponse loadFilesFromAssetFolder (String folder, String url) { 
      List myArrayList = listAssetFiles(folder); 
      for (Object str : myArrayList) { 
       if (url.contains((CharSequence) str)) { 
        try { 
         Log.i(TAG2, "File:" + str); 
         Log.i(TAG2, "MIME:" + getMimeType(url)); 
         return new WebResourceResponse(getMimeType(url), "UTF-8", getAssets().open(String.valueOf(folder+"/" + str))); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
      return null; 
     } 

     //@TargetApi(Build.VERSION_CODES.LOLLIPOP) 
     @SuppressLint("NewApi") 
     @Override 
     public WebResourceResponse shouldInterceptRequest(final WebView view, String url) { 
      //Log.i(TAG2, "SHOULD OVERRIDE INIT"); 
      //String url = webResourceRequest.getUrl().toString(); 
      String extension = MimeTypeMap.getFileExtensionFromUrl(url); 
      //I have some folders for files with the same extension 
      if (extension.equals("css") || extension.equals("js") || extension.equals("img")) { 
       return loadFilesFromAssetFolder(extension, url); 
      } 
      //more possible extensions for font folder 
      if (extension.equals("woff") || extension.equals("woff2") || extension.equals("ttf") || extension.equals("svg") || extension.equals("eot")) { 
       return loadFilesFromAssetFolder("font", url); 
      } 

      return null; 
     } 
0

Questo può aiuta:

@TargetApi(Build.VERSION_CODES.LOLLIPOP) 
@Override 
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { 
    String url = request.getUrl().toString(); 
    WebResourceResponse response = super.shouldInterceptRequest(view, request); 
    // load native js 
    if (url != null && url.contains(INJECTION_TOKEN/* scheme define */)) { 

     response = new WebResourceResponse(
       "text/javascript", 
       "utf-8", 
       loadJsInputStream(url, JsCache.getJsFilePath(path) /* InputStream */)); 
    } 
    return response; 
} 
+0

Il "testo/javascript" come riferimento mimeType qui: http://stackoverflow.com/questions/8589645/how-to-determine-mime-type-of-file-in-android – WCG

Problemi correlati