Flutter 混合開發實戰問題記錄(四)編譯執行時問題的一些總結

小豬睡枕頭double發表於2019-07-03

專案中的一些模組用flutter重新開發後在兩次雲測和灰度少量渠道後發現了些問題,分為兩類:

一個是非編譯/執行時問題,即dart語法使用錯誤或widget佈局錯誤使用出現的問題

因為這類問題對於所有人幾乎都會遇到,不再詳細說解決方案,只簡單羅列下我遇到的,提醒別人注意即可:

一、非編譯執行問題

1 黑黃相間提示:內容溢位

需要顯示的內容超出了widget容器或螢幕的範圍會出現,一般放入滾動容器中可解

2 image元件的封裝

因為官方image元件提供了類似scaleType的屬性:fit,當出現圖片寬大於高,或高大於寬時,fitWidth或fitHeight就直接替換為BoxFit.cover吧,可以做下相容,另外因為原生元件沒有提供磁碟快取功能,可以自己實現或直接載入個三方庫,比較推薦 flutter_cached_network_image ,然後可以封裝自己的imageloader了, 我寫了個簡易的例子

3 劉海屏適配:用 SafeArea 防止帶劉海的螢幕,或者iPhonex 底部bottom 的頁面顯示異常

class FlutterAlign extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Align(
        alignment: Alignment(-1, 1),
        child: Container(
          child: Text(
            "Hello",
          ),
        ),
      ),
    );
  }
}
複製程式碼

4 關於toast

flutter作為一款UI框架,使用原則貌似是隻要是實現不復雜,原生非不可替代的控制元件都應該用flutter來做,不過toast這個東西為了保持跟原生介面一致性,還是呼叫原生吧,不過我遇到的一個小問題是:有個介面有可能需要快速頻繁提示toast,而且原生程式碼中使用的toast是自定義的不排隊toast(繼承Toast),由於內部機制,快速插入toast佇列資訊會造成系統等待,短時間不再響應toast彈出,解決方案可以是按鈕控制節流(throttle)或防抖(debounce),也可以優化下toast排隊機制。 不過最後還是決定用flutter做一個備用吧,網上的多數方案是使用Overlays

Overlays通過把子widget插入到overlay的stack裡面, 讓依賴它的子widget可以浮在其它的可見元素上面。OverlayEntry可以管理漂浮的widgets。(一個OverlayEntry就是一個層)
複製程式碼

我貼一個簡單實現

import 'package:flutter/material.dart';

class FlutterToast {
  static OverlayEntry _overlayEntry; //toast靠它加到螢幕上
  static bool _showing = false; //toast是否正在showing
  static DateTime _startedTime; //開啟一個新toast的當前時間,用於對比是否已經展示了足夠時間
  static String _msg;
  static void toast(
      BuildContext context,
      String msg,
      ) async {
    assert(msg != null);
    _msg = msg;
    _startedTime = DateTime.now();
    //獲取OverlayState
    OverlayState overlayState = Overlay.of(context);
    _showing = true;
    if (_overlayEntry == null) {
      _overlayEntry = OverlayEntry(
          builder: (BuildContext context) => Positioned(
            //top值,可以改變這個值來改變toast在螢幕中的位置
            top: MediaQuery.of(context).size.height * 2 / 3,
            child: Container(
                alignment: Alignment.center,
                width: MediaQuery.of(context).size.width,
                child: Padding(
                  padding: EdgeInsets.symmetric(horizontal: 80.0),
                  child: AnimatedOpacity(
                    opacity: _showing ? 1.0 : 0.0, //目標透明度
                    duration: _showing
                        ? Duration(milliseconds: 100)
                        : Duration(milliseconds: 400),
                    child: _buildToastWidget(),
                  ),
                )),
          ));
      overlayState.insert(_overlayEntry);
    } else {
      _overlayEntry.markNeedsBuild();
    }
    await Future.delayed(Duration(milliseconds: 2000)); //等待兩秒

    if (DateTime.now().difference(_startedTime).inMilliseconds >= 2000) {
      _showing = false;
      _overlayEntry.markNeedsBuild();
    }
  }

  static _buildToastWidget() {
    return Center(
      child: Card(
        color: Colors.black,
        child: Padding(
          padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0),
          child: Text(
            _msg,
            style: TextStyle(
              fontSize: 14.0,
              color: Colors.white,
            ),
          ),
        ),
      ),
    );
  }
}
複製程式碼

可以根據需要調節UI,讓它和你的原生toast保持一致,但是有個問題,它彈出後會被鍵盤覆蓋,由於機制問題,所以暫時貌似還不能解決,也因如此,flutter這種toast預設在中間彈出防止被蓋住。





除去UI等異常,另一種就是直接debug或release報錯,或者機型適配出現的問題了,多出現在dart VM或SDK中

二、編譯執行問題

1 [FATAL:flutter/runtime/dart_vm.cc(416)] Error while initializing the Dart VM: Wrong full snapshot version, expected '0c73eb70aa4d30f450273cb424be8c62' found 'eed485c757fba5d731e4054412c99f2e'

問題發生於升級flutter sdk之後,直接run出錯,覆蓋版本不詳,我的是1.3.7升級到1.5和之後的版本,搜尋了issue後找到了個方案:

1) removing the content of flutter/bin/cache

2) then running flutter upgrade again

3) then running flutter clean prior to flutter run

複製程式碼

2 部分紅米手機的崩潰

E/flutter: [ERROR:flutter/runtime/dart_vm.cc(259)] VM snapshot must be valid. A/flutter: [FATAL:flutter/shell/common/shell.cc(212)] Check failed: vm. Must be able to initialize the VM. --------- beginning of crash

升級sdk到1.4之後解決

3 cpu架構中so包支援問題

因為是混合開發,flutter作為外掛支援原生專案,所以需要支援什麼樣的cpu架構視原生專案情況而定,我們的平臺底層庫只支援

ndk {
    abiFilters 'armeabi'
    }
複製程式碼

對於flutter SDK的修改:我們只需要修改android-arm、android-arm-profile和android-arm-release下的flutter.jar,將其中的lib/armeabi-v7a/libflutter.so移動到lib/armeabi/libflutter.so即可:

1 先進入目錄
cd $FLUTTER_ROOT/bin/cache/artifacts/engine

2 然後執行 
for arch in android-arm android-arm-profile android-arm-release; do
  pushd $arch
  cp flutter.jar flutter-armeabi-v7a.jar # 備份
  unzip flutter.jar lib/armeabi-v7a/libflutter.so
  mv lib/armeabi-v7a lib/armeabi
  zip -d flutter.jar lib/armeabi-v7a/libflutter.so
  zip flutter.jar lib/armeabi/libflutter.so
  popd
done
複製程式碼

注: 所有的x86/x86_64/armeabi-v7a/arm64-v8a裝置都支援armeabi架構的.so檔案,因此似乎移除其他ABIs的.so檔案是一個減少APK大小的好技巧。但事實上並不是:這不只影響到函式庫的效能和相容性,x86裝置能夠很好的執行ARM型別函式庫,但並不保證100%不發生crash,特別是對舊裝置。64位裝置(arm64-v8a, x86_64, mips64)能夠執行32位的函式庫,但是以32位模式執行,在64位平臺上執行32位版本的ART和Android元件,將丟失專為64位優化過的效能(ART,webview,media等等)。

相關文章