web-dev-qa-db-fra.com

Impossible de charger l'image sélectionnée dans la galerie sous Android 4.4 (KitKat) à l'aide du plug-in PhoneGap Camera

J'essaie de définir la source d'une balise img dans mon application en fonction de l'image choisie dans la galerie d'images du périphérique à l'aide du plug-in PhoneGap/Cordova Camera.

Il fonctionnait auparavant comme prévu sur les anciennes versions d'Android (3.3) et fonctionne parfaitement sur iOS, mais ne parvient pas à résoudre le chemin de l'image sous 4.4 (KitKat).

Le chemin renvoyé pour l'URL d'image renvoyée ressemble à ceci:

content://com.Android.providers.media.documents/document/image%3A352

Lorsque j'utilise ce chemin pour définir comme image src via JavaScript, l'URL ne peut pas être résolue et génère donc une erreur de chargement. Il n’ya pas de problème lorsque vous prenez une photo avec l’appareil photo, cela ne semble se produire que lors du choix d’une photo existante dans la galerie.

J'ai essayé l'encodage en base64 et la méthode mentionnée dans la documentation resolveLocalFileSystemURI(); mais je n'ai pas eu de chance avec cela. J'ai également essayé de supprimer le plug-in de l'appareil photo et de reconstruire l'application, mais pas de joie.

Mon hypothèse est que quelque chose a changé avec la manière dont KitKat gère la galerie et que le plug-in PhoneGap/Camera n'a pas encore été mis à jour pour s'adapter à cela.

33
ArgosBen

Quelque chose a cassé dans Android 4.4 avec l'encodage URI des images.

Un bogue a été déposé contre Cordova ici: https://issues.Apache.org/jira/browse/CB-5398

Dans la documentation de getPicture , dans la section Android Quicks, il aborde ce problème et pointe vers une question StackOverflow avec une solution de contournement (modifiez le code Java du plug-in Camera pour le forcer à ouvrir l'application Gallery à la place du Storage Access Framework. app.)

Il semble également que vous puissiez définir le type de destination à DATA_URL.

16
MBillau

Une sorte de solution de contournement très très sale fonctionne pour moi tant que ce bogue est corrigé. Utiliser en cas d'extrême nécessité :)

if (imageURI.substring(0,21)=="content://com.Android") {
  photo_split=imageURI.split("%3A");
  imageURI="content://media/external/images/media/"+photo_split[1];
}
19
Miguel Delgado

Voici une solution simple à ce problème:

remplacez ceci:

content://com.Android.providers.media.documents/document/image%3A352

par ça:

content://com.Android.providers.media.documents/document/image%253A352

si vous utilisez JavaScript, vous pouvez utiliser ce code:

var path = content://com.Android.providers.media.documents/document/image%3A352;
path = path.replace("%", "%25");

cette technique force l’uri à laisser passer "% 3A" tel quel, sans le changer en ":", espérons que cela fonctionnera pour vous!

4
Nourdine Alouane

Adobe m'assure que ce problème sera corrigé dans 3.5.0. Il n'est pas corrigé dans 3.4. La sortie de la version 3.5.0 étant prévue pour la mi-mai, je vais attendre d'ici là.

Adobe affirme qu'il ne s'agissait pas d'un changement pouvant être apporté au niveau du plugin. C'était un changement fondamental dans le code de Cordova. C'est dommage que cela ait pris si longtemps pour qu'ils proposent cette solution.

MISE À JOUR: Cordova 3.5.0 a été publié le 9 mai. Vous pouvez télécharger le noeud bia et voir si les problèmes sont réellement résolus.

4
MLU

Pas beaucoup plus robuste que quelques vérifications supplémentaires pour des conditions spéciales telles que "contenu:" sans extensions, etc. De plus, comme je dois le télécharger, je détecte l'extension ou je crée une extension .jpg si le fichier n'en a pas:

// Android 4.4 cordova workarounds ... returns new kind or URL for content from chooser
                //if (imageUrl.substring(0,21)=="content://com.Android") {
                if(imageUrl.indexOf('content://') != -1 && imageUrl.indexOf("%3A") != -1){
                    //"PlainFileUrl = content://com.Android.providers.media.documents/document/image%3A14",
                    photo_split=imageUrl.split("%3A");
                    imageUrl="content://media/external/images/media/"+photo_split[1];
                }
                // workaround end

                var fileName = imageUrl.substr(imageUrl.lastIndexOf('/') + 1);
                var extension;

                // check for content: protocol to make sure is not
                // a file with no extension
                if (imageUrl.indexOf('content://') != -1) {
                    if(imageUrl.lastIndexOf('.') > imageUrl.lastIndexOf('/')){
                        extension = imageUrl.substr(imageUrl.lastIndexOf('.') + 1);
                    }else{
                        extension = "jpg";
                        fileName = fileName + ".jpg";
                        LogService.log("Created File Extension jpg");
                    }
                } else {
                    if (imageUrl.lastIndexOf('.') == -1 || (imageUrl.lastIndexOf('.') < imageUrl.lastIndexOf('/')) ) {
                        extension = "invalid";
                    } else {
                        extension = imageUrl.substr(imageUrl.lastIndexOf('.') + 1);
                    }
                }
2
christianmenkens

Chaque fois que uri est passé dans <img src="uri" /> il est décodé implicitement 

content: //com.Android.providers.media.documents/document/image%3A9888 (1)

dans

content: //com.Android.providers.media.documents/document/image: 9888 (2)

Cependant, après le retour de Intent.ACTION_OPEN_DOCUMENT ou Intent.ACTION_GET_CONTENT, Android vous fournit l’autorisation de lecture de (1) , pas (2) . Dans ce cas, WebView enregistrera une erreur dans l’attente:

Java.lang.SecurityException: refus d'autorisation: lecture com.Android.providers.media.MediaDocumentsProvider uri content: //com.Android.providers.media.documents/document/image: 9888 de pid = 13163, uid = 10165 nécessite Android.permission.MANAGE_DOCUMENTS ou grantUriPermission ()

ou

Impossible d'ouvrir l'URL du contenu

Extrait de code

Tout ce dont vous avez besoin pour résoudre le problème est 

    String uriToUseInWebView = transformForWebView(uri.toString());

    private String transformForWebView(String uri) {
        for (int i = 0; i < timesDecodingWebView(); i++)
            uri = uri.replace("%", Uri.encode("%"));
        return uri;
    }

    private int timesDecodingWebView() {
        if (Build.VERSION.RELEASE.equals("4.4.2")) {
            return 2;
        } else {
            return 1;
        }
    }

dans votre code Java avant de passer uri à HTML/JS pour vous assurer que (1) sera effectivement chargé.

J'ai testé cela sur 4.4.2, 4.4.4 et 5.0. La partie amusante est que Android 4.4.2 décode deux fois la uri en interne.

0
riwnodennyk