需求是这样的,最近通过我们SDK的Webview打开了公司另外一个系统H5支付页面,这个H5页面左上角有个返回按钮,因为不是从我们的H5页面跳转过去的,所以左上角的返回图标执行的windows.history.back(-1);没有生效,商户投诉无法退出。解决办法是1.让这个H5页面点击我们webview暴露出去的一个js事件,点击的时候关闭当前webview Activity,这样成本比较大,另外一个系统也要改,另外这个H5支付系统也给其他系统调用,不太现实。 2.重写H5的windows.history.back(-1);事件,让用户点击的时候能够关闭当前Activity,但是要注意一点,这个H5页面有些情况是需要通过这个事件返回上个页面的,所以要加个判断
if (webView.canGoBackOrForward(step)),能否返回,能返回还是继续执行返回上个页面,不能全盘替换。好,下面给出代码。
/**
* onCreate方法.
*
* @param savedInstanceState 无
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(Utils.getResourceId(Utils.packageName, "layout", "activity_web_view"));
mWebView = (WebView) findViewById(Utils
.getResourceId(Utils.packageName, "id", "web_view"));
WebSettings webset = mWebView.getSettings();
webset.setJavaScriptEnabled(true);// 表示webview可以执行服务器端的js代码
webset.setSupportZoom(true);
webset.setDomStorageEnabled(true);
webset.setJavaScriptCanOpenWindowsAutomatically(true);//允许js弹出窗口
mWebView.requestFocus();
webset.setUseWideViewPort(true);
webset.setLoadWithOverviewMode(true);
webset.setSupportZoom(true);
webset.setBuiltInZoomControls(true);
//20191022解决net::ERR_CACHE_MISS,19以上不能使用缓存
if (18 < Build.VERSION.SDK_INT ){
//18 = JellyBean MR2, KITKAT=19
webset.setCacheMode(WebSettings.LOAD_NO_CACHE);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webset.setMixedContentMode(android.webkit.WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
progressDialog = new ProgressDialog(WebViewActivity.this);
mWebView.addJavascriptInterface(new JsInterface(this), "mobile");
mWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
//H5返回支付结果页面去查询支付结果
if (url.contains("service/showResultPage")) {
new AsyncSign(WebViewActivity.this).execute();
return;
}
//20191119荣耀v20会出现dialog的Unable to add window,加个判断
if(!isFinishing()&&!progressDialog.isShowing()) {
progressDialog.setMessage("加载中,请稍后...");
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.show();
}
}
@Override
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
// 重写此方法才能够处理在浏览器中的按键事件
return super.shouldOverrideKeyEvent(view, event);
}
//20200623 add 加载这个假页面后触发关闭当前activity
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
shouldOverrideUrlLoadingNew(view,url);
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public void onPageFinished(WebView view, String url) {
//20200623 add 重写 windows.history.back(-1)方法,赋值一个假页面
onPageFinishedNew(view,url);
// 在页面加载结束时调用
super.onPageFinished(view, url);
if(progressDialog!=null&&progressDialog.isShowing())
{
progressDialog.dismiss();
}
}
@Override
public void onReceivedError(WebView view, int errorCode, String description,
String failingUrl) {
// 重写此方法可以让webview处理https请求
super.onReceivedError(view, errorCode, description, failingUrl);
}
});
mWebView.setWebChromeClient(new MyWebChromeClient() );
mWebView.setPictureListener(new MyPictureListener());
}
/**
* 20191030页面更新 .
*/
class MyPictureListener implements WebView.PictureListener {
@Override
public void onNewPicture(WebView view, Picture arg1) {
if(progressDialog!=null&&progressDialog.isShowing())
{
progressDialog.dismiss();
}
}
}
//begin 20200623重写history.back(-1)方法,解决指定跳转到H5支付无法返回问题
/**
* 自定义的,当js调用history.go时加载的链接,以监听history.go方法的调用
*/
private final static String CONSTANTS_GO_BACK = "/CONSTANTS_GO_BACK#";
/**
* 在WebViewClient对应方法中调用
* 注:此方法需手动调用,或者使用defaultClient == true
*/
public void shouldOverrideUrlLoadingNew(WebView webView,String url) {
if (!StringUtil.isEmpty(url) && url.contains(CONSTANTS_GO_BACK)) {
int step = -1;
try {
//解析js调用history.back时传入的参数
step = Integer.parseInt(url.split("#")[1]);
} catch (Exception e) {
e.printStackTrace();
}
if (webView.canGoBackOrForward(step)) {
webView.goBackOrForward(step);
} else {
//当没有上一个页面,而js调用了history.go时回调方法
Utils.returnResultInfo(this, AsyGlobalInfo.CODE_EXIT, "中途退出", null);
WebViewActivity.this.finish();
}
}
}
/**
* 在WebViewClient对应方法中调用
* 注:此方法需手动调用,或者使用defaultClient == true
*/
public void onPageFinishedNew(WebView webView,String url) {
//重写js页面window.history.back方法
// String script1 = "javascript:(function(){window.history.go = function(index){" +
// "window.location.href='" + CONSTANTS_GO_BACK + "'+index;" +
// "}})()";
// webView.loadUrl(script1);
//重写js页面goToPreStep方法会出现跳转两次
//String script1 = "javascript:(function(){goToPreStep= function(){" +
//"alert(quickStep);"+
//"}})()";
//webView.loadUrl(script1);
//重写js页面window.history.back方法
String script = "javascript:(function(){window.history.back= function(index){" +
"window.location.href='" + CONSTANTS_GO_BACK + "'+index;" +
"}})()";
webView.loadUrl(script);
}
//end
/**
* MyWebChromeClient .
*/
private class MyWebChromeClient extends WebChromeClient {
/**
*
* @param view .
* @param newProgress .
*/
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
if(newProgress==100){
if(progressDialog!=null&&progressDialog.isShowing())
{
progressDialog.dismiss();
}
}
}
}
思路比较秒的,webview的onPageFinished重写当前H5页面的window.history.back方法,给当前页面换个新地址
"window.location.href='" + CONSTANTS_GO_BACK + "'+index;",当用户点击回退的时候,当前页面变成了CONSTANTS_GO_BACK 这个假地址,加载页面的时候会触发shouldOverrideUrlLoading,这个事件里就发现是url包含CONSTANTS_GO_BACK这个地址,就可以执行关闭当前Activity了。我也参考了网上的一些资料,整理出来较完整的demo供参考。