Android 5.0 (以前のバージョンはテストしていません。ある情報からこの情報を知りました) から、WebView で <input type="file"> のファイルを開く実装が変更され、クリックしても応答がなく、ファイルを開く操作を処理するには WebChromeClient を再読み込みする必要があります。
バージョンは常に更新され、反復されるため、インターネット上の一部の実装では非推奨の関数が使用されます。以下は registerForActivityResult を使用する「2023/4」の実装です。startActivityForResult と比較すると、コールバックを使用するため、複数の関数で関数を実装する必要がなくなります。
まず、ActivityResultLauncher を登録してファイル ブラウザを開いてファイルを選択します。
//解决安卓5及以上版本html<input type="file">无响应问题
private ValueCallback<Uri[]> checkedFile;
private ActivityResultLauncher<String[]> explorer;
//在Activity.onCreate中实现以下内容,实现打开文件浏览器选择文件的功能
protected void onCreate(Bundle savedInstanceState) {
........
explorer = registerForActivityResult(new ActivityResultContracts.OpenDocument(),
result -> {
LOG.debug("Open file `{}`", result);
if(checkedFile != null) {
if(result == null) {
checkedFile.onReceiveValue(null); //result没选择时为null
} else {
checkedFile.onReceiveValue(new Uri[]{result});
}
checkedFile = null;
}
});
........
}
次に、Android 5 以降では、WebChromeClient.onShowFileChoose をオーバーロードします (古いバージョンでは他の機能をオーバーロードする必要があります。インターネット上の他の紹介を参照してください。5 未満では互換性を持たせる必要がないと思われるため、実装されていません)。
WebChromeClient chromeClient = new WebChromeClient() {
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
if (checkedFile != null) {
//防止上一次没选文件,直接退出的情况,导致后面选择无法正常工作
checkedFile.onReceiveValue(null);
}
checkedFile = filePathCallback;
String[] acceptTypes = fileChooserParams.getAcceptTypes();
LOG.debug("fileChooserParams:{},sdk_int:{}", Arrays.stream(acceptTypes).toArray(), Build.VERSION.SDK_INT);
if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.N){
explorer.launch(new String[]{"*/*"});
} else {
explorer.launch(acceptTypes);
}
return true;
}
};
........
//设置到webview中
webview.setWebChromeClient(chromeClient);
なお、Android 7 以前のバージョンはコード内で判定されており、fileChooserParams パラメータを使用して選択したファイルの種類を制限することはできません。それ以外の場合、クリックに対する応答がなく、エラー メッセージも表示されません。理由は不明なので、ここでは「*/*」が渡されます。
1 つの重要なポイント: onShowFileChooser で checkFile を取得します。これはコールバックです。エクスプローラーがファイルを選択した後、checkedFile.onReceiveValue を呼び出して結果を Web ビューに渡します。
HTML での処理は、通常の Web ブラウザーの処理とまったく同じです。以下は、画像ファイルの取得とトリミングの例です。完全な内容については、このリンク、serverui/file/settings/home.js · master · Zhijian Grid / Zhijian Grid Enterprise Service · GitCode の startCropLogo 関数を参照してください。
var file = e.target.files[0];
if (!/\.(gif|jpg|jpeg|png|bmp|GIF|JPG|PNG)$/.test(e.target.value)) {
this.$refs.alertDlg.show(this.tags.invalidImg);
return false
}
var reader = new FileReader()
reader.onload = (e) => {
var data
if (typeof e.target.result === 'object') {
// 把Array Buffer转化为blob 如果是base64不需要
data = window.URL.createObjectURL(new Blob([e.target.result]))
} else {
data = e.target.result
}
this.logoOpts.img = data
this.loading=false;
}
// reader.readAsDataURL(file)// 转化为base64
reader.readAsArrayBuffer(file)// 转化为blob