Android Lollipop下WebView的onShowFileChooser失效,音频文件上传失败求助
解决Android Lollipop WebView音频文件上传问题
我来帮你搞定这个WebView无法上传音频的麻烦!在Android Lollipop(API 21及以上)版本中,WebView的文件上传机制有了更新,onShowFileChooser是替代旧版openFileChooser的新方法,你遇到的问题大概率是这个方法的实现不完整或者权限、Intent配置不到位。结合你的代码片段,我整理了几个关键修复步骤:
1. 完整重写WebChromeClient的文件上传回调
你的代码里只定义了mUploadMessage(旧版回调用的),但Lollipop及以上需要处理ValueCallback<Uri[]>类型的新回调。请替换你的WebChromeClient实现为以下代码:
public class MainActivity extends AppCompatActivity { WebView web; ProgressBar progressBar; private ValueCallback<Uri> mUploadMessage; // 兼容旧版本 private ValueCallback<Uri[]> mUploadMessageLollipop; // Lollipop+ 专用回调 private final static int FILECHOOSER_RESULTCODE = 1; private final static int FILECHOOSER_RESULTCODE_LOLLIPOP = 2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); web = findViewById(R.id.webview); progressBar = findViewById(R.id.progressBar); // 初始化WebView核心设置 WebSettings webSettings = web.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setAllowFileAccess(true); webSettings.setAllowContentAccess(true); web.setWebChromeClient(new WebChromeClient() { // 兼容Android 5.0以下的文件上传回调 public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { mUploadMessage = uploadMsg; openFileSelector("audio/*"); } // Lollipop及以上版本的核心回调方法 @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { mUploadMessageLollipop = filePathCallback; // 指定只筛选音频文件,避免用户误选其他类型 openFileSelector("audio/*"); return true; } }); // 加载你的目标网页 web.loadUrl("你的网页地址"); } // 封装打开系统文件选择器的通用逻辑 private void openFileSelector(String acceptType) { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType(acceptType); intent.addCategory(Intent.CATEGORY_OPENABLE); // 支持多选音频文件(可选,根据业务需求调整) intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); startActivityForResult( Intent.createChooser(intent, "选择音频文件"), Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? FILECHOOSER_RESULTCODE_LOLLIPOP : FILECHOOSER_RESULTCODE ); }
2. 完善onActivityResult的回调处理
你原来的onActivityResult代码不完整,需要区分新旧版本的回调逻辑,正确返回Uri结果给WebView:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); // 处理Android 5.0以下的回调结果 if (requestCode == FILECHOOSER_RESULTCODE) { if (mUploadMessage == null) return; Uri result = (data == null || resultCode != RESULT_OK) ? null : data.getData(); mUploadMessage.onReceiveValue(result); mUploadMessage = null; } // 处理Lollipop及以上版本的回调结果 else if (requestCode == FILECHOOSER_RESULTCODE_LOLLIPOP) { if (mUploadMessageLollipop == null) return; Uri[] results = null; if (resultCode == RESULT_OK && data != null) { // 处理单个文件选择 if (data.getData() != null) { results = new Uri[]{data.getData()}; } // 处理多个文件选择 else if (data.getClipData() != null) { int count = data.getClipData().getItemCount(); results = new Uri[count]; for (int i = 0; i < count; i++) { results[i] = data.getClipData().getItemAt(i).getUri(); } } } mUploadMessageLollipop.onReceiveValue(results); mUploadMessageLollipop = null; } } }
3. 确保权限配置正确
在AndroidManifest.xml中添加必要的权限声明:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 如果需要支持录制音频后上传,额外添加这个权限 --> <uses-permission android:name="android.permission.RECORD_AUDIO" />
注意:如果你的App目标SDK版本是23及以上,即使是在Lollipop设备上,也需要在运行时动态申请READ_EXTERNAL_STORAGE权限,否则文件选择器可能无法正常读取本地文件。
4. 测试时的小提示
- 确保测试设备上存在可选择的音频文件,或者支持录制音频(如果业务需要)
- 确认网页中的文件上传按钮正确触发了WebView的回调逻辑
- 检查WebView的
setAllowFileAccess(true)和setAllowContentAccess(true)是否已经开启
按照以上步骤修复后,你的WebView应该就能正常触发音频文件上传的回调了。
内容的提问来源于stack exchange,提问作者Kishi Vimalo




