flutter 編譯報錯總結(不斷更新)

tabbin發表於2019-09-04

問題

Cannot fit requested classes in a single dex file (# methods: 66370 > 65536)

原因分析

主要原因是你的專案貌似有點大,已經超過65k個方法。一個dex已經裝不下了,需要個多個dex,也就是multidex ,因為Android系統定義總方法數是一個short int,short int 最大值為65536。

解決方案

  1. 在app module中的build.gradle中新增依賴
    implementation 'com.android.support:multidex:1.0.3' 
    //
    dependencies {
        implementation fileTree(include: ['*.jar'], dir: 'libs')
        implementation 'com.android.support:appcompat-v7:28.0.0'
        implementation 'com.android.support.constraint:constraint-layout:1.1.3'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
        //新增到此處
        implementation 'com.android.support:multidex:1.0.3'
    }
  2. 在app module中的build.gradle中的defaultConfig中新增以下程式碼
    android {
        compileSdkVersion 28
        defaultConfig {
            applicationId "com.example.demo"
            minSdkVersion 16
            targetSdkVersion 28
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
            //新增到此處
            multiDexEnabled true
        }
    }
import 'dart:ui';//window需要import ui庫

void main(){
  //如果size是0,則設定回撥,在回撥中runApp
  if(window.physicalSize.isEmpty){
    window.onMetricsChanged = (){
      //在回撥中,size仍然有可能是0
      if(!window.physicalSize.isEmpty){
        window.onMetricsChanged = null;
        runApp(MyApp());
      }
    };
  } else{
    //如果size非0,則直接runApp
    runApp(MyApp());
  }
}

分析

這段程式碼裡有兩個東西需要了解一下的,第一個是window.onMetricsChanged,原始碼的註釋是這樣寫的

/// A callback that is invoked whenever the [devicePixelRatio],\
/// [physicalSize], [padding], or [viewInsets] values change, for example\
/// when the device is rotated or when the application is resized (e.g. when\
/// showing applications side-by-side on Android).

也就是當devicePixelRatio、physicalSize、padding、viewInsets這幾個東西變化時會觸發的回撥,其中螢幕大小就是physicalSize

第二個是physicalSize,上面說了這個是螢幕大小,但是它一開始是0*0,直到Flutter初始化時將它賦值為螢幕大小才能獲取到非0的值

好了,說完了上面兩個東西,就來說說問題。問題的坑點在於,mian()方法並不是在Flutter給physicalSize賦值後才執行的,兩者並沒有固定的先後順序,從測試來看,跟裝置的效能有關

之前的錯誤解法

之前是下面這樣寫的,然後在新ipad air的profile模式下以及所有機型的debug模式下都會白屏,只有比較舊的mini4不會白屏

void main(){
  window.onMetricsChanged = (){
    runApp(MyApp());
    window.onMetricsChanged = null;
  };
}

經排查,發現原因是mini夠慢,在設定了onMetricsChanged回撥後flutter還沒有讀取到螢幕size,也就還沒出觸發onMetricsChanged。

然而在新air上,則是機率性的,有時和mini一樣,有時在設定onMetricsChanged之前flutter就已經讀取了螢幕size了,所以後面一段時間都不會觸發onMetricsChanged,導致白屏。更奇怪的是,有時設定的onMetricsChanged倍觸發後,仍然是白屏,排查後發現air上不止一次resize,而只有最後一次非0。

所以完整的程式碼中有這一段保護:

window.onMetricsChanged = (){
  //這裡仍然有可能是0
  if(!window.physicalSize.isEmpty){
    window.onMetricsChanged = null;
    runApp(MyApp());
  }
};

連結:https://www.jianshu.com/p/4f0651241956\

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章