2011-01-24 27 views
52

Tengo una vista web en mi aplicación en la que se abre un sitio (siempre igual, es mi propia página). El sitio tiene un código JS que carga algunas imágenes desde el host remoto.Interceptar y anular solicitudes HTTP de WebView

Quiero interceptar solicitudes a tales imágenes (por patrón de URL) y devolver mi propio contenido (es decir, otra imagen) o dejar la solicitud intacta dependiendo de la lógica de la aplicación interna.

¿Es posible hacer eso?

EDITAR: El estado actual de la cuestión ...

WebView tiene una capacidad de establecer una WebViewClient (según lo observado por Axarydax). WebViewClient tener dos métodos útiles

  • shouldOverrideUrlLoading
  • onLoadResource

shouldOverrideUrlLoading es capaz de interceptar cualquier carga url, si la carga es provocada por la interacción de página (es decir, se hace clic en enlace en una página, WebView.loadURL ("") no está activando este método). También puede cancelar la carga de URL al devolver falso. Este enfoque no es utilizable, porque 'no es capaz de interceptar la carga de los recursos de la página (y las imágenes, lo que necesito interceptar, es un recurso de esa página).

onLoadResource se activa cada vez que se carga ese recurso de página (y las imágenes! Thx a jessyjones), pero no hay forma de cancelarlo. Eso hace que este método no sea adecuado para mi tarea también.

Respuesta

45

Parece que el nivel 11 de API tiene soporte para lo que necesita. Ver WebViewClient.shouldInterceptRequest().

+3

¡Una palabra de PRECAUCIÓN! Si intercepta un intento del navegador para recuperar una imagen (o probablemente cualquier recurso) y luego devolver 'null' (lo que significa que la WebView continuará recuperando la imagen), cualquier solicitud futura a este recurso podría ir a la caché y NO activará' shouldInterceptRequest() '. desea interceptar CADA solicitud de imagen, necesita desactivar el caché o (lo que hice) llamar a 'WebView.clearCache (true)'. – ADDruid

+2

Estoy tratando de agregar cookies personalizadas y encabezados adicionales. ¿Alguna idea de cómo se podría hacer eso? – Karoly

+0

Desde la API 24, la versión de 'shouldInterceptRequest' que toma' String url' está en desuso. Para tratar con eso, vea esta pregunta: https://stackoverflow.com/q/36484074/56285 (Con respecto a la desaprobación, ' shouldInterceptReque st' es análogo a 'shouldOverrideUrlLoading'.) – Jonik

63

Prueba de esto, lo he usado en un wiki-como aplicación personal:

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

Ok, que es la manera de interceptar la llamada (por cierto, va a desencadenar si mi página se carga una imagen, no hacer una recarga completa?), Pero ¿cómo puedo suministrar respuesta para la llamada interceptada producida por mi código Java? – Olegas

+1

puede usar el método loadData() de WebView para insertar un html en él. Uso: webView.loadData (" ...", "text/html", "utf-8"); – Axarydax

+0

No adecuado. El contenido estático cargado a través de loadData no tiene acceso a contenido adicional que se carga a través de la red. Como solución temporal, se puede usar loadData ("javascript: ....") (para interactuar con algún código de "cliente"). Este puede ser un buen y adecuado enfoque si shouldOverrideUrlLoading se llama para cada recurso de página (imágenes de contenido exactamente). Pero no fue así. – Olegas

10

Por lo que yo sé, no se llama shouldOverrideUrlLoading para las imágenes, sino más bien por los links ... creo que la adecuada método es

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

Este método se llama para cada recurso (imagen, styleesheet, guión) que se carga por la vista web, pero ya que es un vacío, no he encontrado una manera de cambiar esa url y reemplazar para que cargue un recurso local ...

+0

Sí, con este método obtuve todas las URL cargadas (una raíz, y todos los recursos allí). Pero aún la pregunta es: cómo anular la carga = (Tengo algunas ideas sobre cómo reemplazar el contenido de la imagen, pero aún no está claro cómo anular la llamada original. – Olegas

3

Una solución definitiva sería incorporar un servidor http simple escuchando en su puerto 'secreto' en loopback. A continuación, se puede sustituir la URL src imagen emparejado con algo como http://localhost:123/.../mypic.jpg

4

Usted no menciona la versión de la API, pero desde la API 11 hay el método WebViewClient.shouldInterceptRequest

Tal vez esto podría ayudar?

+0

y ¿qué ocurre con la inspección? (http://stackoverflow.com/questions/24000805/how-to-inspect-http-request-made-by-webviews) –

+2

Aquí hay un ejemplo de Schoenobates: https://gist.github.com/kibotu/32313b957cd01258cf67 –

8

Aquí está mi solución que uso para mi aplicación.

Tengo varias carpetas de activos con archivos de fuentes css/js/img anf.

La aplicación obtiene todos los nombres de archivo y busca si se solicita un archivo con este nombre. En caso afirmativo, lo carga desde la carpeta de activos.

//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

Esto puede ayuda:

@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

El "texto/javascript" como referencia de mimeType aquí: http://stackoverflow.com/questions/8589645/how-to-determine-mime-type-of-file-in-android – WCG

Cuestiones relacionadas