web-dev-qa-db-fra.com

Intercepter et remplacer les demandes HTTP de WebView

J'ai une WebView dans mon application dans laquelle un site est ouvert (toujours le même, c'est ma propre page). Le site contient du code JS qui charge des images à partir de l'hôte distant.

Je souhaite intercepter les demandes de telles images (par un motif d'URL) et restituer mon propre contenu (c'est-à-dire une autre image), ou laisser la demande intacte, selon la logique interne de l'application.

Est-il possible de faire ça?

EDIT : L'état actuel de la question ...

WebView a la capacité de définir un WebViewClient (comme noté par Axarydax). WebViewClient ont deux méthodes utiles

  • shouldOverrideUrlLoading
  • onLoadResource

shouldOverrideUrlLoading est capable d'intercepter tout chargement d'URL. Si le chargement est déclenché par une interaction de page (c'est-à-dire qu'un lien sur une page est cliqué, WebView.loadURL ("") ne déclenche pas cette méthode). Il est également possible d'annuler le chargement d'URL en renvoyant false. Cette approche n'est pas utilisable, car elle ne peut pas intercepter le chargement des ressources de la page (et les images, ce que j'ai besoin d'intercepter, est une telle ressource de page).

onLoadResource se déclenche chaque fois que la ressource de page (et les images! merci à jessyjones) sont en cours de chargement, mais il n'y a aucun moyen de l'annuler. Cela rend également cette méthode inadaptée à ma tâche.

60
Olegas

Il semble que l’API de niveau 11 prenne en charge ce dont vous avez besoin. Voir WebViewClient.shouldInterceptRequest() .

48
dkneller

Essayez ceci, je l'ai utilisé dans une application personnelle de type wiki:

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

Pour autant que je sache, shouldOverrideUrlLoading ne soit pas appelé pour les images mais plutôt pour les hyperliens ... Je pense que la méthode appropriée est

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

Cette méthode est appelée pour chaque ressource (image, feuille de style, script) chargée par la vue Web, mais comme il s'agit d'un vide, je n'ai pas trouvé de moyen de changer cette URL et de la remplacer afin qu'elle charge une ressource locale ...

10
jessyjones

Voici la solution que j'utilise pour mon application.

J'ai plusieurs dossiers de ressources avec des fichiers de polices css/js/img anf.

L'application obtient tous les noms de fichiers et recherche si un fichier portant ce nom est demandé. Si oui, il le charge à partir du dossier de ressources.

//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;
        }
9
EscapeNetscape

Vous ne mentionnez pas la version de l'API, mais depuis l'API 11, il existe la méthode WebViewClient.shouldInterceptRequest

Peut-être que cela pourrait aider?

4
user484261

Une solution ultime consisterait à intégrer un simple serveur http à l’écoute sur votre port "secret" en boucle. Ensuite, vous pouvez remplacer l'URL src de l'image correspondante par quelque chose comme http: // localhost: 123 /.../ mypic.jpg

3
Sergey Emantayev

Cela peut aider:

@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;
}
2
WCG