{
+ /**
+ * Called when another App Component is about to become attached to the {@link
+ * io.flutter.embedding.engine.FlutterEngine} this App Component is currently attached to.
+ *
+ * This App Component's connections to the {@link io.flutter.embedding.engine.FlutterEngine}
+ * are still valid at the moment of this call.
+ */
+ detachFromFlutterEngine(): void;
+
+ /**
+ * Retrieve the App Component behind this exclusive App Component.
+ *
+ * @return The app component.
+ */
+ getAppComponent(): T;
+}
\ No newline at end of file
diff --git a/ohos/test_cached_network_image/lib/path_provider_ohos/ohos/path_provider/oh_modules/.ohpm/@ohos+flutter_ohos@file+libs+flutter_ohos.har/oh_modules/@ohos/flutter_ohos/src/main/ets/embedding/ohos/FlutterAbility.ets b/ohos/test_cached_network_image/lib/path_provider_ohos/ohos/path_provider/oh_modules/.ohpm/@ohos+flutter_ohos@file+libs+flutter_ohos.har/oh_modules/@ohos/flutter_ohos/src/main/ets/embedding/ohos/FlutterAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..07a374a7109e9a1ffcd5680220534c9796681e64
--- /dev/null
+++ b/ohos/test_cached_network_image/lib/path_provider_ohos/ohos/path_provider/oh_modules/.ohpm/@ohos+flutter_ohos@file+libs+flutter_ohos.har/oh_modules/@ohos/flutter_ohos/src/main/ets/embedding/ohos/FlutterAbility.ets
@@ -0,0 +1,414 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import UIAbility from '@ohos.app.ability.UIAbility';
+import window from '@ohos.window';
+import { FlutterAbilityDelegate, Host } from './FlutterAbilityDelegate';
+import Log from '../../util/Log';
+import FlutterEngine from '../engine/FlutterEngine';
+import FlutterShellArgs from '../engine/FlutterShellArgs';
+import FlutterAbilityLaunchConfigs from './FlutterAbilityLaunchConfigs';
+import common from '@ohos.app.ability.common';
+import Want from '@ohos.app.ability.Want';
+import display from '@ohos.display';
+import { FlutterPlugin } from '../engine/plugins/FlutterPlugin';
+import { AsyncCallback } from '@ohos.base';
+import AbilityConstant from '@ohos.app.ability.AbilityConstant';
+import I18n from '@ohos.i18n'
+import { PlatformBrightness } from '../engine/systemchannels/SettingsChannel';
+import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
+import { DVModelContainer } from '../../view/DynamicView/dynamicView';
+import { RootDvModeManager } from '../../plugin/platform/RootDvModelManager';
+import { Configuration } from '@ohos.app.ability.Configuration';
+
+const TAG = "FlutterAbility";
+/**
+ * flutter ohos基础ability,请在让主ability继承自该类。
+ * 该类主要职责:
+ * 1、持有FlutterAbilityDelegate并初始化;
+ * 2、生命周期传递;
+ */
+export class FlutterAbility extends UIAbility implements Host {
+ private delegate: FlutterAbilityDelegate;
+ private windowStage: window.WindowStage;
+ private mainWindow: window.Window;
+ private viewportMetrics = new ViewportMetrics();
+ private displayInfo: display.Display;
+
+ /**
+ * onCreate
+ * 1、create and attach delegate
+ * 2、config windows transparent noNeed?
+ * 3、lifecycle.onCreate
+ * 4. setContentView() noNeed
+ */
+ async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
+ Log.i(TAG, "bundleCodeDir=" + this.context.bundleCodeDir);
+ // globalThis.flutterAbility = this
+ this.displayInfo = display.getDefaultDisplaySync();
+ this.viewportMetrics.devicePixelRatio = this.displayInfo.densityPixels
+
+ this.delegate = new FlutterAbilityDelegate(this);
+ await this.delegate.onAttach(this.context);
+ Log.i(TAG, 'onAttach end');
+ this.delegate.platformPlugin.setUIAbilityContext(this.context);
+ this.delegate.onRestoreInstanceState(want);
+ this.delegate.sendSettings();
+
+ if (this.stillAttachedForEvent("onCreate")) {
+ this.delegate.onCreate();
+ }
+
+ console.log('MyAbility onCreate');
+ // globalThis.applicationContext = this.context.getApplicationContext();
+ }
+
+ onDestroy() {
+ if (this.stillAttachedForEvent("onDestroy")) {
+ this.delegate.onDestroy();
+ }
+ }
+
+ /**
+ * window状态改变回调
+ * @param windowStage
+ */
+ async onWindowStageCreate(windowStage: window.WindowStage) {
+ this.windowStage = windowStage
+ try {
+ windowStage.on('windowStageEvent', (data) => {
+ let stageEventType: window.WindowStageEventType = data;
+ switch (stageEventType) {
+ case window.WindowStageEventType.SHOWN: // 切到前台
+ Log.i(TAG, 'windowStage foreground.');
+ break;
+ case window.WindowStageEventType.ACTIVE: // 获焦状态
+ Log.i(TAG, 'windowStage active.');
+ if (this.stillAttachedForEvent("onWindowFocusChanged")) {
+ this.delegate.onWindowFocusChanged(true);
+ }
+ break;
+ case window.WindowStageEventType.INACTIVE: // 失焦状态
+ Log.i(TAG, 'windowStage inactive.');
+ if (this.stillAttachedForEvent("onWindowFocusChanged")) {
+ this.delegate.onWindowFocusChanged(false);
+ }
+ break;
+ case window.WindowStageEventType.HIDDEN: // 切到后台
+ Log.i(TAG, 'windowStage background.');
+ break;
+ default:
+ break;
+ }
+ });
+
+ this.mainWindow = windowStage.getMainWindowSync()
+ this.mainWindow.on('windowSizeChange', (data) => {
+ this.onWindowPropertiesUpdated();
+ });
+
+ this.mainWindow.on('avoidAreaChange', (data) => {
+ this.onWindowPropertiesUpdated();
+ });
+
+ this.mainWindow.on('keyboardHeightChange', (data) => {
+ this.onWindowPropertiesUpdated();
+ });
+
+ this.loadContent();
+ this.mainWindow.setWindowLayoutFullScreen(true);
+ } catch (exception) {
+ Log.e(TAG, 'Failed to enable the listener for window stage event changes. Cause:' + JSON.stringify(exception));
+ }
+ }
+
+ loadContent() {
+ if (this.windowStage != null && this.stillAttachedForEvent("loadContent")) {
+ Log.i(TAG, 'loadContent');
+ this.windowStage.loadContent('pages/Index', (err, data) => {
+ if (err.code) {
+ Log.e(TAG, 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
+ return;
+ }
+ this.onWindowPropertiesUpdated();
+ Log.i(TAG, 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
+ });
+ if (this.stillAttachedForEvent("onWindowStageCreate")) {
+ this.delegate.onWindowStageCreate();
+ }
+ this.delegate.getFlutterNapi().updateRefreshRate(this.displayInfo.refreshRate)
+ this.onFlutterEngineReady()
+ }
+ }
+
+ onFlutterEngineReady(): void {
+
+ }
+
+ private updateViewportMetrics() {
+ this.delegate.getFlutterNapi().setViewportMetrics(this.viewportMetrics.devicePixelRatio,
+ this.viewportMetrics.physicalWidth,
+ this.viewportMetrics.physicalHeight,
+ this.viewportMetrics.physicalViewPaddingTop,
+ this.viewportMetrics.physicalViewPaddingRight,
+ this.viewportMetrics.physicalViewPaddingBottom,
+ this.viewportMetrics.physicalViewPaddingLeft,
+ this.viewportMetrics.physicalViewInsetTop,
+ this.viewportMetrics.physicalViewInsetRight,
+ this.viewportMetrics.physicalViewInsetBottom,
+ this.viewportMetrics.physicalViewInsetLeft,
+ this.viewportMetrics.systemGestureInsetTop,
+ this.viewportMetrics.systemGestureInsetRight,
+ this.viewportMetrics.systemGestureInsetBottom,
+ this.viewportMetrics.systemGestureInsetLeft,
+ this.viewportMetrics.physicalTouchSlop,
+ new Array(0),
+ new Array(0),
+ new Array(0))
+ }
+
+ onWindowStageDestroy() {
+ if (this.stillAttachedForEvent("onWindowStageDestroy")) {
+ this.delegate.onWindowStageDestroy();
+ }
+ }
+
+ onForeground() {
+ if (this.stillAttachedForEvent("onForeground")) {
+ this.delegate.onForeground();
+ }
+ }
+
+ onBackground() {
+ if (this.stillAttachedForEvent("onBackground")) {
+ this.delegate.onBackground();
+ }
+ }
+
+ release() {
+ if (this.delegate != null) {
+ this.delegate.release();
+ this.delegate = null;
+ }
+ }
+
+ /**
+ * host所有实现方法开始======start
+ */
+
+ getAbility(): UIAbility {
+ return this;
+ }
+
+ shouldDispatchAppLifecycleState(): boolean {
+ return true;
+ }
+
+ provideFlutterEngine(context: common.Context): FlutterEngine {
+ return null;
+ }
+
+ configureFlutterEngine(flutterEngine: FlutterEngine) {
+
+ }
+
+ cleanUpFlutterEngine(flutterEngine: FlutterEngine) {
+
+ }
+
+ getFlutterShellArgs(): FlutterShellArgs {
+ return FlutterShellArgs.fromWant(this.getWant());
+ }
+
+ getDartEntrypointArgs(): Array {
+ if (this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_DART_ENTRYPOINT_ARGS]) {
+ return this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_DART_ENTRYPOINT_ARGS] as Array;
+ }
+ return new Array()
+ }
+
+ detachFromFlutterEngine() {
+ if (this.delegate != null) {
+ this.delegate.onDetach();
+ }
+ }
+
+ popSystemNavigator(): boolean {
+ return false;
+ }
+
+ shouldAttachEngineToActivity(): boolean {
+ return true;
+ }
+
+ getDartEntrypointLibraryUri(): string {
+ return null;
+ }
+
+ getAppBundlePath(): string {
+ return null;
+ }
+
+ getDartEntrypointFunctionName(): string {
+ if (this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_DART_ENTRYPOINT]) {
+ return this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_DART_ENTRYPOINT] as string;
+ }
+ return FlutterAbilityLaunchConfigs.DEFAULT_DART_ENTRYPOINT
+ }
+
+ getInitialRoute(): string {
+ if (this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_INITIAL_ROUTE]) {
+ return this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_INITIAL_ROUTE] as string;
+ }
+ return null
+ }
+
+ getWant(): Want {
+ return this.launchWant;
+ }
+
+ shouldDestroyEngineWithHost(): boolean {
+ return true;
+ }
+
+ shouldRestoreAndSaveState(): boolean{
+ if (this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_ID] != undefined) {
+ return this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_ID] as boolean;
+ }
+ if (this.getCachedEngineId() != null) {
+ // Prevent overwriting the existing state in a cached engine with restoration state.
+ return false;
+ }
+ return true;
+ }
+
+ getCachedEngineId(): string {
+ return this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_ID] as string
+ }
+
+ getCachedEngineGroupId(): string {
+ return this.launchWant.parameters[FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_GROUP_ID] as string
+ }
+
+ /**
+ * host所有实现方法结束======end
+ */
+ private stillAttachedForEvent(event: string) {
+ Log.i(TAG, 'Ability ' + event);
+ if (this.delegate == null) {
+ Log.w(TAG, "FlutterAbility " + event + " call after release.");
+ return false;
+ }
+ if (!this.delegate.isAttached) {
+ Log.w(TAG, "FlutterAbility " + event + " call after detach.");
+ return false;
+ }
+ return true;
+ }
+
+ addPlugin(plugin: FlutterPlugin): void {
+ if (this.delegate != null) {
+ this.delegate.addPlugin(plugin)
+ }
+ }
+
+ removePlugin(plugin: FlutterPlugin): void {
+ if (this.delegate != null) {
+ this.delegate.removePlugin(plugin)
+ }
+ }
+
+ private onWindowPropertiesUpdated(){
+ if (!this.delegate.isAttached) {
+ return;
+ }
+ let systemAvoidArea = this.mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
+ let gestureAvoidArea = this.mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM_GESTURE);
+ let keyboardAvoidArea = this.mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_KEYBOARD);
+ const properties = this.mainWindow.getWindowProperties();
+ this.viewportMetrics.physicalWidth = properties.windowRect.width;
+ this.viewportMetrics.physicalHeight = properties.windowRect.height;
+
+ this.viewportMetrics.physicalViewPaddingTop = systemAvoidArea.topRect.height
+ this.viewportMetrics.physicalViewPaddingLeft = systemAvoidArea.leftRect.width
+ this.viewportMetrics.physicalViewPaddingBottom = systemAvoidArea.bottomRect.height
+ this.viewportMetrics.physicalViewPaddingRight = systemAvoidArea.rightRect.width
+
+ this.viewportMetrics.physicalViewInsetTop = keyboardAvoidArea.topRect.height
+ this.viewportMetrics.physicalViewInsetLeft = keyboardAvoidArea.leftRect.width
+ this.viewportMetrics.physicalViewInsetBottom = keyboardAvoidArea.bottomRect.height
+ this.viewportMetrics.physicalViewInsetRight = keyboardAvoidArea.rightRect.width
+
+ this.viewportMetrics.systemGestureInsetTop = gestureAvoidArea.topRect.height
+ this.viewportMetrics.systemGestureInsetLeft = gestureAvoidArea.leftRect.width
+ this.viewportMetrics.systemGestureInsetBottom = gestureAvoidArea.bottomRect.height
+ this.viewportMetrics.systemGestureInsetRight = gestureAvoidArea.rightRect.width
+
+ this.updateViewportMetrics()
+ }
+
+ onMemoryLevel(level: AbilityConstant.MemoryLevel): void {
+ Log.i(TAG, 'onMemoryLevel: ' + level);
+ if (level === AbilityConstant.MemoryLevel.MEMORY_LEVEL_CRITICAL) {
+ this.delegate.onLowMemory();
+ }
+ }
+
+ onConfigurationUpdated(config: Configuration){
+ Log.i(TAG, 'onConfigurationUpdated config:' + JSON.stringify(config));
+ this.delegate.flutterEngine.getSettingsChannel().startMessage()
+ .setAlwaysUse24HourFormat(I18n.System.is24HourClock())
+ .setPlatformBrightness(config.colorMode != ConfigurationConstant.ColorMode.COLOR_MODE_DARK
+ ? PlatformBrightness.LIGHT : PlatformBrightness.DARK);
+ }
+
+ getWindowId(callback: AsyncCallback): void {
+ if (callback === null) {
+ return;
+ }
+ try {
+ window.getLastWindow(this.context, (error, win) => {
+ if (error.code) {
+ callback(error, -1);
+ return;
+ }
+ let windowId = win.getWindowProperties().id;
+ callback(error, windowId);
+ });
+ } catch (err) {
+ Log.e(TAG, "get window id error!");
+ callback(err, -1);
+ }
+ }
+}
+
+export class ViewportMetrics {
+ devicePixelRatio: number = 1.0;
+ physicalWidth: number = 0;
+ physicalHeight: number = 0;
+ physicalViewPaddingTop: number = 0;
+ physicalViewPaddingRight: number = 0;
+ physicalViewPaddingBottom: number = 0;
+ physicalViewPaddingLeft: number = 0;
+ physicalViewInsetTop: number = 0;
+ physicalViewInsetRight: number = 0;
+ physicalViewInsetBottom: number = 0;
+ physicalViewInsetLeft: number = 0;
+ systemGestureInsetTop: number = 0;
+ systemGestureInsetRight: number = 0;
+ systemGestureInsetBottom: number = 0;
+ systemGestureInsetLeft: number = 0;
+ physicalTouchSlop = -1;
+}
\ No newline at end of file
diff --git a/ohos/test_cached_network_image/lib/path_provider_ohos/ohos/path_provider/oh_modules/.ohpm/@ohos+flutter_ohos@file+libs+flutter_ohos.har/oh_modules/@ohos/flutter_ohos/src/main/ets/embedding/ohos/FlutterAbilityDelegate.ets b/ohos/test_cached_network_image/lib/path_provider_ohos/ohos/path_provider/oh_modules/.ohpm/@ohos+flutter_ohos@file+libs+flutter_ohos.har/oh_modules/@ohos/flutter_ohos/src/main/ets/embedding/ohos/FlutterAbilityDelegate.ets
new file mode 100644
index 0000000000000000000000000000000000000000..9046981a47219a7eb553dd4d3baeefa639069281
--- /dev/null
+++ b/ohos/test_cached_network_image/lib/path_provider_ohos/ohos/path_provider/oh_modules/.ohpm/@ohos+flutter_ohos@file+libs+flutter_ohos.har/oh_modules/@ohos/flutter_ohos/src/main/ets/embedding/ohos/FlutterAbilityDelegate.ets
@@ -0,0 +1,440 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import common from '@ohos.app.ability.common';
+import FlutterEngineConfigurator from './FlutterEngineConfigurator';
+import FlutterEngineProvider from './FlutterEngineProvider';
+import FlutterEngine from '../engine/FlutterEngine';
+import PlatformPlugin, { PlatformPluginDelegate } from '../../plugin/PlatformPlugin';
+import Want from '@ohos.app.ability.Want';
+import FlutterShellArgs from '../engine/FlutterShellArgs';
+import DartExecutor, { DartEntrypoint } from '../engine/dart/DartExecutor';
+import FlutterAbilityLaunchConfigs from './FlutterAbilityLaunchConfigs';
+import Log from '../../util/Log';
+import FlutterInjector from '../../FlutterInjector';
+import UIAbility from '@ohos.app.ability.UIAbility';
+import ExclusiveAppComponent from './ExclusiveAppComponent';
+import AbilityConstant from '@ohos.app.ability.AbilityConstant';
+import TextInputPlugin from '../../plugin/editing/TextInputPlugin';
+import { FlutterPlugin } from '../engine/plugins/FlutterPlugin';
+import FlutterEngineCache from '../engine/FlutterEngineCache';
+import FlutterEngineGroupCache from '../engine/FlutterEngineGroupCache';
+import FlutterEngineGroup, { Options } from '../engine/FlutterEngineGroup';
+import MouseCursorPlugin, { MouseCursorViewDelegate } from '../../plugin/mouse/MouseCursorPlugin';
+import Settings from './Settings';
+
+const TAG = "FlutterAbilityDelegate";
+const PLUGINS_RESTORATION_BUNDLE_KEY = "plugins";
+const FRAMEWORK_RESTORATION_BUNDLE_KEY = "framework";
+
+/**
+ * 主要职责:
+ * 1、初始化engine
+ * 2、处理ability生命周期回调
+ */
+class FlutterAbilityDelegate implements ExclusiveAppComponent {
+ private host: Host;
+ flutterEngine: FlutterEngine;
+ platformPlugin: PlatformPlugin;
+ private context: common.Context;
+ private textInputPlugin: TextInputPlugin;
+ private isFlutterEngineFromHost: boolean;
+ private engineGroup: FlutterEngineGroup;
+ private mouseCursorPlugin: MouseCursorPlugin;
+ private settings: Settings;
+
+ constructor(host: Host) {
+ this.host = host;
+ }
+
+ /**
+ * 是否还attach在ability上
+ */
+ isAttached = false;
+
+ async onAttach(context: common.Context): Promise {
+ this.context = context;
+ this.ensureAlive();
+ if (this.flutterEngine == null) {
+ await this.setupFlutterEngine();
+ }
+ //shouldAttachEngineToActivity
+ if (this.host.shouldAttachEngineToActivity()) {
+ // Notify any plugins that are currently attached to our FlutterEngine that they
+ // are now attached to an Ability.
+ Log.d(TAG, "Attaching FlutterEngine to the Ability that owns this delegate.");
+ this.flutterEngine.getAbilityControlSurface().attachToAbility(this);
+ }
+
+ //providePlatformPlugin
+
+ //configureFlutterEngine
+ this.isAttached = true;
+ Log.d(TAG, "onAttach end start loadcontent")
+ this.host.loadContent()
+ this.textInputPlugin = new TextInputPlugin(this.flutterEngine.getTextInputChannel());
+ this.platformPlugin = new PlatformPlugin(this.flutterEngine.getPlatformChannel(), this.context);
+ this.mouseCursorPlugin = new MouseCursorPlugin(this.host, this.flutterEngine.getMouseCursorChannel());
+ this.settings = new Settings(this.flutterEngine.getSettingsChannel());
+ this.flutterEngine.getSystemLanguages();
+ }
+
+ /**
+ * 加载app.so资源或者snapshot
+ */
+ private doInitialFlutterViewRun(): void {
+ let initialRoute = this.host.getInitialRoute();
+ if (initialRoute == null) {
+ initialRoute = this.maybeGetInitialRouteFromIntent(this.host.getWant());
+ if (initialRoute == null) {
+ initialRoute = FlutterAbilityLaunchConfigs.DEFAULT_INITIAL_ROUTE;
+ }
+ }
+ const libraryUri = this.host.getDartEntrypointLibraryUri();
+ Log.d(TAG, "Executing Dart entrypoint: " + this.host.getDartEntrypointFunctionName() + ", library uri: " + libraryUri == null ? "\"\"" : libraryUri + ", and sending initial route: " + initialRoute);
+
+ // The engine needs to receive the Flutter app's initial route before executing any
+ // Dart code to ensure that the initial route arrives in time to be applied.
+ this.flutterEngine.getNavigationChannel().setInitialRoute(initialRoute);
+
+ let appBundlePathOverride = this.host.getAppBundlePath();
+ if (appBundlePathOverride == null || appBundlePathOverride == '') {
+ appBundlePathOverride = FlutterInjector.getInstance().getFlutterLoader().findAppBundlePath();
+ }
+
+ const dartEntrypoint: DartEntrypoint = new DartEntrypoint(
+ appBundlePathOverride,
+ this.host.getDartEntrypointLibraryUri(),
+ this.host.getDartEntrypointFunctionName()
+ );
+ this.flutterEngine.dartExecutor.executeDartEntrypoint(dartEntrypoint, this.host.getDartEntrypointArgs());
+ }
+
+ private maybeGetInitialRouteFromIntent(want: Want): string {
+ return null;
+ }
+
+
+ /**
+ * 通过参数,配置flutterEngine
+ * @param want
+ */
+ onRestoreInstanceState(want: Want) {
+ let frameworkState: Uint8Array = want.parameters[FRAMEWORK_RESTORATION_BUNDLE_KEY] as Uint8Array;
+ if (this.host.shouldRestoreAndSaveState()) {
+ this.flutterEngine.getRestorationChannel().setRestorationData(frameworkState ?? null);
+ }
+ }
+
+ /**
+ * 初始化flutterEngine
+ */
+ async setupFlutterEngine() {
+ // First, check if the host wants to use a cached FlutterEngine.
+ const cachedEngineId = this.host.getCachedEngineId();
+ Log.d(TAG, "cachedEngineId=" + cachedEngineId);
+ if (cachedEngineId && cachedEngineId.length > 0) {
+ this.flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId);
+ this.isFlutterEngineFromHost = true;
+ if (this.flutterEngine == null) {
+ throw new Error(
+ "The requested cached FlutterEngine did not exist in the FlutterEngineCache: '"
+ + cachedEngineId
+ + "'");
+ }
+ return;
+ }
+
+ // Second, defer to subclasses for a custom FlutterEngine.
+ this.flutterEngine = this.host.provideFlutterEngine(this.context);
+ if (this.flutterEngine != null) {
+ this.isFlutterEngineFromHost = true;
+ return;
+ }
+
+ // Third, check if the host wants to use a cached FlutterEngineGroup
+ // and create new FlutterEngine using FlutterEngineGroup#createAndRunEngine
+ const cachedEngineGroupId = this.host.getCachedEngineGroupId();
+ Log.d(TAG, "cachedEngineGroupId=" + cachedEngineGroupId);
+ if (cachedEngineGroupId != null) {
+ const flutterEngineGroup = FlutterEngineGroupCache.instance.get(cachedEngineGroupId);
+ if (flutterEngineGroup == null) {
+ throw new Error(
+ "The requested cached FlutterEngineGroup did not exist in the FlutterEngineGroupCache: '"
+ + cachedEngineGroupId
+ + "'");
+ }
+
+ this.flutterEngine = await flutterEngineGroup.createAndRunEngineByOptions(this.addEntrypointOptions(new Options(this.context)));
+ this.isFlutterEngineFromHost = false;
+ return;
+ }
+
+ // Our host did not provide a custom FlutterEngine. Create a FlutterEngine to back our
+ // FlutterView.
+ Log.d(
+ TAG,
+ "No preferred FlutterEngine was provided. Creating a new FlutterEngine for this FlutterAbility.");
+
+ let group = this.engineGroup;
+ if (group == null) {
+ group = new FlutterEngineGroup();
+ await group.checkLoader(this.context, this.host.getFlutterShellArgs().toArray());
+ }
+ this.flutterEngine = await group.createAndRunEngineByOptions(this.addEntrypointOptions(new Options(this.context)
+ .setAutomaticallyRegisterPlugins(false).setWaitForRestorationData(this.host.shouldRestoreAndSaveState())));
+ this.isFlutterEngineFromHost = false;
+ }
+
+ addEntrypointOptions(options: Options): Options {
+ let appBundlePathOverride = this.host.getAppBundlePath();
+ if (appBundlePathOverride == null || appBundlePathOverride.length == 0) {
+ appBundlePathOverride = FlutterInjector.getInstance().getFlutterLoader().findAppBundlePath();
+ }
+
+ const dartEntrypoint = new DartEntrypoint(appBundlePathOverride, null, this.host.getDartEntrypointFunctionName());
+ let initialRoute = this.host.getInitialRoute();
+ if (initialRoute == null) {
+ initialRoute = this.maybeGetInitialRouteFromIntent(this.host.getWant());
+ if (initialRoute == null) {
+ initialRoute = FlutterAbilityLaunchConfigs.DEFAULT_INITIAL_ROUTE;
+ }
+ }
+ return options
+ .setDartEntrypoint(dartEntrypoint)
+ .setInitialRoute(initialRoute)
+ .setDartEntrypointArgs(this.host.getDartEntrypointArgs());
+ }
+
+ /**
+ * 释放所有持有对象
+ */
+ release() {
+ this.host = null;
+ this.flutterEngine = null;
+ }
+
+ onDetach() {
+ if (this.host.shouldAttachEngineToActivity()) {
+ // Notify plugins that they are no longer attached to an Activity.
+ Log.d(TAG, "Detaching FlutterEngine from the Ability");
+ this.flutterEngine.getAbilityControlSurface().detachFromAbility();
+ }
+ }
+
+ onLowMemory(): void {
+ this.getFlutterNapi().notifyLowMemoryWarning();
+ this.flutterEngine.getSystemChannel().sendMemoryPressureWarning();
+ }
+
+ /**
+ * 生命周期回调
+ */
+
+ onCreate() {
+ this.ensureAlive();
+ if (this.shouldDispatchAppLifecycleState()) {
+ this.flutterEngine.getLifecycleChannel().appIsInactive();
+ }
+ }
+
+ onDestroy() {
+ this.ensureAlive();
+ if (this.shouldDispatchAppLifecycleState()) {
+ this.flutterEngine.getLifecycleChannel().appIsDetached();
+ }
+ this.textInputPlugin.detach();
+ }
+
+ onWindowStageCreate() {
+ this.ensureAlive();
+ this.doInitialFlutterViewRun();
+ if (this.shouldDispatchAppLifecycleState()) {
+ this.flutterEngine.getLifecycleChannel().appIsResumed();
+ }
+ }
+
+ onWindowStageDestroy() {
+
+ }
+
+ onWindowFocusChanged(hasFocus: boolean):void {
+ if (this.shouldDispatchAppLifecycleState()) {
+ this.flutterEngine.getAbilityControlSurface().onWindowFocusChanged(hasFocus);
+ if (hasFocus) {
+ this.flutterEngine.getLifecycleChannel().aWindowIsFocused();
+ } else {
+ this.flutterEngine.getLifecycleChannel().noWindowsAreFocused();
+ }
+ }
+ }
+
+ onForeground() {
+ this.ensureAlive();
+ if (this.shouldDispatchAppLifecycleState()) {
+ this.flutterEngine.getLifecycleChannel().appIsResumed();
+ }
+ }
+
+ onBackground() {
+ if (this.shouldDispatchAppLifecycleState()) {
+ this.flutterEngine.getLifecycleChannel().appIsPaused();
+ }
+ }
+
+ /**
+ * 生命周期回调结束
+ */
+
+ shouldDispatchAppLifecycleState(): boolean {
+ return this.host.shouldDispatchAppLifecycleState() && this.isAttached;
+ }
+
+ ensureAlive() {
+ if (this.host == null) {
+ throw new Error("Cannot execute method on a destroyed FlutterAbilityDelegate.");
+ }
+ }
+
+ getFlutterNapi() {
+ return this.flutterEngine.getFlutterNapi()
+ }
+
+ detachFromFlutterEngine() {
+ if (this.host.shouldDestroyEngineWithHost()) {
+ // The host owns the engine and should never have its engine taken by another exclusive
+ // activity.
+ throw new Error(
+ "The internal FlutterEngine created by "
+ + this.host
+ + " has been attached to by another activity. To persist a FlutterEngine beyond the "
+ + "ownership of this ablity, explicitly create a FlutterEngine");
+ }
+
+ // Default, but customizable, behavior is for the host to call {@link #onDetach}
+ // deterministically as to not mix more events during the lifecycle of the next exclusive
+ // activity.
+ this.host.detachFromFlutterEngine();
+ }
+
+ getAppComponent(): UIAbility {
+ const ability = this.host.getAbility();
+ if (ability == null) {
+ throw new Error(
+ "FlutterActivityAndFragmentDelegate's getAppComponent should only "
+ + "be queried after onAttach, when the host's ability should always be non-null");
+ }
+ return ability;
+ }
+
+ onNewWant(want: Want, launchParams: AbilityConstant.LaunchParam): void {
+ this.ensureAlive()
+ if (this.flutterEngine != null) {
+ Log.i(TAG, "Forwarding onNewWant() to FlutterEngine and sending pushRouteInformation message.");
+ this.flutterEngine.getAbilityControlSurface().onNewWant(want, launchParams);
+ const initialRoute = this.maybeGetInitialRouteFromIntent(want);
+ if (initialRoute && initialRoute.length > 0) {
+ this.flutterEngine.getNavigationChannel().pushRouteInformation(initialRoute);
+ }
+ } else {
+ Log.w(TAG, "onNewIntent() invoked before FlutterFragment was attached to an Activity.");
+ }
+ }
+
+ onSaveState(reason: AbilityConstant.StateType, wantParam: Record