Android WebView调用系统相册和相机,注入以及与H5的交互

本文详细介绍Android WebView的配置、调用系统相册与相机、与H5交互、Cookie解析及注入等核心功能。涵盖WebSettings配置、权限管理、重定向处理、H5与原生互调技巧,适合开发者深入理解并应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android WebView调用系统相册和相机,注入以及与H5的交互

推荐:
如何设计一个优雅健壮的Android WebView?(上)
如何设计一个优雅健壮的Android WebView?(下)

Android Webview在使用的过程中,其实也是挺简单的,最基本的只需要加Seeting的配置即可成为一个H5链接的承载,但是不乏在使用的会遇到一些坑,这篇文章主要总结的是我在项目中所使用的一下Webview的功能等。各位大神,如果写的不正确的地方,请提出来!
一.Webview的基本配置

Webview的WebSettings基本配置大概也就那么多,当然了也有其他的少用的配置,这个可以根据需求来定,具体的每一个配置属性有注释,其他的属性大家可以在网上都能查到。我所使用的如下:

				public void setWebSettings(WebView mView){
				        WebSettings setting = mView.getSettings();
				        //支持Js
				        setting.setJavaScriptEnabled(true);
				        setting.setJavaScriptCanOpenWindowsAutomatically(true);
				        //缓存模式
				        setting.setCacheMode(WebSettings.LOAD_DEFAULT);
				        //支持内容重新布局
				        setting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
				        //将图片调整到适合webview的大小
				        setting.setUseWideViewPort(true);
				        setting.setLoadWithOverviewMode(true);
				        //设置可以访问文件
				        setting.setAllowFileAccess(true);
				        //支持自动加载图片
				        setting.setLoadsImagesAutomatically(true);
				        try {
				            setting.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
				        } catch (NoSuchMethodError e) {
				            e.printStackTrace();
				        }
				    }

对于Webview中的两个Client(WebViewClient和WebChromeClient)的配置,这里我也不在简述,毕竟方法太多了,在接下来的书写中会有一部分的描述使用。

二.Webview调用系统相册和相机
  1. 所需要的权限(注意针对于6.0系统,需要申请权限)
android.Manifest.permission.CAMERA)
android.Manifest.permission.READ_EXTERNAL_STORAGE
  1. 继承mWebChromeClient,对于系统相机和相册都是通过表单数据来返回给webview的,这里注意对比5.0以上和以下系统所是使用的方法,以下所有的代码都是对相机和相册的使用封装
		public class BaseWebChromeClient extends WebChromeClient {
		    private final static int FILE_REQUEST_CODE_SNAPSHOT = 100; //拍照表单的结果回调
		    private final static int FILE_CHOOSER_RESULT_CODE = 101;// 相册表单的结果回调
		    private ValueCallback<Uri> mUploadMessage;// 5.0以下表单的数据信息
		    public ValueCallback<Uri[]> mUploadCallbackAboveL;//5.0以上表单的数据信息
		    private Uri imageUri;
		    private Context mContext;
		
		    public BaseWebChromeClient(Context context) {
		        mContext = context;
		    }
		
		    @Override
		    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
		        return super.onJsAlert(view, url, message, result);
		    }
		
		    @Override
		    public void onProgressChanged(WebView view, int newProgress) {
		        super.onProgressChanged(view, newProgress);
		        if (newProgress == 100) {
		            ((BaseActivity) mContext).dismissLoadingDialog();
		        }
		    }
		
		    @Override
		    public void onReceivedTitle(WebView view, String title) {
		        super.onReceivedTitle(view, title);
		        //处理404错误 android 6.0 以下通过title获取
		        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
		            if (title.contains("404") || title.contains("500") || title.contains("Error")) {
		                if (mContext instanceof BaseWebActivity) {
		                    ((BaseWebActivity) mContext).showErrorRefresh(view, mContext.getResources().getString(R.string.webview_not_found));
		                }
		            }
		        }
		    }
		
		//<---------------------------------重要代码-------------------------------------------->
		    @Override
		    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
		        mUploadCallbackAboveL = filePathCallback;
		        PictureBusiness.getInstance().setUploadCallbackAboveL(mUploadCallbackAboveL);
		        String[] fileParams = fileChooserParams.getAcceptTypes();
		        if (fileParams.length > 0) {
		            for (int i = 0; i < fileParams.length; i++) {
		                LogUtil.i("BaseWebChromeClient", "FileChooserParams ----> " + fileParams[i]);
		            }
		        }
		        if (fileParams[0].equals(PictureBusiness.IMAGE)) {
		            PictureBusiness.getInstance().changePicture((Activity) mContext, PictureBusiness.IMAGE, false);
		        } else if (fileParams[0].contains(PictureBusiness.VIDEO)) {
		            PictureBusiness.getInstance().changePicture((Activity) mContext, PictureBusiness.VIDEO, false);
		        }
		        return true;
		    }
		
		    public void openFileChooser(ValueCallback<Uri> uploadMsg) {
		        mUploadMessage = uploadMsg;
		    }
		
		    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
		        mUploadMessage = uploadMsg;
		    }
		
		    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
		        mUploadMessage = uploadMsg;
		    }
		
		
		    public void onActivityResult(int requestCode, int resultCode, Intent data) {
		        if (resultCode != Activity.RESULT_OK) {
		            if (mUploadMessage != null) {
		                mUploadMessage.onReceiveValue(null);
		            }
		            return;
		        }
		        //相册 & 拍照
		        if (requestCode == FILE_REQUEST_CODE_SNAPSHOT || requestCode == FILE_CHOOSER_RESULT_CODE) {
		            if (null == mUploadMessage && null == mUploadCallbackAboveL) {
		                return;
		            }
		            Uri result = data == null || (resultCode != RESULT_OK) ? null : data.getData();
		            if (mUploadCallbackAboveL != null) {
		                onActivityResultAboveL(requestCode, resultCode, data);
		            } else if (mUploadMessage != null) {
		                /*if (result != null) {
		                    String path = getPath(mContext.getApplicationContext(), result);
		                    Uri uri = Uri.fromFile(new File(path));
		                    mUploadMessage.onReceiveValue(uri);
		                } else {
		                    mUploadMessage.onReceiveValue(imageUri);
		                }
		                mUploadMessage = null;*/
		            }
		        }
		    }
		
		
		    @SuppressWarnings("null")
		    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
		    private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) {
		        if (mUploadCallbackAboveL == null) {
		            return;
		        }
		        Uri[] results = null;
		        switch (requestCode) {
		            case FILE_CHOOSER_RESULT_CODE:
		                if (resultCode == Activity.RESULT_OK) {
		                    if (data == null) {
		                        results = new Uri[]{imageUri};
		                    } else {
		                        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();
		                            }
		                        }
		                        if (dataString != null) {
		                            results = new Uri[]{Uri.parse(dataString)};
		                        }
		                    }
		                }
		                break;
		            case FILE_REQUEST_CODE_SNAPSHOT:
		                if (resultCode == Activity.RESULT_OK) {
		                    String videoPath = null;
		                    File capture = PictureBusiness.getInstance().getSnapshot();
		                    if (capture != null && capture.exists()) {
		                        videoPath = capture.getAbsolutePath();
		                    }
		                    if (videoPath != null) {
		                        results = new Uri[]{Uri.parse("file://" + videoPath)};
		                    }
		                }
		                break;
		            default:
		                break;
		        }
		
		        if (results != null) {
		            mUploadCallbackAboveL.onReceiveValue(results);
		            mUploadCallbackAboveL = null;
		        } else {
		            results = new Uri[]{imageUri};
		            mUploadCallbackAboveL.onReceiveValue(results);
		            mUploadCallbackAboveL = null;
		        }
		        return;
		    }
		
		}
我在使用的过程中基本上是 没有问题的,但是部分手机上显示到webivew中的时候图片会有反转,这个也没有来的急解决,各位大佬有改过的可以评论一下方法

3.代码中使用
①在onResume中做判断

		if (mWebChromeClient.mUploadCallbackAboveL != null) {
		            mWebChromeClient.mUploadCallbackAboveL.onReceiveValue(null);
		            mWebChromeClient.mUploadCallbackAboveL = null;
		        }

②重写onActivityResult方法

		 mWebChromeClient.onActivityResult(requestCode, resultCode, data);
三.使用Webview的拦截方法 shouldOverrideUrlLoading (重定向)

shouldOverrideUrlLoading :这个方法的返回值

  return true 表示当前url即使是重定向url也不会再执行(除了在return true之前使用webview.loadUrl(url)除外,因为这个会重新加载)
  return false  表示由系统执行url,直到不再执行此方法,即加载完重定向的ur(即具体的url,不再有重定向)

这个拦截方法其实也可以作为和H5的交互,比如在我自已的项目需求中,有一个按钮需要点击跳转,这个时候将返回设置为true,通过H5返回的数据(协商定义)进行判断跳转处理

四.解析Webview的Cookie

获取Cookie使用的是CookieManager,这里我举例项目中使用Cookie,如下代码:

		 @Override
		    protected void shouldUrlLoading(WebView view, String request) {
		        if (request.contains("backpwd") || request.contains("regagreement") || request.contains("problem/a5.html")) {
		            mBaseWeb.loadUrl(request);
		        } else {
		            //登录成功后,拦截操作
		            try {
		                LogUtil.i("login", URLDecoder.decode(request, "utf-8"));
		                if (URLDecoder.decode(request, "utf-8").contains(boLogin.getRedirect_url())) {
		                //------使用代码 start-------
		                    CookieManager cookieManager = CookieManager.getInstance();
		                    String cookieStr = cookieManager.getCookie(url);
		                    LoginCookie cookie = getLoginCookie(cookieStr);
		                    //------使用代码 end-----
		                    LoginBean loginBean = new LoginBean();
		                    loginBean.setUid(cookie.getBfuid());
		                    loginBean.setThirdUid("");
		                    loginBean.setToken(cookie.getLoginToken());
		                    loginBean.setuName(cookie.getBf_user_name());
		                    loginBean.setLoginType(cookie.getLogin_type());
		                    LoginBusiness.login(this, loginBean);
		                }
		            } catch (UnsupportedEncodingException e) {
		                e.printStackTrace();
		            }
		        }
		    }

getLoginCookie方法如下:

			/**
			     * 解析Cookie
			     *
			     * @param cookieStr
			     * @return
			     */
			    protected LoginCookie getLoginCookie(String cookieStr) {
			        HashMap<String, String> cookieContiner = new HashMap<>();
			        String[] keyvalues = cookieStr.split(";");
			        for (int i = 0; i < keyvalues.length; i++) {
			            String[] keyPair = keyvalues[i].split("=");
			            String cookieKey = keyPair[0].trim();
			            String cookieValue = keyPair.length > 1 ? keyPair[1].trim() : "";
			            cookieContiner.put(cookieKey, cookieValue);
			        }
			        String cookie = JSONObject.toJSONString(cookieContiner);
			        LogUtil.i("cookie", "login cookie = " + cookieStr + "\n" + cookie);
			        LoginCookie loginCookie = JSONObject.parseObject(cookie, LoginCookie.class);
			        return loginCookie;
			    }

以上只是举个例子,具体H5返回的Cookie需要由后端来定

五.Webview的注入

关于Webview的注入我了解的有两种,也是最常用的,即H5调用Android的方式和Android调用H5的方式

  1. Android调用H5的方式
    一般我们加载网页的是通过mWeb.loadUrl(url);加载的,这个其实也可以调用H5提供的方法,既能表示也能注入也能表示调用H5的方式,具体一行代码搞定:
    		    webView.loadUrl("javascript:"+"方法名");
    
  2. H5调用Android的方式
    写一个类,加注解@JavascriptInterface,如下
@SuppressLint("JavascriptInterface")
    class JSInterface {
        /**
         * Toast
         *
         * @param mToast 显示内容
         */
        @JavascriptInterface
        public void toast(String mToast) {
            SRLog.i(TAG, "--->toast " + mToast);
            Toast.makeText(WebActivity.this, mToast, Toast.LENGTH_SHORT).show();
        }

        /**
         * 中间件  消息控制
         *
         * @param str 内容
         */
        @JavascriptInterface
        public void startMiddleWare(String str) {
            SRLog.i(TAG, "--->middle " + str);
            TellManager.getInstance().sendAsr(getApplication(), getPackageName(), str);
            finish();
        }

注意,WebSettings中的属性setJavaScriptEnabled(true);要设置为true
使用方式:

        JSInterface  mJsInterface = new JSInterface(this);
        mBaseWeb.addJavascriptInterface(mJsInterface, "InjectOsUser");
        //InjectOsUser这个是需要提供给H5调用的,如InjectOsUser.toast("xxx");
六.总结
以上就是WebView的部分使用,这也是有可能大部分项目中能使用到的功能,这里我也不在叙述WebViewClient中的一些方法,如onPageStarted,onPageFinished等,这些方法的使用也比较简单。最后在推荐一个对WebView的使用非常全的网站,大家可以在上面查到更多的方法。

如何设计一个优雅健壮的Android WebView?(上)
如何设计一个优雅健壮的Android WebView?(下)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值