B站視訊
www.bilibili.com/video/BV18e… www.bilibili.com/video/BV1RZ…
本節目標
- 詳情頁技術方案比較
- 載入 web 內容
- 自動計算高度
- 清除廣告、推薦
- 攔截請求
- loading 狀態顯示
- 分享外掛
- 遠端 android 裝置除錯
詳情展示
技術方案選擇
分析工具 UI automator view
- 檔案位置
/Users/ducafecat/Library/Android/sdk/tools/bin/uiautomatorviewer
淘寶方案
混合方式
頭條
混合方式
什麼值得買
單一 webView
技術點分析
-
- webView 原生 混合方式
-
- 計算 web 頁面高度
-
- 攔截請求,自定義指令
-
- 記憶體佔用(儘量少的 dom 元素)
安裝外掛
- webview_flutter
pub.flutter-io.cn/packages/we…
- pubspec.yaml
dependencies:
webview_flutter: ^0.3.20+2
複製程式碼
- ios/Runner/Info.plist
<key>io.flutter.embedded_views_preview</key>
<true/>
複製程式碼
構建介面程式碼
// 頂部導航
Widget _buildAppBar() {
return Container();
}
// 頁標題
Widget _buildPageTitle() {
return Container();
}
// 頁頭部
Widget _buildPageHeader() {
return Container();
}
// web內容
Widget _buildWebView() {
return Container();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppBar(),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
_buildPageTitle(),
Divider(height: 1),
_buildPageHeader(),
_buildWebView(),
],
),
),
);
}
複製程式碼
url 載入
Widget _buildWebView() {
return Container(
height: _webViewHeight,
child: WebView(
initialUrl:
'$SERVER_API_URL/news/content/${widget.item.id}', //widget.url,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) async {
_controller.complete(webViewController);
},
gestureNavigationEnabled: true,
),
);
}
複製程式碼
計算高度
-
PX DP
-
裝置畫素密度
一個邏輯畫素佔用多少個實際畫素
-
註冊 js
double _webViewHeight = 200;
javascriptChannels: <JavascriptChannel>[
_invokeJavascriptChannel(context),
].toSet(),
複製程式碼
// 註冊js回撥
JavascriptChannel _invokeJavascriptChannel(BuildContext context) {
return JavascriptChannel(
name: 'Invoke',
onMessageReceived: (JavascriptMessage message) {
print(message.message);
var webHeight = double.parse(message.message);
if (webHeight != null) {
setState(() {
_webViewHeight = webHeight;
});
}
});
}
複製程式碼
- 回撥
onPageFinished: (String url) {
_getWebViewHeight();
setState(() {
_isPageFinished = true;
});
},
複製程式碼
// 獲取頁面高度
_getWebViewHeight() async {
await (await _controller.future)?.evaluateJavascript('''
try {
// Invoke.postMessage([document.body.clientHeight,document.documentElement.clientHeight,document.documentElement.scrollHeight]);
let scrollHeight = document.documentElement.scrollHeight;
if (scrollHeight) {
Invoke.postMessage(scrollHeight);
}
} catch {}
''');
}
複製程式碼
清除廣告、推薦
onPageStarted: (String url) {
Timer(Duration(seconds: 1), () {
setState(() {
_isPageFinished = true;
});
_removeAd();
_getViewHeight();
});
},
複製程式碼
_removeWebViewAd() async {
await (await _controller.future)?.evaluateJavascript('''
try {
function removeElement(elementName){
let _element = document.getElementById(elementName);
if(!_element) {
_element = document.querySelector(elementName);
}
if(!_element) {
return;
}
let _parentElement = _element.parentNode;
if(_parentElement){
_parentElement.removeChild(_element);
}
}
removeElement('module-engadget-deeplink-top-ad');
removeElement('module-engadget-deeplink-streams');
removeElement('footer');
} catch{}
''');
}
複製程式碼
攔截請求
- 頁面中 href
<div class="tags">
<a href="/tag/chrome-os" class="tag">chrome os</a>
<a href="/tag/chromebook" class="tag">chromebook</a>
<a href="/tag/computer" class="tag">computer</a>
<a href="/tag/gear" class="tag">gear</a>
<a href="/tag/google" class="tag">google</a>
<a href="/tag/laptop" class="tag">laptop</a>
<a href="/tag/personal computing" class="tag">personal computing</a>
<a href="/tag/personalcomputing" class="tag">personalcomputing</a>
<a href="/tag/pixelbook-go" class="tag">pixelbook go</a>
</div>
複製程式碼
- navigation 攔截
navigationDelegate: (NavigationRequest request) {
if (request.url != '$SERVER_API_URL/news/content/${widget.item.id}') {
toastInfo(msg: request.url);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
複製程式碼
loading 狀態顯示
bool _isPageFinished = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: _buildAppBar(),
body: Stack(
children: <Widget>[
SingleChildScrollView(
child: Column(
children: <Widget>[
_buildPageTitle(),
Divider(height: 1),
_buildPageHeader(),
_buildWebView(),
],
),
),
_isPageFinished == true
? Container()
: Align(
alignment: Alignment.center,
child: LoadingBouncingGrid.square(),
),
],
));
}
複製程式碼
分享
安裝外掛
dependencies:
share: ^0.6.4
複製程式碼
程式碼
onPressed: () {
Share.share('${widget.item.title} ${widget.item.url}');
},
複製程式碼
真機除錯
- scrcpy
資源
視訊
藍湖設計稿(加微信給授權 ducafecat)
lanhuapp.com/url/lYuz1 密碼: gSKl
藍湖現在收費了,所以檢視標記還請自己上傳 xd 設計稿 商業設計稿檔案不好直接分享, 可以加微信聯絡 ducafecat
YAPI 介面管理
程式碼
參考
pub.flutter-io.cn/packages/we… pub.flutter-io.cn/packages/lo… pub.flutter-io.cn/packages/sh… github.com/Genymobile/…