Flutter啟動流程

caobugs發表於2019-04-08

Flutter是怎麼啟動起來的,是在Android的Activity的啟動之後嗎?等等這樣的問題,在這個文章中將被解答。

從MainActivity開始

新建立一個Flutter專案,在清單檔案中預設被啟動的Activity是MainActivity,而MainActivity繼承的是FlutterActivity。那麼問題好像簡單了,我們分析一下FlutterActivity,下面是MainActivity的程式碼。

public class MainActivity extends FlutterActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);
  }
}
複製程式碼

上面的原始碼很簡單,有兩個點需要關注,第一個就是在MainActivity.onCreate()中呼叫了GeneratedPluginRegistrant.registerWith()這個方法,第二個是MainActivity繼承自FlutterActivity,我們對這兩個關注點依次進行分析。

GeneratedPluginRegistrant.registerWith()分析

我們檢視GeneratedPluginRegistrant,發現這個類是Android Studio自動生成的,並且不建議修改,這個類也非常簡單,下面是GeneratedPluginRegistrant的程式碼。

public final class GeneratedPluginRegistrant {
  public static void registerWith(PluginRegistry registry) {
    if (alreadyRegisteredWith(registry)) {
      return;
    }
  }

  private static boolean alreadyRegisteredWith(PluginRegistry registry) {
    final String key = GeneratedPluginRegistrant.class.getCanonicalName();
    if (registry.hasPlugin(key)) {
      return true;
    }
    registry.registrarFor(key);
    return false;
  }
}
複製程式碼

如果PluginRegistry已經包含了GeneratedPluginRegistrant就直接返回true,如沒有就呼叫PluginRegistry.registrarFor()進行註冊。

我們分析一下PluginRegistry,看看是怎麼註冊的,發現PluginRegistry是一個介面,下面是PluginRegistry的程式碼。

public interface PluginRegistry {
    Registrar registrarFor(String pluginKey);
}
複製程式碼

PluginRegistry的實現是誰呢?是FlutterActivity,下面開發分析FlutterActivity,暫時看FlutterActivity比較重要,因為這個類是MainActivity的父類,還是PluginRegistry的具體實現類。

FlutterActivity分析

下面是FlutterActivity的程式碼。

public class FlutterActivity extends Activity implements FlutterView.Provider, PluginRegistry, ViewFactory {
    private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
  
    private final FlutterActivityEvents eventDelegate = delegate;
    private final FlutterView.Provider viewProvider = delegate;
    private final PluginRegistry pluginRegistry = delegate;
  
    @Override
    public final boolean hasPlugin(String key) {
        return pluginRegistry.hasPlugin(key);
    }

    @Override
    public final Registrar registrarFor(String pluginKey) {
        return pluginRegistry.registrarFor(pluginKey);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        eventDelegate.onCreate(savedInstanceState);
    }

    @Override
    protected void onDestroy() {
        eventDelegate.onDestroy();
        super.onDestroy();
    }
  
  	@Override
    protected void onStop() {
        eventDelegate.onStop();
        super.onStop();
    }
    //省略了一些程式碼
}

複製程式碼

從上面的程式碼中可以看出來,FlutterActivity是繼承Activity和實現了PluginRegistry。分析一下onCreate,onStop,onDestroy這些生命週期方法被FlutterActivity.eventDelegate代理了,這個時候我們明白了,FlutterActivity就是一個空殼,真正實現是代理類FlutterActivityDelegate。

我們具體看一下,下面是FlutterActivity.onCreate()的程式碼。

 @Override
 protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     eventDelegate.onCreate(savedInstanceState);
 }
複製程式碼

FlutterActivity.$onCreate()比較簡單,呼叫了super的onCreate()和eventDelegate.onCreate(),也就是呼叫了代理類的onCreate方法,下面分析FlutterActivityDelegate。

FlutterActivityDelegate分析

從上面的分析可以得出結論,FlutterActivity什麼都沒有做,都交個了FlutterActivityDelegate去幹,這裡類實現了PluginRegistry,下面是FlutterActivityDelegate的程式碼。

public final class FlutterActivityDelegate
        implements FlutterActivityEvents,
                   FlutterView.Provider,
                   PluginRegistry {
		@Override
    public void onCreate(Bundle savedInstanceState) {
      
    }                     
}

複製程式碼

還是先分析FlutterActivityDelegate.onCreate(),這個真正幹活的onCreate方法還是比較複雜的,下面是FlutterActivityDelegate.onCreate()的程式碼。

@Override
public void onCreate(Bundle savedInstanceState) {
    String[] args = getArgsFromIntent(activity.getIntent());//1
    FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), args);//2
    flutterView = viewFactory.createFlutterView(activity);//3
    if (flutterView == null) {
        FlutterNativeView nativeView = viewFactory.createFlutterNativeView();
        flutterView = new FlutterView(activity, null, nativeView);//4
        flutterView.setLayoutParams(matchParent);
        activity.setContentView(flutterView);//5
        launchView = createLaunchView();
        if (launchView != null) {
            addLaunchView();
        }
    }
    if (loadIntent(activity.getIntent())) {
        return;
    }
    String appBundlePath = FlutterMain.findAppBundlePath(activity.getApplicationContext());
    if (appBundlePath != null) {
        runBundle(appBundlePath);
    }
}
複製程式碼
註釋1

得到了一些引數,這些引數是幹啥用的?我們拿一個trace-startup引數為例進行簡單介紹下面是FlutterActivityDelegate.getArgsFromIntent()的程式碼。

private static String[] getArgsFromIntent(Intent intent) {
    ArrayList<String> args = new ArrayList<>();
    if (intent.getBooleanExtra("trace-startup", false)) {
        args.add("--trace-startup");
    }
    if (intent.getBooleanExtra("start-paused", false)) {
        args.add("--start-paused");
    }
  
    if (!args.isEmpty()) {
        String[] argsArray = new String[args.size()];
        return args.toArray(argsArray);
    }
    return null;
}
複製程式碼

當你安裝一個App的時候,可以用下面這個命令,

flutter run --trace-startup --profile
複製程式碼

安裝完之後會生下面這個json,

{
  "engineEnterTimestampMicros": 273508186457,
  "timeToFrameworkInitMicros": 271420,
  "timeToFirstFrameMicros": 469796,
  "timeAfterFrameworkInitMicros": 198376
}
複製程式碼

這個json會顯示進入Flutter引擎的時間和展示應用第一幀的時間等等。

註釋2

呼叫 FlutterMain.ensureInitializationComplete(),這方法初始化了Flutter,下面是ensureInitializationComplete的程式碼。

    public static void ensureInitializationComplete(Context applicationContext, String[] args) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
          throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
        }
        try {
            sResourceExtractor.waitForCompletion();
            List<String> shellArgs = new ArrayList<>();
            shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat");
    
            String appBundlePath = findAppBundlePath(applicationContext);
            String appStoragePath = PathUtils.getFilesDir(applicationContext);
          
            nativeInit(applicationContext, shellArgs.toArray(new String[0]),
                appBundlePath, appStoragePath, engineCachesPath);//1
        } catch (Exception e) {
            Log.e(TAG, "Flutter initialization failed.", e);
            throw new RuntimeException(e);
        }
    }

		//native方法
    private static native void nativeInit(Context context, String[] args, String 				bundlePath, String appStoragePath, String engineCachesPath);
複製程式碼

先判斷是不是主執行緒,如果不是主執行緒直接丟擲異常。初始化引數呼叫 FlutterMain.nativeInit()方法,這個方法是native方法,主要的用途是初始化Flutter。

註釋3

ViewFactory是一個介面,ViewFactory.createFlutterView()的具體實現有兩個,分別是FlutterActivity.createFlutterView()和FlutterFragmentActivity.createFlutterView()現在這個兩個具體實現都返回null,也就是一定會走到註釋4。

註釋4

建立FlutterView,那麼FlutterView是什麼呢?看一下類的宣告,下面是FlutterView的宣告的程式碼,

public class FlutterView extends SurfaceView implements BinaryMessenger, TextureRegistry 

}
複製程式碼

原來是一 SurfaceView,這個就很容易理解了。

註釋5

關鍵來了,下面是呼叫setContentView的程式碼,

 activity.setContentView(flutterView);
複製程式碼

把FlutterView載入到Activity中,折騰了半天,就是做了這樣一件事,說白了就是建立了一個FlutterView,並且把這個view顯示到螢幕上。

下面是Flutter的啟動流程圖。

Flutter啟動流程

相關文章