请求Android SDK33-34版本WebView文件上传功能的实现方案
适配SDK33-34的WebView文件上传实现方案
1. 声明并动态申请权限
SDK33及以上版本,文件读取权限拆分为媒体类型权限,需在配置和代码中做对应处理:
- 在
AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <!-- 兼容SDK32及以下版本 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
- 在Activity/Fragment中动态申请权限:
private static final int PERMISSION_REQUEST_CODE = 1001; private void requestMediaPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { String[] permissions = { Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_AUDIO }; if (ContextCompat.checkSelfPermission(this, permissions[0]) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE); } } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { String permission = Manifest.permission.READ_EXTERNAL_STORAGE; if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{permission}, PERMISSION_REQUEST_CODE); } } }
在Activity启动时调用requestMediaPermissions(),确保用户授权后再启用文件上传功能。
2. 配置WebChromeClient处理文件选择回调
WebView的文件上传依赖WebChromeClient的onShowFileChooser方法,SDK33+下直接使用官方提供的FileChooserParams构建Intent即可:
private ValueCallback<Uri[]> mFilePathCallback; private static final int FILE_CHOOSER_REQUEST_CODE = 1000; webView.setWebChromeClient(new WebChromeClient() { @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { mFilePathCallback = filePathCallback; Intent intent = fileChooserParams.createIntent(); try { startActivityForResult(intent, FILE_CHOOSER_REQUEST_CODE); } catch (ActivityNotFoundException e) { mFilePathCallback = null; Toast.makeText(MainActivity.this, "无法打开文件选择器", Toast.LENGTH_SHORT).show(); return false; } return true; } });
3. 处理文件选择结果
根据你使用的Android版本,选择对应的结果处理方式:
方式1:使用onActivityResult(兼容旧版)
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode != FILE_CHOOSER_REQUEST_CODE || mFilePathCallback == null) { return; } Uri[] results = null; if (resultCode == RESULT_OK && data != null) { ClipData clipData = data.getClipData(); if (clipData != null) { results = new Uri[clipData.getItemCount()]; for (int i = 0; i < clipData.getItemCount(); i++) { results[i] = clipData.getItemAt(i).getUri(); } } else { results = new Uri[]{data.getData()}; } } mFilePathCallback.onReceiveValue(results); mFilePathCallback = null; }
方式2:使用registerForActivityResult(AndroidX推荐)
在Activity的onCreate中注册结果回调:
private ActivityResultLauncher<Intent> fileChooserLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (mFilePathCallback == null) return; Uri[] results = null; if (result.getResultCode() == RESULT_OK && result.getData() != null) { Intent data = result.getData(); ClipData clipData = data.getClipData(); if (clipData != null) { results = new Uri[clipData.getItemCount()]; for (int i = 0; i < clipData.getItemCount(); i++) { results[i] = clipData.getItemAt(i).getUri(); } } else { results = new Uri[]{data.getData()}; } } mFilePathCallback.onReceiveValue(results); mFilePathCallback = null; } );
然后修改onShowFileChooser中的启动代码:
fileChooserLauncher.launch(intent);
4. 配置WebSettings基础参数
确保WebView启用必要的设置以支持文件上传:
WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); // 文件上传控件依赖JS webSettings.setAllowFileAccess(true); webSettings.setAllowContentAccess(true); // SDK30+允许本地文件跨域访问 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { webSettings.setAllowFileAccessFromFileURLs(true); webSettings.setAllowUniversalAccessFromFileURLs(true); }
内容的提问来源于stack exchange,提问作者Jeremy
相关产品推荐
相关产品推荐

