Flutter 新聞客戶端 - 09 詳情頁展示、分享、遠端真機除錯

會煮咖啡的貓發表於2020-06-24

Flutter 新聞客戶端 - 09 詳情頁展示、分享、遠端真機除錯

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

Flutter 新聞客戶端 - 09 詳情頁展示、分享、遠端真機除錯

淘寶方案

Flutter 新聞客戶端 - 09 詳情頁展示、分享、遠端真機除錯

混合方式

頭條

Flutter 新聞客戶端 - 09 詳情頁展示、分享、遠端真機除錯

Flutter 新聞客戶端 - 09 詳情頁展示、分享、遠端真機除錯

混合方式

什麼值得買

Flutter 新聞客戶端 - 09 詳情頁展示、分享、遠端真機除錯

Flutter 新聞客戶端 - 09 詳情頁展示、分享、遠端真機除錯

Flutter 新聞客戶端 - 09 詳情頁展示、分享、遠端真機除錯

單一 webView

技術點分析

    1. webView 原生 混合方式
    1. 計算 web 頁面高度
    1. 攔截請求,自定義指令
    1. 記憶體佔用(儘量少的 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,
      ),
    );
  }
複製程式碼

計算高度

  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

github.com/Genymobile/…

資源

視訊

藍湖設計稿(加微信給授權 ducafecat)

lanhuapp.com/url/lYuz1 密碼: gSKl

藍湖現在收費了,所以檢視標記還請自己上傳 xd 設計稿 商業設計稿檔案不好直接分享, 可以加微信聯絡 ducafecat

YAPI 介面管理

yapi.demo.qunar.com/

程式碼

github.com/ducafecat/f…

參考

pub.flutter-io.cn/packages/we… pub.flutter-io.cn/packages/lo… pub.flutter-io.cn/packages/sh… github.com/Genymobile/…

VSCode 外掛

相關文章