45

私は<input type="file">アンドロイドのウェブビューで使用していました。このスレッドのおかげで機能しました: WebView でのファイルのアップロード

しかし、受け入れられた回答 (またはその他) は、Android 4.4 kitkat webview では機能しなくなりました。

誰もそれを修正する方法を知っていますか?

ターゲット18でも機能しません。

Android 4.4 のソース コードをいくつか調べましたが、WebChromeClient は変更されていないようですが、kitkat の WebView ではsetWebChromeClient動作しないか、少なくともopenFileChooser関数では動作しないと思います。

4

9 に答える 9

30

更新 2: phonegap/cordova で使用する簡単なプラグインがあります

https://github.com/MaginSoft/MFileChooser

更新: Cesidio DiBenedetto プラグインを使用したサンプル プロジェクト

https://github.com/jcesarmobile/FileBrowserAndroidTest

Android オープン ソース プロジェクトで問題を開いたところ、答えは次のとおりでした。

ステータス: WorkingAsIntended

残念ながら、openFileChooser は公開 API ではありません。Android の将来のリリースでは、公開 API に取り組んでいます。

phonegap/cordova を使用している場合は、この回避策がバグ トラッカーに投稿されています。

Cesidio DiBenedetto さんがコメントを追加しました - 28/Mar/14 01:27

こんにちは、私もこの問題を経験しているので、当面の間、Cordova FileChooser プラグインを「応急処置」に書きました。基本的に、Android 4.4(KitKat)では、以前のコメントで述べたように、ファイル ダイアログは開かれません。ただし、onclick イベントは引き続き発生するため、FileChooser プラグインを呼び出してファイル ダイアログを開き、選択時にファイルへのフル パスを含む変数を設定できます。この時点で、FileTransfer プラグインを使用してサーバーにアップロードし、onprogress イベントにフックして進行状況を表示できます。このプラグインは主に Android 4.4 用に構成されているため、以前のバージョンの Android では引き続きネイティブ ファイル ダイアログを使用することをお勧めします。多くのデバイスで考えられるすべてのシナリオを完全にテストしていないため、プラグインに問題がある可能性があります。

https://github.com/cdibened/filechooser

独自の回避策を作成したため、テストしていません

クロム開発者からのコメント

次のメジャー リリースでは、ファイル リクエストを処理するためにパブリック API を WebViewClient に追加する予定です。

彼らは現在それをバグと見なしているようで、修正する予定です

于 2013-11-13T19:17:15.107 に答える
21

上記の Cesidio DiBenedetto の回避策をアプリに実装することができました。うまく機能していますが、 PhoneGap/Cordoveを使用したことがない人(私のように) にとっては、少し難しいかもしれません。そこで、実装中にまとめたちょっとしたハウツーを以下に示します。

Apache Cordovaは、Web テクノロジを使用するだけでマルチプラットフォームのモバイル アプリを構築できるプラットフォームです。主な機能は、ネイティブ API を JavaScript にエクスポートするため、Web サイトとネイティブ アプリケーションの間で通信する方法を提供することです。一般的な PhoneGap/Cordova アプリは、Cordova レイヤーと一緒に 1 つの APK にバンドルされている静的な Web サイトです。しかし、Cordova を使用してリモート Web サイトを表示することはできます。

回避策は次のとおりです。Webサイトの表示WebViewに使用する標準の代わりに。CordovaWebViewユーザーが [参照] をクリックしてファイルを選択すると、標準の JavaScript (jQuery...) を使用してそのクリックをキャッチし、Cordova API を使用してネイティブ側で Cesidio DiBenedetto の filechooser プラグインをアクティブにし、素敵なファイル ブラウザーを開きます。ユーザーがファイルを選択すると、ファイルは JavaScript 側に送り返され、そこから Web サーバーにアップロードされます。

知っておくべき重要なことは、Web サイトに Cordova サポートを追加する必要があるということです。さて、実際のハウツーは...

まず、Cordova を既存のアプリに追加する必要があります。私はこのドキュメントに従いました。いくつかの手順がわかりにくかったので、詳しく説明します。

  1. Cordova をダウンロードしてアプリの外に展開し、説明に従って cordova-3.4.0.jarをビルドします。local.propertiesファイルが見つからないため、おそらく初めて失敗します。エラー出力で作成方法を指示されます。Android アプリのビルドに使用する SDK を指定するだけです。

  2. コンパイルされた jar ファイルをアプリのlibディレクトリにコピーし、jar をライブラリとして追加します。私のように Android Studio を使用している場合はcompile fileTree(dir: 'libs', include: ['*.jar', '*.aar'])build.gradledependencies内にあることを確認してください。次に、Sync project with gradle filesボタンをクリックするだけで問題ありません。

  3. /res/xml/main.xmlファイルを作成する必要はありません。CordovaWebView は、標準の WebView と同じように扱うことができるため、レイアウト ファイルに直接配置できます。

  4. 元のドキュメントの手順 5 ~ 7 に従ってActivity、 が実行される場所を独自に作成しますCordobaWebView/framework/src/org/apache/cordova/CordovaActivity.javaダウンロードした Cordova パッケージの を確認することをお勧めします。実装に必要なほとんどのメソッドを単純にコピーできます。6. ステップは、filechooser プラグインを使用できるようにするため、この目的にとって非常に重要です。

  5. HTML および JavaScript ファイルはどこにもコピーしないでください。後で Web サイトに追加します。

  6. config.xmlファイルをコピーすることを忘れないでください(変更する必要はありません)。

に Web サイトをロードするにはCordovaWebView、その URL を cwv.loadUrl()の代わりに に渡すだけですConfig.getStartUrl()

次に、FileChooser プラグインをアプリに追加する必要があります。cordova plugin add標準の Cordova セットアップを使用していないため、readme の指示に従ってヒットすることはできず、手動で追加する必要があります。

  1. リポジトリをダウンロードし、ソース ファイルをアプリにコピーします。resフォルダーのコンテンツがアプリの res フォルダーに移動することを確認してください。今のところ、JavaScript ファイルは無視してかまいません。

  2. READ_EXTERNAL_STORAGEアプリに権限を追加します。

  3. 次のコードを/res/xml/config.xmlに追加します。

<feature name="FileChooser">
    <param name="android-package" value="com.cesidiodibenedetto.filechooser.FileChooser" />
</feature>

今こそ、Web サイトに Cordova サポートを追加するときです。思ったより簡単で、cordova.jsを Web サイトにリンクするだけですが、知っておくべきことが 2 つあります。

まず、各プラットフォーム (Android、iOS、WP) には独自のcordova.jsがあるため、必ず Android バージョンを使用してください (これは、/framework/assets/wwwでダウンロードした Cordova パッケージにあります)。

次に、Web サイトがCordovaWebViewと標準のブラウザー (デスクトップまたはモバイル) の両方からアクセスされる場合、通常は、ページが に表示されている場合にのみcordova.jsCordovaWebViewをロードすることをお勧めします。検出する方法はいくつか見つかりましCordovaWebViewたが、次の方法がうまくいきました。あなたのウェブサイトの完全なコードは次のとおりです。

function getAndroidVersion(ua) {
    var ua = ua || navigator.userAgent; 
    var match = ua.match(/Android\s([0-9\.]*)/);
    return match ? parseFloat(match[1]) : false;
};

if (window._cordovaNative && getAndroidVersion() >= 4.4) {
    // We have to use this ugly way to get cordova working
    document.write('<script src="/js/cordova.js" type="text/javascript"></script>');
}

Android のバージョンもチェックしていることに注意してください。この回避策は、キットカットにのみ必要です。

この時点で、Web サイトからFileChooserプラグインを手動で呼び出すことができるはずです。

var cordova = window.PhoneGap || window.Cordova || window.cordova;
cordova.exec(function(data) {}, function(data) {}, 'FileChooser', 'open', [{}]);

これにより、ファイル ブラウザーが開き、ファイルを選択できるようになります。これは、イベント deviceready が発生した後にのみ実行できることに注意してください。テストするには、jQuery を使用してこのコードをボタンにバインドします。

最後のステップは、これをすべてまとめて、アップロード フォームを機能させることです。これを実現するには、 READMEに記載されている Cesidio DiBenedetto の指示に従うだけです。ユーザーがFileChooserでファイルを選択すると、ファイルパスが JavaScript 側に返され、そこから別の Cordova プラグインFileTransferが実際のアップロードを実行するために使用されます。つまり、ファイルはネイティブ側ではなく、ネイティブ側にアップロードされますCordovaWebView(私が正しく理解している場合)。

別の Cordova プラグインを自分のアプリケーションに追加する気にはなれませんでした。また、それが Cookie でどのように機能するかもわかりませんでした (認証されたユーザーのみがファイルのアップロードを許可されているため、要求と共に Cookie を送信する必要があります)。それは私のやり方です。FileChooserプラグインを変更して、パスではなくファイル全体を返すようにしました。したがって、ユーザーがファイルを選択すると、そのコンテンツを読み取り、 を使用してエンコードしbase64、JSON としてクライアント側に渡し、そこでデコードして、JavaScript を使用してサーバーに送信します。それは機能しますが、base64 はかなり CPU を必要とするため、大きなファイルがアップロードされるとアプリが少しフリーズする可能性があるため、明らかな欠点があります。

それを行うには、まずこのメソッドをFileUtilsに追加します。

public static byte[] readFile(final Context context, final Uri uri) throws IOException {
    File file = FileUtils.getFile(context, uri);
    return org.apache.commons.io.FileUtils.readFileToByteArray(file);
}

Apache Commons ライブラリを使用することに注意してください。それを含めるか、外部ライブラリを必要としない他の方法でファイルを読み取ることを忘れないでください。

次に、FileChooser.onActivityResultメソッドを変更して、パスではなくファイルの内容を返します。

// Get the URI of the selected file
final Uri uri = data.getData();
Log.i(TAG, "Uri = " + uri.toString());
JSONObject obj = new JSONObject();
try {
    obj.put("filepath", FileUtils.getPath(this.cordova.getActivity(), uri));
    obj.put("name", FileUtils.getFile(this.cordova.getActivity(), uri).getName());
    obj.put("type", FileUtils.getMimeType(this.cordova.getActivity(), uri));

    // attach the actual file content as base64 encoded string
    byte[] content = FileUtils.readFile(this.cordova.getActivity(), uri);
    String base64Content = Base64.encodeToString(content, Base64.DEFAULT);
    obj.put("content", base64Content);

    this.callbackContext.success(obj);
} catch (Exception e) {
    Log.e("FileChooser", "File select error", e);
    this.callbackContext.error(e.getMessage());
}

最後に、これは Web サイトで使用するコードです (jQuery が必要です)。

var cordova = window.PhoneGap || window.Cordova || window.cordova;
if (cordova) {
    $('form.fileupload input[type="file"]', context).on("click", function(e) {    
        cordova.exec(
            function(data) { 
                var url = $('form.fileupload', context).attr("action");

                // decode file from base64 (remove traling = first and whitespaces)
                var content = atob(data.content.replace(/\s/g, "").replace(/=+$/, ""));

                // convert string of bytes into actual byte array
                var byteNumbers = new Array(content.length);
                for (var i = 0; i < content.length; i++) {
                    byteNumbers[i] = content.charCodeAt(i);
                }
                var byteContent = new Uint8Array(byteNumbers);

                var formData = new FormData();
                var blob = new Blob([byteContent], {type: data.type}); 
                formData.append('file', blob, data.name);

                $.ajax({
                    url: url,
                    data: formData,
                    processData: false,
                    contentType: false,
                    type: 'POST',
                    success: function(data, statusText, xhr){
                        // do whatever you need
                    }
                });
            },
            function(data) { 
                console.log(data);
                alert("error");
            },
            'FileChooser', 'open', [{}]);
    });
}

それだけです。これが機能するまでに数時間かかったので、誰かの助けになることを願って私の知識を共有しています.

于 2014-05-04T16:00:33.907 に答える
5

Web ビューのファイル チューザーは、最新の Android リリース 4.4.3 で動作するようになりました。

Nexus 5 を使って自分で試してみました。

于 2014-06-25T08:59:07.123 に答える
1

Kitkatバージョンが type=file フォーム フィールドと互換性がないという事実にもかかわらず、webviewwebview のaddJavascriptInterfaceメソッドを使用してファイル アップロード タスクを実行できます。サーバー側で Android のバージョンを判断し、それより低い場合はプライベート メソッド4.4を使用しWebViewChromeClient、4.4 以上の場合はサーバーに Android メソッドを呼び出して相互に通信させます (例: ファイル コンテンツの非同期アップロード)

// コード

webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewJavaScriptInterface(this), "app");


ここに役立つリンクがあります...

call-android-methods-from-javascript

于 2014-09-13T06:42:49.837 に答える
0

Kitkat の新しいファイル ブラウザーは、Chrome でも同じようにクレイジーになりました。WebView が現在 Chromium を使用していることを考えると、これは関連する問題である可能性があります。カメラから直接ファイルをアップロードすると機能することがわかりましたが、「画像」フォルダーからは機能しません。代わりに「ギャラリー」からアップロードした場合は、同じファイルにアクセスできます。ガッ。

修正の準備ができているようですが、リリースを待っています:

https://code.google.com/p/chromium/issues/detail?id=278640

于 2013-12-04T21:28:38.680 に答える
-1

crosswalk-webview-21.51.546.7 を使用し、カメラ経由で画像を選択する場合。でonActivityResult() the intent.getData()あるnull。カメラによる画像のアップロードが機能しないことを意味します。

于 2016-11-15T13:11:29.287 に答える