一、前言
應用uni-app
框架開發(fā)好APP上架使用過程中,發(fā)現(xiàn)應用經(jīng)過長時間由后臺切換至前臺時,通過webview
方式嵌套的H5頁面發(fā)生白屏現(xiàn)象。
二、問題分析
任何手機設備上,當手機內(nèi)存不足時,os都會回收資源。一般是先回收后臺打開的資源。如果當前應用占用的資源過高,當前應用也有可能崩潰。尤其是在調(diào)用攝像頭點擊拍照時,手機內(nèi)存占用會達到一個峰值,此時較容易出問題。
有關內(nèi)存管理,詳參博文《安全生產(chǎn):內(nèi)存溢出和內(nèi)存泄漏》。
在iOS上,當內(nèi)存不足時,根據(jù)uiwebview
和wkwebview
的不同,它自身有不同的回收策略。
如果是uiwebview
的app(常見于5+app),內(nèi)存不足時整個app會崩潰,即閃退。
如果是wkwebview
的app(uni-app和wap2app在iOS上默認就是wkwebview
),內(nèi)存不足時,單個wkwebview
會崩潰。也就是所謂的應用還在,而頁面白屏。
這個問題在所有使用wkwebview
的應用都會出現(xiàn),比如微信的公眾號網(wǎng)頁里也存在。在微信小程序里,它做了一個自動恢復手段,可以讓jscore
存儲數(shù)據(jù)狀態(tài),崩潰的wkwebview
自動恢復。所以在遇到問題時,會白一下然后恢復渲染。
三、解決方案
-
uni-app
因為引入了獨立的jscore
處理數(shù)據(jù)狀態(tài),jscore
不會崩潰,所以官方采用了和微信小程序一致的策略,補充自動的白屏恢復能力。親測使用HBuilder 3.6.4.20220922
并無白屏自動恢復功能,懷疑是HBuilder版本問題! -
uni-app
中也可以使用nvue
來避免這個問題,nvue
頁面不會出現(xiàn)內(nèi)存不足引發(fā)的白屏崩潰。
3.1 nvue 頁面替代 vue 頁面
nvue
文件webview
使用方式如下:
//nvue 中的webview需要自行設置寬高否則無法展示<template>
<view>
<web-view ref="webview" src="/hybrid/html/local.html" style="width: 500px;height: 600px;" @onPostMessage="getMessage"></web-view>
</view>
</template>
<script>
export default {
data(){
return {
}
},
onLoad() {
setTimeout(()=>{
this.handlePostMessage('測試傳參')
},200)
},
methods: {
handlePostMessage(res) {
this.$refs.webview.evalJs(`handleMessage()`);
},
getMessage(e) {
uni.showModal({
content: JSON.stringify(e.detail),
showCancel: false
})
}
}
}
</script>
h5頁面內(nèi)容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>本地網(wǎng)頁</title>
<style type="text/css">
.btn {
display: block;
margin: 20px auto;
padding: 5px;
background-color: #007aff;
border: 0;
color: #ffffff;
height: 40px;
width: 200px;
}
.btn-red {
background-color: #dd524d;
}
.btn-yellow {
background-color: #f0ad4e;
}
.desc {
padding: 10px;
color: #999999;
}
</style>
</head>
<body>
<p class="desc">web-view 組件加載本地 html 示例,僅在 App 環(huán)境下生效。點擊下列按鈕,跳轉(zhuǎn)至其它頁面。</p>
<div class="btn-list">
<button class="btn" type="button" data-action="navigateTo">navigateTo</button>
<button class="btn" type="button" data-action="redirectTo">redirectTo</button>
<button class="btn" type="button" data-action="navigateBack">navigateBack</button>
<button class="btn" type="button" data-action="reLaunch">reLaunch</button>
<button class="btn" type="button" data-action="switchTab">switchTab</button>
</div>
<p class="desc" id="lizhao">網(wǎng)頁向應用發(fā)送消息。注意:小程序端應用會在此頁面后退時接收到消息。</p>
<div class="btn-list">
<button class="btn btn-red" type="button" id="postMessage">postMessage</button>
</div>
<!-- uni 的 SDK -->
<script type="text/javascript" src="https://unpkg.com/@dcloudio/uni-webview-js@0.0.1/index.js"></script>
<script type="text/javascript">
window.handleMessage=function(data){
alert('傳來的參數(shù)'+data)
}
document.addEventListener('UniAppJSBridgeReady', function() {
document.querySelector('.btn-list').addEventListener('click', function(evt) {
var target = evt.target;
if (target.tagName === 'BUTTON') {
var action = target.getAttribute('data-action');
switch (action) {
case 'switchTab':
uni.switchTab({
url: '/pages/tabBar/API/API'
});
break;
case 'reLaunch':
uni.reLaunch({
url: '/pages/tabBar/API/API'
});
break;
case 'navigateBack':
uni.navigateBack({
delta: 1
});
break;
default:
uni[action]({
url: '/pages/component/button/button'
});
break;
}
}
});
document.querySelector("#postMessage").addEventListener('click', function() {
uni.postMessage({
data: {
action: 'message888888'
}
});
})
});
</script>
</body>
</html>
注意??:uni-app
中的 nvue
頁面問題nvue
頁面不使用 webview
渲染,但其中的web-view
組件說明如下:
-
nvue
的weex 組件模式
:weex
模式下的web-view
組件是weex
自己實現(xiàn)的,它目前仍然使用UIWebview
。官方會追蹤weex
的升級。 -
nvue
的uni-app組件模式
:web-view
組件使用WKWebview
,不可修改為uiWebview
。
3.2 白屏檢測刷新
3.2.1 自動刷新
- 需要一個全局掛載的工具類,
Vue.prototype.$utils = utils
- 在需要使用的頁面(一般為tab頁)最外層需要設置為同一個class名稱;
- 在
onshow
方法調(diào)用;
let pageList = {};
const utils = {
reloadCurrentPage: function(_self, isTab = true) {
// #ifdef APP-PLUS
// 獲取當前路由及傳參,以備頁面刷新之用
var route = _self.$scope.route;
var data = _self.$scope.options && _self.$scope.options.data;
var url = '/' + route;
if (data) {
url = '/' + route + '?data=' + data;
}
var isRecovery = true; // 頁面刷新標識
let newTime = Date.now();
if (pageList[url]) {
const query = uni.createSelectorQuery().in(_self);
//這里select()中替換為自己的樣式class名稱
query.select('.container').fields({size:true}, data => {
isRecovery = false; // 重置頁面刷新標識
}).exec();
setTimeout(() => {
// 頁面白屏,需觸發(fā)刷新機制
if (isRecovery) {
//如果獲取不到節(jié)點
//確保只刷新一次
if (newTime - pageList[url] > 3000) {
//超過3秒才重新刷新,這里設置幾秒就行,目的是防止無限刷新
//因為刷新后頁面肯定會出來,但是立馬再次調(diào)用該方法不一定能獲取節(jié)點(DOM樹未必構建完畢)
pageList[url] = newTime;
// 若為tab標簽欄位
if (isTab) {
uni.reLaunch({
url
})
} else {
// 若為頁面
uni.redirectTo({
url
})
}
}
}
}, 600)
} else {
// 頁面正常,記錄當前時間
pageList[url] = newTime;
}
// if (plus.os.name === 'iOS') {
// }
// #endif
}
}
3.2.2 手動刷新
webview
頁面提供按鈕以支持用戶手動刷新,
手動刷新實現(xiàn)邏輯如下:
手動刷新按鈕在檢測到白屏事件發(fā)生時顯示:
query.select('.container').fields({size:true}, data => {
isShow = true; // 展示刷新按鈕
}).exec();
應用3.2.1小節(jié)提供的刷新方法,當點擊刷新按鈕調(diào)用刷新方式。
3.3 總結
在前端減少內(nèi)存使用,最重要的就是圖片渲染,尤其是大圖片。
在頁面上不要渲染多張大圖,比如從攝像頭或相冊選擇多張圖,并縮放尺寸渲染在頁面上,雖然肉眼看起來手機屏幕上是幾張小圖,但實際上是多張大圖只是被縮小,這種情況非常耗費內(nèi)存。一張圖片3m,9張這樣的大圖同時渲染到屏幕上,什么手機都受不了。
一個縮略圖控制在幾k或十幾k,才是合理的。文章來源:http://www.zghlxwxcb.cn/news/detail-631347.html
詳情頁面展現(xiàn)多張大圖并不受影響。如果圖片滾動在屏幕外,os內(nèi)存不足時也會自動收回這些屏幕外圖片占用的渲染資源,最吃資源的就是同屏渲染多張大圖。文章來源地址http://www.zghlxwxcb.cn/news/detail-631347.html
四、拓展閱讀
- 《uni-app中Webview的使用注意》
- 《uni-app SelectorQuery》
- 《跨平臺應用開發(fā)進階(五十六):應用渲染異常問題分析及解決》
- 《安全生產(chǎn):內(nèi)存溢出和內(nèi)存泄漏》
到了這里,關于跨平臺應用開發(fā)進階(五十)uni-app ios web-view嵌套H5項目白屏問題分析及解決的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!