这篇记录一次cordova 热更新插件导致的历史记录不存在的问题。
一 情况说明
热更新插件:
使用后发现,手机的回退按钮无法实现页面回退而是项目推出。
在控制台测试发现历史记录为空。
网上查阅了一下资料发现cordova 的热更新插件会导致历史记录不可用
You probably already saw a description in the comments, why this is done. But anyways:
When we launch the app - it points to the index.html in the assets folder. But we want it to work with the content from the external storage (where our updated code is placed). So we redirect user to that “external” index.html. But browser (WebView) tracks that in it’s history. Without webView.clearHistory() when user clicks back button on the device - he will return to the index page from the assets, and we don’t want that.
Same thing will happen if we downloaded new content from the server, installed it and reloaded the page. Again, we are changing the directory and the page. And if user clicks on back button - he will return to the old page.
That’s why we clear history when page is initialised. But this might be an issue if you’r app is multy-page application: if for each navigation you load new page in the WebView - then plugin is re-initialised and history get cleaned.
来自于:asAnotherJack
其中这位博主提供了一种解决方案:
链接:https://www.jianshu.com/p/3d869a6a8398
如果对热更新有一定了解就会明白,我们初始会有一个原版的文件夹(位于assets目录下的文件),当对比更新数据发现需要热更新的时候,会额外创建一个新的文件夹,然后将相关的新文件复制进去,然后将系统的引用指向该文件夹,实现了热更新的伪操作。所以热更新不是覆盖,而是新增,这就会出现一些问题。
当我们热更新后没有清楚记录的时候,此时history里是有之前的assets目录下的历史记录的,返回会导致用户可能再通过返回栈退回到assets目录下的页面。
二 解决方案
第一种修改源码
来自于上面的博主,
打开位于src目录下的com\nordnetab\chcp\main\HotCodePushPlugin.java,熟悉cordova的都了解,这个继承自CordovaPlugin的家伙就是原生和h5交互的桥梁,在这个里边发现了一个jsInit(CallbackContext callback)方法,看名字也差不多知道是初始化的时候调用的,里边果然发现了这么一段代码:
// Clear web history.
// In some cases this is necessary, because on the launch we redirect user to the
// external storage. And if he presses back button - browser will lead him back to
// assets folder, which we don’t want.
handler.post(new Runnable() {
@Override
public void run() {
webView.clearHistory();
}
});
注释也写的很清楚了。
然后因为我们目前的app,在首页是有返回事件的拦截的(弹了一个对话框询问是否确认退出),那也就是说,我们的app是无论如何都没办法退回到旧的assets目录下的页面的,因为返回事件拦截掉了,然后我就试着把上边这几行代码注掉了,暂时没发现什么问题。
第二种 纯前端
处于项目的可维护性,插件是git下来的,不想通过频繁修改源码,后期非开发人员维护会非常麻烦,所以考虑用纯前端的方式解决这种问题。
解决思路很简单,因为cordova更新后,都会返回首页,所以我们在非首页的页面手动生成历史记录存放在storage缓存中,然后通过相关的事件监听实现一种回退功能。
下面是详细的代码:
function transitionLocation(pagecode, backpage, tourl) {
window.localStorage.setItem("historyurl", pagecode + "," + backpage);
if (isnotnull(tourl)) {
window.location.href =tourl;
}
}
function locationold(type, url, message) {
var old = window.localStorage.getItem("historyurl");
var thisurl = window.location.pathname;
var endurl = "../index";
if (isnotnull(old) && old.length > 10) {
var arrays = old.split(",");
if (thisurl.indexOf(arrays[0]) > 0 && isnotnull(arrays[1])) {
window.localStorage.setItem("historyurl", "");
endurl = arrays[1];
} else if (isnotnull(url)) {
endurl = url;
} else {
app.alert("页面跳转出现异常", endurl);
}
} else if (isnotnull(url)) {
endurl = url;
} else {
app.confirm(function () {
window.location.href = endurl;
}, "跳转出现异常,是否返回首页?");
}
if (isnotnull(message) && message.length > 5) {
alert(message, endurl);
} else {
window.location.href = endurl;
}
}
逻辑很简单:
transitionLocation(“filter”, “thisurl”, "tourl ");
- thisurl:在跳后页面回跳到之前页面运行的地址
- tourl :当前页面要跳转到跳转页面说走的地址
- filter : 判断historyurl 对当前页面有用
当返回的时候,
locationold("type", "default");
type:扩展属性,用于灵活扩展,这里没有用处
default:用于不存在history时的默认跳转
这种方法的缺点在于需要在跳转前进行封装.
扩展
这种方法是可以扩展,通过扩展解决上述问题
我们可以通过监听popstatus 来判断是否按的返回键