When attached to JNI, this {@link DartExecutor} begins handling 2-way communication to/from + * the Dart execution context. This communication is facilitate via 2 APIs: + * + *
When detached from JNI, this {@link DartExecutor} stops handling 2-way communication to/from + * the Dart execution context. + */ + onDetachedFromNAPI(): void { + Log.d(TAG, "Detached from NAPI. De-registering the platform message handler for this Dart execution context."); + this.flutterNapi.setPlatformMessageHandler(null); + } + + /** + * Is this {@link DartExecutor} currently executing Dart code? + * + * @return true if Dart code is being executed, false otherwise + */ + isExecutingDart(): boolean { + return this.isApplicationRunning; + } + + /** + * Starts executing Dart code based on the given {@code dartEntrypoint} and the {@code + * dartEntrypointArgs}. + * + *
See {@link DartEntrypoint} for configuration options. + * + * @param dartEntrypoint specifies which Dart function to run, and where to find it + * @param dartEntrypointArgs Arguments passed as a list of string to Dart's entrypoint function. + */ + executeDartEntrypoint(dartEntrypoint: DartEntrypoint, dartEntrypointArgs?: string[]): void { + if (this.isApplicationRunning) { + Log.w(TAG, "Attempted to run a DartExecutor that is already running."); + return; + } + + TraceSection.begin("DartExecutor#executeDartEntrypoint"); + try { + Log.d(TAG, "Executing Dart entrypoint: " + dartEntrypoint); + this.flutterNapi.runBundleAndSnapshotFromLibrary( + dartEntrypoint.pathToBundle, + dartEntrypoint.dartEntrypointFunctionName, + dartEntrypoint.dartEntrypointLibrary, + this.assetManager, + dartEntrypointArgs); + + this.isApplicationRunning = true; + } finally { + TraceSection.end("DartExecutor#executeDartEntrypoint"); + } + } + + /** + * Starts executing Dart code based on the given {@code dartCallback}. + * + *
See {@link DartCallback} for configuration options. + * + * @param dartCallback specifies which Dart callback to run, and where to find it + */ + executeDartCallback(dartCallback: DartCallback): void { + if (this.isApplicationRunning) { + Log.w(TAG, "Attempted to run a DartExecutor that is already running."); + return; + } + + TraceSection.begin("DartExecutor#executeDartCallback"); + try { + Log.d(TAG, "Executing Dart callback: " + dartCallback); + this.flutterNapi.runBundleAndSnapshotFromLibrary( + dartCallback.pathToBundle, + dartCallback.callbackHandle.callbackName, + dartCallback.callbackHandle.callbackLibraryPath, + dartCallback.resourceManager, + null); + + this.isApplicationRunning = true; + } finally { + TraceSection.end("DartExecutor#executeDartCallback"); + } + } + + /** + * Returns a {@link BinaryMessenger} that can be used to send messages to, and receive messages + * from, Dart code that this {@code DartExecutor} is executing. + */ + + getBinaryMessenger(): BinaryMessenger { + return this.binaryMessenger; + } + + makeBackgroundTaskQueue(options: TaskQueueOptions): TaskQueue { + return this.getBinaryMessenger().makeBackgroundTaskQueue(options); + } + + + send(channel: String, message: ArrayBuffer, callback?: BinaryReply): void { + this.getBinaryMessenger().send(channel, message, callback); + } + + setMessageHandler(channel: String, handler: BinaryMessageHandler, taskQueue?: TaskQueue): void { + this.getBinaryMessenger().setMessageHandler(channel, handler, taskQueue); + } + + enableBufferingIncomingMessages(): void { + this.getBinaryMessenger().enableBufferingIncomingMessages(); + } + + + /** + * Returns the number of pending channel callback replies. + * + *
When sending messages to the Flutter application using {@link BinaryMessenger#send(String, + * ByteBuffer, io.flutter.plugin.common.BinaryMessenger.BinaryReply)}, developers can optionally + * specify a reply callback if they expect a reply from the Flutter application. + * + *
This method tracks all the pending callbacks that are waiting for response, and is supposed + * to be called from the main thread (as other methods). Calling from a different thread could + * possibly capture an indeterministic internal state, so don't do it. + * + *
Currently, it's mainly useful for a testing framework like Espresso to determine whether all + * the async channel callbacks are handled and the app is idle. + */ + getPendingChannelResponseCount(): number { + return this.dartMessenger.getPendingChannelResponseCount(); + } + + /** + * Returns an identifier for this executor's primary isolate. This identifier can be used in + * queries to the Dart service protocol. + */ + + getIsolateServiceId(): String { + return this.isolateServiceId; + } + + + + /** + * Set a listener that will be notified when an isolate identifier is available for this + * executor's primary isolate. + */ + setIsolateServiceIdListener(listener: IsolateServiceIdListener): void { + this.isolateServiceIdListener = listener; + if (this.isolateServiceIdListener != null && this.isolateServiceId != null) { + this.isolateServiceIdListener.onIsolateServiceIdAvailable(this.isolateServiceId); + } + } + + /** + * Notify the Dart VM of a low memory event, or that the application is in a state such that now + * is an appropriate time to free resources, such as going to the background. + * + *
This does not notify a Flutter application about memory pressure. For that, use the {@link + * io.flutter.embedding.engine.systemchannels.SystemChannel#sendMemoryPressureWarning}. + * + *
Calling this method may cause jank or latency in the application. Avoid calling it during + * critical periods like application startup or periods of animation. + */ + notifyLowMemoryWarning(): void { + if (this.flutterNapi.isAttached()) { + this.flutterNapi.notifyLowMemoryWarning(); + } + } + + disableBufferingIncomingMessages(): void { + this.getBinaryMessenger().enableBufferingIncomingMessages(); + } +} + + +/** + * Configuration options that specify which Dart entrypoint function is executed and where to find + * that entrypoint and other assets required for Dart execution. + */ +export class DartEntrypoint { + /** The path within the AssetManager where the app will look for assets. */ + pathToBundle: string; + + /** The library or file location that contains the Dart entrypoint function. */ + dartEntrypointLibrary: string; + + /** The name of a Dart function to execute. */ + dartEntrypointFunctionName: string; + + constructor(pathToBundle: string, + dartEntrypointLibrary: string, + dartEntrypointFunctionName: string) { + this.pathToBundle = pathToBundle; + this.dartEntrypointLibrary = dartEntrypointLibrary; + this.dartEntrypointFunctionName = dartEntrypointFunctionName; + } + + static createDefault() { + const flutterLoader = FlutterInjector.getInstance().getFlutterLoader(); + if (!flutterLoader.initialized) { + throw new Error( + "DartEntrypoints can only be created once a FlutterEngine is created."); + } + return new DartEntrypoint(flutterLoader.findAppBundlePath(), null, "main"); + } +} + + +/** Callback interface invoked when the isolate identifier becomes available. */ +interface IsolateServiceIdListener { + onIsolateServiceIdAvailable(isolateServiceId: String): void; +} + + +/** + * Configuration options that specify which Dart callback function is executed and where to find + * that callback and other assets required for Dart execution. + */ +export class DartCallback { + /** Standard Android AssetManager, provided from some {@code Context} or {@code Resources}. */ + public resourceManager: resourceManager.ResourceManager; + + /** The path within the AssetManager where the app will look for assets. */ + public pathToBundle: string; + + /** A Dart callback that was previously registered with the Dart VM. */ + public callbackHandle: FlutterCallbackInformation; + + constructor(resourceManager: resourceManager.ResourceManager, + pathToBundle: string, + callbackHandle: FlutterCallbackInformation) { + this.resourceManager = resourceManager; + this.pathToBundle = pathToBundle; + this.callbackHandle = callbackHandle; + } + + toString(): String { + return "DartCallback( bundle path: " + + this.pathToBundle + + ", library path: " + + this.callbackHandle.callbackLibraryPath + + ", function: " + + this.callbackHandle.callbackName + + " )"; + } +} + +export class DefaultBinaryMessenger implements BinaryMessenger { + private messenger: DartMessenger; + + constructor(messenger: DartMessenger) { + this.messenger = messenger; + } + + makeBackgroundTaskQueue(options: TaskQueueOptions): TaskQueue { + return this.messenger.makeBackgroundTaskQueue(options); + } + + /** + * Sends the given {@code messages} from Android to Dart over the given {@code channel} and then + * has the provided {@code callback} invoked when the Dart side responds. + * + * @param channel the name of the logical channel used for the message. + * @param message the message payload, a direct-allocated {@link ByteBuffer} with the message + * bytes between position zero and current position, or null. + * @param callback a callback invoked when the Dart application responds to the message + */ + + send(channel: String, message: ArrayBuffer, callback?: BinaryReply): void { + this.messenger.send(channel, message, callback); + } + + /** + * Sets the given {@link io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler} as the + * singular handler for all incoming messages received from the Dart side of this Dart execution + * context. + * + * @param channel the name of the channel. + * @param handler a {@link BinaryMessageHandler} to be invoked on incoming messages, or null. + */ + setMessageHandler(channel: String, handler: BinaryMessageHandler, taskQueue?: TaskQueue): void { + this.messenger.setMessageHandler(channel, handler); + } + + enableBufferingIncomingMessages(): void { + this.messenger.enableBufferingIncomingMessages(); + } + + disableBufferingIncomingMessages(): void { + this.messenger.disableBufferingIncomingMessages(); + } +} + +class IsolateChannelMessageHandler implements BinaryMessageHandler { + private isolateServiceId: String; + private isolateServiceIdListener: IsolateServiceIdListener; + + constructor(isolateServiceId: String, isolateServiceIdListener: IsolateServiceIdListener) { + this.isolateServiceId = isolateServiceId; + this.isolateServiceIdListener = isolateServiceIdListener; + } + + onMessage(message: ArrayBuffer, callback: BinaryReply): void { + this.isolateServiceId = StringCodec.INSTANCE.decodeMessage(message); + if (this.isolateServiceIdListener != null) { + this.isolateServiceIdListener.onIsolateServiceIdAvailable(this.isolateServiceId); + } + } +} \ No newline at end of file diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartMessenger.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartMessenger.ts new file mode 100644 index 0000000000000000000000000000000000000000..0a2c32013cf295c59bcac93fa9288894e18b69fe --- /dev/null +++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/DartMessenger.ts @@ -0,0 +1,235 @@ +/* +* 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 Log from '../../../util/Log' +import { BinaryMessageHandler, BinaryMessenger, BinaryReply, TaskQueue, TaskQueueOptions } from '../../../plugin/common/BinaryMessenger'; +import FlutterNapi from '../FlutterNapi'; +import { PlatformMessageHandler } from './PlatformMessageHandler'; +import { TraceSection } from '../../../util/TraceSection'; + +/** + * Message conduit for 2-way communication between Android and Dart. + * + *
See {@link BinaryMessenger}, which sends messages from Android to Dart + * + *
See {@link PlatformMessageHandler}, which handles messages to Android from Dart + */ + +const TAG = "DartMessenger"; + +export class DartMessenger implements BinaryMessenger, PlatformMessageHandler { + + flutterNapi: FlutterNapi; + + /** + * Maps a channel name to an object that contains the task queue and the handler associated with + * the channel. + * + *
Reads and writes to this map must lock {@code handlersLock}.
+ */
+ messageHandlers: Map Reads and writes to this map must lock {@code handlersLock}.
+ */
+ bufferedMessages: Map When sending messages to the Flutter application using {@link BinaryMessenger#send(String,
+ * ByteBuffer, io.flutter.plugin.common.BinaryMessenger.BinaryReply)}, developers can optionally
+ * specify a reply callback if they expect a reply from the Flutter application.
+ *
+ * This method tracks all the pending callbacks that are waiting for response, and is supposed
+ * to be called from the main thread (as other methods). Calling from a different thread could
+ * possibly capture an indeterministic internal state, so don't do it.
+ */
+ getPendingChannelResponseCount(): number {
+ return this.pendingReplies.size;
+ }
+}
+
+
+
+
+
+
+/**
+ * Holds information about a platform handler, such as the task queue that processes messages from
+ * Dart.
+ */
+class HandlerInfo {
+ handler: BinaryMessageHandler;
+
+ constructor(handler: BinaryMessageHandler) {
+ this.handler = handler;
+ }
+}
+
+/**
+ * Holds information that allows to dispatch a Dart message to a platform handler when it becomes
+ * available.
+ */
+class BufferedMessageInfo {
+ message: ArrayBuffer;
+ replyId: number;
+ messageData: number;
+
+ constructor(message: ArrayBuffer,
+ replyId: number,
+ messageData: number) {
+ this.message = message;
+ this.replyId = replyId;
+ this.messageData = messageData;
+ }
+}
+
+
+
+
+
+class Reply implements BinaryReply {
+ flutterNapi: FlutterNapi;
+ replyId: number;
+ done: boolean = false;
+
+ constructor(flutterNapi: FlutterNapi, replyId: number) {
+ this.flutterNapi = flutterNapi;
+ this.replyId = replyId;
+ }
+
+ reply(reply: ArrayBuffer) {
+ if (this.done) {
+ throw new Error("Reply already submitted");
+ }
+ if (reply == null) {
+ this.flutterNapi.invokePlatformMessageEmptyResponseCallback(this.replyId);
+ } else {
+ this.flutterNapi.invokePlatformMessageResponseCallback(this.replyId, reply, reply.byteLength);
+ }
+ }
+}
+
+interface DartMessengerTaskQueue {
+ dispatch(): void;
+}
\ No newline at end of file
diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/PlatformMessageHandler.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/PlatformMessageHandler.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b6e3411862cb936f4e9af2c6e0ab6a49be3c9dce
--- /dev/null
+++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/dart/PlatformMessageHandler.ts
@@ -0,0 +1,22 @@
+/*
+* 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.
+*/
+
+export interface PlatformMessageHandler {
+
+ handleMessageFromDart(channel: String,message: ArrayBuffer,replyId: number, messageData: number): void;
+
+ handlePlatformMessageResponse(replyId: number, reply: ArrayBuffer): void;
+
+}
\ No newline at end of file
diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/ApplicationInfoLoader.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/ApplicationInfoLoader.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b8af4f6fb756f4e344e5040d828244ada46d0783
--- /dev/null
+++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/ApplicationInfoLoader.ts
@@ -0,0 +1,24 @@
+/*
+* 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 FlutterApplicationInfo from './FlutterApplicationInfo';
+import common from '@ohos.app.ability.common';
+
+export default class ApplicationInfoLoader {
+ static load(context: common.Context) {
+ let applicatioinInfo = new FlutterApplicationInfo(null, null, null, null, null, context.bundleCodeDir + '/libs/arm64', true);
+ return applicatioinInfo
+ }
+}
\ No newline at end of file
diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterApplicationInfo.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterApplicationInfo.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0db68ee9da2876e12e9c50734c68c2781469b0c4
--- /dev/null
+++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterApplicationInfo.ts
@@ -0,0 +1,50 @@
+/*
+* 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.
+*/
+
+const DEFAULT_AOT_SHARED_LIBRARY_NAME = "libapp.so";
+const DEFAULT_VM_SNAPSHOT_DATA = "vm_snapshot_data";
+const DEFAULT_ISOLATE_SNAPSHOT_DATA = "isolate_snapshot_data";
+const DEFAULT_FLUTTER_ASSETS_DIR = "flutter_assets";
+
+
+/**
+ * application 信息,后期看如何设置
+ */
+export default class FlutterApplicationInfo {
+ aotSharedLibraryName: string;
+ vmSnapshotData: string;
+ isolateSnapshotData: string;
+ flutterAssetsDir: string;
+ domainNetworkPolicy: string;
+ nativeLibraryDir: string;
+ automaticallyRegisterPlugins: boolean;
+ //是否是开发模式,先放在这里,后续应该从context获取
+ isDebugMode: boolean;
+ //是否是profile模式
+ isProfile: boolean;
+
+ constructor(aotSharedLibraryName: string, vmSnapshotData: string, isolateSnapshotData: string, flutterAssetsDir: string, domainNetworkPolicy: string,
+ nativeLibraryDir: string, automaticallyRegisterPlugins: boolean) {
+ this.aotSharedLibraryName = aotSharedLibraryName == null ? DEFAULT_AOT_SHARED_LIBRARY_NAME : aotSharedLibraryName;
+ this.vmSnapshotData = vmSnapshotData == null ? DEFAULT_VM_SNAPSHOT_DATA : vmSnapshotData;
+ this.isolateSnapshotData = isolateSnapshotData == null ? DEFAULT_ISOLATE_SNAPSHOT_DATA : isolateSnapshotData;
+ this.flutterAssetsDir = flutterAssetsDir == null ? DEFAULT_FLUTTER_ASSETS_DIR : flutterAssetsDir;
+ this.domainNetworkPolicy = domainNetworkPolicy == null ? "" : domainNetworkPolicy;
+ this.nativeLibraryDir = nativeLibraryDir;
+ this.automaticallyRegisterPlugins = automaticallyRegisterPlugins;
+ this.isDebugMode = true;
+ this.isProfile = false;
+ }
+}
\ No newline at end of file
diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterLoader.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterLoader.ts
new file mode 100644
index 0000000000000000000000000000000000000000..730da648d2c34fd3ce9e0ab7fc6755a6994d4647
--- /dev/null
+++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/loader/FlutterLoader.ts
@@ -0,0 +1,221 @@
+/*
+* 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.
+*/
+
+/**
+ * flutterLoader,负责dart虚拟机启动和dart代码加载
+ */
+import FlutterShellArgs from '../FlutterShellArgs';
+import FlutterNapi from '../FlutterNapi';
+import Log from '../../../util/Log';
+import FlutterApplicationInfo from './FlutterApplicationInfo';
+import common from '@ohos.app.ability.common';
+import StringUtils from '../../../util/StringUtils';
+import ApplicationInfoLoader from './ApplicationInfoLoader';
+import bundleManager from '@ohos.bundle.bundleManager';
+import fs from '@ohos.file.fs';
+
+const TAG = "FlutterLoader";
+
+//flutter引擎so
+const DEFAULT_LIBRARY = "libflutter.so";
+//jit产物默认kenel文件
+const DEFAULT_KERNEL_BLOB = "kernel_blob.bin";
+//jit产物,默认快照文件
+const VMSERVICE_SNAPSHOT_LIBRARY = "libvmservice_snapshot.so";
+//key值
+const SNAPSHOT_ASSET_PATH_KEY = "snapshot-asset-path";
+//key值
+const VM_SNAPSHOT_DATA_KEY = "vm-snapshot-data";
+//key值
+const ISOLATE_SNAPSHOT_DATA_KEY = "isolate-snapshot-data";
+
+
+const AOT_SHARED_LIBRARY_NAME = "aot-shared-library-name";
+
+const AOT_VMSERVICE_SHARED_LIBRARY_NAME = "aot-vmservice-shared-library-name";
+
+//文件路径分隔符
+const FILE_SEPARATOR = "/";
+
+/**
+ * 定位在hap包中的flutter资源,并且加载flutter native library.
+ */
+export default class FlutterLoader {
+ flutterNapi: FlutterNapi;
+ initResult: InitResult;
+ flutterApplicationInfo: FlutterApplicationInfo;
+ context: common.Context;
+ initialized: boolean;
+ //初始化开始时间戳
+ initStartTimestampMillis: number;
+
+ constructor(flutterNapi: FlutterNapi) {
+ this.flutterNapi = flutterNapi;
+ }
+
+ /**
+ * Starts initialization of the native system.
+ *
+ * This loads the Flutter engine's native library to enable subsequent JNI calls. This also
+ * starts locating and unpacking Dart resources packaged in the app's APK.
+ *
+ * Calling this method multiple times has no effect.
+ *
+ * @param applicationContext The Android application context.
+ * @param settings Configuration settings.
+ */
+ async startInitialization(context: common.Context) {
+ Log.d(TAG, "flutterLoader start init")
+ this.initStartTimestampMillis = Date.now();
+ this.context = context;
+ this.flutterApplicationInfo = ApplicationInfoLoader.load(context);
+ Log.d(TAG, "context.filesDir=" + context.filesDir)
+ Log.d(TAG, "context.cacheDir=" + context.cacheDir)
+ Log.d(TAG, "context.bundleCodeDir=" + context.bundleCodeDir)
+ if (this.flutterApplicationInfo.isDebugMode) {
+ await this.copyResource(context)
+ }
+ this.initResult = new InitResult(
+ `${context.filesDir}/`,
+ `${context.cacheDir}/`,
+ `${context.filesDir}`
+ )
+ Log.d(TAG, "flutterLoader end init")
+ }
+
+ private async copyResource(context: common.Context) {
+ let filePath = context.filesDir + FILE_SEPARATOR + this.flutterApplicationInfo.flutterAssetsDir
+ if (!fs.accessSync(filePath + FILE_SEPARATOR + DEFAULT_KERNEL_BLOB)) {
+ Log.d(TAG, "start copyResource")
+ fs.mkdirSync(filePath)
+
+ let icudtlBuffer = await this.context.resourceManager.getRawFileContent(this.flutterApplicationInfo.flutterAssetsDir + "/icudtl.dat")
+ let icudtlFile = fs.openSync(filePath + FILE_SEPARATOR + "/icudtl.dat", fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
+ fs.writeSync(icudtlFile.fd, icudtlBuffer.buffer)
+
+ let kernelBuffer = await this.context.resourceManager.getRawFileContent(this.flutterApplicationInfo.flutterAssetsDir + FILE_SEPARATOR + DEFAULT_KERNEL_BLOB)
+ let kernelFile = fs.openSync(filePath + FILE_SEPARATOR + DEFAULT_KERNEL_BLOB, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
+ fs.writeSync(kernelFile.fd, kernelBuffer.buffer)
+
+ let vmBuffer = await this.context.resourceManager.getRawFileContent(this.flutterApplicationInfo.flutterAssetsDir + FILE_SEPARATOR + this.flutterApplicationInfo.vmSnapshotData)
+ let vmFile = fs.openSync(filePath + FILE_SEPARATOR + this.flutterApplicationInfo.vmSnapshotData, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
+ fs.writeSync(vmFile.fd, vmBuffer.buffer)
+
+ let isolateBuffer = await this.context.resourceManager.getRawFileContent(this.flutterApplicationInfo.flutterAssetsDir + FILE_SEPARATOR + this.flutterApplicationInfo.isolateSnapshotData)
+ let isolateFile = fs.openSync(filePath + FILE_SEPARATOR + this.flutterApplicationInfo.isolateSnapshotData, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
+ fs.writeSync(isolateFile.fd, isolateBuffer.buffer)
+ Log.d(TAG, "copyResource end")
+ } else {
+ Log.d(TAG, "no copyResource")
+ }
+ }
+
+ /**
+ * 初始化dart虚拟机方法
+ * @param flutterShellArgs
+ */
+ ensureInitializationComplete(shellArgs: Array Relevant resources that this {@code FlutterPlugin} may need are provided via the {@code
+ * binding}. The {@code binding} may be cached and referenced until {@link
+ * #onDetachedFromEngine(FlutterPluginBinding)} is invoked and returns.
+ */
+ onAttachedToEngine(binding: FlutterPluginBinding): void;
+
+ /**
+ * This {@code FlutterPlugin} has been removed from a {@link
+ * io.flutter.embedding.engine.FlutterEngine} instance.
+ *
+ * The {@code binding} passed to this method is the same instance that was passed in {@link
+ * #onAttachedToEngine(FlutterPluginBinding)}. It is provided again in this method as a
+ * convenience. The {@code binding} may be referenced during the execution of this method, but it
+ * must not be cached or referenced after this method returns.
+ *
+ * {@code FlutterPlugin}s should release all resources in this method.
+ */
+ onDetachedFromEngine(binding: FlutterPluginBinding): void;
+}
+
+export class FlutterPluginBinding {
+ private applicationContext: common.Context;
+ private binaryMessenger: BinaryMessenger;
+ private flutterAssets: FlutterAssets;
+ private group: FlutterEngineGroup;
+
+ constructor(applicationContext: common.Context, binaryMessenger: BinaryMessenger, flutterAssets: FlutterAssets, group: FlutterEngineGroup) {
+ this.applicationContext = applicationContext;
+ this.binaryMessenger = binaryMessenger;
+ this.flutterAssets = flutterAssets;
+ this.group = group;
+ }
+
+ getApplicationContext(): common.Context {
+ return this.applicationContext;
+ }
+
+ getBinaryMessenger(): BinaryMessenger {
+ return this.binaryMessenger;
+ }
+
+ getFlutterAssets(): FlutterAssets {
+ return this.flutterAssets;
+ }
+
+ getEngineGroup(): FlutterEngineGroup {
+ return this.group;
+ }
+}
+
+/** Provides Flutter plugins with access to Flutter asset information. */
+export interface FlutterAssets {
+ /**
+ * Returns the relative file path to the Flutter asset with the given name, including the file's
+ * extension, e.g., {@code "myImage.jpg"}.
+ *
+ * The returned file path is relative to the Ohos app's standard assets directory.
+ * Therefore, the returned path is appropriate to pass to Ohos's {@code ResourceManage}, but
+ * the path is not appropriate to load as an absolute path.
+ */
+ getAssetFilePathByName(assetFileName: string): string;
+
+ /**
+ * Same as {@link #getAssetFilePathByName(String)} but with added support for an explicit
+ * Ohos {@code bundleName}.
+ */
+ getAssetFilePathByName(assetFileName: string, bundleName: string): string;
+
+ /**
+ * Returns the relative file path to the Flutter asset with the given subpath, including the
+ * file's extension, e.g., {@code "/dir1/dir2/myImage.jpg"}.
+ *
+ * The returned file path is relative to the Ohos app's standard assets directory.
+ * Therefore, the returned path is appropriate to pass to Ohos's {@code ResourceManage}, but
+ * the path is not appropriate to load as an absolute path.
+ */
+ getAssetFilePathBySubpath(assetSubpath: string): string;
+
+ /**
+ * Same as {@link #getAssetFilePathBySubpath(String)} but with added support for an explicit
+ * Ohos {@code bundleName}.
+ */
+ getAssetFilePathBySubpath(assetSubpath: string, bundleName: string): string;
+}
\ No newline at end of file
diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/PluginRegistry.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/PluginRegistry.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1a322ec2ba1bbcfcbce180b00ec4df6356733180
--- /dev/null
+++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/PluginRegistry.ts
@@ -0,0 +1,73 @@
+/*
+* 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 { FlutterPlugin } from './FlutterPlugin';
+
+export default interface PluginRegistry {
+ /**
+ * Attaches the given {@code plugin} to the {@link io.flutter.embedding.engine.FlutterEngine}
+ * associated with this {@code PluginRegistry}.
+ */
+ add(plugin: FlutterPlugin): void;
+
+ /**
+ * Attaches the given {@code plugins} to the {@link io.flutter.embedding.engine.FlutterEngine}
+ * associated with this {@code PluginRegistry}.
+ */
+ addList(plugins: Set If no matching plugin is found, {@code null} is returned.
+ */
+ //Class extends FlutterPlugin>
+ get(pluginClassName: string): FlutterPlugin;
+
+ /**
+ * Detaches the plugin of the given type from the {@link
+ * io.flutter.embedding.engine.FlutterEngine} associated with this {@code PluginRegistry}.
+ *
+ * If no such plugin exists, this method does nothing.
+ */
+ //Class extends FlutterPlugin>
+ remove(pluginClassName: string): void;
+
+ /**
+ * Detaches the plugins of the given types from the {@link
+ * io.flutter.embedding.engine.FlutterEngine} associated with this {@code PluginRegistry}.
+ *
+ * If no such plugins exist, this method does nothing.
+ */
+ //Class extends FlutterPlugin>
+ removeList(pluginClassNames: Set If no plugins are currently attached, this method does nothing.
+ */
+ removeAll(): void;
+}
\ No newline at end of file
diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityAware.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityAware.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bd68f68aee68859e0c13b696743c8d9d280b7500
--- /dev/null
+++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityAware.ts
@@ -0,0 +1,75 @@
+/*
+* 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.
+*/
+
+/**
+ * {@link io.flutter.embedding.engine.plugins.FlutterPlugin} that is interested in {@link
+ * ohos.app.ability.UIAbility} lifecycle events related to a {@link
+ * io.flutter.embedding.engine.FlutterEngine} running within the given {@link ohos.app.ability.UIAbility}.
+ */
+import { AbilityPluginBinding } from './AbilityPluginBinding';
+
+export default interface AbilityAware {
+ /**
+ * This {@code AbilityAware} {@link io.flutter.embedding.engine.plugins.FlutterPlugin} is now
+ * associated with an {@link ohos.app.ability.UIAbility}.
+ *
+ * This method can be invoked in 1 of 2 situations:
+ *
+ * Detachment can occur for a number of reasons.
+ *
+ * Any {@code Lifecycle} listeners that were registered in {@link
+ * #onAttachedToAbility(AbilityPluginBinding)} or {@link
+ * #onReattachedToAbilityForConfigChanges(AbilityPluginBinding)} should be deregistered here to
+ * avoid a possible memory leak and other side effects.
+ */
+ onDetachedFromAbility(): void;
+}
diff --git a/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityControlSurface.ts b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityControlSurface.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b93b7b14b520ec7b3c38a536d161fc5f29c878a2
--- /dev/null
+++ b/shell/platform/ohos/flutter_embedding/flutter/src/main/ets/embedding/engine/plugins/ability/AbilityControlSurface.ts
@@ -0,0 +1,27 @@
+/*
+* 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 AbilityConstant from '@ohos.app.ability.AbilityConstant';
+import Want from '@ohos.app.ability.Want';
+import UIAbility from '@ohos.app.ability.UIAbility';
+import ExclusiveAppComponent from '../../../ohos/ExclusiveAppComponent';
+
+export default interface ActivityControlSurface {
+ attachToAbility(exclusiveActivity: ExclusiveAppComponent
+ *
+ *
+ * The given {@link AbilityPluginBinding} contains {@link ohos.app.ability.UIAbility}-related
+ * references that an {@code AbilityAware} {@link
+ * io.flutter.embedding.engine.plugins.FlutterPlugin} may require, such as a reference to the
+ * actual {@link ohos.app.ability.UIAbility} in question. The {@link AbilityPluginBinding} may be
+ * referenced until either {@link #onDetachedFromAbilityForConfigChanges()} or {@link
+ * #onDetachedFromAbility()} is invoked. At the conclusion of either of those methods, the
+ * binding is no longer valid. Clear any references to the binding or its resources, and do not
+ * invoke any further methods on the binding or its resources.
+ */
+ onAttachedToAbility(binding: AbilityPluginBinding): void ;
+
+ /**
+ * This plugin has been detached from an {@link ohos.app.ability.UIAbility}.
+ *
+ *
+ *
+ *
+ * By the end of this method, the {@link ohos.app.ability.UIAbility} that was made available in {@link
+ * #onAttachedToAbility(AbilityPluginBinding)} is no longer valid. Any references to the
+ * associated {@link ohos.app.ability.UIAbility} or {@link AbilityPluginBinding} should be cleared.
+ *
+ *