You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中设置WebChromeClient后无法调用WebView的onPageStarted及文件上传问题

针对你遇到的两个Android WebView问题的解决方案

问题1:设置WebChromeClient后无法调用WebView的onPageStarted方法

这是个很容易混淆的点——onPageStarted是WebViewClient的专属回调方法,和WebChromeClient完全是两个独立的类,职责完全不同。

你只设置WebChromeClient并不会影响WebViewClient的回调,大概率是你没给WebView配置自定义的WebViewClient,或者不小心忽略了它的设置。解决方法很简单:同时给WebView设置WebViewClient并重写onPageStarted即可,两个Client可以共存,互不干扰:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
        // 在这里写你的页面开始加载逻辑,比如显示加载进度条
    }
});

// 你的WebChromeClient设置依然保留,它负责处理浏览器UI相关的逻辑(比如文件选择、JS弹窗)
webView.setWebChromeClient(new WebChromeClient() {
    // 你的WebChromeClient逻辑
});

简单总结:WebViewClient管页面加载生命周期,WebChromeClient管浏览器交互UI,两者各司其职,同时设置就好。


问题2:WebView文件上传的完整实现

从你给出的代码片段来看,你已经处理了权限申请的第一步,但完整的文件上传还需要在WebChromeClient中处理文件选择的回调,还要适配不同Android版本的差异。下面是完整的实现方案:

1. 补全权限申请的回调逻辑

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    // 假设权限请求的code是100
    if (requestCode == 100) {
        boolean allPermissionsGranted = true;
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                allPermissionsGranted = false;
                break;
            }
        }
        if (allPermissionsGranted) {
            // 权限全部通过,重新加载WebView或者触发文件选择操作
            loadWebView(yourTargetUrl);
        } else {
            // 提示用户需要权限才能完成文件上传
            Toast.makeText(getActivity(), "需要存储和相机权限才能上传文件", Toast.LENGTH_SHORT).show();
        }
    }
}

2. 在WebChromeClient中重写文件选择回调(适配多版本)

// 定义全局变量保存回调,用于在onActivityResult中返回结果
private ValueCallback<Uri[]> mFilePathCallback;
private ValueCallback<Uri> mUploadMsg;
private static final int FILE_CHOOSER_REQUEST_CODE = 101;

// 在loadWebView方法中设置WebChromeClient
webView.setWebChromeClient(new WebChromeClient() {
    // 适配Android 5.0及以上版本
    @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(getActivity(), "无法打开文件选择器", Toast.LENGTH_SHORT).show();
            return false;
        }
        return true;
    }

    // 适配Android 4.1-4.4版本
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        mUploadMsg = uploadMsg;
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*"); // 允许选择所有类型文件
        startActivityForResult(Intent.createChooser(intent, "选择文件"), FILE_CHOOSER_REQUEST_CODE);
    }
});

3. 在onActivityResult中处理返回的文件Uri

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == FILE_CHOOSER_REQUEST_CODE) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (mFilePathCallback == null) return;
            Uri[] results = null;
            // 处理选择的文件结果
            if (resultCode == Activity.RESULT_OK && data != null) {
                String dataString = data.getDataString();
                ClipData clipData = data.getClipData();
                if (clipData != null) {
                    results = new Uri[clipData.getItemCount()];
                    for (int i = 0; i < clipData.getItemCount(); i++) {
                        ClipData.Item item = clipData.getItemAt(i);
                        results[i] = item.getUri();
                    }
                } else if (dataString != null) {
                    results = new Uri[]{Uri.parse(dataString)};
                }
            }
            // 将结果返回给WebView
            mFilePathCallback.onReceiveValue(results);
            mFilePathCallback = null;
        } else {
            // 处理低版本逻辑
            if (mUploadMsg == null) return;
            Uri result = (resultCode == Activity.RESULT_OK && data != null) ? data.getData() : null;
            mUploadMsg.onReceiveValue(result);
            mUploadMsg = null;
        }
    }
}

4. 补全WebView的基础配置

@SuppressLint("SetJavaScriptEnabled")
private void loadWebView(String url) {
    if (getActivity() == null) return;
    // 权限检查
    if (Build.VERSION.SDK_INT >= 23 && 
        (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || 
         ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) {
        ActivityCompat.requestPermissions(getActivity(), 
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 
                100);
        return;
    }
    // WebView基础配置
    WebSettings settings = webView.getSettings();
    settings.setJavaScriptEnabled(true);
    settings.setAllowFileAccess(true);
    settings.setAllowFileAccessFromFileURLs(true);
    settings.setAllowUniversalAccessFromFileURLs(true);
    // 同时设置WebViewClient和WebChromeClient
    webView.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            // 页面开始加载的逻辑
        }
    });
    // 上面的WebChromeClient设置写在这里
    webView.loadUrl(url);
}

内容的提问来源于stack exchange,提问作者user4813855

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:19:45