PhoneGap/Cordova Camera Pluginを使用して、デバイスイメージギャラリーから選択したイメージに基づいて、アプリでimgタグのソースを設定しようとしています。
以前は、Android(3.3))の古いバージョンで意図したとおりに機能し、iOSでは正常に動作しますが、4.4(KitKat)ではイメージパスの解決に失敗しました。
返される画像URLの返されるパスは次のようになります。
_content://com.Android.providers.media.documents/document/image%3A352
_
このパスを使用してJavaScriptを介して画像srcとして設定すると、URLを解決できないため、ロードエラーが発生します。カメラで写真を撮るときに問題はありません。ギャラリーから既存の写真を選択するときにのみ発生するようです。
Base64へのエンコードを試み、ドキュメントresolveLocalFileSystemURI();
に記載されている方法も試しましたが、これらには運がありませんでした。カメラプラグインを削除してアプリを再構築しようとしましたが、喜びはありませんでした。
私の推測では、KitKatがギャラリーを処理する方法で何かが変更され、PhoneGap/Cameraプラグインはまだこれに対応するように更新されていません。
画像のURIエンコーディングでAndroid 4.4で何かが壊れました。
コルドバに対してバグがここに提出されました: https://issues.Apache.org/jira/browse/CB-5398
getPicture のドキュメントのAndroid Quicksセクションの下で、この問題について説明し、回避策(Stackプラグインの編集Javaコード。)
別の方法として、宛先タイプをDATA_URLに設定することも考えられます。
このバグが修正されている間、本当に非常に汚い回避策の一種が私のために機能します。極端に必要な場合に使用:)
if (imageURI.substring(0,21)=="content://com.Android") {
photo_split=imageURI.split("%3A");
imageURI="content://media/external/images/media/"+photo_split[1];
}
この問題の簡単な修正方法を次に示します。
これを置き換えます:
content://com.Android.providers.media.documents/document/image%3A352
これで:
content://com.Android.providers.media.documents/document/image%253A352
javaScriptを使用している場合、次のコードを使用できます。
var path = content://com.Android.providers.media.documents/document/image%3A352;
path = path.replace("%", "%25");
この手法は、URIを「:」に変更せずに、「%3A」をそのまま渡すように強制します。
アドビは、この問題が3.5.0で修正されることを保証します。 3.4では修正されていません。 3.5.0は5月中旬にリリースされる予定なので、それまで待ちます。
Adobeは、これはプラグインレベルで行うことができる変更ではないと主張しています。 Cordovaコードの基本的な変更でした。彼らがこの修正を思い付くまでに時間がかかったのは残念です。
更新:Cordova 3.5.0は5月9日にリリースされました。biaノードをダウンロードして、問題が実際に解決されたかどうかを確認できます。
「content:」などの特別な条件を、拡張機能を使用せずにさらにいくつかチェックするだけで、さらに堅牢になりません。また、アップロードする必要があるため、拡張子を検出しています。ファイルに拡張子がない場合は.jpg拡張子を作成します。
// 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);
}
}
いくつかのuri
が<img src="uri" />
に渡されるたびに、暗黙的にデコードされます
content://com.Android.providers.media.documents/document/image%3A9888(1)
に
content://com.Android.providers.media.documents/document/image:9888(2)
ただし、Intent.ACTION_OPEN_DOCUMENT
またはIntent.ACTION_GET_CONTENT
から戻った後Androidは、(1)、(2)ではありません。この場合、WebView
は予期してエラーを記録します。
Java.lang.SecurityException:許可の拒否:pid = 13163からcom.Android.providers.media.MediaDocumentsProvider uri content://com.Android.providers.media.documents/document/image:9888を読み取るには、uid = 10165にはAndroidが必要です。 permission.MANAGE_DOCUMENTS、またはgrantUriPermission()
または
コンテンツURLを開けません
コードスニペット
問題を解決するために必要なのは
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;
}
}
あなたのJavaコードでuri
をHTML/JSに渡してから、(1)実際にロードされます。
4.4.2、4.4.4、5.0でテストしました。面白い部分は、Android 4.4.2がuri
を内部で2回デコードすることです。