diff --git a/.gitignore b/.gitignore
index 4d31fb360942a314d99597807edff44673bcfca4..f82fc89478553b46cd48d4217e9fa8e6b5549b7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,5 +79,5 @@ lefthook.yml
# eslint
.eslintcache
-scripts
-harmony/image_editor.har
\ No newline at end of file
+./scripts/*
+*.tgz
diff --git a/OAT.xml b/OAT.xml
index bf6666b93e7910a47fe605005e03d6faf24d65d6..bd897f20ccae80ce5dcbe22f65c626665fb05dd2 100644
--- a/OAT.xml
+++ b/OAT.xml
@@ -16,6 +16,7 @@
+
@@ -32,6 +33,7 @@
+
@@ -52,6 +54,7 @@
+
diff --git a/example/.gitignore b/example/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..7613cdedd309866629ce9ae75eb3855ea0849f0a
--- /dev/null
+++ b/example/.gitignore
@@ -0,0 +1,71 @@
+.husky
+bundle.harmony.js
+package-lock.json
+*.hbc
+lintCppResult.txt
+
+# ---
+
+# OSX
+#
+.DS_Store
+
+# Xcode
+#
+build/
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+*.xccheckout
+*.moved-aside
+DerivedData
+*.hmap
+*.ipa
+*.xcuserstate
+
+# Android/IntelliJ
+#
+build/
+.idea
+.gradle
+local.properties
+*.iml
+*.hprof
+.cxx/
+*.keystore
+!debug.keystore
+BuildProfile.ets
+
+# node.js
+#
+node_modules/
+npm-debug.log
+yarn-error.log
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
+# screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/
+
+**/fastlane/report.xml
+**/fastlane/Preview.html
+**/fastlane/screenshots
+**/fastlane/test_output
+
+# Bundle artifact
+*.jsbundle
+
+# Ruby / CocoaPods
+/vendor/bundle/
+
+# Temporary files created by Metro to check the health of the file watcher
+.metro-health-check*
+*.htrace
\ No newline at end of file
diff --git a/example/app.json b/example/app.json
new file mode 100644
index 0000000000000000000000000000000000000000..7586f6fa99a6680a35a27fac7255ba721880d461
--- /dev/null
+++ b/example/app.json
@@ -0,0 +1,4 @@
+{
+ "name": "app_name",
+ "displayName": "tester"
+}
\ No newline at end of file
diff --git a/example/babel.config.js b/example/babel.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..481136144aa7bed704ad81628802d8a43930a6a1
--- /dev/null
+++ b/example/babel.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ presets: ['module:metro-react-native-babel-preset'],
+ plugins: [
+ ],
+};
diff --git a/example/contexts.ts b/example/contexts.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9437598452691ccc56d19f5532607475aa5d33b4
--- /dev/null
+++ b/example/contexts.ts
@@ -0,0 +1,3 @@
+import React from 'react';
+
+export const AppParamsContext = React.createContext(undefined);
diff --git a/example/harmony/.gitignore b/example/harmony/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..72d73fb4b6240ccd907882c931ce08ee45ca62ba
--- /dev/null
+++ b/example/harmony/.gitignore
@@ -0,0 +1,24 @@
+# it may cause some issues when building the project when switching branches
+package-lock.json
+# we add this because we want to keep the signing configs out of git
+/build-profile.json5
+
+rnoh_modules
+
+**/oh-package-lock.json5
+# ---
+
+/node_modules
+/local.properties
+/.idea
+**/build
+/.hvigor
+.cxx
+/.clangd
+/.clang-format
+/.clang-tidy
+/oh_modules
+hvigorw
+hvigorw.bat
+hvigor/hvigor-wrapper.js
+
diff --git a/example/harmony/AppScope/app.json5 b/example/harmony/AppScope/app.json5
new file mode 100644
index 0000000000000000000000000000000000000000..058bd391dac60928a1857aa31e4b0f712a7bc743
--- /dev/null
+++ b/example/harmony/AppScope/app.json5
@@ -0,0 +1,10 @@
+{
+ "app": {
+ "bundleName": "com.harmony.wechat.lib.demo",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
diff --git a/example/harmony/AppScope/resources/base/element/string.json b/example/harmony/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..698a720065342ae0dadad63eb87d45fec8725f36
--- /dev/null
+++ b/example/harmony/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "RN Tester"
+ }
+ ]
+}
diff --git a/example/harmony/AppScope/resources/base/media/app_icon.png b/example/harmony/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/example/harmony/AppScope/resources/base/media/app_icon.png differ
diff --git a/example/harmony/build-profile.template.json5 b/example/harmony/build-profile.template.json5
new file mode 100644
index 0000000000000000000000000000000000000000..6953759305460498e1c355836fdd63634bfccccf
--- /dev/null
+++ b/example/harmony/build-profile.template.json5
@@ -0,0 +1,40 @@
+{
+ "app": {
+ "products": [
+ {
+ "name": 'default',
+ "signingConfig": 'default',
+ "compileSdkVersion": '5.0.1(13)',
+ "compatibleSdkVersion": '5.0.0(12)',
+ "runtimeOS": 'HarmonyOS'
+ },
+ ],
+ "buildModeSet": [
+ {
+ "name": 'debug',
+ },
+ {
+ "name": 'release',
+ },
+ ],
+ "signingConfigs": []
+ },
+ "modules": [
+ {
+ "name": 'entry',
+ "srcPath": './entry',
+ "targets": [
+ {
+ "name": 'default',
+ "applyToProducts": [
+ 'default'
+ ],
+ },
+ ],
+ },
+ {
+ "name": "image_editor",
+ "srcPath": '../../harmony/image_editor'
+ }
+ ],
+}
diff --git a/example/harmony/codelinter.json b/example/harmony/codelinter.json
new file mode 100644
index 0000000000000000000000000000000000000000..e7f91acb037aeda939967a042f16033f4c6e21b9
--- /dev/null
+++ b/example/harmony/codelinter.json
@@ -0,0 +1,32 @@
+{
+ "files": ["**/*.ts", "**/*.ets"],
+ "ignore": [
+ "**/ohosTest/**/*",
+ "**/node_modules/**/*",
+ "**/hvigorfile.ts",
+ "**/node_modules/**/*",
+ "**/oh_modules/**/*",
+ "**/build/**/*",
+ "**/.preview/**/*"
+ ],
+ "plugins": ["@typescript-eslint"],
+ "ruleSet": [],
+ "rules": {
+ "@typescript-eslint/await-thenable": "warn",
+ "@typescript-eslint/consistent-type-imports": "warn",
+ "@typescript-eslint/explicit-function-return-type": "warn",
+ "@typescript-eslint/explicit-module-boundary-types": "warn",
+ "@typescript-eslint/no-dynamic-delete": "warn",
+ "@typescript-eslint/no-explicit-any": "warn",
+ "@typescript-eslint/no-for-in-array": "warn",
+ "@typescript-eslint/no-this-alias": "warn",
+ "@typescript-eslint/no-unnecessary-type-constraint": "warn",
+ "@typescript-eslint/no-unsafe-argument": "warn",
+ "@typescript-eslint/no-unsafe-assignment": "warn",
+ "@typescript-eslint/no-unsafe-call": "warn",
+ "@typescript-eslint/no-unsafe-member-access": "warn",
+ "@typescript-eslint/no-unsafe-return": "warn",
+ "@typescript-eslint/prefer-literal-enum-member": "warn"
+ },
+ "overrides": []
+}
diff --git a/example/harmony/entry/.gitignore b/example/harmony/entry/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..bbc049cfeb689c61d6c2922810f652cbb19aad21
--- /dev/null
+++ b/example/harmony/entry/.gitignore
@@ -0,0 +1,7 @@
+/node_modules
+/.preview
+/build
+/.cxx
+package-lock.json
+/oh_modules
+/assets
diff --git a/example/harmony/entry/build-profile.json5 b/example/harmony/entry/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..2408c163287e825139a36f35cbec83e9772c49db
--- /dev/null
+++ b/example/harmony/entry/build-profile.json5
@@ -0,0 +1,19 @@
+{
+ "apiType": 'stageMode',
+ "buildOption": {
+ "externalNativeOptions": {
+ "path": "./src/main/cpp/CMakeLists.txt",
+ "arguments": "",
+ "cppFlags": "-s",
+ },
+ },
+ "targets": [
+ {
+ "name": "default",
+ "runtimeOS": "HarmonyOS"
+ },
+ {
+ "name": "ohosTest",
+ }
+ ]
+}
\ No newline at end of file
diff --git a/example/harmony/entry/hvigorfile.ts b/example/harmony/entry/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aced8afddf910b99762b7eff3a8df92cb9f30c2b
--- /dev/null
+++ b/example/harmony/entry/hvigorfile.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2024 Huawei Device 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.
+ */
+
+// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
+export { hapTasks } from '@ohos/hvigor-ohos-plugin';
diff --git a/example/harmony/entry/oh-package.json5 b/example/harmony/entry/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..f6b5d35b20f51ead27420f5bf907d49d011de124
--- /dev/null
+++ b/example/harmony/entry/oh-package.json5
@@ -0,0 +1,11 @@
+{
+ "license": "ISC",
+ "devDependencies": {},
+ "name": "entry",
+ "description": "example description",
+ "version": "1.0.0",
+ "dependencies": {
+ "@rnoh/react-native-openharmony": "0.72.38",
+ "@react-native-ohos/image-editor": "file:../../node_modules/@react-native-ohos/image-editor/harmony/image_editor.har"
+ }
+}
diff --git a/example/harmony/entry/src/main/cpp/.gitignore b/example/harmony/entry/src/main/cpp/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..881dde5479f322de9db2b2bb98fd94a95f73715e
--- /dev/null
+++ b/example/harmony/entry/src/main/cpp/.gitignore
@@ -0,0 +1,2 @@
+jsbundle.h
+generated/
diff --git a/example/harmony/entry/src/main/cpp/CMakeLists.txt b/example/harmony/entry/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..59903eca70807dbad2c7ec01eab93ce8859cd550
--- /dev/null
+++ b/example/harmony/entry/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,32 @@
+project(rnapp)
+cmake_minimum_required(VERSION 3.4.1)
+set(CMAKE_SKIP_BUILD_RPATH TRUE)
+set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
+set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
+set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../oh_modules/@rnoh/react-native-openharmony/src/main/cpp")
+set(RNOH_GENERATED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/generated")
+set(LOG_VERBOSITY_LEVEL 1)
+set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
+set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
+set(WITH_HITRACE_SYSTRACE 1) # for other CMakeLists.txt files to use
+add_compile_definitions(WITH_HITRACE_SYSTRACE)
+
+
+add_subdirectory("${RNOH_CPP_DIR}" ./rn)
+
+# RNOH_BEGIN: manual_package_linking_1
+add_subdirectory("${OH_MODULES}/@react-native-ohos/image-editor/src/main/cpp" ./image-editor)
+# RNOH_END: manual_package_linking_1
+
+file(GLOB GENERATED_CPP_FILES "${CMAKE_CURRENT_SOURCE_DIR}/generated/*.cpp") # this line is needed by codegen v1
+add_library(rnoh_app SHARED
+ ${GENERATED_CPP_FILES}
+ "./PackageProvider.cpp"
+ "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
+)
+target_link_libraries(rnoh_app PUBLIC rnoh)
+
+# RNOH_BEGIN: manual_package_linking_2
+target_link_libraries(rnoh_app PUBLIC rnoh_image_editor)
+# RNOH_END: manual_package_linking_2
diff --git a/example/harmony/entry/src/main/cpp/PackageProvider.cpp b/example/harmony/entry/src/main/cpp/PackageProvider.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d1ed6b5cfe4ea7d174793e89bc8399d5f963dfdd
--- /dev/null
+++ b/example/harmony/entry/src/main/cpp/PackageProvider.cpp
@@ -0,0 +1,20 @@
+/*
+*
+* Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
+* Use of this source code is governed by a MIT license that can be
+* found in the LICENSE file
+*
+*/
+#include "RNOH/PackageProvider.h"
+#include "generated/RNOHGeneratedPackage.h"
+#include "ReactNativeOhosReactNativeImageEditorPackage.h"
+
+using namespace rnoh;
+
+std::vector> PackageProvider::getPackages(Package::Context ctx)
+{
+ return {
+ std::make_shared(ctx), // generated by codegen-harmony v1 at app build time
+ std::make_shared(ctx),
+ };
+}
diff --git a/example/harmony/entry/src/main/ets/RNPackagesFactory.ets b/example/harmony/entry/src/main/ets/RNPackagesFactory.ets
new file mode 100644
index 0000000000000000000000000000000000000000..a7d3eb57aa103b99ba239a0ba757a400c616521a
--- /dev/null
+++ b/example/harmony/entry/src/main/ets/RNPackagesFactory.ets
@@ -0,0 +1,19 @@
+/*
+*
+* Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
+* Use of this source code is governed by a MIT license that can be
+* found in the LICENSE file
+*
+*/
+
+import type { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts';
+import {ImageEditorPackage} from '@react-native-ohos/image-editor/ts';
+/**
+ * Importing ets files from top level barrel file doesn't work.
+ */
+
+export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
+ return [
+ new ImageEditorPackage(ctx),
+ ];
+}
diff --git a/example/harmony/entry/src/main/ets/entryability/EntryAbility.ets b/example/harmony/entry/src/main/ets/entryability/EntryAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..35746494ac1dda87b830c77681493aed4f389b61
--- /dev/null
+++ b/example/harmony/entry/src/main/ets/entryability/EntryAbility.ets
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
+ * Use of this source code is governed by a MIT license that can be
+ * found in the LICENSE file.
+ */
+
+import {RNAbility} from '@rnoh/react-native-openharmony';
+import { AbilityConstant, Want } from '@kit.AbilityKit';
+
+export default class EntryAbility extends RNAbility {
+
+ onCreate(want: Want) {
+ super.onCreate(want)
+ }
+
+ getPagePath() {
+ return 'pages/Index';
+ }
+}
diff --git a/example/harmony/entry/src/main/ets/pages/Index.ets b/example/harmony/entry/src/main/ets/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..5d4aa1e47485efbe3ddcffd5503e622c99463a46
--- /dev/null
+++ b/example/harmony/entry/src/main/ets/pages/Index.ets
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
+ * Use of this source code is governed by a MIT license that can be
+ * found in the LICENSE file.
+ */
+
+import {
+ AnyJSBundleProvider,
+ ComponentBuilderContext,
+ FileJSBundleProvider,
+ MetroJSBundleProvider,
+ ResourceJSBundleProvider,
+ RNApp,
+ RNOHErrorDialog,
+ RNOHLogger,
+ TraceJSBundleProviderDecorator,
+ RNOHCoreContext
+} from '@rnoh/react-native-openharmony';
+import font from '@ohos.font';
+import { createRNPackages } from '../RNPackagesFactory';
+
+const arkTsComponentNames: Array = [
+];
+
+@Builder
+export function buildCustomRNComponent(ctx: ComponentBuilderContext) {
+ // There seems to be a problem with the placement of ArkTS components in mixed mode. Nested Stack temporarily avoided.
+ Stack() {
+ }
+ .position({ x: 0, y: 0 })
+
+}
+
+const wrappedCustomRNComponentBuilder = wrapBuilder(buildCustomRNComponent)
+
+/**
+ * If you want to use custom fonts, you need to register them here.
+ * We should support react-native-asset to handle registering fonts automatically.
+ */
+const fonts: font.FontOptions[] = [
+ {
+ familyName: 'Pacifico-Regular',
+ familySrc: '/assets/fonts/Pacifico-Regular.ttf'
+ },
+ {
+ familyName: 'StintUltraCondensed-Regular',
+ familySrc: '/assets/fonts/StintUltraCondensed-Regular.ttf'
+ }
+]
+
+@Entry
+@Component
+struct Index {
+ @StorageLink('RNOHCoreContext') private rnohCoreContext: RNOHCoreContext | undefined = undefined
+ @State shouldShow: boolean = false
+ private logger!: RNOHLogger
+ bundlePath: string = 'bunlde.harmony.js'
+ @State hasBundle: boolean = false
+
+ aboutToAppear() {
+ this.logger = this.rnohCoreContext!.logger.clone("Index")
+ const stopTracing = this.logger.clone("aboutToAppear").startTracing()
+ for (const customFont of fonts) {
+ font.registerFont(customFont)
+ }
+
+ this.shouldShow = true
+ stopTracing()
+ }
+
+ onBackPress(): boolean | undefined {
+ // NOTE: this is required since `Ability`'s `onBackPressed` function always
+ // terminates or puts the app in the background, but we want Ark to ignore it completely
+ // when handled by RN
+ this.rnohCoreContext!.dispatchBackPress()
+ return true
+ }
+
+ build() {
+ Column() {
+ if (this.rnohCoreContext && this.shouldShow) {
+ if (this.rnohCoreContext?.isDebugModeEnabled) {
+ RNOHErrorDialog({ ctx: this.rnohCoreContext })
+ }
+ RNApp({
+ rnInstanceConfig: {
+ createRNPackages,
+ enableNDKTextMeasuring: true,
+ enableBackgroundExecutor: false,
+ enableCAPIArchitecture: true,
+ arkTsComponentNames: arkTsComponentNames,
+ },
+ initialProps: { "foo": "bar" } as Record,
+ appKey: "app_name",
+ wrappedCustomRNComponentBuilder: wrappedCustomRNComponentBuilder,
+ onSetUp: (rnInstance) => {
+ rnInstance.enableFeatureFlag("ENABLE_RN_INSTANCE_CLEAN_UP")
+ },
+ jsBundleProvider: new TraceJSBundleProviderDecorator(
+ new AnyJSBundleProvider([
+ new MetroJSBundleProvider(),
+ // NOTE: to load the bundle from file, place it in
+ // `/data/app/el2/100/base/com.rnoh.tester/files/bundle.harmony.js`
+ // on your device. The path mismatch is due to app sandboxing on HarmonyOS
+ new FileJSBundleProvider('/data/storage/el2/base/files/bundle.harmony.js'),
+ // new FileJSBundleProvider(context.filesDir + '/' + this.bundlePath),
+ new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'hermes_bundle.hbc'),
+ new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle.harmony.js')
+ ]),
+ this.rnohCoreContext.logger),
+ })
+ }
+ Text("1233333333122 1212323")
+ }
+ .height('100%')
+ .width('100%')
+ }
+}
diff --git a/example/harmony/entry/src/main/module.json5 b/example/harmony/entry/src/main/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..fdf398e25ce0c8977e8a9854935f853541466e71
--- /dev/null
+++ b/example/harmony/entry/src/main/module.json5
@@ -0,0 +1,52 @@
+{
+ "module": {
+ "name": "entry",
+ "type": "entry",
+ "description": "$string:module_desc",
+ "mainElement": "EntryAbility",
+ "deviceTypes": [
+ "default"
+ ],
+ "querySchemes": [
+ "weixin",
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:main_pages",
+ // below property is supported from 5.0.0 - it is needed by bundleManager.canOpenLink to check if the app can open some url
+ // "querySchemes": ["maps", "http", "https", "customDomain"],
+ "requestPermissions": [
+ {
+ "name": "ohos.permission.INTERNET"
+ },
+ ],
+ "metadata": [
+ {
+ "name": "OPTLazyForEach",
+ "value": "true",
+ }
+ ],
+ "abilities": [
+ {
+ "name": "EntryAbility",
+ "srcEntry": "./ets/entryability/EntryAbility.ets",
+ "description": "$string:EntryAbility_desc",
+ "icon": "$media:app_icon",
+ "label": "$string:EntryAbility_label",
+ "startWindowIcon": "$media:app_icon",
+ "startWindowBackground": "$color:start_window_background",
+ "visible": true,
+ "skills": [
+ {
+ "entities": [
+ "entity.system.home"
+ ],
+ "actions": [
+ "action.system.home"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/example/harmony/entry/src/main/resources/.gitignore b/example/harmony/entry/src/main/resources/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..037cea9e70bef8c906560a871a394f748ec2325d
--- /dev/null
+++ b/example/harmony/entry/src/main/resources/.gitignore
@@ -0,0 +1 @@
+rawfile/assets
diff --git a/example/harmony/entry/src/main/resources/base/element/color.json b/example/harmony/entry/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/example/harmony/entry/src/main/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/example/harmony/entry/src/main/resources/base/element/string.json b/example/harmony/entry/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..074b2173f51352f71629252715526554911d44bb
--- /dev/null
+++ b/example/harmony/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "RN Tester"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/example/harmony/entry/src/main/resources/base/profile/main_pages.json b/example/harmony/entry/src/main/resources/base/profile/main_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce
--- /dev/null
+++ b/example/harmony/entry/src/main/resources/base/profile/main_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "pages/Index"
+ ]
+}
diff --git a/example/harmony/entry/src/main/resources/rawfile/1.txt b/example/harmony/entry/src/main/resources/rawfile/1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..71f6ee3dfcd13fad21fc73e697c7c5a3c31ec039
--- /dev/null
+++ b/example/harmony/entry/src/main/resources/rawfile/1.txt
@@ -0,0 +1 @@
+text test
\ No newline at end of file
diff --git a/example/harmony/format.ps1 b/example/harmony/format.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..7735881fded75cc61ee05ec623e0848b85f6d639
--- /dev/null
+++ b/example/harmony/format.ps1
@@ -0,0 +1,12 @@
+$directoryPath = Split-Path -Parent $MyInvocation.MyCommand.Path
+$filePaths = Get-ChildItem $directoryPath -Recurse -Include *.h, *.cpp |
+Where-Object {
+ $_.DirectoryName -notmatch 'third-party' -and
+ $_.DirectoryName -notmatch 'patches' -and
+ $_.DirectoryName -notmatch 'node_modules' -and
+ $_.DirectoryName -notmatch '.cxx' -and
+ $_.DirectoryName -notmatch 'build'
+}
+foreach ($filePath in $filePaths) {
+ & "clang-format.exe" -style=file -i $filePath.FullName
+}
\ No newline at end of file
diff --git a/example/harmony/hvigor/.gitignore b/example/harmony/hvigor/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..aa1ec1ea0618124672d14a63d00d943240f2db2a
--- /dev/null
+++ b/example/harmony/hvigor/.gitignore
@@ -0,0 +1 @@
+*.tgz
diff --git a/example/harmony/hvigor/hvigor-config.json5 b/example/harmony/hvigor/hvigor-config.json5
new file mode 100644
index 0000000000000000000000000000000000000000..c8ba182673e80fbc3da9e614580e9453b718cd3b
--- /dev/null
+++ b/example/harmony/hvigor/hvigor-config.json5
@@ -0,0 +1,21 @@
+{
+ "modelVersion": "5.0.0",
+ "dependencies": {
+ },
+ "execution": {
+ // "analyze": "default", /* Define the build analyze mode. Value: [ "default" | "verbose" | false ]. Default: "default" */
+ // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */
+ // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */
+ // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */
+ // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */
+ },
+ "logging": {
+ // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
+ },
+ "debugging": {
+ "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
+ },
+ "nodeOptions": {
+ // "maxOldSpaceSize": 4096 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process */
+ }
+}
\ No newline at end of file
diff --git a/example/harmony/hvigorfile.ts b/example/harmony/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6478186902c0c1ad7c966a929c7d6b7d8ae7a9f3
--- /dev/null
+++ b/example/harmony/hvigorfile.ts
@@ -0,0 +1,2 @@
+// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
+export { appTasks } from '@ohos/hvigor-ohos-plugin';
\ No newline at end of file
diff --git a/example/harmony/oh-package.json5 b/example/harmony/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..25ebaf50e0c1652413ca2e283eb9e713467d33ed
--- /dev/null
+++ b/example/harmony/oh-package.json5
@@ -0,0 +1,14 @@
+{
+ "modelVersion": "5.0.0",
+ "license": "ISC",
+ "name": "rnoh",
+ "description": "example description",
+ "repository": {},
+ "version": "1.0.0",
+ "dependencies": {
+ "@rnoh/react-native-openharmony": "0.72.38"
+ },
+ "overrides": {
+ "@rnoh/react-native-openharmony": "0.72.38"
+ }
+}
diff --git a/example/index.js b/example/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..9f1e098965d0c3e4dba8d7ed76b52953f981c8a5
--- /dev/null
+++ b/example/index.js
@@ -0,0 +1,12 @@
+/*
+*
+* Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
+* Use of this source code is governed by a MIT license that can be
+* found in the LICENSE file
+*
+*/
+import {AppRegistry, View, Text} from 'react-native';
+import {name as appName} from './app.json';
+import App from './src/Example';
+
+AppRegistry.registerComponent(appName, () => App);
\ No newline at end of file
diff --git a/example/jest.config.js b/example/jest.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..bfbfdcd1ba0a800596cb0a4446a2ace7b7e2e6ec
--- /dev/null
+++ b/example/jest.config.js
@@ -0,0 +1,13 @@
+/*
+*
+* Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
+* Use of this source code is governed by a MIT license that can be
+* found in the LICENSE file
+*
+*/
+
+/** @type {import('ts-jest').JestConfigWithTsJest} */
+module.exports = {
+ preset: 'ts-jest',
+ testEnvironment: 'node',
+};
diff --git a/example/metro.config.js b/example/metro.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..f33c325ac1fad6c7733a76bfe002d136fb442c8f
--- /dev/null
+++ b/example/metro.config.js
@@ -0,0 +1,24 @@
+const {mergeConfig, getDefaultConfig} = require('@react-native/metro-config');
+const {createHarmonyMetroConfig} = require('react-native-harmony/metro.config');
+
+/**
+ * @type {import("metro-config").ConfigT}
+ */
+const config = {
+ transformer: {
+ getTransformOptions: async () => ({
+ transform: {
+ experimentalImportSupport: false,
+ inlineRequires: true,
+ },
+ }),
+ },
+};
+
+module.exports = mergeConfig(
+ getDefaultConfig(__dirname),
+ createHarmonyMetroConfig({
+ reactNativeHarmonyPackageName: 'react-native-harmony',
+ }),
+ config,
+);
diff --git a/example/package.json b/example/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..d658da14b5b8c8f9aaa6b1529fa5927acb8f9a29
--- /dev/null
+++ b/example/package.json
@@ -0,0 +1,66 @@
+{
+ "name": "react-native-harmony-tester",
+ "version": "1.0.0",
+ "private": true,
+ "scripts": {
+ "reStart": "npm run install:pkg && npm run codegen && hdc rport tcp:8081 tcp:8081 && react-native start",
+ "start": "hdc rport tcp:8081 tcp:8081 && react-native start",
+ "codegen": "react-native codegen-harmony --rnoh-module-path ./harmony/entry/oh_modules/@rnoh/react-native-openharmony",
+ "pack:pkg": "cd ../ && npm i --legacy-peer-deps && npm pack && cd ./example",
+ "install:pkg": "npm uninstall @react-native-ohos/image-editor && npm run pack:pkg && npm i @react-native-ohos/image-editor@file:../react-native-ohos-image-editor-3.2.1-rc.2.tgz",
+ "dev": "npm run codegen && react-native bundle-harmony --dev --minify=false",
+ "prod": "npm run codegen && react-native bundle-harmony --dev=false --minify=true",
+ "postinstall": "node ./scripts/create-build-profile.js",
+ "fast:pkg": "npm run pack:pkg && npm i --legacy-peer-deps && npm run dev"
+ },
+ "dependencies": {
+ "@gorhom/portal": "^1.0.14",
+ "@react-native-ohos/image-editor": "file:../react-native-ohos-image-editor-3.2.1-rc.2.tgz",
+ "react": "18.2.0",
+ "react-native": "0.72.5",
+ "@rnoh/testerino": "npm:@react-native-oh-tpl/testerino@0.0.9",
+ "react-native-harmony": "npm:@react-native-oh/react-native-harmony@^0.72.32"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.20.0",
+ "@babel/preset-env": "^7.20.0",
+ "@babel/runtime": "^7.20.0",
+ "@react-native-community/eslint-config": "^3.2.0",
+ "@react-native/eslint-config": "^0.74.0",
+ "@react-native/metro-config": "^0.72.6",
+ "@tsconfig/react-native": "^2.0.2",
+ "@types/chai": "^4.3.4",
+ "@types/d3-scale-chromatic": "^3.0.0",
+ "@types/fs-extra": "^11.0.1",
+ "@types/jest": "^29.5.5",
+ "@types/metro-config": "^0.76.2",
+ "@types/react": "17.0.14",
+ "@types/react-dom": "17.0.14",
+ "@types/react-test-renderer": "^18.0.0",
+ "babel-jest": "^29.2.1",
+ "csv-parser": "^3.0.0",
+ "eslint": "^8.19.0",
+ "eslint-plugin-prettier": "^5.0.1",
+ "fs-extra": "^11.1.1",
+ "husky": "^8.0.3",
+ "jest": "^29.7.0",
+ "json5": "^2.2.3",
+ "metro": "^0.76.3",
+ "metro-config": "^0.76.3",
+ "metro-react-native-babel-preset": "0.73.9",
+ "prettier": "3.2.4",
+ "react-test-renderer": "18.2.0",
+ "simple-statistics": "^7.8.3",
+ "ts-jest": "^29.1.1",
+ "typescript": "^5.3.2",
+ "yargs": "^17.7.2"
+ },
+ "overrides": {
+ "@rnoh/react-native-harmony-cli": "npm:@react-native-oh/react-native-harmony-cli@^0.0.27",
+ "@react-native-community/cli": "11.3.6",
+ "@react-native/codegen": "0.74.0"
+ },
+ "resolutions": {
+ "@react-native-community/cli": "11.3.6"
+ }
+}
diff --git a/example/scripts/create-build-profile.js b/example/scripts/create-build-profile.js
new file mode 100644
index 0000000000000000000000000000000000000000..a7841d078f1258af521d389da9dc43c718903c6e
--- /dev/null
+++ b/example/scripts/create-build-profile.js
@@ -0,0 +1,39 @@
+const fs = require('fs');
+const JSON5 = require('json5');
+const path = require('path');
+
+const templatePath = path.join(
+ __dirname,
+ '..',
+ 'harmony',
+ 'build-profile.template.json5',
+);
+const existingProfilePath = path.join(
+ __dirname,
+ '..',
+ 'harmony',
+ 'build-profile.json5',
+);
+
+if (fs.existsSync(existingProfilePath)) {
+ let existingProfile = JSON5.parse(
+ fs.readFileSync(existingProfilePath, 'utf-8'),
+ );
+ let template = JSON5.parse(fs.readFileSync(templatePath, 'utf-8'));
+ let signingConfigs =
+ existingProfile.app && existingProfile.app.signingConfigs;
+
+ existingProfile = {...template};
+
+ if (signingConfigs) {
+ existingProfile.app.signingConfigs = signingConfigs;
+ }
+
+ fs.writeFileSync(
+ existingProfilePath,
+ JSON5.stringify(existingProfile, null, 2),
+ );
+} else {
+ // File doesn't exist, create a copy from the template
+ fs.copyFileSync(templatePath, existingProfilePath);
+}
\ No newline at end of file
diff --git a/example/src/Example.tsx b/example/src/Example.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..b39987beb19fcac7ba446c951ee2f871e1488890
--- /dev/null
+++ b/example/src/Example.tsx
@@ -0,0 +1,152 @@
+/*
+*
+* Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
+* Use of this source code is governed by a MIT license that can be
+* found in the LICENSE file
+*
+*/
+
+import React, { Component } from "react";
+import {
+ Image,
+ ScrollView,
+ Text,
+ View,
+ StyleSheet,
+ Button,
+ Alert,
+ KeyboardAvoidingView,
+} from "react-native";
+
+import ImageEditor from "@react-native-community/image-editor";
+
+export interface Props {
+ // noop
+}
+
+interface Size {
+ width: number;
+ height: number;
+}
+
+interface State {
+ photoUri: any;
+ photoWidth: number;
+ photoHeight: number;
+ croppedImageURI: string | null;
+ targetSize?: Size;
+ cropHorizontal: boolean;
+}
+
+class App extends Component {
+ constructor(props: Props) {
+ super(props);
+ this.state = {
+ photoUri: "https://octodex.github.com/images/OctoAsians_dex_Full.png",
+ photoWidth: 896,
+ photoHeight: 896,
+ croppedImageURI: null,
+ targetSize: {
+ width: 0,
+ height: 0,
+ },
+ cropHorizontal: false,
+ };
+ }
+
+ _crop = async () => {
+ let cropData = {
+ offset: { x: 100, y: 100 },
+ size: { width: 300, height: 300 },
+ quality: 1,
+ format: "jpeg",
+ };
+ if (
+ cropData.size.width + cropData.offset.x > this.state.photoWidth ||
+ cropData.size.height + cropData.offset.y > this.state.photoHeight
+ ) {
+ Alert.alert("The cropped size exceeds the original size");
+ return;
+ }
+ const croppedImageURI = await ImageEditor.cropImage(
+ this.state.photoUri,
+ cropData
+ );
+ if (croppedImageURI) {
+ this.setState({
+ croppedImageURI,
+ targetSize: {
+ width: cropData.size.width,
+ height: cropData.size.height,
+ },
+ });
+
+ if (this.state.targetSize.width >= this.state.targetSize.height) {
+ this.setState({
+ cropHorizontal: true,
+ });
+ } else {
+ this.setState({
+ cropHorizontal: false,
+ });
+ }
+ }
+ };
+
+ render() {
+ const {
+ photoUri,
+ photoWidth,
+ photoHeight,
+ croppedImageURI,
+ targetSize,
+ cropHorizontal,
+ } = this.state;
+ return (
+
+
+
+
+
+ {croppedImageURI ? (
+
+
+
+ ) : (
+ 未生成图片
+ )}
+
+ {croppedImageURI}
+
+
+
+ );
+ }
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ },
+ button: {
+ padding: 10,
+ },
+ flex: {
+ display: "flex",
+ flexDirection: "row",
+ justifyContent: "flex-start",
+ alignItems: "center",
+ },
+});
+
+export default App;
\ No newline at end of file
diff --git a/example/tsconfig.json b/example/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..9a2c8c222cb885dde1a7a015f7dfe57de4828c85
--- /dev/null
+++ b/example/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "extends": "@tsconfig/react-native/tsconfig.json",
+ "compilerOptions": {
+ "jsx": "react-native",
+ "paths": {
+ "react-native": [
+ "./node_modules/react-native-harmony"
+ ],
+ },
+ },
+ "exclude": [
+ "harmony"
+ ]
+}
\ No newline at end of file
diff --git a/harmony/image_editor.har b/harmony/image_editor.har
new file mode 100644
index 0000000000000000000000000000000000000000..929d44e23007770afff21cb84a39dfd36d31782d
Binary files /dev/null and b/harmony/image_editor.har differ
diff --git a/harmony/image_editor/BuildProfile.ets b/harmony/image_editor/BuildProfile.ets
new file mode 100644
index 0000000000000000000000000000000000000000..52f8fb1a26b80703d49bb804aad81532995b3f5e
--- /dev/null
+++ b/harmony/image_editor/BuildProfile.ets
@@ -0,0 +1,24 @@
+/*
+*
+* Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved
+* Use of this source code is governed by a MIT license that can be
+* found in the LICENSE file
+*
+*/
+/**
+ * Use these variables when you tailor your ArkTS code. They must be of the const type.
+ */
+export const HAR_VERSION = '3.2.1-rc.2';
+export const BUILD_MODE_NAME = 'debug';
+export const DEBUG = true;
+export const TARGET_NAME = 'default';
+
+/**
+ * BuildProfile Class is used only for compatibility purposes.
+ */
+export default class BuildProfile {
+ static readonly HAR_VERSION = HAR_VERSION;
+ static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
+ static readonly DEBUG = DEBUG;
+ static readonly TARGET_NAME = TARGET_NAME;
+}
\ No newline at end of file
diff --git a/harmony/image_editor/oh-package-lock.json5 b/harmony/image_editor/oh-package-lock.json5
new file mode 100644
index 0000000000000000000000000000000000000000..3f97b95a033b8d5f449df6d676f499ac7257d76b
--- /dev/null
+++ b/harmony/image_editor/oh-package-lock.json5
@@ -0,0 +1,19 @@
+{
+ "meta": {
+ "stableOrder": true
+ },
+ "lockfileVersion": 3,
+ "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
+ "specifiers": {
+ "@rnoh/react-native-openharmony@0.72.38": "@rnoh/react-native-openharmony@0.72.38"
+ },
+ "packages": {
+ "@rnoh/react-native-openharmony@0.72.38": {
+ "name": "@rnoh/react-native-openharmony",
+ "version": "0.72.38",
+ "integrity": "sha512-br5SIrbB0OarSLirenleE7eTOX1lNccMJ7nb/G7qWTyJ7kW4DalmTXVKYpoT2qaOLls1uEE7McD1OjbZZM9jug==",
+ "resolved": "https://ohpm.openharmony.cn/ohpm/@rnoh/react-native-openharmony/-/react-native-openharmony-0.72.38.har",
+ "registryType": "ohpm"
+ }
+ }
+}
\ No newline at end of file
diff --git a/harmony/image_editor/src/main/ets/ImageEditorModule.ts b/harmony/image_editor/src/main/ets/ImageEditorModule.ts
index 6ff69d7e04674c9bea21070b8d1bf89fc83a1da1..ec60ffb7e11812ea9229c7c2efeca28d02ae1f18 100644
--- a/harmony/image_editor/src/main/ets/ImageEditorModule.ts
+++ b/harmony/image_editor/src/main/ets/ImageEditorModule.ts
@@ -79,7 +79,7 @@ async function imageEditor(newOptions:ImageCropData, uri: string,uiContext:Conte
if(uri.startsWith("data:")){
imageData = await loadBase(uri)
} else if(uri.startsWith('http')) {
- imageData = await loadHttp(uri)
+ imageData = await loadHttp(uri, logger)
} else {
openFile = fs.openSync(uri, fs.OpenMode.READ_ONLY)
imageData = openFile.fd
diff --git a/harmony/image_editor/src/main/module.json5 b/harmony/image_editor/src/main/module.json5
index 901ace1c15537e633348adc5c1808b9b396bffc9..862c3600a3ca28c82f2ca70ffe7861defde80523 100644
--- a/harmony/image_editor/src/main/module.json5
+++ b/harmony/image_editor/src/main/module.json5
@@ -5,5 +5,10 @@
"deviceTypes": [
'default'
],
+ "requestPermissions": [
+ {
+ "name": "ohos.permission.INTERNET"
+ }
+ ]
},
-}
\ No newline at end of file
+}