You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动