FlutterEngin啓動流程&android

Flutter提供了獨立的運行環境Flutter.so做爲Dart代碼的運行環境和控制邏輯,完整的UI框架彙總邏輯和dartVM都是封裝在flutter.so庫中,在Android中開發完成以後,系統會打包到Asset目錄下,安裝成功以後,會抽取Asset文件夾下的Dart相關文件到Android安裝包的環境中,進行加載執行,最終把FlutterUI相關的界面彙總在Android端提供的SurfaceView中進行渲染,開始分析Flutter相關文件在android的加載流程java

Android初始化

Flutter Engine編譯完成以後會生成一個FlutterJar包,提供給Android和Flutter代碼交互的過程 android

Flutter代碼在Android端代碼啓動時,是如何加載相關的Dart代碼,進行執行,最終在手機端是如何顯示出來的c++

!!! info "Android初始化過程"shell

* 1.Android Application啓動
* 2.FlutterMain類初始化Flutter相關的文件,請查看flutter的Apk包中的文件結構
* 3.抽取Apk包中的Flutter相關的資源
* 4.System.loadLibrary(「flutter」)加載`libflutter.so` 引擎文件
* 5.JNI第一次加載so庫時,會自動調用JNI_OnLoad方法,關聯Flutter java平臺代碼到JNI中
* 6.在FlutterMain.cc中調用`Init()`初始化在java端抽取的flutter代碼,把相關的文件路徑傳遞到JNI中,進行初始化,JNI層能夠讀取的文件路徑
複製代碼

Application中進行初始化:

!!! info "STEP"緩存

* 1.Application中調用FlutterMain.startInitialization(this);
* 2.初始化配置文件的路徑和文件名配置,方便讀取不一樣位置的flutter文件
* 3.抽取Aot優化過的代碼
* 4.加載資源文件到資源查找路徑中
* 5.加載so庫:System.loadLibrary("flutter");
* 6.FlutterActivity:對View、事件一系列動做的初始化
複製代碼

android應用啓動Application初始化Dart相關的代碼 Android項目下打包完成以後,抽取Flutter.jar下的libFlutter.so文件在lib文件夾下,資源文件和虛擬機和相關的配置文件到lib下,這一步文件仍是今天加載的文件。安裝App成功以後,App第一次啓動會判斷時間戳來判斷當前的文件是否須要再次抽取到Android的目錄文件夾下。app

初始化Flutter文件

Application啓動Flutter.jar進行初始化

public class FlutterApplication extends Application {
    private Activity mCurrentActivity = null;

    public FlutterApplication() {
    }

    @CallSuper
    public void onCreate() {
        super.onCreate();
        FlutterMain.startInitialization(this);
    }

    public Activity getCurrentActivity() {
        return this.mCurrentActivity;
    }

    public void setCurrentActivity(Activity mCurrentActivity) {
        this.mCurrentActivity = mCurrentActivity;
    }
}
複製代碼

抽取Flutter相關代碼,加載Flutter.so庫

flutter在apk中的文件須要加載纔可以運行dart代碼框架

1.初始化配置文件 2.抽象相關的代碼Apk包Asset目錄中的數據抽取到apk包下的目錄中 3.System.loadLibrary("flutter");初始化so庫async

public void startInitialization(@NonNull Context applicationContext, @NonNull FlutterLoader.Settings settings) {
    if (this.settings == null) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            throw new IllegalStateException("startInitialization must be called on the main thread");
        } else {
            this.settings = settings;
            long initStartTimestampMillis = SystemClock.uptimeMillis();
            this.initConfig(applicationContext);
            this.initResources(applicationContext);
            System.loadLibrary("flutter");
            VsyncWaiter.getInstance((WindowManager)applicationContext.getSystemService("window")).init();
            long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
            FlutterJNI.nativeRecordStartTimestamp(initTimeMillis);
        }
    }
}
複製代碼

初始化配置文件,在apk包安裝到手機以後,在apk的目錄下能夠找,初始化查找的路徑函數

private void initConfig(@NonNull Context applicationContext) {
    Bundle metadata = this.getApplicationInfo(applicationContext).metaData;
    if (metadata != null) {
        this.aotSharedLibraryName = metadata.getString(PUBLIC_AOT_SHARED_LIBRARY_NAME, "libapp.so");
        this.flutterAssetsDir = metadata.getString(PUBLIC_FLUTTER_ASSETS_DIR_KEY, "flutter_assets");
        this.vmSnapshotData = metadata.getString(PUBLIC_VM_SNAPSHOT_DATA_KEY, "vm_snapshot_data");
        this.isolateSnapshotData = metadata.getString(PUBLIC_ISOLATE_SNAPSHOT_DATA_KEY, "isolate_snapshot_data");
    }
}
複製代碼

apk是一個文件壓縮包,flutter代碼發在apk包中的Assert中,須要出去出來發在apk的安裝目錄中,經過ExtractTask類解析抽取,AssetManager管理器能夠抽取出相關的Flutter代碼,會根據目錄下的時間戳文件來判斷文件是否已經被抽取過res_timestampoop

private void initResources(@NonNull Context applicationContext) {
        (new ResourceCleaner(applicationContext)).start();
        String dataDirPath = PathUtils.getDataDirectory(applicationContext);
        String packageName = applicationContext.getPackageName();
        PackageManager packageManager = applicationContext.getPackageManager();
        AssetManager assetManager = applicationContext.getResources().getAssets();
        this.resourceExtractor = new ResourceExtractor(dataDirPath, packageName, packageManager, assetManager);
        this.resourceExtractor.addResource(this.fullAssetPathFrom(this.vmSnapshotData)).addResource(this.fullAssetPathFrom(this.isolateSnapshotData)).addResource(this.fullAssetPathFrom("kernel_blob.bin"));
        this.resourceExtractor.start();
    }
複製代碼

到目前爲止只是android在啓動時進行靜態的加載數據,相關的文件已經添加到Android目錄文件夾下。

初始化UI界面、Plug,事件監聽回調方法

1.在主線程中初始化Flutter文件的安裝路徑 2.FlutterLoader主要負責抽取Flutter的相關文件到從apk包中的asset文件夾下抽取到安裝目錄文件下

FlutterEngine是一個so庫,只有加載到Java的執行路徑中才能初始化Dart虛擬機,提供Dart運行的環境,在接下來的文章中將一些分析FlutterEngine初始化過程,在Android中Application啓動完成,已經初始化進程以後,就能夠開啓Activity,在清單文件中配置的啓動Activity類繼承了FlutterActivity

1.初始化Androidwindow屬性,提供一個全屏狀態個Flutter來使用 2.等待Flutter引擎初始化完成 3.createFlutterView 提供給開發者本身定義Flutter SurfaceView的機制 4.若是createFlutterView用戶沒有定製,那麼使用系統默認的SurfaceView 5.FlutterView提供了面向用戶操做的類,FlutterNativeView提供了Android代碼和Flutter的互操做機制 6.調用setContentView添加SurfaceView 7.添加第一幀到系統,能夠避免Flutter初始化的時候出現白屏現象

通過上面的初始化過程,已經初始化完成UI界面,可是還有Flutter.so文件的加載工做尚未完成

public void onCreate(Bundle savedInstanceState) {
    if (VERSION.SDK_INT >= 21) {
        Window window = this.activity.getWindow();
        window.addFlags(-2147483648);
        window.setStatusBarColor(1073741824);
        window.getDecorView().setSystemUiVisibility(1280);
    }

    String[] args = getArgsFromIntent(this.activity.getIntent());
    加載flutter.so庫,經過FlutterJNI.nativeInit方法
    FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
    this.flutterView = this.viewFactory.createFlutterView(this.activity);
    if (this.flutterView == null) {
        FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
        this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
        this.flutterView.setLayoutParams(matchParent);
        this.activity.setContentView(this.flutterView);
        this.launchView = this.createLaunchView();
        if (this.launchView != null) {
            this.addLaunchView();
        }
    }

    if (!this.loadIntent(this.activity.getIntent())) {
        String appBundlePath = FlutterMain.findAppBundlePath();
        if (appBundlePath != null) {
            this.runBundle(appBundlePath);
        }

    }
}
複製代碼

FlutterView初始化時須要加載Flutter相關的資源

1.初始化FlutterNativeView監聽Flutter.so庫的事件監聽,加載,卸載so庫的事件 FlutterPluginRegistry:註冊系統層級的插件管理對象 DartExecutor:真正的管理FlutterAndroid側的插件綁定及解綁定,事件級別的的處理 FlutterJNI:監聽Flutter側回調Android端的代碼邏輯,so庫層級的事件處理 FlutterUiDisplayListener:Flutter初始化完成以後會回到到Android端的UI改變監聽 2.

public FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
    super(context, attrs);
    this.nextTextureId = new AtomicLong(0L);
    this.mIsSoftwareRenderingEnabled = false;
    this.didRenderFirstFrame = false;
    this.onAccessibilityChangeListener = new OnAccessibilityChangeListener() {
        public void onAccessibilityChanged(boolean isAccessibilityEnabled, boolean isTouchExplorationEnabled) {
            FlutterView.this.resetWillNotDraw(isAccessibilityEnabled, isTouchExplorationEnabled);
        }
    };
    Activity activity = getActivity(this.getContext());
    if (activity == null) {
        throw new IllegalArgumentException("Bad context");
    } else {
        if (nativeView == null) {
            this.mNativeView = new FlutterNativeView(activity.getApplicationContext());
        } else {
            this.mNativeView = nativeView;
        }

        this.dartExecutor = this.mNativeView.getDartExecutor();
        this.flutterRenderer = new FlutterRenderer(this.mNativeView.getFlutterJNI());
        this.mIsSoftwareRenderingEnabled = this.mNativeView.getFlutterJNI().nativeGetIsSoftwareRenderingEnabled();
        this.mMetrics = new FlutterView.ViewportMetrics();
        this.mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;
        this.setFocusable(true);
        this.setFocusableInTouchMode(true);
        this.mNativeView.attachViewAndActivity(this, activity);
        this.mSurfaceCallback = new Callback() {
            public void surfaceCreated(SurfaceHolder holder) {
                FlutterView.this.assertAttached();
                FlutterView.this.mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
            }

            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                FlutterView.this.assertAttached();
                FlutterView.this.mNativeView.getFlutterJNI().onSurfaceChanged(width, height);
            }

            public void surfaceDestroyed(SurfaceHolder holder) {
                FlutterView.this.assertAttached();
                FlutterView.this.mNativeView.getFlutterJNI().onSurfaceDestroyed();
            }
        };
        this.getHolder().addCallback(this.mSurfaceCallback);
        this.mActivityLifecycleListeners = new ArrayList();
        this.mFirstFrameListeners = new ArrayList();
        註冊系統級別的插件監聽
        this.navigationChannel = new NavigationChannel(this.dartExecutor);
        this.keyEventChannel = new KeyEventChannel(this.dartExecutor);
        this.lifecycleChannel = new LifecycleChannel(this.dartExecutor);
        this.localizationChannel = new LocalizationChannel(this.dartExecutor);
        this.platformChannel = new PlatformChannel(this.dartExecutor);
        this.systemChannel = new SystemChannel(this.dartExecutor);
        this.settingsChannel = new SettingsChannel(this.dartExecutor);
        final PlatformPlugin platformPlugin = new PlatformPlugin(activity, this.platformChannel);
        this.addActivityLifecycleListener(new ActivityLifecycleListener() {
            public void onPostResume() {
                platformPlugin.updateSystemUiOverlays();
            }
        });
        this.mImm = (InputMethodManager)this.getContext().getSystemService("input_method");
        PlatformViewsController platformViewsController = this.mNativeView.getPluginRegistry().getPlatformViewsController();
        this.mTextInputPlugin = new TextInputPlugin(this, this.dartExecutor, platformViewsController);
        this.androidKeyProcessor = new AndroidKeyProcessor(this.keyEventChannel, this.mTextInputPlugin);
        this.androidTouchProcessor = new AndroidTouchProcessor(this.flutterRenderer);
        this.mNativeView.getPluginRegistry().getPlatformViewsController().attachTextInputPlugin(this.mTextInputPlugin);
        this.sendLocalesToDart(this.getResources().getConfiguration());
        this.sendUserPlatformSettingsToDart();
    }
}
複製代碼

SurfaceView事件和FlutterEngine事件

在Android端進行SurfaceView進行初始化時,SurfaceView的回到函數中,經過FlutterJNI類中的本地方法和JNI層中的方法進行綁定,FlutterEngine在進行Flutter的渲染時,就能夠傳遞相關的Surface給Android平臺進行渲染顯示

this.mSurfaceCallback = new Callback() {
    public void surfaceCreated(SurfaceHolder holder) {
        FlutterView.this.assertAttached();
        FlutterView.this.mNativeView.getFlutterJNI().onSurfaceCreated(holder.getSurface());
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        FlutterView.this.assertAttached();
        FlutterView.this.mNativeView.getFlutterJNI().onSurfaceChanged(width, height);
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        FlutterView.this.assertAttached();
        FlutterView.this.mNativeView.getFlutterJNI().onSurfaceDestroyed();
    }
};

複製代碼

FlutterMain

調用Flutter for android 庫初始化Flutter相關的文件

1.FlutterMain.startInitialization(this);

2.System.loadLibrary('flutter')加載so

在engine中調用engine/src/flutter/shell/platform/android/library_loader.cc,JNI中的代碼初始化:

!!! info "主要完成三件事"

* 1.初始化FlutterMain做爲JNI層回調的類

* 2.初始化平臺事件的處理類

* 3.初始化UI繪製Sync信號的傳遞
複製代碼

System.loadLibrary 調用過程

在Flutter.jar初始化時,調用System.loadLibrary 查找解壓出來的Flutter.so文件,調用dlopen打開打開so庫,加載C++相關的資源,加載完成後調用JNI_OnLoad,具體調用過程參考下圖,當調用JNI_OnLoad完成後so庫以及提供了能夠運行的函數,接下來就是初始化Flutter相關的代碼和業務邏輯

JNI_OnLoad

JNI中對應相關的類進行初始化

  • 第一次加載so庫時,調用當前的方法,完成一下三件事:

  • 註冊Java層代碼到JNI層,方便後續的回調Java層代碼

  • engine/src/flutter/shell/platform/android/flutter_main.cc

  • /src/flutter/shell/platform/android/io/flutter/view/FlutterView.java

初始化相關的平臺View的事件處理邏輯

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  // Initialize the Java VM.
  fml::jni::InitJavaVM(vm);

  JNIEnv* env = fml::jni::AttachCurrentThread();
  bool result = false;

  // Register FlutterMain.
  result = shell::FlutterMain::Register(env);
  FML_CHECK(result);

  // Register PlatformView
  // 處理平臺的UI/事件相關的內容,生命週期的管理,後臺執行
  result = shell::PlatformViewAndroid::Register(env);
  FML_CHECK(result);

  // Register VSyncWaiter.
  // 真正處理相關的UI繪製事件
  result = shell::VsyncWaiterAndroid::Register(env);
  FML_CHECK(result);

  return JNI_VERSION_1_4;
}
複製代碼

FlutterMain::Register(env)

在library_loader庫中進行組成,編譯engine回調java成代碼

bool FlutterMain::Register(JNIEnv* env) {
  static const JNINativeMethod methods[] = {
      {
          .name = "nativeInit",
          .signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/"
                       "lang/String;Ljava/lang/String;Ljava/lang/String;)V",
          .fnPtr = reinterpret_cast<void*>(&Init),
      },
      {
          .name = "nativeRecordStartTimestamp",
          .signature = "(J)V",
          .fnPtr = reinterpret_cast<void*>(&RecordStartTimestamp),
      },
  };

  jclass clazz = env->FindClass("io/flutter/view/FlutterMain");

  if (clazz == nullptr) {
    return false;
  }

  return env->RegisterNatives(clazz, methods, arraysize(methods)) == 0;
  }
複製代碼

Shell

result = shell::PlatformViewAndroid::Register(env);對應java層事件的處理 /engine/src/flutter/shell/platform/android/platform_view_android.h

class PlatformViewAndroid final : public PlatformView {

    <!-- 沒有對Register進行初始化 -->
    public:
    static bool Register(JNIEnv* env);
複製代碼

VsyncWaiterAndroid

VsyncWaiterAndroid::Register(env);處理相關的frame rate問題,同步平臺層的事件和dart UI的事件更新,JNI回調Java層的代碼io/flutter/view/VsyncWaiter,Android平臺層對幀率的控制使用的類:android.view.Choreographer

// 對應flutter for android 庫中的:io.flutter.view.VsyncWaiter
//
bool VsyncWaiterAndroid::Register(JNIEnv* env) {
  static const JNINativeMethod methods[] = {{
      .name = "nativeOnVsync",
      .signature = "(JJJ)V",
      .fnPtr = reinterpret_cast<void*>(&OnNativeVsync),
  }};

  jclass clazz = env->FindClass("io/flutter/view/VsyncWaiter");

  if (clazz == nullptr) {
    return false;
  }

  g_vsync_waiter_class = new fml::jni::ScopedJavaGlobalRef<jclass>(env, clazz);

  FML_CHECK(!g_vsync_waiter_class->is_null());

  g_async_wait_for_vsync_method_ = env->GetStaticMethodID(
      g_vsync_waiter_class->obj(), "asyncWaitForVsync", "(J)V");

  FML_CHECK(g_async_wait_for_vsync_method_ != nullptr);

  return env->RegisterNatives(clazz, methods, arraysize(methods)) == 0;
}
複製代碼

flutter_main::nativeInit

apk中文件抽取完成以後處理初始化JNI中的代碼,加載flutter相關的文件代碼,io/flutter/view/FlutterMain.class ,nativeInit(applicationContext, (String[])shellArgs.toArray(new String[0]), appBundlePath, appStoragePath, engineCachesPath);,初始化完成以後十里河

nativeInit() 在Java層能夠使用相關的命令傳遞相關的參數 Java層中apk文件抽取完成後初始化參數信息, 主要是傳遞相關的初始化參數到JNI層,方便加載相關的文件 初始化Flutter路徑信息

void FlutterMain::Init(JNIEnv* env,
                       jclass clazz,
                       jobject context,
                       jobjectArray jargs,
                       jstring bundlePath,
                       jstring appStoragePath,
                       jstring engineCachesPath) {
  std::vector<std::string> args;
  args.push_back("flutter");
  for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) {
    args.push_back(std::move(arg));
  }
  // 初始化命令行參數
  auto command_line = fml::CommandLineFromIterators(args.begin(), args.end());

  auto settings = SettingsFromCommandLine(command_line);

  // 初始化資源目錄結構
  settings.assets_path = fml::jni::JavaStringToString(env, bundlePath);

  // Restore the callback cache.
  // TODO(chinmaygarde): Route all cache file access through FML and remove this
  // setter.
  // 設置緩存目錄
  blink::DartCallbackCache::SetCachePath(
      fml::jni::JavaStringToString(env, appStoragePath));
  // 初始化Android緩存目錄
  fml::paths::InitializeAndroidCachesPath(
      fml::jni::JavaStringToString(env, engineCachesPath));
  // 從磁盤加載緩存數據
  blink::DartCallbackCache::LoadCacheFromDisk();

  // 如何運行時配置文件路徑
  if (!blink::DartVM::IsRunningPrecompiledCode()) {
    // Check to see if the appropriate kernel files are present and configure
    // settings accordingly.
    auto application_kernel_path =
        fml::paths::JoinPaths({settings.assets_path, "kernel_blob.bin"});

    if (fml::IsFile(application_kernel_path)) {
      settings.application_kernel_asset = application_kernel_path;
    }
  }
  // 添加回調進入消息隊列
  settings.task_observer_add = [](intptr_t key, fml::closure callback) {
    fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback));
  };
  // 移除消息隊列
  settings.task_observer_remove = [](intptr_t key) {
    fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
  };

#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
  // There are no ownership concerns here as all mappings are owned by the
  // embedder and not the engine.
  auto make_mapping_callback = [](const uint8_t* mapping, size_t size) {
    return [mapping, size]() {
      return std::make_unique<fml::NonOwnedMapping>(mapping, size);
    };
  };

  settings.dart_library_sources_kernel =
      make_mapping_callback(kPlatformStrongDill, kPlatformStrongDillSize);
#endif  // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG

  // Not thread safe. Will be removed when FlutterMain is refactored to no
  // longer be a singleton.
  g_flutter_main.reset(new FlutterMain(std::move(settings)));
}
複製代碼

執行到這個地方,Apk中的文件已經抽取完成,回調方法,回調事件已經完成,路徑的初始化信息已經初始化

總結

經過上面的分析,已經初始化完成Flutter和Android的調用邏輯,經過上面的分析,總結一下Flutter初始化的大概邏輯

1.App啓動,在Application中調用FlutterMain中的startInitialization方法,完成路徑的配置,flutter代碼的抽取,加載Flutter.so庫

2.開始初始化Activity中的UI界面和綁定Android和Flutter通訊,回調等一系列的操做FlutterActivityDelegate中完成

3.在``中調用nativeInit方法初始化Flutter.so庫進行DartVM的初始化操做

4.Flutter.so庫加載時調用JNI_OnLoad方法中初始化FlutterMain做爲Android端的調用入口

5.初始化PlatformViewAndroid,Android端和FlutterView通訊交互的入口

6.Flutter.so初始化完成Engine相關的資源以後,在FlutterLoader.class中調用nativeInit方法初始化

7.經過FlutterJNI中的nativeAttach方法初始化Flutter.so開始綁定Android端和Flutter相關的事件回調

8.在Android端進行SurfaceView進行初始化時,SurfaceView的回到函數Callback中,經過FlutterJNI類中的本地方法和JNI層中的方法進行綁定,FlutterEngine在進行Flutter的渲染時,就能夠傳遞相關的Surface給Android平臺進行渲染顯示

至此,Android端啓動、加載Flutter資源、初始化FlutterEngine,綁定SurfaceView和FlutterEngine引擎的對象,註冊系統級別的插件功能,已經初始化完成,下一篇中咱們將,分析FlutterEngine引擎是怎麼初始化的,畢竟要在手機上看到Flutter引擎代碼的顯示

相關文章
相關標籤/搜索