在 iOS 上
在您的 Flutter 项目 ios/Runner 目录中自动生成了一个 main.m 文件,该文件定义了 C program implements、int main(int argc, char* argv[]); 的常规主函数。
一个编译输出只能有一个main方法,当程序启动时编译器会立即运行。以下代码创建了一个UIApplicationMain,它“创建应用程序对象和应用程序委托并设置事件循环”:
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
它是simpler in Swift,只需将AppDelegate 注释为@UIApplicationMain。
AppDelegate 是启动 Flutter 的类,因为它扩展了 FlutterAppDelegate。当FlutterAppDelegate被实例化时,iOS会创建FlutterViewController,它会创建一个FlutterEngine。它创建FlutterViewController,因为FlutterViewController 是在Main.storyboard 中配置的,而Info.plist 已在应用程序中指定。所以从技术上讲,Flutter 应用程序是 Storyboard 应用程序?。
无论如何,当 iOS 创建故事板时,AppDelegate 上会设置 window 属性。您可以使用window.rootViewController 在 AppDelegate 中获取FlutterViewController。一个Objective-C++文件,FlutterViewController.mm的sharedSetupWithProject方法使用[[FlutterEngine alloc]initWithName:...创建了一个FlutterEngine:
- (void)sharedSetupWithProject:(nullable FlutterDartProject*)project
initialRoute:(nullable NSString*)initialRoute {
// Need the project to get settings for the view. Initializing it here means
// the Engine class won't initialize it later.
if (!project) {
project = [[[FlutterDartProject alloc] init] autorelease];
}
FlutterView.forceSoftwareRendering = project.settings.enable_software_rendering;
auto engine = fml::scoped_nsobject<FlutterEngine>{[[FlutterEngine alloc]
initWithName:@"io.flutter"
project:project
allowHeadlessExecution:self.engineAllowHeadlessExecution
restorationEnabled:[self restorationIdentifier] != nil]};
if (!engine) {
return;
}
_viewOpaque = YES;
_weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterViewController>>(self);
_engine = std::move(engine);
_flutterView.reset([[FlutterView alloc] initWithDelegate:_engine opaque:self.isViewOpaque]);
[_engine.get() createShell:nil libraryURI:nil initialRoute:initialRoute];
_engineNeedsLaunch = YES;
_ongoingTouches.reset([[NSMutableSet alloc] init]);
[self loadDefaultSplashScreenView];
[self performCommonViewControllerInitialization];
}
最终,在FlutterEngine.mm 中,launchEngine 被调用,并带有入口点(dart 的主函数。)
- (void)launchEngine:(NSString*)entrypoint libraryURI:(NSString*)libraryOrNil {
// Launch the Dart application with the inferred run configuration.
self.shell.RunEngine([_dartProject.get() runConfigurationForEntrypoint:entrypoint
libraryOrNil:libraryOrNil]);
}
Shell::RunEngine 是实现in shell.cc 的 C++ 函数。我现在要停在那里。这可能是事件循环开始的地方?,使用platform_runner->PostTask(...)。
在安卓上
在生成的 Flutter 项目的 android 目录中,MainActivity 在 AndroidManifest.xml 中声明为从主屏幕启动的应用程序。
当activity启动时,Android会调用activity的onCreate方法。因为MainActivity 扩展了FlutterActivity,所以调用了这个onCreate 方法。 FlutterActivityAndFragmentDelegate 被实例化,它的onAttach 方法被调用。最终,FlutterEngine 的 Java 表示使用以下命令创建:
flutterEngine =
new FlutterEngine(
host.getContext(),
host.getFlutterShellArgs().toArray(),
/*automaticallyRegisterPlugins=*/ false,
/*willProvideRestorationData=*/ host.shouldRestoreAndSaveState());
这使用FlutterJNI 与 C++ FlutterEngine 库进行通信。
/**
* Interface between Flutter embedding's Java code and Flutter engine's C/C++ code.
*
* <p>Flutter's engine is built with C/C++. The Android Flutter embedding is responsible for
* coordinating Android OS events and app user interactions with the C/C++ engine. Such coordination
* requires messaging from an Android app in Java code to the C/C++ engine code. This communication
* requires a JNI (Java Native Interface) API to cross the Java/native boundary.
*
稍后,在FlutterActivityAndFragmentDelegate中,doInitialFlutterViewRun被调用,这会创建一个DartEntryPoint,你的main方法再次,基于FlutterActivity的ActivityInfo。这将使用以下内容获取入口函数名称,但默认为"main":
@NonNull
public String getDartEntrypointFunctionName() {
try {
Bundle metaData = getMetaData();
String desiredDartEntrypoint =
metaData != null ? metaData.getString(DART_ENTRYPOINT_META_DATA_KEY) : null;
return desiredDartEntrypoint != null ? desiredDartEntrypoint : DEFAULT_DART_ENTRYPOINT;
} catch (PackageManager.NameNotFoundException e) {
return DEFAULT_DART_ENTRYPOINT;
}
}
然后,flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint); 被调用。因此,您的主要方法已“被调用”。但这使用了FlutterJNI 和 FlutterEngine C++ 代码。首先调用flutterJNI.runBundleAndSnapshotFromLibrary,最后调用这个JNI原生方法:
private native void nativeRunBundleAndSnapshotFromLibrary(
long nativeShellHolderId,
@NonNull String bundlePath,
@Nullable String entrypointFunctionName,
@Nullable String pathToEntrypointFunction,
@NonNull AssetManager manager);
这个原生方法定义在platform_view_adroid_jni_impl.cc:
{
.name = "nativeRunBundleAndSnapshotFromLibrary",
.signature = "(JLjava/lang/String;Ljava/lang/String;"
"Ljava/lang/String;Landroid/content/res/AssetManager;)V",
.fnPtr = reinterpret_cast<void*>(&RunBundleAndSnapshotFromLibrary),
},
RunBundleAndSnapshotFromLibrary 是 C++ 方法:
static void RunBundleAndSnapshotFromLibrary(JNIEnv* env,
jobject jcaller,
jlong shell_holder,
jstring jBundlePath,
jstring jEntrypoint,
jstring jLibraryUrl,
jobject jAssetManager) {
auto asset_manager = std::make_shared<flutter::AssetManager>();
asset_manager->PushBack(std::make_unique<flutter::APKAssetProvider>(
env, // jni environment
jAssetManager, // asset manager
fml::jni::JavaStringToString(env, jBundlePath)) // apk asset dir
);
auto entrypoint = fml::jni::JavaStringToString(env, jEntrypoint);
auto libraryUrl = fml::jni::JavaStringToString(env, jLibraryUrl);
ANDROID_SHELL_HOLDER->Launch(asset_manager, entrypoint, libraryUrl);
}
AndroidShellHolder::Launch 在哪里:
void AndroidShellHolder::Launch(std::shared_ptr<AssetManager> asset_manager,
const std::string& entrypoint,
const std::string& libraryUrl) {
if (!IsValid()) {
return;
}
asset_manager_ = asset_manager;
auto config = BuildRunConfiguration(asset_manager, entrypoint, libraryUrl);
if (!config) {
return;
}
shell_->RunEngine(std::move(config.value()));
}
就像 iOS 一样,Shell::RunEngine 被调用。