diff --git a/shell/platform/ohos/flutter_embedding/flutter/index.ets b/shell/platform/ohos/flutter_embedding/flutter/index.ets index 8e44d572561bacb5f4f11cf0da363584980be719..0de593b3b020cdf570fea9c06373d15699e7fa14 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/index.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/index.ets @@ -60,6 +60,7 @@ export { default as FlutterAbilityLaunchConfigs } from './src/main/ets/embedding export { default as FlutterEngineConfigurator } from './src/main/ets/embedding/ohos/FlutterEngineConfigurator'; export { default as FlutterEngineProvider } from './src/main/ets/embedding/ohos/FlutterEngineProvider'; export { default as FlutterEntry } from './src/main/ets/embedding/ohos/FlutterEntry'; +export { default as FlutterWindow } from './src/main/ets/embedding/ohos/FlutterWindow'; export { default as FlutterManager, DragDropCallback as DragDropCallback } from './src/main/ets/embedding/ohos/FlutterManager'; export * from './src/main/ets/embedding/ohos/FlutterPage'; export { default as KeyboardManager } from './src/main/ets/embedding/ohos/KeyboardManager'; diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets index 533e1e6a510b7b6b002088b4121dfa5f5a2d09b1..f109e10a491a96afc62248e840a0b22ef5ecd3bd 100644 --- a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterPage.ets @@ -53,6 +53,7 @@ export struct FlutterPage { XComponent({ id: this.viewId, type: this.xComponentType, libraryname: 'flutter' }) .id(this.viewId) .focusable(true) + .focusOnTouch(true) .onLoad((context) => { this.flutterView?.onSurfaceCreated() Log.d(TAG, "XComponent onLoad "); @@ -133,6 +134,7 @@ export struct FlutterPage { XComponent({ id: this.viewId, type: this.xComponentType, libraryname: 'flutter' }) .id(this.viewId) .focusable(true) + .focusOnTouch(true) .onLoad((context) => { this.flutterView?.onSurfaceCreated() Log.d(TAG, "XComponent onLoad "); diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterWindow.ets b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterWindow.ets new file mode 100644 index 0000000000000000000000000000000000000000..f0c5e5144f50ba9a03ceb014b7e5cb4ad1b43bae --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/ohos/FlutterWindow.ets @@ -0,0 +1,276 @@ +/* +* Copyright (c) 2024 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 FlutterEngine from '../engine/FlutterEngine'; +import PlatformPlugin from '../../plugin/PlatformPlugin'; +import Want from '@ohos.app.ability.Want'; +import FlutterShellArgs from '../engine/FlutterShellArgs'; +import UIAbility from '@ohos.app.ability.UIAbility'; +import ExclusiveAppComponent from './ExclusiveAppComponent'; +import { FlutterAbilityAndEntryDelegate, Host } from './FlutterAbilityAndEntryDelegate'; +import FlutterAbilityLaunchConfigs from './FlutterAbilityLaunchConfigs'; +import Log from '../../util/Log'; +import { FlutterView } from '../../view/FlutterView'; +import FlutterManager from './FlutterManager'; +import window from '@ohos.window'; +import FlutterEngineConfigurator from './FlutterEngineConfigurator'; +import { FlutterPlugin } from '../engine/plugins/FlutterPlugin'; + +const TAG = "FlutterWindow"; + +/** + * 支持嵌入其他应用组件的flutter页面 + */ +export default class FlutterWindow implements Host { + private static ARG_SHOULD_ATTACH_ENGINE_TO_ABILITY: string = "should_attach_engine_to_ability"; + + protected uiAbility: UIAbility | null = null + protected delegate: FlutterAbilityAndEntryDelegate | null = null + protected flutterView: FlutterView | null = null + protected context: Context; + protected windowStage: window.WindowStage | null = null + private parameters: Record = {}; + protected engineConfigurator: FlutterEngineConfigurator | null = null + protected hasInit: boolean = false; + + constructor(context: Context, params: Record = {}) { + this.context = context; + this.uiAbility = FlutterManager.getInstance().getUIAbility(context); + this.parameters = params; + this.windowStage = FlutterManager.getInstance().getWindowStage(this.uiAbility); + this.hasInit = false; + } + + async aboutToInit() { + Log.i(TAG, 'aboutToInit'); + if (this.hasInit == false) { + this.delegate = new FlutterAbilityAndEntryDelegate(this); + this.flutterView = this.delegate?.createView(this.context); + this.flutterView?.onWindowCreated(); + await this?.delegate?.onAttach(this.context); + Log.i(TAG, 'onAttach end'); + this?.delegate?.platformPlugin?.setUIAbilityContext(this.uiAbility!!.context); + this.delegate?.onCreate(); + this.delegate?.onWindowStageCreate() + this.windowStage?.on('windowStageEvent', this.windowStageEventCallback); + this.hasInit = true; + this.delegate?.initWindow(); + } + } + + protected windowStageEventCallback = (data: window.WindowStageEventType) => { + 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.'); + this.delegate?.getFlutterEngine()?.getTextInputChannel()?.textInputMethodHandler?.handleChangeFocus(true); + this?.delegate?.onWindowFocusChanged(true); + break; + case window.WindowStageEventType.INACTIVE: // 失焦状态 + Log.i(TAG, 'windowStage inactive.'); + this?.delegate?.onWindowFocusChanged(false); + break; + case window.WindowStageEventType.HIDDEN: // 切到后台 + Log.i(TAG, 'windowStage background.'); + break; + } + } + + setFlutterEngineConfigurator(configurator: FlutterEngineConfigurator) { + this.engineConfigurator = configurator; + } + + getFlutterView(): FlutterView { + return this.flutterView!! + } + + getFlutterEngine(): FlutterEngine | null { + return this.delegate?.flutterEngine! + } + + aboutToDestroy() { + Log.d(TAG, "FlutterWindow aboutToDestroy==="); + try { + this.windowStage?.off('windowStageEvent', this.windowStageEventCallback); + } catch (err) { + + } + if (this.flutterView != null) { + this.flutterView.onDestroy(); + this.flutterView = null; + } + if (this.delegate != null) { + this.delegate?.onDetach(); + this.delegate?.release() + } + } + + onPageShow() { //生命周期 + Log.d(TAG, "FlutterWindow onPageShow==="); + this?.delegate?.onForeground(); + } + + onPageHide() { //生命周期 + Log.d(TAG, "FlutterWindow onPageHide==="); + this?.delegate?.onBackground(); + } + + onBackPress() { + Log.d(TAG, "FlutterWindow onBackPress==="); + this?.delegate?.flutterEngine?.getNavigationChannel()?.popRoute(); + this?.delegate?.flutterEngine?.getTextInputChannel()?.textInputMethodHandler?.hide(); + } + + shouldDispatchAppLifecycleState(): boolean { + return true; + } + + detachFromFlutterEngine() { + if (this?.delegate != null) { + this?.delegate?.onDetach(); + } + } + + getAbility(): UIAbility { + return this.uiAbility!! + } + + loadContent() { + + } + + shouldAttachEngineToAbility(): boolean { + let param = this.parameters![FlutterEntry.ARG_SHOULD_ATTACH_ENGINE_TO_ABILITY]; + if (!param) { + return true; + } + return param as boolean + } + + getCachedEngineId(): string { + let param = this.parameters![FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_ID]; + if (!param) { + return ""; + } + return param as string + } + + getCachedEngineGroupId(): string | null { + let param = this.parameters![FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_GROUP_ID]; + if (!param) { + return null; + } + return param as string + } + + shouldDestroyEngineWithHost(): boolean { + if ((this.getCachedEngineId() != null && this.getCachedEngineId().length > 0) || this.delegate!!.isFlutterEngineFromHost()) { + // Only destroy a cached engine if explicitly requested by app developer. + return false; + } + return true; + } + + attachToEngineAutomatically(): boolean { + return true; + } + + getFlutterShellArgs(): FlutterShellArgs { + return new FlutterShellArgs(); + } + + getDartEntrypointArgs(): string[] { + if (this.parameters![FlutterAbilityLaunchConfigs.EXTRA_DART_ENTRYPOINT_ARGS]) { + return this.parameters![FlutterAbilityLaunchConfigs.EXTRA_DART_ENTRYPOINT_ARGS] as Array; + } + return new Array() + } + + getDartEntrypointLibraryUri(): string { + return ""; + } + + getAppBundlePath(): string { + return ""; + } + + getDartEntrypointFunctionName(): string { + if (this.parameters![FlutterAbilityLaunchConfigs.EXTRA_DART_ENTRYPOINT]) { + return this.parameters![FlutterAbilityLaunchConfigs.EXTRA_DART_ENTRYPOINT] as string; + } + return FlutterAbilityLaunchConfigs.DEFAULT_DART_ENTRYPOINT + } + + getInitialRoute(): string { + if (this.parameters![FlutterAbilityLaunchConfigs.EXTRA_INITIAL_ROUTE]) { + return this.parameters![FlutterAbilityLaunchConfigs.EXTRA_INITIAL_ROUTE] as string + } + return ""; + } + + getWant(): Want { + return new Want(); + } + + shouldRestoreAndSaveState(): boolean { + if (this.parameters![FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_ID] != undefined) { + return this.parameters![FlutterAbilityLaunchConfigs.EXTRA_CACHED_ENGINE_ID] as boolean; + } + if (this.getCachedEngineId() != null && this.getCachedEngineId().length > 0) { + // Prevent overwriting the existing state in a cached engine with restoration state. + return false; + } + return true; + } + + getExclusiveAppComponent(): ExclusiveAppComponent | null { + return this.delegate ? this.delegate : null + } + + provideFlutterEngine(context: Context): FlutterEngine | null { + return null; + } + + providePlatformPlugin(flutterEngine: FlutterEngine): PlatformPlugin | undefined { + return new PlatformPlugin(flutterEngine.getPlatformChannel()!, this.context, this); + } + + configureFlutterEngine(flutterEngine: FlutterEngine) { + if (this.engineConfigurator) { + this.engineConfigurator.configureFlutterEngine(flutterEngine) + } + } + + cleanUpFlutterEngine(flutterEngine: FlutterEngine) { + if (this.engineConfigurator) { + this.engineConfigurator.cleanUpFlutterEngine(flutterEngine) + } + } + + popSystemNavigator(): boolean { + return false; + } + + addPlugin(plugin: FlutterPlugin): void { + this.delegate?.addPlugin(plugin) + } + + removePlugin(plugin: FlutterPlugin): void { + this.delegate?.removePlugin(plugin) + } +} \ No newline at end of file