开发背景
跟其余公司合做的一个项目,传递参数的方式为原生经过自定义header头参数,由前端来接收。
踩坑
1 原生传参
安卓原生传参的方式很简单,经过webview.loadUrl这个方法,以下:
javascript
Map<String, String> map = new HashMap<String, String>(); map.put("Payment-Token", "*****"); myWebView.loadUrl(myEdit.getText().toString(), map);
2 H5接收参数
也很简单,在网上查到的是ajax的方式,可是最后项目用的原生获取header参数的,不必为了接收个参数,在我大VUE框架里引入jquery,以下:
php
let req = new XMLHttpRequest(); req.open('GET', document.location, false); req.send(null); let paymentToken = req.getResponseHeader('payment-token') ? req.getResponseHeader('payment-token') : ''; this.paymentToken = paymentToken; if (paymentToken == '') { this.setShade('订单信息获取失败'); }
你看,多么简单。而后测试的时候就被啪啪打脸了。前端说没收到参数,原生说传了,互相僵持了一下午,最后用修改UserAgent的方式来传递参数的前端
myWebView.getSettings().setUserAgentString("****");
今天开会,以为这种方式不行不正规,仍是要用以前loadUrl的方式传递header参数,突然公司的大佬一句话点醒了我,纯前端VUE只能接收到response的header。java
重点来了
请求一个网页其中包括了一次request(请求)以及一次response(响应)。因此,咱们常说的header头也有两个,一个是request的header头,一个是response的header头。问题点就在这,圈起来。原生那边发的是request的header,而H5则接收的是response的header。
这个时候服务器的做用就来了,公司用的是nginx服务器,我在其中作了一些配置,逻辑就是获取request中的header参数,而后动态设置到response的header中,打完收工,代码以下
python
add_header 'Payment-Token' '$http_payment_token';
其中也能够看出,单纯前端VUE项目与渲染页面式前端项目(php,python)项目的区别,前者的权限没有后者的权限那么多,像php能直接经过Request->header的方式读取request的参数,而VUE则不行。jquery
咱们来看看如下几个webview使用的案列。android
参考文献:ios
WebView详解与简单实现Android与H5互调nginx
案例一headerweb
直接上需求效果图:
需求:WebView添加header,h5读取头部,而且隐藏底部菜单栏。
须要添加的header数据:ECR-APP:android
咱们平时大多数状况使用的是loadUrl(String url)加载方法,下面咱们来看另外一个loadUrl构造方法。
loadUrl(String url, Map<String, String> additionalHttpHeaders)
参数additionalHttpHeaders字面上的意思是:额外的http头部信息。这个方法是Android 2.2 (也就是API 8),WebView新增长了一个接口方法,就是为了便于咱们加载网页同时又能够发送HTTP头信息的。
看看具体的使用:
HashMap<String, String> header = new HashMap<>(); header.put("ECR-APP", "android"); mWebView.loadUrl("http://m.test.366ec.net/Default2c.aspx",header);
立刻运行效验一下:
网页上底部的菜单已经去掉了。
案例二cookie
cookie用于记录用户登陆信息,用户下次进入须要登陆的界面再也不须要重复登陆。
先看看需求:
会一直出现登陆界面。那么怎么解决屡次登陆问题?WebView会将加载的url经过http请求传输到服务器。那么Cookie信息会经过header传递过去。
设置cookie代码以下:
private void syncCookieToWebView(String url, List<String> cookies) { CookieSyncManager.createInstance(this); CookieManager cm = CookieManager.getInstance(); cm.setAcceptCookie(true); if (cookies != null) { for (String cookie : cookies) { cm.setCookie(url, cookie);//注意端口号和域名,这种方式能够同步全部cookie,包括sessionid } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { CookieManager.getInstance().flush(); } else { CookieSyncManager.getInstance().sync(); } }
如下是调用代码:
List<String> cookies = new ArrayList<>(); //键值对类型 用等号("=")链接 具体根据后台给定 cookies.add("StoreManagerTicket=" + "加密token");//根据后台协商而定 syncCookieToWebView("加载的地址", cookies);
CookieManager会将这个Cookie存入该应用程序/data/data/databases/目录下的webviewCookiesChromium.db数据库的cookies表中。打开网页,WebView从数据库中读取该cookie值,放到http请求的头部,传递到服务器。
运行一下,看看还会出现屡次登陆的问题吗?
跳转正常,没有出现屡次登陆的问题。
案例三注入js
不知道你在项目中遇到这样的场景没有?手机端与h5交互,提供数据支持。如调本地相机,获取到的图片上传到网页;调用定位返回地址给网页;调用二维码扫描界面返回扫描结果等等。
以下,有这样一个场景,网页上有【扫描】图标,点击打开手机扫描界面,扫描成功后上传扫描结果。那么在手机端通常会有以下方法:
JsOpenScanFunction(String callbackFunction)
参数callbackFunction表示扫描成功后webview.load调用的方法而且只有一个参数(扫描结果)。
通常前端h5会这样进行调用Android手机端打开二维码的方法:
//callback回调方法 window.JsInterface.JsOpenScanFunction(callback)
ios端会这样调用:
window.webkit.messageHandlers.JsOpenScanFunction.postMessage(callback)
在h5端会分步处理,无疑会增长开发人员的工做量,试想一下,若是交互的地方不少,那么h5端开发人员做何感想?并且后期的维护也是一件很是繁琐的事情,就没有更好的方案吗?
若是h5端能够像调用本地方法那样简单调用手机端方法,那不是很是fashion。
那么就须要分别在Android端和ios端分布注入js代码,方便h5端调用。
注入的方式以下:
@Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); if (mIsAddJsCode) {//默认true mIsAddJsCode = false; mWebView.loadUrl("javascript:" + "function JsOpenScanFunction(s) {\n window.JsInterface.JsOpenScanFunction(s);\n}"); } }
在onPageStarted方法下注入js方法:
function JsOpenScanFunction(s) { window.JsInterface.JsOpenScanFunction(s); }
这样h5只须要调用JsOpenScanFunction(s)方法就能够实现不一样平台调用二维码扫描的功能。今后妈妈在已不担忧多端调用的问题了。
注意:JsOpenScanFunction(s) 方法,须要前端和移动端事先约定。
参考:https://blog.csdn.net/u012551350/article/details/56674602