Android WebView 不支持 H5 input type="file" 解决方法

本文介绍了解决Android WebView在不同版本中实现文件选择功能的方法。通过调整WebChromeClient,针对不同Android版本提供了兼容方案,使得可以在网页中使用文件上传功能。

学无止境,每天都在进步,是我最快乐的事情!

<input style="width: 0px; height: 0px;" id="image" type="file" accept="image/*">

上面的代码是H5里面的,我通过网页查看源码拿出来的,看了很多文章,我才知道,Android中webview却屏蔽了这个type=”file” 这个功能,说是为了安全起见,真是搞不懂!
起初我很迷茫,用手机可以打开网址,点击按钮可以打开相册,ios也可以,尼玛,Android就是没反应,有的机型甚至还崩溃,无语,苦恼,没办法,到群里去问,有个哥们很好,给了我点建议,和一些文章查看,终于搞定了。
说那么多,么有,上代码:

 private WebView wv;
    private String url ="http://shanghai.job1s.com/wap/member/index.php?c=photo";

    private ValueCallback<Uri> mUploadMessage;
    public ValueCallback<Uri[]> uploadMessage;
    public static final int REQUEST_SELECT_FILE = 100;
    private final static int FILECHOOSER_RESULTCODE = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        wv = (WebView) findViewById(R.id.webview);
        //设置支持Javascript
        wv.getSettings().setJavaScriptEnabled(true);  

        wv.loadUrl(url);
        wv.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                //返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器
                view.loadUrl(url);
                return false;
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
            }

            @Override
            public void onPageFinished(WebView view, String url) {
            }
        });


        wv.setWebChromeClient(new WebChromeClient(){

            // For 3.0+ Devices (Start)
            // onActivityResult attached before constructor
            protected void openFileChooser(ValueCallback uploadMsg, String acceptType)
            {
                mUploadMessage = uploadMsg;
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType("image/*");
                startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
            }


            // For Lollipop 5.0+ Devices
            @TargetApi(Build.VERSION_CODES.LOLLIPOP)
            public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams)
            {
                if (uploadMessage != null) {
                    uploadMessage.onReceiveValue(null);
                    uploadMessage = null;
                }

                uploadMessage = filePathCallback;

                Intent intent = fileChooserParams.createIntent();
                try
                {
                    startActivityForResult(intent, REQUEST_SELECT_FILE);
                } catch (ActivityNotFoundException e)
                {
                    uploadMessage = null;
                    Toast.makeText(getBaseContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
                    return false;
                }
                return true;
            }

            //For Android 4.1 only
            protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
            {
                mUploadMessage = uploadMsg;
                Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
                intent.addCategory(Intent.CATEGORY_OPENABLE);
                intent.setType("image/*");
                startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE);
            }

            protected void openFileChooser(ValueCallback<Uri> uploadMsg)
            {
                mUploadMessage = uploadMsg;
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.addCategory(Intent.CATEGORY_OPENABLE);
                i.setType("image/*");
                startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
            }

        });

    }


    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent)
    {

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
        {
            if (requestCode == REQUEST_SELECT_FILE)
            {
                if (uploadMessage == null)
                    return;
                uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
                uploadMessage = null;
            }
        }
        else if (requestCode == FILECHOOSER_RESULTCODE)
        {
            if (null == mUploadMessage)
                return;
            // Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
            // Use RESULT_OK only if you're implementing WebView inside an Activity
            Uri result = intent == null || resultCode != MainActivity.RESULT_OK ? null : intent.getData();
            mUploadMessage.onReceiveValue(result);
            mUploadMessage = null;
        }
        else
            Toast.makeText(getBaseContext(), "Failed to Upload Image", Toast.LENGTH_LONG).show();
    }
在 UniApp 中使用 `webview` 加载的 H5 页面中,如果页面包含 `<input type="file">` 标签,在安卓设备上点击该标签时,默认行为可能会仅显示相机选项,而无法直接访问文件管理器或相册。这个问题通常与安卓系统限制以及 `webview` 的权限配置有关。 ### 问题原因 安卓系统在不同版本中对 `webview` 中的文件访问权限进行了限制,尤其是在 Android 10 及以上版本中,系统默认不会直接允许 `webview` 访问本地文件系统。因此,当用户点击 `<input type="file">` 时,系统可能仅提供相机选项,而不显示文件选择器或相册[^4]。 ### 解决方案 #### 1. 配置权限请求 在原生 Android 层面,需要确保应用具有访问存储的权限。可以通过自定义 `Activity` 并在启动文件选择器之前请求权限[^4]。例如: ```java import io.dcloud.PandoraEntryActivity; public class YYPandoraEntryActivity extends PandoraEntryActivity { @Override public void startActivityForResult(Intent intent, int requestCode) { if (intent.getAction().equals("android.intent.action.GET_CONTENT")) { PermissionUtil.requestPermissions(YYPlatApplication.getCurrActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, new PermissionUtil.OnPermissionListener() { @Override public void onPermissionGranted() { runOnUiThread(() -> YYPandoraEntryActivity.super.startActivityForResult(intent, requestCode)); } @Override public void onPermissionDenied() { AbCenter.ME().postEvent("message", "permissionMessage,WRITE_EXTERNAL_STORAGE,READ_EXTERNAL_STORAGE"); } }); } else { super.startActivityForResult(intent, requestCode); } } } ``` #### 2. 使用 `Intent` 启动文件选择器 在某些情况下,可以通过拦截 `Intent` 并手动启动文件选择器来绕过默认行为。例如: ```java Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("*/*"); intent.addCategory(Intent.CATEGORY_OPENABLE); startActivityForResult(intent, FILE_CHOOSER_RESULT_CODE); ``` #### 3. 使用 Hybrid 模式处理文件上传 在 `webview` 中,可以通过 Hybrid 模式实现文件上传功能。具体来说,可以在 H5 页面中监听 `<input type="file">` 的 `change` 事件,并通过 `uni.getFileSystemManager()` 获取文件的 `ArrayBuffer` 对象,然后上传到服务器[^2]。示例代码如下: ```javascript document.querySelector('input[type="file"]').addEventListener('change', function(event) { const file = event.target.files[0]; const reader = new FileReader(); reader.onload = function(e) { const blob = new Blob([e.target.result], { type: file.type }); const formData = new FormData(); formData.append('file', blob, file.name); // 使用 axios 或其他方式上传文件 axios.post('/file/api/Upload', formData, { headers: { 'Content-Type': 'multipart/form-data' } }); }; reader.readAsArrayBuffer(file); }); ``` #### 4. 使用原生插件 如果需要更复杂的文件处理功能,可以考虑使用 UniApp 提供的原生插件。例如,某些插件可以直接返回 `File` 对象,而不是 `blob` 路径,从而简化文件上传流程[^1]。 ### 总结 在 UniApp 中使用 `webview` 加载的 H5 页面中,点击 `<input type="file">` 时在安卓设备上仅显示相机选项的问题,主要与权限配置和系统限制有关。通过请求存储权限、自定义 `Activity`、使用 Hybrid 模式或引入原生插件,可以有效解决这一问题。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值