diff --git a/.gitignore b/.gitignore
index 33cc2630ba5..f3eb78a9e39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -106,3 +106,11 @@ framework/voltron/VoltronCore/VoltronCore.xcodeproj/project.xcworkspace
framework/voltron/VoltronCore/VoltronCore.xcodeproj/xcuserdata/
renderer/voltron/core/lib/
+
+.hvigor/
+oh_modules/*
+oh-package-lock.json5
+.clang-format
+.clang-tidy
+.clangd
+BuildProfile.ets
diff --git a/AppScope/app.json5 b/AppScope/app.json5
new file mode 100644
index 00000000000..e0605ec6682
--- /dev/null
+++ b/AppScope/app.json5
@@ -0,0 +1,10 @@
+{
+ "app": {
+ "bundleName": "com.tencent.hippydemo",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
diff --git a/AppScope/resources/base/element/string.json b/AppScope/resources/base/element/string.json
new file mode 100644
index 00000000000..5d806813dd8
--- /dev/null
+++ b/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "HippyDemo"
+ }
+ ]
+}
diff --git a/AppScope/resources/base/media/app_icon.png b/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 00000000000..cd45accb1df
Binary files /dev/null and b/AppScope/resources/base/media/app_icon.png differ
diff --git a/build-profile.json5 b/build-profile.json5
new file mode 100644
index 00000000000..660eb033a34
--- /dev/null
+++ b/build-profile.json5
@@ -0,0 +1,57 @@
+{
+ "app": {
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compatibleSdkVersion": "5.0.0(12)",
+ "runtimeOS": "HarmonyOS"
+ }
+ ],
+ "buildModeSet": [
+ {
+ "name": "debug",
+ "buildOption": {
+ "externalNativeOptions": {
+ "abiFilters": [
+ "arm64-v8a"
+ ]
+ }
+ }
+ },
+ {
+ "name": "release"
+ }
+ ]
+ },
+ "modules": [
+ {
+ "name": "entry_har",
+ "srcPath": "./framework/examples/ohos-har-demo",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "entry",
+ "srcPath": "./framework/examples/ohos-demo",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "hippy",
+ "srcPath": "./framework/ohos"
+ },
+ ]
+}
diff --git a/buildconfig/cmake/GlobalPackagesModule.cmake b/buildconfig/cmake/GlobalPackagesModule.cmake
index 061c633845f..166d9573910 100644
--- a/buildconfig/cmake/GlobalPackagesModule.cmake
+++ b/buildconfig/cmake/GlobalPackagesModule.cmake
@@ -45,6 +45,13 @@ function(GlobalPackages_Add_jni)
endif()
endfunction()
+function(GlobalPackages_Add_oh_napi)
+ if (NOT TARGET oh_napi)
+ InfraPackage_Add(OH_NAPI
+ LOCAL "${PROJECT_ROOT_DIR}/modules/ohos/oh_napi")
+ endif()
+endfunction()
+
function(GlobalPackages_Add_vfs)
if (NOT TARGET vfs)
InfraPackage_Add(VFS
diff --git a/devtools/devtools-backend/CMakeLists.txt b/devtools/devtools-backend/CMakeLists.txt
index e51e0c82a84..f319ec12b47 100644
--- a/devtools/devtools-backend/CMakeLists.txt
+++ b/devtools/devtools-backend/CMakeLists.txt
@@ -50,7 +50,11 @@ endif ()
# endregion
# region footstone
-GlobalPackages_Add(footstone)
+if (OHOS)
+ GlobalPackages_Add_footstone()
+else ()
+ GlobalPackages_Add(footstone)
+endif ()
target_link_libraries(${PROJECT_NAME} PRIVATE footstone)
# endregion
diff --git a/devtools/devtools-backend/include/api/adapter/data/domain_metas.h b/devtools/devtools-backend/include/api/adapter/data/domain_metas.h
index 9a1e41b54bd..cdad49eedaf 100644
--- a/devtools/devtools-backend/include/api/adapter/data/domain_metas.h
+++ b/devtools/devtools-backend/include/api/adapter/data/domain_metas.h
@@ -22,7 +22,11 @@
#include
#include
+// nlohmann/json.hpp:3177:30: error: out-of-line definition of constexpr static data member is redundant in C++17 and is deprecated [-Werror,-Wdeprecated]
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated"
#include "nlohmann/json.hpp"
+#pragma clang diagnostic pop
namespace hippy::devtools {
diff --git a/devtools/devtools-backend/include/api/adapter/devtools_common_protocol_adapter.h b/devtools/devtools-backend/include/api/adapter/devtools_common_protocol_adapter.h
index 4a188a21c72..7c02eccaa5b 100644
--- a/devtools/devtools-backend/include/api/adapter/devtools_common_protocol_adapter.h
+++ b/devtools/devtools-backend/include/api/adapter/devtools_common_protocol_adapter.h
@@ -19,6 +19,7 @@
*/
#pragma once
+#pragma clang diagnostic ignored "-Wdeprecated"
#include
#include "nlohmann/json.hpp"
diff --git a/devtools/devtools-backend/include/tunnel/tcp/frame_codec.h b/devtools/devtools-backend/include/tunnel/tcp/frame_codec.h
index 32a1bef8f29..176fe67d4d0 100644
--- a/devtools/devtools-backend/include/tunnel/tcp/frame_codec.h
+++ b/devtools/devtools-backend/include/tunnel/tcp/frame_codec.h
@@ -21,6 +21,7 @@
#pragma once
#include
+#include
#include
#include
diff --git a/devtools/devtools-backend/src/tunnel/tcp/tcp_channel.cc b/devtools/devtools-backend/src/tunnel/tcp/tcp_channel.cc
index 77fc77651a7..9a717d6eb93 100644
--- a/devtools/devtools-backend/src/tunnel/tcp/tcp_channel.cc
+++ b/devtools/devtools-backend/src/tunnel/tcp/tcp_channel.cc
@@ -20,6 +20,7 @@
#include "tunnel/tcp/tcp_channel.h"
#include
+#include
#include
#include
#include
diff --git a/devtools/devtools-integration/CMakeLists.txt b/devtools/devtools-integration/CMakeLists.txt
index 6577bf9fc02..32c7b6dfdc0 100644
--- a/devtools/devtools-integration/CMakeLists.txt
+++ b/devtools/devtools-integration/CMakeLists.txt
@@ -30,4 +30,7 @@ elseif (ANDROID)
add_subdirectory(${PROJECT_ROOT_DIR}/devtools/devtools-integration/android/src/main/cpp)
elseif (IOS)
add_subdirectory(${PROJECT_ROOT_DIR}/devtools/devtools-integration/ios)
+elseif (OHOS)
+ add_subdirectory(${PROJECT_ROOT_DIR}/devtools/devtools-integration/ohos)
endif()
+
diff --git a/devtools/devtools-integration/native/CMakeLists.txt b/devtools/devtools-integration/native/CMakeLists.txt
index 8abcb8a90f5..55cffdd2799 100644
--- a/devtools/devtools-integration/native/CMakeLists.txt
+++ b/devtools/devtools-integration/native/CMakeLists.txt
@@ -51,22 +51,38 @@ endif ()
# endregion
# region footstone
-GlobalPackages_Add(footstone)
+if (OHOS)
+ GlobalPackages_Add_footstone()
+else ()
+ GlobalPackages_Add(footstone)
+endif ()
target_link_libraries(${PROJECT_NAME} PRIVATE footstone)
# endregion
# region vfs
-GlobalPackages_Add(vfs)
+if (OHOS)
+ GlobalPackages_Add_vfs()
+else ()
+ GlobalPackages_Add(vfs)
+endif ()
target_link_libraries(${PROJECT_NAME} PRIVATE vfs)
# endregion
# region dom
-GlobalPackages_Add(dom)
+if (OHOS)
+ GlobalPackages_Add_dom()
+else ()
+ GlobalPackages_Add(dom)
+endif ()
target_link_libraries(${PROJECT_NAME} PRIVATE dom)
# endregion
# region devtools
-GlobalPackages_Add(devtools_backend)
+if (OHOS)
+ GlobalPackages_Add_devtools_backend()
+else ()
+ GlobalPackages_Add(devtools_backend)
+endif ()
target_link_libraries(${PROJECT_NAME} PRIVATE devtools_backend)
# endregion
diff --git a/devtools/devtools-integration/ohos/CMakeLists.txt b/devtools/devtools-integration/ohos/CMakeLists.txt
new file mode 100644
index 00000000000..a6af6fdd0de
--- /dev/null
+++ b/devtools/devtools-integration/ohos/CMakeLists.txt
@@ -0,0 +1,73 @@
+#
+# Tencent is pleased to support the open source community by making
+# Hippy available.
+#
+# Copyright (C) 2022 THL A29 Limited, a Tencent company.
+# All rights reserved.
+#
+# 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.
+#
+
+cmake_minimum_required(VERSION 3.14)
+
+project("devtools_integration")
+
+get_filename_component(PROJECT_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../" REALPATH)
+
+include("${PROJECT_ROOT_DIR}/buildconfig/cmake/InfraPackagesModule.cmake")
+include("${PROJECT_ROOT_DIR}/buildconfig/cmake/compiler_toolchain.cmake")
+
+set(CMAKE_CXX_STANDARD 17)
+
+# region library
+add_library(${PROJECT_NAME} STATIC)
+target_include_directories(${PROJECT_NAME} PUBLIC include)
+target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILE_OPTIONS})
+# endregion
+
+# region jni
+GlobalPackages_Add_oh_napi()
+target_link_libraries(${PROJECT_NAME} PUBLIC oh_napi)
+# endregion
+
+# region footstone
+GlobalPackages_Add_footstone()
+target_link_libraries(${PROJECT_NAME} PRIVATE footstone)
+# endregion
+
+# region dom
+GlobalPackages_Add_dom()
+target_link_libraries(${PROJECT_NAME} PRIVATE dom)
+# endregion
+
+# region vfs
+GlobalPackages_Add_vfs()
+target_link_libraries(${PROJECT_NAME} PRIVATE vfs)
+# endregion
+
+# region devtools
+GlobalPackages_Add_devtools_backend()
+target_link_libraries(${PROJECT_NAME} PRIVATE devtools_backend)
+# endregion
+
+# region devtools_integration
+add_subdirectory(${PROJECT_ROOT_DIR}/devtools/devtools-integration/native ${CMAKE_CURRENT_BINARY_DIR}/devtools-integration/native)
+target_link_libraries(${PROJECT_NAME} PUBLIC devtools_integration_native)
+# endregion
+
+# region source set
+set(SOURCE_SET
+ src/devtools_napi.cc)
+
+target_sources(${PROJECT_NAME} PUBLIC ${SOURCE_SET})
+# endregion
diff --git a/devtools/devtools-integration/ohos/include/devtools_napi.h b/devtools/devtools-integration/ohos/include/devtools_napi.h
new file mode 100644
index 00000000000..cca4ffa10b7
--- /dev/null
+++ b/devtools/devtools-integration/ohos/include/devtools_napi.h
@@ -0,0 +1,32 @@
+/*
+ * Tencent is pleased to support the open source community by making
+ * Hippy available.
+ *
+ * Copyright (C) 2022 THL A29 Limited, a Tencent company.
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include "footstone/string_view.h"
+#include "footstone/task_runner.h"
+#include
+#include
+
+namespace hippy::devtools {
+
+
+}
+
diff --git a/devtools/devtools-integration/ohos/src/devtools_napi.cc b/devtools/devtools-integration/ohos/src/devtools_napi.cc
new file mode 100644
index 00000000000..2d40910b69f
--- /dev/null
+++ b/devtools/devtools-integration/ohos/src/devtools_napi.cc
@@ -0,0 +1,190 @@
+// #include "driver/scope.h"
+#include "footstone/string_view_utils.h"
+#include "napi/native_api.h"
+
+// #include "dom_manager_napi.h"
+#include
+#include
+#include "oh_napi/data_holder.h"
+#include "oh_napi/oh_napi_register.h"
+#include "oh_napi/ark_ts.h"
+#include "dom/dom_manager.h"
+#include "dom/root_node.h"
+#include "footstone/check.h"
+#include "footstone/logging.h"
+#include "footstone/persistent_object_map.h"
+#include "footstone/task_runner.h"
+#include "footstone/worker_impl.h"
+#include "devtools_napi.h"
+
+#include "devtools/devtools_data_source.h"
+// #include "devtools/vfs/devtools_handler.h"
+
+namespace hippy::devtools {
+
+using WorkerManager = footstone::runner::WorkerManager;
+using string_view = footstone::stringview::string_view;
+using StringViewUtils = footstone::stringview::StringViewUtils;
+constexpr uint32_t kPoolSize = 1;
+constexpr char kDevToolsNapiTag[] = "DevTools-Napi:";
+std::shared_ptr worker_manager;
+using DevtoolsDataSource = hippy::devtools::DevtoolsDataSource;
+
+static napi_value OnCreateDevtools(napi_env env, napi_callback_info info) {
+ // size_t requireArgc = 2;
+ ArkTS arkTs(env);
+ size_t argc = 2;
+ napi_value args[2] = {nullptr};
+
+ napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
+ std::vector argVector = arkTs.GetCallbackArgs(info);
+ FOOTSTONE_DLOG(INFO) << "devtools napi::OnCreateDevtools::" << argVector.size();
+
+ if (argc != 2) {
+ napi_throw_error(env, nullptr, " Requires 2 arguments: data directory and WebSocket URL.");
+ return nullptr;
+ }
+
+ napi_valuetype dirType = arkTs.GetType(args[0]);
+ napi_valuetype wsType = arkTs.GetType(args[1]);
+ if (!(dirType == napi_string && wsType == napi_string)) {
+ napi_throw_error(env, nullptr, "Both arguments must be strings.");
+ return nullptr;
+ }
+
+ std::string data_dir = arkTs.GetString(args[0]);
+ std::string ws_url = arkTs.GetString(args[1]);
+
+ worker_manager = std::make_shared(kPoolSize);
+
+ DevtoolsDataSource::SetFileCacheDir(data_dir);
+
+ auto devtools_data_source =
+ std::make_shared();
+ devtools_data_source->CreateDevtoolsService(ws_url, worker_manager);
+ uint32_t id = devtools::DevtoolsDataSource::Insert(devtools_data_source);
+
+ napi_value result = arkTs.CreateInt(static_cast(id));
+
+ return result;
+}
+
+static napi_value OnDestroyDevtools(napi_env env, napi_callback_info info) {
+ ArkTS arkTs(env);
+ size_t argc = 2;
+ napi_value args[2] = {nullptr};
+
+ napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
+ std::vector argVector = arkTs.GetCallbackArgs(info);
+ FOOTSTONE_DLOG(INFO) << "devtools napi::OnDestroyDevtools::" << argVector.size();
+
+ if (argc != 2) {
+ napi_throw_error(env, nullptr, " Requires 2 arguments: data directory and WebSocket URL.");
+ return nullptr;
+ }
+
+ napi_valuetype devtoolsIdType = arkTs.GetType(args[0]);
+ napi_valuetype isReloadType = arkTs.GetType(args[1]);
+ if (!(devtoolsIdType == napi_number && isReloadType == napi_boolean)) {
+ napi_throw_error(env, nullptr, "Both arguments must be strings.");
+ return nullptr;
+ }
+
+ int devtools_id = arkTs.GetInteger(args[0]);
+ bool is_reload = arkTs.GetBoolean(args[1]);
+ std::shared_ptr devtools_data_source = DevtoolsDataSource::Find(footstone::checked_numeric_cast(devtools_id));
+ devtools_data_source->Destroy(is_reload);
+ bool flag = DevtoolsDataSource::Erase(footstone::checked_numeric_cast(devtools_id));
+ FOOTSTONE_DLOG(INFO) << kDevToolsNapiTag << "OnDestroyDevtools devtools_id=" << devtools_id << ",flag=" << flag;
+ FOOTSTONE_DCHECK(flag);
+ worker_manager->Terminate();
+ napi_value result = arkTs.GetUndefined();
+ return result;
+}
+
+
+static napi_value OnBindDevtools(napi_env env, napi_callback_info info) {
+ ArkTS arkTs(env);
+ size_t argc = 4;
+ napi_value args[4] = {nullptr};
+
+ napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
+ std::vector argVector = arkTs.GetCallbackArgs(info);
+ FOOTSTONE_DLOG(INFO) << "devtools napi::OnBindDevtools::" << argVector.size();
+
+ if (argc != 4) {
+ napi_throw_error(env, nullptr, " Requires 4 arguments: data directory and WebSocket URL.");
+ return nullptr;
+ }
+
+ napi_valuetype devtoolsIdType = arkTs.GetType(args[0]);
+ // napi_valuetype driverIdType = arkTs.GetType(args[1]);
+ napi_valuetype domIdType = arkTs.GetType(args[2]);
+ // napi_valuetype renderIdType = arkTs.GetType(args[3]);
+ if (!(devtoolsIdType == napi_number && domIdType == napi_number)) {
+ napi_throw_error(env, nullptr, "Both arguments must be strings.");
+ return nullptr;
+ }
+
+ int devtools_id = arkTs.GetInteger(args[0]);
+ // int driver_id = arkTs.GetInteger(args[1]);
+ int dom_id = arkTs.GetInteger(args[2]);
+ // int render_id = arkTs.GetInteger(args[3]);
+ std::shared_ptr devtools_data_source =
+ DevtoolsDataSource::Find(footstone::checked_numeric_cast(devtools_id));
+ std::any dom_manager;
+ auto flag = hippy::global_data_holder.Find(footstone::checked_numeric_cast(dom_id), dom_manager);
+ FOOTSTONE_CHECK(flag);
+ auto dom_manager_object = std::any_cast>(dom_manager);
+ devtools_data_source->Bind(dom_manager_object);
+
+ napi_value result = arkTs.GetUndefined();
+ return result;
+}
+
+static napi_value OnAttachToRoot(napi_env env, napi_callback_info info) {
+ ArkTS arkTs(env);
+ size_t argc = 2;
+ napi_value args[2] = {nullptr};
+
+ napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
+ std::vector argVector = arkTs.GetCallbackArgs(info);
+ FOOTSTONE_DLOG(INFO) << "devtools napi::OnAttachToRoot::" << argVector.size();
+
+ if (argc != 2) {
+ napi_throw_error(env, nullptr, " Requires 2 arguments: data directory and WebSocket URL.");
+ return nullptr;
+ }
+
+ napi_valuetype devtoolsIdType = arkTs.GetType(args[0]);
+ napi_valuetype rootIdType = arkTs.GetType(args[1]);
+ if (!(devtoolsIdType == napi_number && rootIdType == napi_number)) {
+ napi_throw_error(env, nullptr, "Both arguments must be number.");
+ return nullptr;
+ }
+
+ int devtools_id = arkTs.GetInteger(args[0]);
+ int root_id = arkTs.GetInteger(args[1]);
+
+ auto &root_map = RootNode::PersistentMap();
+ std::shared_ptr root_node;
+ auto ret = root_map.Find(footstone::checked_numeric_cast(root_id), root_node);
+ if (!ret) {
+ FOOTSTONE_DLOG(WARNING) << kDevToolsTag << "OnAttachToRoot root_node is nullptr";
+ return nullptr;
+ }
+
+ FOOTSTONE_DLOG(INFO) << kDevToolsTag << "OnAttachToRoot root_id=" << root_id;
+ std::shared_ptr devtools_data_source =
+ DevtoolsDataSource::Find(footstone::checked_numeric_cast(devtools_id));
+ devtools_data_source->SetRootNode(root_node);
+ napi_value result = arkTs.GetUndefined();
+ return result;
+}
+
+REGISTER_OH_NAPI("Devtools", "Devtools_OnCreateDevtools", OnCreateDevtools)
+REGISTER_OH_NAPI("Devtools", "Devtools_OnDestroyDevtools", OnDestroyDevtools)
+REGISTER_OH_NAPI("Devtools", "Devtools_OnBindDevtools", OnBindDevtools)
+REGISTER_OH_NAPI("Devtools", "Devtools_OnAttachToRoot", OnAttachToRoot)
+
+} // namespace devtools
diff --git a/docs/api/hippy-vue/components.md b/docs/api/hippy-vue/components.md
index c2fa9c550e1..21bb0090935 100644
--- a/docs/api/hippy-vue/components.md
+++ b/docs/api/hippy-vue/components.md
@@ -65,7 +65,7 @@
| scrollEnabled | 当值为 `false` 的时候,内容不能滚动。`default: true` `(仅在 overflow-y/x: scroll 时适用)` | `boolean` | `Android、iOS、Web-Renderer、Voltron` |
| showScrollIndicator | 是否显示滚动条。 `default: false`(仅在 overflow-y/x: scroll 时适用) | `boolean` | `Android、Voltron` |
| showsHorizontalScrollIndicator | 当此值设为 `false` 的时候,`ScrollView` 会隐藏水平的滚动条。`default: true` `(仅在 overflow-y/x: scroll 时适用)`| `boolean` | `iOS、Voltron` |
-| showsVerticalScrollIndicator | 当此值设为 `false` 的时候,`ScrollView` 会隐藏垂直的滚动条。 `default: true` `(仅在 overflow-y/x: scroll 时适用)`| `boolean` | `iOS、Voltron` |
+| showsVerticalScrollIndicator | 当此值设为 `false` 的时候,`ScrollView` 会隐藏垂直的滚动条。 `default: true` `(仅在 overflow-y/x: scroll 时适用)`| `boolean` | `iOS、Voltron` |
| nativeBackgroundAndroid | 配置水波纹效果,`最低支持版本 2.13.1`;配置项为 `{ borderless: boolean, color: Color, rippleRadius: number }`; `borderless` 表示波纹是否有边界,默认false;`color` 波纹颜色;`rippleRadius` 波纹半径,若不设置,默认容器边框为边界; `注意:设置水波纹后默认不显示,需要在对应触摸事件中调用 setPressed 和 setHotspot 方法进行水波纹展示,详情参考相关`[demo](//github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo/src/components/demos/demo-div.vue) | `Object`| `Android` |
| pointerEvents | 用于控制视图是否可以成为触摸事件的目标。 | `enum('box-none', 'none', 'box-only', 'auto')` | `iOS` |
| nestedScrollPriority* | 嵌套滚动事件处理优先级,`default:self`。相当于同时设置 `nestedScrollLeftPriority`、 `nestedScrollTopPriority`、 `nestedScrollRightPriority`、 `nestedScrollBottomPriority`。 `Android最低支持版本 2.16.0,iOS最低支持版本3.3.3` | `enum(self,parent,none)` | `Android、iOS` |
@@ -184,17 +184,17 @@
| 参数 | 描述 | 类型 | 支持平台 |
| ------------------ | ------------------------------------------------------------ | ------------------------------------ | --------- |
-| src | 内嵌用的网址 | `string` | `Android、iOS、Web-Renderer、Voltron` |
-| method | 请求方式,`get`、`post` | `string` | `Android、iOS` |
-| userAgent | Webview userAgent | `string` | `Android、iOS、Voltron`|
+| src | 内嵌用的网址 | `string` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| method | 请求方式,`get`、`post` | `string` | `Android、iOS、Ohos` |
+| userAgent | Webview userAgent | `string` | `Android、iOS、Voltron、Ohos` |
## 事件
| 事件名称 | 描述 | 类型 | 支持平台 |
| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- |
-| load | 网页加载成功后会触发 | `(object: { url: string }) => void` | `Android、iOS、Web-Renderer、Voltron` |
-| loadStart | 网页开始加载时触发 | `(object: { url: string }) => void` | `Android、iOS、Web-Renderer、Voltron` |
-| loadEnd | 网页加载结束时触发 (`success`与`error`参数仅`Android`、`iOS`上可用,最低支持版本`2.15.3`) | `(object: { url: string, success: boolean, error: string }) => void` | `Android、iOS、Web-Renderer、Voltron` |
+| load | 网页加载成功后会触发 | `(object: { url: string }) => void` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| loadStart | 网页开始加载时触发 | `(object: { url: string }) => void` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| loadEnd | 网页加载结束时触发 (`success`与`error`参数仅`Android`、`iOS`上可用,最低支持版本`2.15.3`) | `(object: { url: string, success: boolean, error: string }) => void` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
---
@@ -211,9 +211,9 @@
| 参数 | 描述 | 类型 | 支持平台 |
| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- |
-| src | 图片地址。现在支持的图片格式有 png , jpg , jpeg , bmp , gif 。 | string | `Android、iOS、Web-Renderer、Voltron` |
-| capInsets | 当调整 img 大小的时候,由 capInsets 指定的边角尺寸会被固定而不进行缩放,而中间和边上其他的部分则会被拉伸。这在制作一些可变大小的圆角按钮、阴影、以及其它资源的时候非常有用。 | `{ top: number, left: number, bottom: number, right: number }` | `Android、iOS、Voltron` |
-| placeholder | 指定当 `img` 组件还没加载出 `src` 属性指定的图片或者图片加载出错时的占位符图片 | `string`: 图片 base64 字符串 | `Android、iOS、Web-Renderer、Voltron` |
+| src | 图片地址。现在支持的图片格式有 png , jpg , jpeg , bmp , gif 。 | string | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| capInsets | 当调整 img 大小的时候,由 capInsets 指定的边角尺寸会被固定而不进行缩放,而中间和边上其他的部分则会被拉伸。这在制作一些可变大小的圆角按钮、阴影、以及其它资源的时候非常有用。 | `{ top: number, left: number, bottom: number, right: number }` | `Android、iOS、Voltron` |
+| placeholder | 指定当 `img` 组件还没加载出 `src` 属性指定的图片或者图片加载出错时的占位符图片 | `string`: 图片 base64 字符串 | `Android、iOS、Web-Renderer、Voltron、Ohos` |
> `2.8.1` 版本后支持终端本地图片能力,可通过 webpack `file-loader` 加载。
@@ -221,17 +221,17 @@
| 参数 | 描述 | 类型 | 支持平台 |
| ------------------ | ------------------------------------------------------------ | ------------------------------------ | --------- |
-| resize-mode | 决定当组件尺寸和图片尺寸不成比例的时候如何调整图片的大小。(`Web-Renderer 不支持 repeat`) | `enum (cover, contain, stretch, repeat, center)` | `Android、iOS、Web-Renderer、Voltron` |
+| resize-mode | 决定当组件尺寸和图片尺寸不成比例的时候如何调整图片的大小。(`Web-Renderer 不支持 repeat`) | `enum (cover, contain, stretch, repeat, center)` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
## 事件
| 事件名称 | 描述 | 类型 | 支持平台 |
| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- |
| layout | 当元素挂载或者布局改变的时候调用,参数为: `nativeEvent: { layout: { x, y, width, height } }`,其中 `x` 和 `y` 为相对父元素的坐标位置 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
-| load | 加载成功完成时调用此回调函数。 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
+| load | 加载成功完成时调用此回调函数。 | `Function` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
| loadStart | 加载开始时调用。 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
-| loadEnd | 加载结束后,不论成功还是失败,调用此回调函数。参数为:`nativeEvent: { success: number, width: number, height: number}` | `Function` | `Android、iOS、Web-Renderer、Voltron` |
-| error | 当加载错误的时候调用此回调函数。| `Function` | `Android、iOS、Web-Renderer、Voltron` |
+| loadEnd | 加载结束后,不论成功还是失败,调用此回调函数。参数为:`nativeEvent: { success: number, width: number, height: number}` | `Function` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| error | 当加载错误的时候调用此回调函数。| `Function` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
| progress | 在加载过程中不断调用,参数为 `nativeEvent: { loaded: number, total: number }`, `loaded` 表示加载中的图片大小, `total` 表示图片总大小 | `Function` | `iOS、Voltron` |
| touchstart | 触屏开始事件,最低支持版本 2.6.2,参数为 `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` 和 `clientY` 分别表示点击在屏幕内的绝对位置 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
| touchmove | 触屏移动事件,最低支持版本 2.6.2,参数为 `evt: { touches: [{ clientX: number, clientY: number }] }`,`clientX` 和 `clientY` 分别表示点击在屏幕内的绝对位置 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
@@ -293,15 +293,15 @@
| 参数 | 描述 | 类型 | 支持平台 |
| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | --------- |
-| caret-color | 输入光标颜色。(也可设置为 Style 属性) `最低支持版本2.11.5` | [`color`](api/style/color.md) | `Android、Voltron` |
-| defaultValue | 提供一个文本框中的初始值。当用户开始输入的时候,值就可以改变。 在一些简单的使用情形下,如果你不想用监听消息然后更新 value 属性的方法来保持属性和状态同步的时候,就可以用 defaultValue 来代替。 | `string` | `Android、iOS、Voltron` |
+| caret-color | 输入光标颜色。(也可设置为 Style 属性) `最低支持版本2.11.5` | [`color`](api/style/color.md) | `Android、Voltron、Ohos` |
+| defaultValue | 提供一个文本框中的初始值。当用户开始输入的时候,值就可以改变。 在一些简单的使用情形下,如果你不想用监听消息然后更新 value 属性的方法来保持属性和状态同步的时候,就可以用 defaultValue 来代替。 | `string` | `Android、iOS、Voltron、Ohos` |
| editable | 如果为 false,文本框是不可编辑的。`default: true` | `boolean` | `Android、iOS、Web-Renderer、Voltron` |
-| type | 决定弹出的何种软键盘的。 注意,`password`仅在属性 `multiline=false` 单行文本框时生效。 | `enum(default, numeric, password, email, phone-pad)` | `Android、iOS、Web-Renderer、Voltron` |
-| maxlength | 限制文本框中最多的字符数。使用这个属性而不用JS 逻辑去实现,可以避免闪烁的现象。 | `numbers` | `Android、iOS、Web-Renderer、Voltron` |
+| type | 决定弹出的何种软键盘的。 注意,`password`仅在属性 `multiline=false` 单行文本框时生效。 | `enum(default, numeric, password, email, phone-pad)` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| maxlength | 限制文本框中最多的字符数。使用这个属性而不用JS 逻辑去实现,可以避免闪烁的现象。 | `numbers` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
| numberOfLines | 设置 `input` 最大显示行数,如果 `input` 没有显式设置高度,会根据 `numberOfLines` 来计算高度撑开。在使用的时候必需同时设置 `multiline` 参数为 `true`。 | `number` | `Android、Voltron、Web-Renderer` |
-| placeholder | 如果没有任何文字输入,会显示此字符串。 | `string` | `Android、iOS、Web-Renderer、Voltron` |
-| placeholder-text-color | 占位字符串显示的文字颜色。(也可设置为 Style 属性) `最低支持版本2.13.4` | [`color`](api/style/color.md) | `Android、iOS、Web-Renderer、Voltron` |
-| returnKeyType | 指定软键盘的回车键显示的样式。(其中部分样式仅对单行文本组件有效) | `enum(done, go, next, search, send)` | `Android、iOS、Web-Renderer` |
+| placeholder | 如果没有任何文字输入,会显示此字符串。 | `string` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| placeholder-text-color | 占位字符串显示的文字颜色。(也可设置为 Style 属性) `最低支持版本2.13.4` | [`color`](api/style/color.md) | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| returnKeyType | 指定软键盘的回车键显示的样式。(其中部分样式仅对单行文本组件有效) | `enum(done, go, next, search, send)` | `Android、iOS、Web-Renderer`、Ohos |
| value | 指定 `input` 组件的值。 | `string` | `Android、iOS、Web-Renderer、Voltron` |
| break-strategy* | 设置Android API 23及以上系统的文本换行策略。`default: simple` | `enum(simple, high_quality, balanced)` | `Android(版本 2.14.2以上)` |
@@ -316,13 +316,13 @@
| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- |
| blur | 当文本框失去焦点的时候调用此回调函数。 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
| focus | 当文本框获得焦点的时候调用此回调函数。 | `Function` | `Android、iOS、Voltron` |
-| change | 当文本框内容变化时调用此回调函数。改变后的文字内容会作为参数传递。 | `Function` | `Android、iOS、Voltron` |
+| change | 当文本框内容变化时调用此回调函数。改变后的文字内容会作为参数传递。 | `Function` | `Android、iOS、Voltron、Ohos` |
| keyboardWillShow | 在弹出输入法键盘时候会触发此回调函数,返回值包含键盘高度 `keyboardHeight`,样式如 `{ keyboardHeight: 260 }`。 | `Function` | `Android、iOS、Voltron` |
| keyboardWillHide | 在隐藏输入法键盘时候会触发此回调函数 | `Function` | `Android、iOS、Voltron` |
-| keyboardHeightChanged | 在输入法键盘高度改变时触发此回调函数,返回值包含键盘高度 `keyboardHeight`,样式如 `{ keyboardHeight: 260 }`, `最低支持版本2.14.0`。 | `Function` | `iOS、Voltron` |
-| endEditing | 当文本输入结束后调用此回调函数。 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
+| keyboardHeightChanged | 在输入法键盘高度改变时触发此回调函数,返回值包含键盘高度 `keyboardHeight`,样式如 `{ keyboardHeight: 260 }`, `最低支持版本2.14.0`。 | `Function` | `iOS、Voltron` |
+| endEditing | 当文本输入结束后调用此回调函数。 | `Function` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
| layout | 当元素挂载或者布局改变的时候调用,参数为: `nativeEvent: { layout: { x, y, width, height } }`,其中 `x` 和 `y` 为相对父元素的坐标位置。 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
-| selectionChange | 当输入框选择文字的范围被改变时调用。返回参数的样式如 `{ nativeEvent: { selection: { start, end } } }`。 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
+| selectionChange | 当输入框选择文字的范围被改变时调用。返回参数的样式如 `{ nativeEvent: { selection: { start, end } } }`。 | `Function` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
## 方法
@@ -385,15 +385,15 @@ Hippy 的重点功能,高性能的可复用列表组件,在终端侧会被
| 参数 | 描述 | 类型 | 支持平台 |
| --------------------- | ------------------------------------------------------------ | ----------------------------------------------------------- | -------- |
-| horizontal | 指定 `ul` 是否采用横向布局。`default: undefined` 纵向布局,Android `2.14.1` 版本后可设置 `false` 显式固定纵向布局;iOS 暂不支持横向 `ul` | `boolean \| undefined` | `Android、Voltron` |
-| initialContentOffset | 初始位移值。在列表初始化时即可指定滚动距离,避免初始化后再通过 scrollTo 系列方法产生的闪动。Android 在 `2.8.0` 版本后支持 | `number` | `Android、iOS、Web-Renderer、Voltron` |
+| horizontal | 指定 `ul` 是否采用横向布局。`default: undefined` 纵向布局,Android `2.14.1` 版本后可设置 `false` 显式固定纵向布局;iOS 暂不支持横向 `ul` | `boolean \| undefined` | `Android、Voltron、Ohos` |
+| initialContentOffset | 初始位移值。在列表初始化时即可指定滚动距离,避免初始化后再通过 scrollTo 系列方法产生的闪动。Android 在 `2.8.0` 版本后支持 | `number` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
| bounces | 是否开启回弹效果,默认 `true`, Android `2.14.1` 版本后支持该属性,老版本使用 `overScrollEnabled` | `boolean` | `Android、iOS、Voltron` |
| rowShouldSticky | 设置 `ul` 是否需要开启悬停效果能力,与 `li` 的 `sticky` 配合使用。 `default: false` | `boolean` | `Android、iOS、Web-Renderer、Voltron`|
-| scrollEnabled | 滑动是否开启。`default: true` | `boolean` | `Android、iOS、Web-Renderer、Voltron` |
-| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onScroll` 回调事件,默认 200ms | `number` | `Android、iOS、Web-Renderer、Voltron` |
+| scrollEnabled | 滑动是否开启。`default: true` | `boolean` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| scrollEventThrottle | 指定滑动事件的回调频率,传入数值指定了多少毫秒(ms)组件会调用一次 `onScroll` 回调事件,默认 200ms | `number` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
| showScrollIndicator | 是否显示滚动条。`default: true` | `boolean` | `iOS、Voltron` |
-| preloadItemNumber | 指定当列表滚动至倒数第几行时触发 `endReached` 回调。 | `number` | `Android、iOS、Web-Renderer、Voltron` |
-| exposureEventEnabled | Android 曝光能力启用开关,如果要使用 `appear`、`disappear` 相关事件,Android 需要设置该开关(iOS无需设置), `default: true` | `boolean` | `Android、Voltron`|
+| preloadItemNumber | 指定当列表滚动至倒数第几行时触发 `endReached` 回调。 | `number` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| exposureEventEnabled | Android 曝光能力启用开关,如果要使用 `appear`、`disappear` 相关事件,Android 需要设置该开关(iOS无需设置), `default: true` | `boolean` | `Android、Voltron、Ohos` |
| endReached | 当所有的数据都已经渲染过,并且列表被滚动到最后一条时,将触发 `endReached` 回调。 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
| editable | 是否可编辑,开启侧滑删除时需要设置为 `true`。`最低支持版本2.9.0` | `boolean` | `iOS` |
| delText | 侧滑删除文本。`最低支持版本2.9.0` | `string` | `iOS` |
@@ -420,12 +420,12 @@ Hippy 的重点功能,高性能的可复用列表组件,在终端侧会被
| 事件名称 | 描述 | 类型 | 支持平台 |
| ------------- | ------------------------------------------------------------ | ----------------------------------------- | -------- |
-| endReached | 当所有的数据都已经渲染过,并且列表被滚动到最后一条时,将触发 `onEndReached` 回调。 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
-| momentumScrollBegin | 在 `ListView` 开始滑动的时候调起,`2.14.6` 版本后支持 `offset` 相关参数 | `(event: { offsetX: number, offsetY: number }) => any` | `Android、iOS、Web-Renderer、Voltron` |
-| momentumScrollEnd | 在 `ListView` 结束滑动的时候调起,`2.14.6` 版本后支持 `offset` 相关参数 | `(event: { offsetX: number, offsetY: number }) => any` | `Android、iOS、Web-Renderer、Voltron` |
-| scroll | 当触发 `ListView` 的滑动事件时回调。由于在 `ListView` 滑动时回调,调用会非常频繁,请使用 `scrollEventThrottle` 进行频率控制。 注意:ListView 在滚动时会进行组件回收,不要在滚动时对 renderRow() 生成的 ListItemView 做任何 ref 节点级的操作(例如:所有 callUIFunction 和 measureInAppWindow 方法),回收后的节点将无法再进行操作而报错。横向ListView时,Android在 `2.8.0` 版本后支持 | `(event: { offsetX: number, offsetY: number }) => any` | `Android、iOS、Web-Renderer、Voltron` |
-| scrollBeginDrag | 当用户开始拖拽 `ListView` 时调用,`2.14.6` 版本后支持 `offset` 相关参数 | `(event: { offsetX: number, offsetY: number }) => any` | `Android、iOS、Web-Renderer、Voltron` |
-| scrollEndDrag | 当用户停止拖拽 `ListView` 或者放手让 `ListView` 开始滑动的时候调用,`2.14.6` 版本后支持 `offset` 相关参数 | `(event: { offsetX: number, offsetY: number }) => any` | `Android、iOS、Web-Renderer、Voltron` |
+| endReached | 当所有的数据都已经渲染过,并且列表被滚动到最后一条时,将触发 `onEndReached` 回调。 | `Function` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| momentumScrollBegin | 在 `ListView` 开始滑动的时候调起,`2.14.6` 版本后支持 `offset` 相关参数 | `(event: { offsetX: number, offsetY: number }) => any` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| momentumScrollEnd | 在 `ListView` 结束滑动的时候调起,`2.14.6` 版本后支持 `offset` 相关参数 | `(event: { offsetX: number, offsetY: number }) => any` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| scroll | 当触发 `ListView` 的滑动事件时回调。由于在 `ListView` 滑动时回调,调用会非常频繁,请使用 `scrollEventThrottle` 进行频率控制。 注意:ListView 在滚动时会进行组件回收,不要在滚动时对 renderRow() 生成的 ListItemView 做任何 ref 节点级的操作(例如:所有 callUIFunction 和 measureInAppWindow 方法),回收后的节点将无法再进行操作而报错。横向ListView时,Android在 `2.8.0` 版本后支持 | `(event: { offsetX: number, offsetY: number }) => any` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| scrollBeginDrag | 当用户开始拖拽 `ListView` 时调用,`2.14.6` 版本后支持 `offset` 相关参数 | `(event: { offsetX: number, offsetY: number }) => any` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
+| scrollEndDrag | 当用户停止拖拽 `ListView` 或者放手让 `ListView` 开始滑动的时候调用,`2.14.6` 版本后支持 `offset` 相关参数 | `(event: { offsetX: number, offsetY: number }) => any` | `Android、iOS、Web-Renderer、Voltron、Ohos` |
| layout | 当元素挂载或者布局改变的时候调用,参数为: `nativeEvent: { layout: { x, y, width, height } }`,其中 `x` 和 `y` 为相对父元素的坐标位置。 | `Function` | `Android、iOS、Web-Renderer、Voltron` |
| delete | 在列表项侧滑删除时调起。`最低支持版本2.9.0` | `(nativeEvent: { index: number}) => void` | `iOS` |
diff --git a/docs/development/native-event.md b/docs/development/native-event.md
index 02772a9a1ee..f7e5a4ef415 100644
--- a/docs/development/native-event.md
+++ b/docs/development/native-event.md
@@ -142,6 +142,18 @@ hippyEngine.sendEvent("rotate", hippyMap);
- (void)sendEvent:(NSString *)eventName params:(NSDictionary *_Nullable)params;
```
+# Ohos
+
+鸿蒙平台接口和安卓相似。
+
+终端在需要发送事件的地方调用代码:
+
+```typescript
+const map = new Map();
+map.pushString("result", "hello i am from native");
+hippyEngine.sendEvent("rotate", map);
+```
+
# Voltron
```dart
diff --git a/docs/development/native-integration.md b/docs/development/native-integration.md
index c7d43e6ff83..1f343f07c26 100644
--- a/docs/development/native-integration.md
+++ b/docs/development/native-integration.md
@@ -1,6 +1,6 @@
# 环境搭建
-这篇教程,讲述了如何将 Hippy 集成到 Android、iOS 、Flutter、Web(同构) 等平台。
+这篇教程,讲述了如何将 Hippy 集成到 Android、iOS、Ohos、Flutter、Web(同构) 等平台。
@@ -272,6 +272,126 @@ ENV['layout_engine'] = 'Yoga'
之后,重新执行`pod install`命令更新项目依赖即可。
+# Ohos
+
+> 注:以下文档都是假设您已经具备一定的 Ohos 开发经验。
+
+---
+
+## 前期准备
+
+- 已经安装 DevEco Studio 最新版本
+
+## Demo 体验
+
+Ohos Har Demo:Har 包方式依赖 Hippy。 体验方法:DevEco 打开 hippy 项目根目录运行 entry_har。
+
+Ohos Demo:源码依赖 Hippy。体验方法:DevEco 打开 hippy 项目根目录直接运行 entry。
+
+## 接入方式一:Har包快速接入
+
+### 1. 创建一个 Ohos 工程
+
+### 2. Har 包集成
+
+- 配置 oh-package.json5
+
+ ```json
+ "dependencies": {
+ "hippy": "1.3.0"
+ }
+ ```
+
+### 3. 初始化代码
+
+- 获取 libhippy.so 接口对象和 UIAbility context
+
+ ```TypeScript
+ import libHippy from 'libhippy.so'
+ AppStorage.setOrCreate("libHippy", libHippy)
+ AppStorage.setOrCreate("abilityContext", this.context)
+ ```
+
+> 注:App 直接集成 Hippy,context 使用 UIAbility context;如果 App 在一个模块里集成 Hippy,js 等资源也集成在模块里,context 使用 getContext().createModuleContext("moduleName"),否则会找不到 js 等资源。
+
+- 创建 HippyEngine、初始化 HippyEngine、加载业务 bundle
+
+ ```TypeScript
+ this.hippyEngine = createHippyEngine(params)
+ this.hippyEngine.initEngine()
+ this.hippyEngine?.loadModule()
+ ```
+
+- 组装 HippyRoot 组件
+
+ ```TypeScript
+ HippyRoot({
+ hippyEngine: this.hippyEngine,
+ rootViewWrapper: this.rootViewWrapper,
+ onRenderException: (exception: HippyException) => {
+ this.exception = `${exception.message}\n${exception.stack}`
+ },
+ })
+ ```
+
+具体可以参考 [Har Demo](https://github.com/sohotz/Hippy/tree/main/framework/examples/ohos-har-demo) 工程中 `EntryAbility.ets` `Index.ets` 实现
+
+## 接入方式二:源码接入
+
+> 源码接入主要为了方便在 App 项目里直接调试 Hippy 代码(c++ 和 ets 代码)。
+
+### 1. 创建一个 Ohos 工程
+
+### 2. Hippy 代码集成
+
+- 拉取 hippy 代码到项目里(比如:根目录下)
+
+> https://github.com/sohotz/Hippy.git,分支:main
+
+- 配置 oh-package.json5
+
+ ```json
+ "dependencies": {
+ "hippy": "file:../Hippy/framework/ohos/"
+ }
+ ```
+
+### 3. 初始化代码
+
+- 获取 libhippy.so 接口对象和 UIAbility context
+
+ ```TypeScript
+ import libHippy from 'libhippy.so'
+ AppStorage.setOrCreate("libHippy", libHippy)
+ AppStorage.setOrCreate("abilityContext", this.context)
+ ```
+
+- 创建 HippyEngine、初始化 HippyEngine、加载业务 bundle
+
+ ```TypeScript
+ this.hippyEngine = createHippyEngine(params)
+ this.hippyEngine.initEngine()
+ this.hippyEngine?.loadModule()
+ ```
+
+- 组装 HippyRoot 组件
+
+ ```TypeScript
+ HippyRoot({
+ hippyEngine: this.hippyEngine,
+ rootViewWrapper: this.rootViewWrapper,
+ onRenderException: (exception: HippyException) => {
+ this.exception = `${exception.message}\n${exception.stack}`
+ },
+ })
+ ```
+
+具体可以参考 [Demo](https://github.com/sohotz/Hippy/tree/main/framework/examples/ohos-demo) 工程中 `EntryAbility.ets` `ExampleHippyPage.ets` 实现
+
+## 接入方式三:定制场景接入
+
+- 对于需要直接依赖 hippy c++ 代码编译使用的定制场景,可参考 [Demo](https://github.com/sohotz/Hippy/tree/main/framework/examples/ohos-demo) 工程中 `CMakeLists.txt` 说明
+
# Voltron/Flutter
> 注:以下文档都是假设您已经具备一定的 Flutter 开发经验。
diff --git a/docs/development/native-module.md b/docs/development/native-module.md
index aa12b911f1a..1fa924fb13e 100644
--- a/docs/development/native-module.md
+++ b/docs/development/native-module.md
@@ -274,6 +274,141 @@ HIPPY_EXPORT_METHOD(click) {
@end
```
+# 鸿蒙
+
+很多时候 `JS` 需要访问对应终端的一些能力模块,比如数据库、下载、网络请求等,这时候就需要使用 `Module` 来暴露接口给JS使用。Voltron SDK 中默认实现了部分 `Module`,但这极有可能无法满足你的需求,这就需要你对 `Module` 进行扩展封装。
+
+---
+
+## Module扩展
+
+我们将以 `TestModule` 为例,从头扩展一个 `Module`,这个 `Module` 将展示前端如何调用终端能力,并且把结果返回给前端
+
+终端扩展 `Module` 包括四步:
+
+1. 创建 `TestModule`
+2. 实现导出给 `JS` 的方法。
+3. 注册 `Module`。
+
+## 1. 创建 `TestModule`,并且继承 HippyNativeModuleBase
+
+```typescript
+export class ExampleNativeModule extends HippyNativeModuleBase {
+ public static readonly NAME = 'ExampleNativeModule'
+
+ constructor(ctx: HippyEngineContext) {
+ super(ctx)
+ }
+
+ public call(method: string, params: Array, promise: HippyModulePromise): HippyAny {
+ switch (method) {
+ case 'test': {
+ this.test();
+ break;
+ }
+ case 'testPromise': {
+ this.testPromise(params, promise);
+ break;
+ }
+ case 'testSendEvent': {
+ this.testSendEvent(params, promise);
+ }
+ default:
+ super.call(method, params, promise);
+ }
+ return null;
+ }
+
+ public test() {
+ LogUtils.i(ExampleNativeModule.NAME, 'module test');
+ }
+
+ public testPromise(params: Array, promise: HippyModulePromise) {
+ promise.resolve('test');
+ }
+
+ public testSendEvent(params: Array, promise: HippyModulePromise) {
+ LogUtils.i(ExampleNativeModule.NAME, 'testSendEvent');
+ if (this.ctx != null && this.ctx.getModuleManager() != null) {
+ const eventModule = this.ctx.getModuleManager().getJavaScriptModule(EventDispatcher.MODULE_NAME);
+ if (eventModule != null) {
+ const event = 'testEvent';
+ const params = new Map();
+ params.set('testString', 'testStringValue');
+
+ const valueMap = new Map();
+ valueMap.set('testString2', 'testStringValue2');
+ params.set('testMap', valueMap);
+
+ const array: HippyArray = [];
+ array.push(valueMap);
+ params.set('testArray', array);
+
+ (eventModule as EventDispatcher).receiveNativeEvent(event, params);
+ }
+ }
+ }
+
+}
+
+```
+
+需要注意的是,这里与Android、iOS有几处不同。
+
+1. 需要指定 NAME,设置为前端调用的 module name
+
+2. 需要实现 call 方法
+
+## Turbo Module扩展
+
+和 Module 的扩展一致,不过还需要配置 isTurbo 方法,且不需要实现 call 方法,参考如下:
+
+```typescript
+export class ExampleNativeTurboModule extends HippyNativeModuleBase {
+ public static readonly NAME = 'demoTurbo'
+
+ constructor(ctx: HippyEngineContext) {
+ super(ctx)
+ }
+
+ isTurbo(): boolean {
+ return true
+ }
+
+ public getString(info: string): string {
+ return 'demoTurbo' + info;
+ }
+
+ public getNum(num: number): number {
+ return num;
+ }
+
+ public getBoolean(b: boolean): boolean {
+ return b;
+ }
+
+ public getMap(map: HippyMap): HippyMap {
+ return map
+ }
+
+ public getArray(array: HippyArray): HippyArray {
+ return array
+ }
+
+ public getObject(obj: HippyAny): HippyAny {
+ return obj
+ }
+
+ public getTurboConfig(): TurboConfig {
+ return new TurboConfig();
+ }
+
+ public printTurboConfig(turboConfig: TurboConfig): string {
+ return turboConfig.info;
+ }
+}
+
+```
# Voltron
diff --git a/docs/feature/feature2.0/jsi.md b/docs/feature/feature2.0/jsi.md
index 7fd33998677..49298610347 100644
--- a/docs/feature/feature2.0/jsi.md
+++ b/docs/feature/feature2.0/jsi.md
@@ -148,6 +148,107 @@ HIPPY_EXPORT_TURBO_METHOD(setInfo:(NSString *)string) {
更多示例可参考类[DemoIOSTurboModule](https://github.com/Tencent/Hippy/blob/master/examples/ios-demo/HippyDemo/turbomodule/TurboBaseModule.mm)
+## 鸿蒙
+
+* 通过设置引擎初始化参数开启JSI能力
+
+```typescript
+initParams.enableTurbo = true
+```
+
+* 定义Module
+
+> 跟普通NativeModule类似,区别在于需要设置 isTurbo 为 true
+
+```typescript
+export class ExampleNativeTurboModule extends HippyNativeModuleBase {
+ public static readonly NAME = 'demoTurbo'
+
+ constructor(ctx: HippyEngineContext) {
+ super(ctx)
+ }
+
+ isTurbo(): boolean {
+ return true
+ }
+
+ public getString(info: string): string {
+ return 'demoTurbo' + info;
+ }
+
+ public getNum(num: number): number {
+ return num;
+ }
+
+ public getBoolean(b: boolean): boolean {
+ return b;
+ }
+
+ public getMap(map: HippyMap): HippyMap {
+ return map
+ }
+
+ public getArray(array: HippyArray): HippyArray {
+ return array
+ }
+
+ public getObject(obj: HippyAny): HippyAny {
+ return obj
+ }
+
+ public getTurboConfig(): TurboConfig {
+ return new TurboConfig();
+ }
+
+ public printTurboConfig(turboConfig: TurboConfig): string {
+ return turboConfig.info;
+ }
+}
+```
+
+> 嵌套 turbo 对象需要设置注解@HippyTurboObject, 否则会当作普通对象解析
+
+``` typescript
+@HippyTurboObject()
+export class TurboConfig {
+ public static readonly NAME = 'turboConfig'
+ public info = "info from turboConfig"
+ private static instance: TurboConfig;
+
+ public static getInstance() {
+ if (!TurboConfig.instance) {
+ TurboConfig.instance = new TurboConfig();
+ }
+ return TurboConfig.instance;
+ }
+
+ public toString() {
+ return this.info;
+ }
+
+ public getTestString() {
+ return 'test' + this.info;
+ }
+}
+```
+
+> 支持的数据类型说明:
+
+| Objec类型 | Js类型 |
+|:----------|:----------|
+| napi_boolean | Bool |
+| napi_number | Number |
+| napi_bigint | Number |
+| napi_string | String |
+| napi_object | Array |
+| napi_object | Object |
+| NULL | null |
+
+更多示例可参考类[DemoTurboModule](https://github.com/sohotz/Hippy/blob/main/framework/examples/ohos-demo/src/main/ets/hippy_extend/ExampleNativeTurboModule.ets)
+
+* 注册TurboModule模块,跟NativeModule注册方法完全一致
+
+
# 使用例子
diff --git a/dom/CMakeLists.txt b/dom/CMakeLists.txt
index 9027fd00546..7cba289b8ae 100644
--- a/dom/CMakeLists.txt
+++ b/dom/CMakeLists.txt
@@ -37,7 +37,12 @@ target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILE_OPTIONS})
# endregion
# region footstone
-GlobalPackages_Add(footstone)
+if (OHOS)
+ GlobalPackages_Add_footstone()
+else ()
+ GlobalPackages_Add(footstone)
+endif ()
+
target_link_libraries(${PROJECT_NAME} PRIVATE footstone)
# endregion
@@ -47,10 +52,17 @@ if (NOT DEFINED LAYOUT_ENGINE)
endif ()
if ("${LAYOUT_ENGINE}" STREQUAL "Yoga")
- InfraPackage_Add(yoga
- REMOTE "dom/third_party/yoga/1.19.0/git-repo.tgz"
- LOCAL "third_party/yoga"
- )
+ if (ANDROID)
+ InfraPackage_Add(yoga
+ REMOTE "dom/third_party/yoga/1.19.0/git-repo.tgz"
+ LOCAL "third_party/yoga"
+ )
+ else ()
+ InfraPackage_Add(yoga
+ REMOTE "dom/third_party/yoga_ohos/1.19.0/git-repo.tgz"
+ LOCAL "third_party/yoga"
+ )
+ endif ()
target_compile_definitions(${PROJECT_NAME} PRIVATE "USE_YOGA")
target_link_libraries(${PROJECT_NAME} PRIVATE yogacore)
elseif ("${LAYOUT_ENGINE}" STREQUAL "Taitank")
diff --git a/dom/include/dom/dom_node.h b/dom/include/dom/dom_node.h
index b485c468e30..ea9900ed1d2 100644
--- a/dom/include/dom/dom_node.h
+++ b/dom/include/dom/dom_node.h
@@ -243,6 +243,10 @@ class DomNode : public std::enable_shared_from_this {
bool is_virtual_{};
bool layout_only_ = false;
+ // support root wrap_content, invoke SetRootSize with param NAN
+ bool is_layout_width_nan_ = false;
+ bool is_layout_height_nan_ = false;
+
// Node can only be eliminated for the first time,
// and if they cannot be eliminated for the first time, they cannot be eliminated at all times.
bool enable_eliminated_ = true;
diff --git a/dom/include/dom/layout_node.h b/dom/include/dom/layout_node.h
index ddb1926a695..c0234b31c78 100644
--- a/dom/include/dom/layout_node.h
+++ b/dom/include/dom/layout_node.h
@@ -81,6 +81,8 @@ class LayoutNode {
virtual void SetWidth(float width) = 0;
virtual void SetHeight(float height) = 0;
+ virtual void SetMaxWidth(float width) = 0;
+ virtual void SetMaxHeight(float height) = 0;
virtual void SetPosition(Edge edge, float position) = 0;
virtual void SetScaleFactor(float scale_factor) = 0;
virtual bool HasNewLayout() = 0;
diff --git a/dom/include/dom/root_node.h b/dom/include/dom/root_node.h
index 2b8f505565b..e2a7a79059e 100644
--- a/dom/include/dom/root_node.h
+++ b/dom/include/dom/root_node.h
@@ -53,6 +53,18 @@ class DomNodeStyleDiffer {
std::unordered_map>> node_ext_style_map_;
};
+struct ListenerOp {
+ bool add;
+ std::weak_ptr dom_node;
+ std::string name;
+
+ ListenerOp(bool add, std::weak_ptr dom_node, const std::string& name) {
+ this->add = add;
+ this->dom_node = dom_node;
+ this->name = name;
+ }
+};
+
class RootNode : public DomNode {
public:
using TaskRunner = footstone::runner::TaskRunner;
@@ -72,6 +84,8 @@ class RootNode : public DomNode {
virtual void AddEventListener(const std::string& name, uint64_t listener_id, bool use_capture,
const EventCallback& cb) override;
virtual void RemoveEventListener(const std::string& name, uint64_t listener_id) override;
+
+ std::map> &EventListenerOps() { return event_listener_ops_; }
void ReleaseResources();
void CreateDomNodes(std::vector>&& nodes, bool needSortByIndex);
@@ -94,11 +108,16 @@ class RootNode : public DomNode {
void SetRootOrigin(float x, float y);
void Traverse(const std::function&)>& on_traverse);
void AddInterceptor(const std::shared_ptr& interceptor);
+ void SetDisableSetRootSize(bool disable) {
+ disable_set_root_size_ = disable;
+ }
static footstone::utils::PersistentObjectMap>& PersistentMap() {
return persistent_map_;
}
+ std::vector> GetAllTextNodes();
+
private:
static void MarkLayoutNodeDirty(const std::vector>& nodes);
@@ -115,6 +134,7 @@ class RootNode : public DomNode {
std::vector dom_operations_;
std::vector event_operations_;
+ std::map> event_listener_ops_;
void FlushDomOperations(const std::shared_ptr& render_manager);
void FlushEventOperations(const std::shared_ptr& render_manager);
@@ -128,6 +148,8 @@ class RootNode : public DomNode {
std::shared_ptr animation_manager_;
std::unique_ptr style_differ_;
+ bool disable_set_root_size_ { false };
+
static footstone::utils::PersistentObjectMap> persistent_map_;
};
diff --git a/dom/include/dom/taitank_layout_node.h b/dom/include/dom/taitank_layout_node.h
index b1394e6f372..14854b71389 100644
--- a/dom/include/dom/taitank_layout_node.h
+++ b/dom/include/dom/taitank_layout_node.h
@@ -239,13 +239,13 @@ class TaitankLayoutNode : public LayoutNode, public std::enable_shared_from_this
* @brief 设置 max width 属性
* @param max_width 最大宽度
*/
- void SetMaxWidth(float max_width);
+ void SetMaxWidth(float max_width) override;
/**
* @brief 设置 max height 属性
* @param max_height 最大高度
*/
- void SetMaxHeight(float max_height);
+ void SetMaxHeight(float max_height) override;
/**
* @brief 设置 min width 属性
diff --git a/dom/include/dom/yoga_layout_node.h b/dom/include/dom/yoga_layout_node.h
index d0153e5ee63..48906156e9c 100644
--- a/dom/include/dom/yoga_layout_node.h
+++ b/dom/include/dom/yoga_layout_node.h
@@ -46,6 +46,10 @@ class YogaLayoutNode : public LayoutNode, public std::enable_shared_from_this hippy_value);
- void SetFlexBasis(float flex_basis);
+ void SetYGFlexBasis(std::shared_ptr dom_value);
void SetFlex(float flex);
diff --git a/dom/src/dom/animation/animation_manager.cc b/dom/src/dom/animation/animation_manager.cc
index 04aa8fdd332..8e39a617acb 100644
--- a/dom/src/dom/animation/animation_manager.cc
+++ b/dom/src/dom/animation/animation_manager.cc
@@ -345,11 +345,12 @@ void AnimationManager::UpdateCubicBezierAnimation(double current,
HippyValue prop_value(current);
for (auto prop: prop_it->second) {
dom_node->EmplaceStyleMapAndGetDiff(prop, prop_value, diff_value);
- FOOTSTONE_DLOG(INFO) << "animation related_animation_id = " << related_animation_id
- << "node id = " << dom_node->GetId() << ", key = " << prop << ", value = " << prop_value;
+ if (footstone::gEnableUpdateAnimLog) {
+ FOOTSTONE_DLOG(INFO) << "animation related_animation_id = " << related_animation_id
+ << "node id = " << dom_node->GetId() << ", key = " << prop << ", value = " << prop_value;
+ }
}
-
dom_node->SetDiffStyle(std::make_shared<
std::unordered_map>>(std::move(diff_value)));
update_node_map[dom_node_id] = dom_node;
@@ -409,6 +410,8 @@ void AnimationManager::UpdateAnimations() {
return;
}
+ footstone::AutoInUpdateAnimScope autoInUpdateAnimScope;
+
auto now = footstone::time::MonotonicallyIncreasingTime();
std::unordered_map> update_node_map;
// xcode crash if we change for to loop
diff --git a/dom/src/dom/animation/cubic_bezier_animation.cc b/dom/src/dom/animation/cubic_bezier_animation.cc
index df33f510f2b..89b1c61f511 100644
--- a/dom/src/dom/animation/cubic_bezier_animation.cc
+++ b/dom/src/dom/animation/cubic_bezier_animation.cc
@@ -51,22 +51,32 @@ CubicBezier CubicBezierAnimation::ParseCubicBezierStr(const std::string& str) {
double CubicBezierAnimation::CalculateColor(double start_color, double to_color, double scale) {
auto start_value = static_cast(start_color);
- auto start_red = static_cast(((start_value >> 24) & 0xff));
- auto start_green = static_cast(((start_value >> 16) & 0xff));
- auto start_blue = static_cast(((start_value >> 8) & 0xff));
- auto start_alpha = static_cast((start_value & 0xff));
-
+ if (start_color < 0) {
+ auto start_int_value = static_cast(start_color);
+ start_value = static_cast(start_int_value);
+ }
+
+ auto start_alpha = ((start_value >> 24) & 0xff);
+ auto start_red = ((start_value >> 16) & 0xff);
+ auto start_green = ((start_value >> 8) & 0xff);
+ auto start_blue = (start_value & 0xff);
+
auto to_value = static_cast(to_color);
- auto to_red = static_cast(((to_value >> 24) & 0xff));
- auto to_green = static_cast(((to_value >> 16) & 0xff));
- auto to_blue = static_cast(((to_value >> 8) & 0xff));
- auto to_alpha = static_cast((to_value & 0xff));
-
- auto red = static_cast(start_red + (to_red - start_red) * scale);
- auto green = static_cast(start_green + (to_green - start_green) * scale);
- auto blue = static_cast(start_blue + (to_blue - start_blue) * scale);
- auto alpha = static_cast(start_alpha + (to_alpha - start_alpha) * scale);
- auto ret = (static_cast(red) << 24) + (static_cast(green) << 16) + (static_cast(blue) << 8) + alpha;
+ if (to_color < 0) {
+ auto to_int_value = static_cast(to_color);
+ to_value = static_cast(to_int_value);
+ }
+
+ auto to_alpha = ((to_value >> 24) & 0xff);
+ auto to_red = ((to_value >> 16) & 0xff);
+ auto to_green = ((to_value >> 8) & 0xff);
+ auto to_blue = (to_value & 0xff);
+
+ auto red = static_cast(start_red + static_cast(to_red - start_red) * scale);
+ auto green = static_cast(start_green + static_cast(to_green - start_green) * scale);
+ auto blue = static_cast(start_blue + static_cast(to_blue - start_blue) * scale);
+ auto alpha = static_cast(start_alpha + static_cast(to_alpha - start_alpha) * scale);
+ auto ret = (static_cast(alpha) << 24) + (static_cast(red) << 16) + (static_cast(green) << 8) + static_cast(blue);
return static_cast(ret);
}
diff --git a/dom/src/dom/dom_manager.cc b/dom/src/dom/dom_manager.cc
index 2a6a9e1cdb9..b319cea536f 100644
--- a/dom/src/dom/dom_manager.cc
+++ b/dom/src/dom/dom_manager.cc
@@ -132,7 +132,9 @@ void DomManager::EndBatch(const std::weak_ptr& weak_root_node) {
if (!root_node) {
return;
}
- FOOTSTONE_DLOG(INFO) << "[Hippy Statistic] total node size = " << root_node->GetChildCount();
+ if (!footstone::gInUpdateAnimScope || footstone::gEnableUpdateAnimLog) {
+ FOOTSTONE_DLOG(INFO) << "[Hippy Statistic] total node size = " << root_node->GetChildCount();
+ }
root_node->SyncWithRenderManager(render_manager);
}
diff --git a/dom/src/dom/dom_node.cc b/dom/src/dom/dom_node.cc
index 9a55af08db2..6c7d68adc90 100644
--- a/dom/src/dom/dom_node.cc
+++ b/dom/src/dom/dom_node.cc
@@ -205,7 +205,7 @@ void DomNode::DoLayout() {
}
void DomNode::DoLayout(std::vector>& changed_nodes) {
- layout_node_->CalculateLayout(0, 0);
+ layout_node_->CalculateLayout(is_layout_width_nan_ ? NAN : 0, is_layout_height_nan_ ? NAN : 0);
TransferLayoutOutputsRecursive(changed_nodes);
}
@@ -221,6 +221,9 @@ std::tuple DomNode::GetLayoutSize() {
}
void DomNode::SetLayoutSize(float width, float height) {
+ is_layout_width_nan_ = std::isnan(width) ? true : false;
+ is_layout_height_nan_ = std::isnan(height) ? true : false;
+
layout_node_->SetWidth(width);
layout_node_->SetHeight(height);
}
diff --git a/dom/src/dom/layer_optimized_render_manager.cc b/dom/src/dom/layer_optimized_render_manager.cc
index 3c744dc0010..1ce6cadc28d 100644
--- a/dom/src/dom/layer_optimized_render_manager.cc
+++ b/dom/src/dom/layer_optimized_render_manager.cc
@@ -88,8 +88,10 @@ void LayerOptimizedRenderManager::UpdateRenderNode(std::weak_ptr root_
}
}
}
- FOOTSTONE_DLOG(INFO) << "[Hippy Statistic] update node size before optimize = " << nodes.size()
- << ", update node size after optimize = " << nodes_to_update.size();
+ if (!footstone::gInUpdateAnimScope || footstone::gEnableUpdateAnimLog) {
+ FOOTSTONE_DLOG(INFO) << "[Hippy Statistic] update node size before optimize = " << nodes.size()
+ << ", update node size after optimize = " << nodes_to_update.size();
+ }
if (!nodes_to_update.empty()) {
render_manager_->UpdateRenderNode(root_node, std::move(nodes_to_update));
}
diff --git a/dom/src/dom/root_node.cc b/dom/src/dom/root_node.cc
index 0c660158a41..d3b950748ad 100644
--- a/dom/src/dom/root_node.cc
+++ b/dom/src/dom/root_node.cc
@@ -460,7 +460,11 @@ std::shared_ptr RootNode::GetNode(uint32_t id) {
std::tuple RootNode::GetRootSize() { return GetLayoutSize(); }
-void RootNode::SetRootSize(float width, float height) { SetLayoutSize(width, height); }
+void RootNode::SetRootSize(float width, float height) {
+ if (!disable_set_root_size_) {
+ SetLayoutSize(width, height);
+ }
+}
void RootNode::SetRootOrigin(float x, float y) { SetLayoutOrigin(x, y); }
@@ -575,5 +579,16 @@ void RootNode::Traverse(const std::function&
}
}
+std::vector> RootNode::GetAllTextNodes() {
+ std::vector> textNodes;
+ for (auto it = nodes_.begin(); it != nodes_.end(); it++) {
+ auto node = it->second.lock();
+ if (node && node->GetViewName() == "Text") {
+ textNodes.emplace_back(node);
+ }
+ }
+ return textNodes;
+}
+
} // namespace dom
} // namespace hippy
diff --git a/dom/src/dom/yoga_layout_node.cc b/dom/src/dom/yoga_layout_node.cc
index 2d4a4d37bc3..87929a8847c 100644
--- a/dom/src/dom/yoga_layout_node.cc
+++ b/dom/src/dom/yoga_layout_node.cc
@@ -288,6 +288,10 @@ void YogaLayoutNode::SetWidth(float width) { YGNodeStyleSetWidth(yoga_node_, wid
void YogaLayoutNode::SetHeight(float height) { YGNodeStyleSetHeight(yoga_node_, height); }
+void YogaLayoutNode::SetMaxWidth(float width) { YGNodeStyleSetMaxWidth(yoga_node_, width); }
+
+void YogaLayoutNode::SetMaxHeight(float height) { YGNodeStyleSetMaxHeight(yoga_node_, height); }
+
void YogaLayoutNode::SetScaleFactor(float scale_factor) { YGConfigSetPointScaleFactor(yoga_config_, scale_factor); }
static LayoutMeasureMode ToLayoutMeasureMode(YGMeasureMode measure_mode) {
@@ -307,6 +311,7 @@ static YGSize YGMeasureFunction(YGNodeRef node, float width, YGMeasureMode width
YGMeasureMode height_mode) {
auto yoga_node = reinterpret_cast(YGNodeGetContext(node));
int64_t key = yoga_node->GetKey();
+ std::lock_guard lock(mutex);
auto iter = measure_function_map.find(key);
if (iter != measure_function_map.end()) {
auto size = iter->second(width, ToLayoutMeasureMode(width_mode), height, ToLayoutMeasureMode(height_mode), nullptr);
@@ -319,12 +324,17 @@ static YGSize YGMeasureFunction(YGNodeRef node, float width, YGMeasureMode width
}
void YogaLayoutNode::SetMeasureFunction(MeasureFunction measure_function) {
+ std::lock_guard lock(mutex);
measure_function_map[key_] = measure_function;
YGNodeSetContext(yoga_node_, reinterpret_cast(this));
return YGNodeSetMeasureFunc(yoga_node_, YGMeasureFunction);
}
-bool YogaLayoutNode::HasMeasureFunction() { return measure_function_map.find(key_) != measure_function_map.end(); }
+bool YogaLayoutNode::HasMeasureFunction() {
+ std::lock_guard lock(mutex);
+ return measure_function_map.find(key_) != measure_function_map.end();
+}
+
float YogaLayoutNode::GetLeft() { return YGNodeLayoutGetLeft(yoga_node_); }
float YogaLayoutNode::GetTop() { return YGNodeLayoutGetTop(yoga_node_); }
@@ -467,7 +477,8 @@ void YogaLayoutNode::Parser(
if (it != style_delete.end()) YGNodeStyleSetFlexShrink(yoga_node_, 0);
}
if (style_update.find(kFlexBasis) != style_update.end()) {
- SetFlexBasis(static_cast(style_update.find(kFlexBasis)->second->ToDoubleChecked()));
+ auto dom_value = style_update.find(kFlexBasis)->second;
+ SetYGFlexBasis(dom_value);
} else {
auto it = std::find(style_delete.begin(), style_delete.end(), kFlexBasis);
if (it != style_delete.end()) YGNodeStyleSetFlexBasis(yoga_node_, NAN);
@@ -694,11 +705,13 @@ void YogaLayoutNode::Parser(
if (it != style_delete.end()) YGNodeStyleSetAspectRatio(yoga_node_, 0);
}
- // if (style_update.find(kAlignContent) != style_update.end()) {
- // SetAlignContent(GetFlexAlign(style_update.find(kAlignContent)->second->ToString()));
- // }
+ if (style_update.find(kAlignContent) != style_update.end()) {
+ SetAlignContent(GetFlexAlign(style_update.find(kAlignContent)->second->ToStringChecked()));
+ }
}
+YG_SET_NUMBER_PERCENT_AUTO_DECL(FlexBasis)
+
YG_SET_NUMBER_PERCENT_AUTO_DECL(Width)
YG_SET_NUMBER_PERCENT_AUTO_DECL(Height)
@@ -713,8 +726,6 @@ YG_SET_NUMBER_PERCENT_DECL(MinHeight)
void YogaLayoutNode::SetDirection(YGDirection direction) { YGNodeStyleSetDirection(yoga_node_, direction); }
-void YogaLayoutNode::SetFlexBasis(float flex_basis) { YGNodeStyleSetFlexBasis(yoga_node_, flex_basis); }
-
void YogaLayoutNode::SetFlex(float flex) { YGNodeStyleSetFlex(yoga_node_, flex); }
void YogaLayoutNode::SetFlexGrow(float flex_grow) { YGNodeStyleSetFlexGrow(yoga_node_, flex_grow); }
@@ -741,8 +752,8 @@ void YogaLayoutNode::SetFlexWrap(YGWrap wrap_mode) { YGNodeStyleSetFlexWrap(yoga
void YogaLayoutNode::SetJustifyContent(YGJustify justify) { YGNodeStyleSetJustifyContent(yoga_node_, justify); }
-// void YogaLayoutNode::SetAlignContent(YGAlign align_content) { YGNodeStyleSetAlignContent(yoga_node_, align_content);
-// }
+void YogaLayoutNode::SetAlignContent(YGAlign align_content) { YGNodeStyleSetAlignContent(yoga_node_, align_content);
+}
void YogaLayoutNode::SetAlignItems(YGAlign align_items) { YGNodeStyleSetAlignItems(yoga_node_, align_items); }
diff --git a/driver/js/CMakeLists.txt b/driver/js/CMakeLists.txt
index 892b5502695..35b3befaacd 100644
--- a/driver/js/CMakeLists.txt
+++ b/driver/js/CMakeLists.txt
@@ -30,6 +30,16 @@ include("${PROJECT_ROOT_DIR}/buildconfig/cmake/compiler_toolchain.cmake")
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_STANDARD 17)
+# Ohos系统上,配置本来应该放到生成so对应的build-profile.json5里。
+#(externalNativeOptions里arguments项)
+# 现在源码集成配置需在app的build-profile.json5里,不方便,所以先放在这里。
+# 后续hippy产物的独立后,放到hippy模块的build-profile.json5里。
+if (OHOS)
+# set(JS_ENGINE "V8")
+ set(V8_COMPONENT "10.6.194")
+ set(JS_ENGINE "JSH")
+endif ()
+
# region library
add_library(${PROJECT_NAME} STATIC)
target_include_directories(${PROJECT_NAME} PUBLIC include)
@@ -60,6 +70,8 @@ if ("${JS_ENGINE}" STREQUAL "V8")
set(V8_REMOTE_FILENAME "windows-x64.zip")
endif()
endif()
+ elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "OHOS")
+ set(V8_REMOTE_FILENAME "ohos-arm64.tgz")
elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "iOS")
if ("${CMAKE_OSX_ARCHITECTURES}" MATCHES "arm")
set(V8_REMOTE_FILENAME "ios-arm64.tgz")
@@ -115,30 +127,52 @@ if ("${JS_ENGINE}" STREQUAL "V8")
endif ()
elseif ("${JS_ENGINE}" STREQUAL "JSC")
target_compile_definitions(${PROJECT_NAME} PUBLIC "JS_JSC")
+elseif ("${JS_ENGINE}" STREQUAL "JSH")
+ target_compile_definitions(${PROJECT_NAME} PUBLIC "JS_JSH")
endif ()
# endregion
# region footstone
-GlobalPackages_Add(footstone)
+if (OHOS)
+ GlobalPackages_Add_footstone()
+else ()
+ GlobalPackages_Add(footstone)
+endif ()
target_link_libraries(${PROJECT_NAME} PRIVATE footstone)
# endregion
# region vfs
-GlobalPackages_Add(vfs)
+if (OHOS)
+ GlobalPackages_Add_vfs()
+else ()
+ GlobalPackages_Add(vfs)
+endif ()
# Just reference the `dom` header files, no library needed
target_include_directories(${PROJECT_NAME} PRIVATE $)
# endregion
# region dom
-GlobalPackages_Add(dom)
+if (OHOS)
+ GlobalPackages_Add_dom()
+else ()
+ GlobalPackages_Add(dom)
+endif ()
target_link_libraries(${PROJECT_NAME} PRIVATE dom)
# endregion
# region devtools
if (ENABLE_INSPECTOR)
+if (OHOS)
+ GlobalPackages_Add_devtools_backend()
+else ()
GlobalPackages_Add(devtools_backend)
+endif ()
target_link_libraries(${PROJECT_NAME} PUBLIC devtools_backend)
+if (OHOS)
+ GlobalPackages_Add_devtools_integration()
+else ()
GlobalPackages_Add(devtools_integration)
+endif ()
target_link_libraries(${PROJECT_NAME} PUBLIC devtools_integration)
endif ()
# endregion
@@ -174,6 +208,9 @@ if ("${JS_ENGINE}" STREQUAL "V8")
src/vm/v8/native_source_code_android.cc
src/vm/v8/serializer.cc
src/vm/v8/v8_vm.cc)
+
+ set_source_files_properties(src/vm/v8/serializer.cc PROPERTIES COMPILE_FLAGS -fno-rtti)
+
if (NOT V8_WITHOUT_INSPECTOR)
list(APPEND SOURCE_SET
src/vm/v8/inspector/v8_channel_impl.cc
@@ -186,6 +223,13 @@ elseif ("${JS_ENGINE}" STREQUAL "JSC")
src/napi/jsc/jsc_try_catch.cc
src/vm/jsc/jsc_vm.cc
src/vm/jsc/native_source_code_ios.cc)
+elseif ("${JS_ENGINE}" STREQUAL "JSH")
+ list(APPEND SOURCE_SET
+ src/napi/jsh/jsh_class_definition.cc
+ src/napi/jsh/jsh_ctx.cc
+ src/napi/jsh/jsh_try_catch.cc
+ src/vm/jsh/jsh_vm.cc
+ src/vm/jsh/native_source_code_ohos.cc)
endif ()
set(SOURCE_SET_STANDALONE
src/modules/console_module.cc
diff --git a/driver/js/examples/hippy-react-demo/package.json b/driver/js/examples/hippy-react-demo/package.json
index e3225b0130c..50d2737107d 100644
--- a/driver/js/examples/hippy-react-demo/package.json
+++ b/driver/js/examples/hippy-react-demo/package.json
@@ -12,10 +12,12 @@
"serve": "node ./scripts/env-polyfill.js webpack serve --config ./scripts/hippy-webpack.web.dev.js",
"build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.web.js",
"hippy:dev": "node ./scripts/env-polyfill.js hippy-dev -c ./scripts/hippy-webpack.dev.js",
- "hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js",
- "hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js",
+ "hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js --config ./scripts/hippy-webpack.ohos-vendor.js",
+ "hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js --config ./scripts/hippy-webpack.ohos.js",
"web:dev": "npm run hippy:dev & node ./scripts/env-polyfill.js webpack serve --config ./scripts/hippy-webpack.web-renderer.dev.js",
- "web:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.web-renderer.js"
+ "web:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.web-renderer.js",
+ "ohos:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ohos-vendor.js",
+ "ohos:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ohos.js"
},
"keywords": [
"Hippy",
diff --git a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ohos-vendor.js b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ohos-vendor.js
new file mode 100644
index 00000000000..be251153f42
--- /dev/null
+++ b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ohos-vendor.js
@@ -0,0 +1,79 @@
+const fs = require('fs');
+const path = require('path');
+const webpack = require('webpack');
+const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
+
+const platform = 'ohos';
+
+module.exports = {
+ mode: 'production',
+ bail: true,
+ entry: {
+ vendor: [path.resolve(__dirname, './vendor.js')],
+ },
+ output: {
+ filename: `[name].${platform}.js`,
+ path: path.resolve(`./dist/${platform}/`),
+ globalObject: '(0, eval)("this")',
+ library: 'hippyReactBase',
+ },
+ plugins: [
+ new webpack.NamedModulesPlugin(),
+ new webpack.DefinePlugin({
+ 'process.env.NODE_ENV': JSON.stringify('production'),
+ __PLATFORM__: JSON.stringify(platform),
+ }),
+ new CaseSensitivePathsPlugin(),
+ new webpack.DllPlugin({
+ context: path.resolve(__dirname, '..'),
+ path: path.resolve(__dirname, `../dist/${platform}/[name]-manifest.json`),
+ name: 'hippyReactBase',
+ }),
+ ],
+ module: {
+ rules: [
+ {
+ test: /\.(js)$/,
+ use: [
+ {
+ loader: 'babel-loader',
+ options: {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ chrome: 57,
+ },
+ },
+ ],
+ ],
+ plugins: [
+ ['@babel/plugin-proposal-class-properties'],
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ resolve: {
+ extensions: ['.js', '.jsx', '.json'],
+ // if node_modules path listed below is not your repo directory, change it.
+ modules: [path.resolve(__dirname, '../node_modules')],
+ alias: (() => {
+ const aliases = {};
+ // If hippy-react was built exist then make a alias
+ // Remove the section if you don't use it
+ const hippyReactPath = path.resolve(__dirname, '../../../packages/hippy-react');
+ if (fs.existsSync(path.resolve(hippyReactPath, 'dist/index.js'))) {
+ console.warn(`* Using the @hippy/react in ${hippyReactPath}`);
+ aliases['@hippy/react'] = hippyReactPath;
+ } else {
+ console.warn('* Using the @hippy/react defined in package.json');
+ }
+
+ return aliases;
+ })(),
+ },
+};
diff --git a/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ohos.js b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ohos.js
new file mode 100644
index 00000000000..105c494fdb2
--- /dev/null
+++ b/driver/js/examples/hippy-react-demo/scripts/hippy-webpack.ohos.js
@@ -0,0 +1,112 @@
+const fs = require('fs');
+const path = require('path');
+const webpack = require('webpack');
+const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
+const HippyDynamicImportPlugin = require('@hippy/hippy-dynamic-import-plugin');
+const pkg = require('../package.json');
+const manifest = require('../dist/ohos/vendor-manifest.json');
+
+const platform = 'ohos';
+
+module.exports = {
+ mode: 'production',
+ bail: true,
+ entry: {
+ index: ['regenerator-runtime', path.resolve(pkg.main)],
+ },
+ output: {
+ filename: `[name].${platform}.js`,
+ path: path.resolve(`./dist/${platform}/`),
+ globalObject: '(0, eval)("this")',
+ // CDN path can be configured to load children bundles from remote server
+ // publicPath: 'https://xxx/hippy/hippyReactDemo/',
+ },
+ plugins: [
+ new webpack.NamedModulesPlugin(),
+ new webpack.DefinePlugin({
+ 'process.env.NODE_ENV': JSON.stringify('production'),
+ __PLATFORM__: JSON.stringify(platform),
+ }),
+ new CaseSensitivePathsPlugin(),
+ new webpack.DllReferencePlugin({
+ context: path.resolve(__dirname, '..'),
+ manifest,
+ }),
+ new HippyDynamicImportPlugin(),
+ // LimitChunkCountPlugin can control dynamic import ability
+ // Using 1 will prevent any additional chunks from being added
+ // new webpack.optimize.LimitChunkCountPlugin({
+ // maxChunks: 1,
+ // }),
+ // use SourceMapDevToolPlugin can generate sourcemap file
+ // new webpack.SourceMapDevToolPlugin({
+ // test: /\.(js|jsbundle|css|bundle)($|\?)/i,
+ // filename: '[file].map',
+ // }),
+ ],
+ module: {
+ rules: [
+ {
+ test: /\.(jsx?)$/,
+ use: [
+ {
+ loader: 'babel-loader',
+ options: {
+ sourceType: 'unambiguous',
+ presets: [
+ '@babel/preset-react',
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ chrome: 57,
+ },
+ },
+ ],
+ ],
+ plugins: [
+ ['@babel/plugin-proposal-class-properties'],
+ ['@babel/plugin-proposal-decorators', { legacy: true }],
+ ['@babel/plugin-transform-runtime', { regenerator: true }],
+ ],
+ },
+ },
+ ],
+ },
+ {
+ test: /\.(png|jpe?g|gif)$/i,
+ use: [{
+ loader: 'url-loader',
+ options: {
+ // if you would like to use base64 for picture, uncomment limit: true
+ // limit: true,
+ limit: 8192,
+ fallback: 'file-loader',
+ name: '[name].[ext]',
+ outputPath: 'assets/',
+ },
+ }],
+ },
+ ],
+ },
+ resolve: {
+ extensions: ['.js', '.jsx', '.json'],
+ // if node_modules path listed below is not your repo directory, change it.
+ modules: [path.resolve(__dirname, '../node_modules')],
+ alias: (() => {
+ const aliases = {};
+
+ // If hippy-react was built exist then make a alias
+ // Remove the section if you don't use it
+ const hippyReactPath = path.resolve(__dirname, '../../../packages/hippy-react');
+ if (fs.existsSync(path.resolve(hippyReactPath, 'dist/index.js'))) {
+ console.warn(`* Using the @hippy/react in ${hippyReactPath}`);
+ aliases['@hippy/react'] = hippyReactPath;
+ } else {
+ console.warn('* Using the @hippy/react defined in package.json');
+ }
+
+ return aliases;
+ })(),
+ },
+};
diff --git a/driver/js/examples/hippy-vue-demo/package.json b/driver/js/examples/hippy-vue-demo/package.json
index caef249c2b0..55beadb9e50 100644
--- a/driver/js/examples/hippy-vue-demo/package.json
+++ b/driver/js/examples/hippy-vue-demo/package.json
@@ -10,10 +10,12 @@
"repository": "https://github.com/Tencent/Hippy/tree/master/examples/hippy-vue-demo",
"scripts": {
"hippy:dev": "node ./scripts/env-polyfill.js hippy-dev -c ./scripts/hippy-webpack.dev.js",
- "hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios-vendor.js --config ./scripts/hippy-webpack.android-vendor.js",
- "hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ios.js --config ./scripts/hippy-webpack.android.js",
+ "hippy:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ohos-vendor.js",
+ "hippy:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ohos.js",
"web:dev": "npm run hippy:dev & node ./scripts/env-polyfill.js webpack serve --config ./scripts/hippy-webpack.web-renderer.dev.js",
- "web:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.web-renderer.js"
+ "web:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.web-renderer.js",
+ "ohos:vendor": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ohos-vendor.js",
+ "ohos:build": "node ./scripts/env-polyfill.js webpack --config ./scripts/hippy-webpack.ohos.js"
},
"dependencies": {
"@hippy/vue": "3.3.1-rc.1",
diff --git a/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ohos-vendor.js b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ohos-vendor.js
new file mode 100644
index 00000000000..d1158ae17a3
--- /dev/null
+++ b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ohos-vendor.js
@@ -0,0 +1,131 @@
+const fs = require('fs');
+const path = require('path');
+const webpack = require('webpack');
+const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
+
+const platform = 'ohos';
+
+let vueLoader = '@hippy/vue-loader';
+let VueLoaderPlugin;
+const hippyVueLoaderPath = path.resolve(__dirname, '../../../packages/hippy-vue-loader/lib');
+const hippyVueLoaderNodeModulesPath = path.resolve(__dirname, '../../../packages/hippy-vue-loader/node_modules');
+if (fs.existsSync(hippyVueLoaderNodeModulesPath) && fs.existsSync(hippyVueLoaderPath)) {
+ console.warn(`* Using the @hippy/vue-loader in ${hippyVueLoaderPath}`);
+ vueLoader = hippyVueLoaderPath;
+ VueLoaderPlugin = require(path.resolve(__dirname, '../../../packages/hippy-vue-loader/lib/plugin'));
+} else {
+ console.warn('* Using the @hippy/vue-loader defined in package.json');
+ VueLoaderPlugin = require('@hippy/vue-loader/lib/plugin');
+}
+
+module.exports = {
+ mode: 'production',
+ bail: true,
+ entry: {
+ vendor: [path.resolve(__dirname, './vendor.js')],
+ },
+ output: {
+ filename: `[name].${platform}.js`,
+ path: path.resolve(`./dist/${platform}/`),
+ globalObject: '(0, eval)("this")',
+ library: 'hippyVueBase',
+ },
+ plugins: [
+ new webpack.NamedModulesPlugin(),
+ new webpack.DefinePlugin({
+ 'process.env.NODE_ENV': JSON.stringify('production'),
+ __PLATFORM__: JSON.stringify(platform),
+ }),
+ new CaseSensitivePathsPlugin(),
+ new VueLoaderPlugin(),
+ new webpack.DllPlugin({
+ context: path.resolve(__dirname, '..'),
+ path: path.resolve(__dirname, `../dist/${platform}/[name]-manifest.json`),
+ name: 'hippyVueBase',
+ }),
+ ],
+ module: {
+ rules: [
+ {
+ test: /\.vue$/,
+ use: [
+ {
+ loader: vueLoader,
+ options: {
+ compilerOptions: {
+ // whitespace handler, default is 'preserve'
+ whitespace: 'condense',
+ },
+ },
+ },
+ ],
+ },
+ {
+ test: /\.(js)$/,
+ use: [
+ {
+ loader: 'babel-loader',
+ options: {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ chrome: 57,
+ },
+ },
+ ],
+ ],
+ plugins: [
+ ['@babel/plugin-proposal-class-properties'],
+ ],
+ },
+ },
+ ],
+ },
+ ],
+ },
+ resolve: {
+ extensions: ['.js', '.vue', '.json'],
+ // if node_modules path listed below is not your repo directory, change it.
+ modules: [path.resolve(__dirname, '../node_modules')],
+ alias: (() => {
+ const aliases = {
+ vue: '@hippy/vue',
+ '@': path.resolve('./src'),
+ 'vue-router': '@hippy/vue-router',
+ };
+ // If hippy-vue was built exist then make a alias
+ // Remove the section if you don't use it
+ const hippyVuePath = path.resolve(__dirname, '../../../packages/hippy-vue');
+ if (fs.existsSync(path.resolve(hippyVuePath, 'dist/index.js'))) {
+ console.warn(`* Using the @hippy/vue in ${hippyVuePath} as vue alias`);
+ aliases.vue = hippyVuePath;
+ aliases['@hippy/vue'] = hippyVuePath;
+ } else {
+ console.warn('* Using the @hippy/vue defined in package.json');
+ }
+ // If hippy-vue-router was built exist then make a alias
+ // Remove the section if you don't use it
+ const hippyVueRouterPath = path.resolve(__dirname, '../../../packages/hippy-vue-router');
+ if (fs.existsSync(path.resolve(hippyVueRouterPath, 'dist/index.js'))) {
+ console.warn(`* Using the @hippy/vue-router in ${hippyVueRouterPath} as vue-router alias`);
+ aliases['vue-router'] = hippyVueRouterPath;
+ } else {
+ console.warn('* Using the @hippy/vue-router defined in package.json');
+ }
+
+ // If hippy-vue-native-components was built exist then make a alias
+ // Remove the section if you don't use it
+ const hippyVueNativeComponentsPath = path.resolve(__dirname, '../../../packages/hippy-vue-native-components');
+ if (fs.existsSync(path.resolve(hippyVueNativeComponentsPath, 'dist/index.js'))) {
+ console.warn(`* Using the @hippy/vue-native-components in ${hippyVueNativeComponentsPath}`);
+ aliases['@hippy/vue-native-components'] = hippyVueNativeComponentsPath;
+ } else {
+ console.warn('* Using the @hippy/vue-native-components defined in package.json');
+ }
+
+ return aliases;
+ })(),
+ },
+};
diff --git a/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ohos.js b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ohos.js
new file mode 100644
index 00000000000..3775a177b9d
--- /dev/null
+++ b/driver/js/examples/hippy-vue-demo/scripts/hippy-webpack.ohos.js
@@ -0,0 +1,178 @@
+const fs = require('fs');
+const path = require('path');
+const webpack = require('webpack');
+const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
+const HippyDynamicImportPlugin = require('@hippy/hippy-dynamic-import-plugin');
+const pkg = require('../package.json');
+const manifest = require('../dist/ohos/vendor-manifest.json');
+
+const platform = 'ohos';
+let cssLoader = '@hippy/vue-css-loader';
+const hippyVueCssLoaderPath = path.resolve(__dirname, '../../../packages/hippy-vue-css-loader/dist/css-loader.js');
+if (fs.existsSync(hippyVueCssLoaderPath)) {
+ console.warn(`* Using the @hippy/vue-css-loader in ${hippyVueCssLoaderPath}`);
+ cssLoader = hippyVueCssLoaderPath;
+} else {
+ console.warn('* Using the @hippy/vue-css-loader defined in package.json');
+}
+
+let vueLoader = '@hippy/vue-loader';
+let VueLoaderPlugin;
+const hippyVueLoaderPath = path.resolve(__dirname, '../../../packages/hippy-vue-loader/lib');
+const hippyVueLoaderNodeModulesPath = path.resolve(__dirname, '../../../packages/hippy-vue-loader/node_modules');
+if (fs.existsSync(hippyVueLoaderNodeModulesPath) && fs.existsSync(hippyVueLoaderPath)) {
+ console.warn(`* Using the @hippy/vue-loader in ${hippyVueLoaderPath}`);
+ vueLoader = hippyVueLoaderPath;
+ VueLoaderPlugin = require(path.resolve(__dirname, '../../../packages/hippy-vue-loader/lib/plugin'));
+} else {
+ console.warn('* Using the @hippy/vue-loader defined in package.json');
+ VueLoaderPlugin = require('@hippy/vue-loader/lib/plugin');
+}
+
+module.exports = {
+ mode: 'production',
+ bail: true,
+ entry: {
+ index: [path.resolve(pkg.nativeMain)],
+ },
+ output: {
+ filename: `[name].${platform}.js`,
+ path: path.resolve(`./dist/${platform}/`),
+ globalObject: '(0, eval)("this")',
+ // CDN path can be configured to load children bundles from remote server
+ // publicPath: 'https://xxx/hippy/hippyVueDemo/',
+ },
+ plugins: [
+ new webpack.NamedModulesPlugin(),
+ new webpack.DefinePlugin({
+ 'process.env.NODE_ENV': JSON.stringify('production'),
+ __PLATFORM__: JSON.stringify(platform),
+ }),
+ new CaseSensitivePathsPlugin(),
+ new VueLoaderPlugin(),
+ new webpack.DllReferencePlugin({
+ context: path.resolve(__dirname, '..'),
+ manifest,
+ }),
+ new HippyDynamicImportPlugin(),
+ // LimitChunkCountPlugin can control dynamic import ability
+ // Using 1 will prevent any additional chunks from being added
+ // new webpack.optimize.LimitChunkCountPlugin({
+ // maxChunks: 1,
+ // }),
+ // use SourceMapDevToolPlugin can generate sourcemap file
+ // new webpack.SourceMapDevToolPlugin({
+ // test: /\.(js|jsbundle|css|bundle)($|\?)/i,
+ // filename: '[file].map',
+ // }),
+ ],
+ module: {
+ rules: [
+ {
+ test: /\.vue$/,
+ use: [
+ {
+ loader: vueLoader,
+ options: {
+ compilerOptions: {
+ // whitespace handler, default is 'preserve'
+ whitespace: 'condense',
+ },
+ },
+ },
+ ],
+ },
+ {
+ test: /\.css$/,
+ use: [
+ cssLoader,
+ ],
+ },
+ {
+ test: /\.(js)$/,
+ use: [
+ {
+ loader: 'babel-loader',
+ options: {
+ sourceType: 'unambiguous',
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ chrome: 57,
+ },
+ },
+ ],
+ ],
+ plugins: [
+ ['@babel/plugin-proposal-class-properties'],
+ ['@babel/plugin-proposal-decorators', { legacy: true }],
+ ['@babel/plugin-transform-runtime', { regenerator: true }],
+ ],
+ },
+ },
+ ],
+ },
+ {
+ test: /\.(png|jpe?g|gif)$/i,
+ use: [{
+ loader: 'url-loader',
+ options: {
+ // if you would like to use base64 for picture, uncomment limit: true
+ // limit: true,
+ limit: 8192,
+ fallback: 'file-loader',
+ name: '[name].[ext]',
+ outputPath: 'assets/',
+ },
+ }],
+ },
+ ],
+ },
+ resolve: {
+ extensions: ['.js', '.vue', '.json'],
+ // if node_modules path listed below is not your repo directory, change it.
+ modules: [path.resolve(__dirname, '../node_modules')],
+ alias: (() => {
+ const aliases = {
+ vue: '@hippy/vue',
+ '@': path.resolve('./src'),
+ 'vue-router': '@hippy/vue-router',
+ };
+
+ // If hippy-vue was built exist in packages directory then make a alias
+ // Remove the section if you don't use it
+ const hippyVuePath = path.resolve(__dirname, '../../../packages/hippy-vue');
+ if (fs.existsSync(path.resolve(hippyVuePath, 'dist/index.js'))) {
+ console.warn(`* Using the @hippy/vue in ${hippyVuePath} as vue alias`);
+ aliases.vue = hippyVuePath;
+ aliases['@hippy/vue'] = hippyVuePath;
+ } else {
+ console.warn('* Using the @hippy/vue defined in package.json');
+ }
+
+ // If hippy-vue-router was built exist in packages directory then make a alias
+ // Remove the section if you don't use it
+ const hippyVueRouterPath = path.resolve(__dirname, '../../../packages/hippy-vue-router');
+ if (fs.existsSync(path.resolve(hippyVueRouterPath, 'dist/index.js'))) {
+ console.warn(`* Using the @hippy/vue-router in ${hippyVueRouterPath} as vue-router alias`);
+ aliases['vue-router'] = hippyVueRouterPath;
+ } else {
+ console.warn('* Using the @hippy/vue-router defined in package.json');
+ }
+
+ // If hippy-vue-native-components was built in packages directory exist then make a alias
+ // Remove the section if you don't use it
+ const hippyVueNativeComponentsPath = path.resolve(__dirname, '../../../packages/hippy-vue-native-components');
+ if (fs.existsSync(path.resolve(hippyVueNativeComponentsPath, 'dist/index.js'))) {
+ console.warn(`* Using the @hippy/vue-native-components in ${hippyVueNativeComponentsPath}`);
+ aliases['@hippy/vue-native-components'] = hippyVueNativeComponentsPath;
+ } else {
+ console.warn('* Using the @hippy/vue-native-components defined in package.json');
+ }
+
+ return aliases;
+ })(),
+ },
+};
diff --git a/driver/js/examples/hippy-vue-demo/src/components/demos/demo-dynamicimport.vue b/driver/js/examples/hippy-vue-demo/src/components/demos/demo-dynamicimport.vue
index 0afaf20f342..dc21bf736c7 100644
--- a/driver/js/examples/hippy-vue-demo/src/components/demos/demo-dynamicimport.vue
+++ b/driver/js/examples/hippy-vue-demo/src/components/demos/demo-dynamicimport.vue
@@ -40,7 +40,7 @@ export default {
* customChunkPath 会在运行时替换全局配置的publicPath
* import 出错时需在catch里做对应的降级方案
*/
- AsyncComponentFromHttp: process.env.NODE_ENV === 'development' ? () => import(/* webpackMode: "lazy", webpackChunkName: "asyncComponentFromHttp" */'./dynamicImport/async-component-http.vue').then(res => res).catch(err => console.error('import async remote component error', err)) : () => import(/* webpackMode: "lazy",customChunkPath: "https://raw.githubusercontent.com/Tencent/Hippy/master/static/hippy-vue/", webpackChunkName: "asyncComponentFromHttp" */'./dynamicImport/async-component-http.vue').then(res => res).catch(err => console.error('import async remote component error', err)),
+ AsyncComponentFromHttp: process.env.NODE_ENV === 'development' ? () => import(/* webpackMode: "lazy", webpackChunkName: "asyncComponentFromHttp" */'./dynamicImport/async-component-http.vue').then(res => res).catch(err => console.error('import async remote component error', err)) : () => import(/* webpackMode: "lazy",customChunkPath: "https://raw.githubusercontent.com/sohotz/Hippy/main/driver/js/static/hippy-vue/", webpackChunkName: "asyncComponentFromHttp" */'./dynamicImport/async-component-http.vue').then(res => res).catch(err => console.error('import async remote component error', err)),
},
data() {
return {
diff --git a/driver/js/examples/hippy-vue-demo/src/components/demos/demo-list.vue b/driver/js/examples/hippy-vue-demo/src/components/demos/demo-list.vue
index 24d2a913cb2..58a2501ee2a 100644
--- a/driver/js/examples/hippy-vue-demo/src/components/demos/demo-list.vue
+++ b/driver/js/examples/hippy-vue-demo/src/components/demos/demo-list.vue
@@ -108,6 +108,40 @@
+
+
+
diff --git a/driver/js/examples/hippy-vue-demo/src/components/demos/demo-shadow.vue b/driver/js/examples/hippy-vue-demo/src/components/demos/demo-shadow.vue
index 3dc24eb8dde..c474f11dba4 100644
--- a/driver/js/examples/hippy-vue-demo/src/components/demos/demo-shadow.vue
+++ b/driver/js/examples/hippy-vue-demo/src/components/demos/demo-shadow.vue
@@ -1,5 +1,6 @@
+
+
偏移阴影样式
+
+