@react-native-ohos/react-native-reanimated 3.18.3-beta.2 → 3.18.4-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1070 -0
- package/README.md +403 -7
- package/harmony/reanimated/BuildProfile.ets +1 -1
- package/harmony/reanimated/oh-package.json5 +1 -1
- package/harmony/reanimated/src/main/cpp/CMakeLists.txt +2 -0
- package/harmony/reanimated/src/main/cpp/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp +2 -0
- package/harmony/reanimated/src/main/cpp/ReanimatedModule.cpp +32 -14
- package/harmony/reanimated/src/main/cpp/ReanimatedSensor.cpp +248 -0
- package/harmony/reanimated/src/main/cpp/ReanimatedSensor.h +36 -0
- package/harmony/reanimated/src/main/cpp/ReanimatedSensorContainer.cpp +36 -0
- package/harmony/reanimated/src/main/cpp/ReanimatedSensorContainer.h +23 -0
- package/harmony/reanimated/src/main/cpp/patches/NativeModules/ReanimatedModuleProxy.cpp +45 -0
- package/harmony/reanimated/src/main/ets/ReanimatedModule.ts +27 -2
- package/harmony/reanimated.har +0 -0
- package/package.json +18 -4
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a MIT license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
#include "ReanimatedSensor.h"
|
|
6
|
+
#include "glog/logging.h"
|
|
7
|
+
#include <memory>
|
|
8
|
+
#include <vector>
|
|
9
|
+
#include <sensors/oh_sensor.h>
|
|
10
|
+
#include <window_manager/oh_display_info.h>
|
|
11
|
+
#include <window_manager/oh_display_manager.h>
|
|
12
|
+
namespace rnoh {
|
|
13
|
+
static std::unordered_map<Sensor_Type, ReanimatedSensor *> g_sensorSubscriberMap_;
|
|
14
|
+
static std::mutex g_subscriberMapMutex_; // 保护映射表的互斥锁
|
|
15
|
+
|
|
16
|
+
void SensorDataCallbackImpl(Sensor_Event *event) {
|
|
17
|
+
if (event == nullptr) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
int64_t timestamp = -1;
|
|
21
|
+
// 获取传感器数据的时间戳。
|
|
22
|
+
int32_t ret = OH_SensorEvent_GetTimestamp(event, ×tamp);
|
|
23
|
+
if (ret != SENSOR_SUCCESS) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
Sensor_Type sensorType;
|
|
27
|
+
// 获取传感器类型。
|
|
28
|
+
ret = OH_SensorEvent_GetType(event, &sensorType);
|
|
29
|
+
if (ret != SENSOR_SUCCESS) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
Sensor_Accuracy accuracy = SENSOR_ACCURACY_UNRELIABLE;
|
|
33
|
+
// 获取传感器数据的精度。
|
|
34
|
+
ret = OH_SensorEvent_GetAccuracy(event, &accuracy);
|
|
35
|
+
if (ret != SENSOR_SUCCESS) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
float *data = nullptr;
|
|
39
|
+
uint32_t length = 0;
|
|
40
|
+
// 获取传感器数据。
|
|
41
|
+
ret = OH_SensorEvent_GetData(event, &data, &length);
|
|
42
|
+
if (ret != SENSOR_SUCCESS || data == nullptr) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
std::lock_guard<std::mutex> lock(g_subscriberMapMutex_);
|
|
47
|
+
auto it = g_sensorSubscriberMap_.find(sensorType);
|
|
48
|
+
if (it == g_sensorSubscriberMap_.end()) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
ReanimatedSensor *sensorInstance = it->second;
|
|
52
|
+
if (sensorInstance == nullptr) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
switch (sensorType) {
|
|
57
|
+
case SENSOR_TYPE_ACCELEROMETER:
|
|
58
|
+
case SENSOR_TYPE_GYROSCOPE:
|
|
59
|
+
case SENSOR_TYPE_GRAVITY:
|
|
60
|
+
case SENSOR_TYPE_MAGNETIC_FIELD: {
|
|
61
|
+
double sendData[] = {
|
|
62
|
+
data[0],
|
|
63
|
+
data[1],
|
|
64
|
+
data[2],
|
|
65
|
+
};
|
|
66
|
+
// 传入 count,由 runSensor 拷贝到堆,避免跨线程 use-after-free
|
|
67
|
+
sensorInstance->runSensor(sendData, 3);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
case SENSOR_TYPE_ROTATION_VECTOR: {
|
|
71
|
+
double sendData[] = {
|
|
72
|
+
data[0], // x
|
|
73
|
+
data[1], // y
|
|
74
|
+
data[2], // z
|
|
75
|
+
data[3], // w
|
|
76
|
+
// ios
|
|
77
|
+
0, // yaw
|
|
78
|
+
0, // pitch
|
|
79
|
+
0 // roll
|
|
80
|
+
};
|
|
81
|
+
sensorInstance->runSensor(sendData, 7);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
default:
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
rnoh::ReanimatedSensor::ReanimatedSensor(int sensorType, int interval, int iosReferenceFrame,
|
|
91
|
+
std::function<void(double *, int)> setter,
|
|
92
|
+
std::function<void(TaskExecutor::Task &&)> runOnTheMainThread)
|
|
93
|
+
: iosReferenceFrame_(iosReferenceFrame), setter_(std::move(setter)),
|
|
94
|
+
runOnTheMainThread_(std::move(runOnTheMainThread)) {
|
|
95
|
+
if (interval == -1) {
|
|
96
|
+
uint32_t refreshRate = 0;
|
|
97
|
+
OH_NativeDisplayManager_GetDefaultDisplayRefreshRate(&refreshRate);
|
|
98
|
+
if (refreshRate > 0) {
|
|
99
|
+
interval_ = refreshRate * 1000000; // 120hz;
|
|
100
|
+
} else {
|
|
101
|
+
interval_ = 200000000;
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
// js unit is milliseconds
|
|
105
|
+
interval_ = interval * 1000000;
|
|
106
|
+
}
|
|
107
|
+
castSensorType(sensorType);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
void rnoh::ReanimatedSensor::castSensorType(int sensorType) {
|
|
112
|
+
if (sensorType == 1) {
|
|
113
|
+
sensorType_ = SENSOR_TYPE_ACCELEROMETER;
|
|
114
|
+
} else if (sensorType == 2) {
|
|
115
|
+
sensorType_ = SENSOR_TYPE_GYROSCOPE;
|
|
116
|
+
} else if (sensorType == 3) {
|
|
117
|
+
sensorType_ = SENSOR_TYPE_GRAVITY;
|
|
118
|
+
} else if (sensorType == 4) {
|
|
119
|
+
sensorType_ = SENSOR_TYPE_MAGNETIC_FIELD;
|
|
120
|
+
} else if (sensorType == 5) {
|
|
121
|
+
sensorType_ = SENSOR_TYPE_ROTATION_VECTOR;
|
|
122
|
+
} else {
|
|
123
|
+
throw std::invalid_argument("[ReanimatedSensor] Unknown sensorType: " + sensorType);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
bool rnoh::ReanimatedSensor::initialize() {
|
|
128
|
+
if (!isSupportSensor()) {
|
|
129
|
+
LOG(ERROR) << "[ReanimatedSensor] is not support, sensorType:" << sensorType_;
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
id_ = OH_Sensor_CreateSubscriptionId();
|
|
133
|
+
if (id_ == nullptr) {
|
|
134
|
+
LOG(ERROR) << "[ReanimatedSensor] create sensor id failed";
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
int32_t res = OH_SensorSubscriptionId_SetType(id_, sensorType_);
|
|
138
|
+
if (res != SENSOR_SUCCESS) {
|
|
139
|
+
LOG(ERROR) << "[ReanimatedSensor] set sensor type failed ,sensorType:" << sensorType_;
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
auto attr = OH_Sensor_CreateSubscriptionAttribute();
|
|
143
|
+
if (attr == nullptr) {
|
|
144
|
+
LOG(ERROR) << "[ReanimatedSensor] create sensor attribute failed";
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
res = OH_SensorSubscriptionAttribute_SetSamplingInterval(attr, interval_);
|
|
149
|
+
if (res != SENSOR_SUCCESS) {
|
|
150
|
+
LOG(ERROR) << "[ReanimatedSensor] set sensor Interval failed, interval_:" << interval_;
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
subSensor_ = OH_Sensor_CreateSubscriber();
|
|
155
|
+
|
|
156
|
+
{
|
|
157
|
+
std::lock_guard<std::mutex> lock(g_subscriberMapMutex_);
|
|
158
|
+
g_sensorSubscriberMap_[sensorType_] = this;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
int32_t ret = OH_SensorSubscriber_SetCallback(subSensor_, SensorDataCallbackImpl);
|
|
162
|
+
if (ret != SENSOR_SUCCESS) {
|
|
163
|
+
LOG(ERROR) << "[ReanimatedSensor] set sensor callback failed";
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
Sensor_Result sensorRes = OH_Sensor_Subscribe(id_, attr, subSensor_);
|
|
167
|
+
if (sensorRes != SENSOR_SUCCESS) {
|
|
168
|
+
LOG(ERROR) << "[ReanimatedSensor] on sensor subscribe failed";
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
bool rnoh::ReanimatedSensor::isSupportSensor() {
|
|
176
|
+
uint32_t count = 0;
|
|
177
|
+
int32_t ret = OH_Sensor_GetInfos(nullptr, &count);
|
|
178
|
+
bool isSupport = false;
|
|
179
|
+
if (count > 0) {
|
|
180
|
+
Sensor_Info **sensors = OH_Sensor_CreateInfos(count);
|
|
181
|
+
ret = OH_Sensor_GetInfos(sensors, &count);
|
|
182
|
+
for (uint32_t i = 0; i < count; ++i) {
|
|
183
|
+
Sensor_Info *sensorInfoTemp = sensors[i];
|
|
184
|
+
Sensor_Type sensorType;
|
|
185
|
+
ret = OH_SensorInfo_GetType(sensorInfoTemp, &sensorType);
|
|
186
|
+
if (sensorType == sensorType_) {
|
|
187
|
+
isSupport = true;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
ret = OH_Sensor_DestroyInfos(sensors, count);
|
|
192
|
+
}
|
|
193
|
+
return isSupport;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
void rnoh::ReanimatedSensor::runSensor(double *value, size_t count) {
|
|
197
|
+
if (value && setter_ && runOnTheMainThread_ && count > 0) {
|
|
198
|
+
// 跨线程传递必须拷贝到堆:传感器回调运行在传感器线程,
|
|
199
|
+
// 而 setter_ 在主线程异步执行,栈上数据此时已释放(use-after-free)。
|
|
200
|
+
auto dataPtr = std::make_shared<std::vector<double>>(value, value + count);
|
|
201
|
+
runOnTheMainThread_([weakSelf = weak_from_this(), dataPtr]() {
|
|
202
|
+
auto self = weakSelf.lock();
|
|
203
|
+
if (!self) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
self->setter_(dataPtr->data(), self->getInterfaceOrientation());
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
int rnoh::ReanimatedSensor::getInterfaceOrientation() {
|
|
212
|
+
NativeDisplayManager_Rotation rotation;
|
|
213
|
+
auto ret = OH_NativeDisplayManager_GetDefaultDisplayRotation(&rotation);
|
|
214
|
+
if (ret == DISPLAY_MANAGER_OK) {
|
|
215
|
+
switch (rotation) {
|
|
216
|
+
case DISPLAY_MANAGER_ROTATION_270:
|
|
217
|
+
return 270;
|
|
218
|
+
case DISPLAY_MANAGER_ROTATION_90:
|
|
219
|
+
return 90;
|
|
220
|
+
case DISPLAY_MANAGER_ROTATION_180:
|
|
221
|
+
return 180;
|
|
222
|
+
default:
|
|
223
|
+
return 0;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
void rnoh::ReanimatedSensor::cancel() { destroySensor(); }
|
|
231
|
+
|
|
232
|
+
void rnoh::ReanimatedSensor::destroySensor() {
|
|
233
|
+
std::lock_guard<std::mutex> lock(g_subscriberMapMutex_);
|
|
234
|
+
for (auto it = g_sensorSubscriberMap_.begin(); it != g_sensorSubscriberMap_.end();) {
|
|
235
|
+
if (it->second == this) {
|
|
236
|
+
OH_Sensor_Unsubscribe(it->second->id_, it->second->subSensor_);
|
|
237
|
+
OH_Sensor_DestroySubscriptionId(it->second->id_);
|
|
238
|
+
OH_Sensor_DestroySubscriber(it->second->subSensor_);
|
|
239
|
+
it->second->subSensor_ = nullptr;
|
|
240
|
+
it = g_sensorSubscriberMap_.erase(it);
|
|
241
|
+
} else {
|
|
242
|
+
++it;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
rnoh::ReanimatedSensor::~ReanimatedSensor() { destroySensor(); }
|
|
248
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a MIT license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
#ifndef HARMONY_REANIMATEDSENSOR_H
|
|
6
|
+
#define HARMONY_REANIMATEDSENSOR_H
|
|
7
|
+
#include <functional>
|
|
8
|
+
#include <mutex>
|
|
9
|
+
#include <sensors/oh_sensor_type.h>
|
|
10
|
+
#include "RNOH/TaskExecutor/TaskExecutor.h"
|
|
11
|
+
|
|
12
|
+
namespace rnoh {
|
|
13
|
+
class ReanimatedSensor : public std::enable_shared_from_this<ReanimatedSensor> {
|
|
14
|
+
public:
|
|
15
|
+
ReanimatedSensor(int sensorType, int interval, int iosReferenceFrame, std::function<void(double[], int)> setter,
|
|
16
|
+
std::function<void(TaskExecutor::Task &&)> runOnTheMainThread);
|
|
17
|
+
~ReanimatedSensor();
|
|
18
|
+
bool initialize();
|
|
19
|
+
void cancel();
|
|
20
|
+
void castSensorType(int sensorType);
|
|
21
|
+
void runSensor(double *value, size_t count);
|
|
22
|
+
std::function<void(double[], int)> setter_;
|
|
23
|
+
Sensor_Type sensorType_{SENSOR_TYPE_ACCELEROMETER};
|
|
24
|
+
|
|
25
|
+
private:
|
|
26
|
+
void destroySensor();
|
|
27
|
+
bool isSupportSensor();
|
|
28
|
+
int getInterfaceOrientation();
|
|
29
|
+
int interval_{-1};
|
|
30
|
+
int iosReferenceFrame_{-1};
|
|
31
|
+
Sensor_Subscriber *subSensor_{nullptr};
|
|
32
|
+
Sensor_SubscriptionId *id_{nullptr};
|
|
33
|
+
std::function<void(TaskExecutor::Task &&)> runOnTheMainThread_;
|
|
34
|
+
};
|
|
35
|
+
} // namespace rnoh
|
|
36
|
+
#endif // HARMONY_REANIMATEDSENSOR_H
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a MIT license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
#include "ReanimatedSensorContainer.h"
|
|
6
|
+
#include "glog/logging.h"
|
|
7
|
+
namespace rnoh {
|
|
8
|
+
|
|
9
|
+
rnoh::ReanimatedSensorContainer::ReanimatedSensorContainer() {}
|
|
10
|
+
|
|
11
|
+
int rnoh::ReanimatedSensorContainer::registerSensor(int sensorType, int interval, int iosReferenceFrame,
|
|
12
|
+
std::function<void(double *, int)> setter,
|
|
13
|
+
std::function<void(TaskExecutor::Task &&)> runOnTheMainThread) {
|
|
14
|
+
auto sensor =
|
|
15
|
+
std::make_shared<ReanimatedSensor>(sensorType, interval, iosReferenceFrame, setter, runOnTheMainThread);
|
|
16
|
+
int sensorId = -1;
|
|
17
|
+
if (sensor->initialize()) {
|
|
18
|
+
sensorId = nextSensorId;
|
|
19
|
+
nextSensorId++;
|
|
20
|
+
sensorMap_[sensorId] = sensor;
|
|
21
|
+
}
|
|
22
|
+
return sensorId;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
void rnoh::ReanimatedSensorContainer::unregisterSensor(int sensorId) {
|
|
26
|
+
auto it = sensorMap_.find(sensorId);
|
|
27
|
+
if (it == sensorMap_.end()) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
auto sensor = it->second;
|
|
31
|
+
if (sensor != nullptr) {
|
|
32
|
+
sensor->cancel();
|
|
33
|
+
sensorMap_.erase(it);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved
|
|
2
|
+
// Use of this source code is governed by a MIT license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
#ifndef HARMONY_REANIMATEDSENSORCONTAINER_H
|
|
6
|
+
#define HARMONY_REANIMATEDSENSORCONTAINER_H
|
|
7
|
+
#include "ReanimatedSensor.h"
|
|
8
|
+
#include <functional>
|
|
9
|
+
namespace rnoh {
|
|
10
|
+
class ReanimatedSensorContainer {
|
|
11
|
+
public:
|
|
12
|
+
ReanimatedSensorContainer();
|
|
13
|
+
~ReanimatedSensorContainer() noexcept = default;
|
|
14
|
+
int registerSensor(int sensorType, int interval, int iosReferenceFrame, std::function<void(double[], int)> setter,
|
|
15
|
+
std::function<void(TaskExecutor::Task &&)> runOnTheMainThread);
|
|
16
|
+
void unregisterSensor(int sensorId);
|
|
17
|
+
|
|
18
|
+
private:
|
|
19
|
+
std::unordered_map<int, std::shared_ptr<ReanimatedSensor>> sensorMap_;
|
|
20
|
+
int nextSensorId{0};
|
|
21
|
+
};
|
|
22
|
+
} // namespace rnoh
|
|
23
|
+
#endif // HARMONY_REANIMATEDSENSORCONTAINER_H
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
#endif // RCT_NEW_ARCH_ENABLED
|
|
28
28
|
|
|
29
29
|
#include <functional>
|
|
30
|
+
#include <glog/logging.h>
|
|
30
31
|
#include <utility>
|
|
31
32
|
|
|
32
33
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
@@ -228,6 +229,14 @@ void ReanimatedModuleProxy::init(
|
|
|
228
229
|
}
|
|
229
230
|
|
|
230
231
|
ReanimatedModuleProxy::~ReanimatedModuleProxy() {
|
|
232
|
+
LOG(WARNING) << "[RNOH_REA_TEARDOWN_V1] stage=proxy_dtor"
|
|
233
|
+
<< " frame_callbacks=" << frameCallbacks_.size()
|
|
234
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
235
|
+
<< " pending_operations=" << operationsInBatch_.size()
|
|
236
|
+
<< " props_registry=" << static_cast<bool>(propsRegistry_)
|
|
237
|
+
<< " layout_proxy=" << static_cast<bool>(layoutAnimationsProxy_)
|
|
238
|
+
#endif
|
|
239
|
+
;
|
|
231
240
|
// event handler registry and frame callbacks store some JSI values from UI
|
|
232
241
|
// runtime, so they have to go away before we tear down the runtime
|
|
233
242
|
eventHandlerRegistry_.reset();
|
|
@@ -256,8 +265,42 @@ ReanimatedModuleProxy::~ReanimatedModuleProxy() {
|
|
|
256
265
|
}
|
|
257
266
|
layoutAnimationsProxy_.reset();
|
|
258
267
|
|
|
268
|
+
// 主动触发 Hermes GC:在 uiWorkletRuntime_ 销毁前回收 Hermes 堆中持有
|
|
269
|
+
// ShadowNode::Shared(通过 NativeState / ShadowNodeWrapper)的 JSI 对象。
|
|
270
|
+
//
|
|
271
|
+
// 此处 commitHook_ / mountHook_ 仍未 reset,它们持有 uiManager_ 的
|
|
272
|
+
// shared_ptr,确保 GC 回收 ShadowNodeWrapper 触发 ~ShadowNodeFamily 时
|
|
273
|
+
// ComponentDescriptorRegistry 仍然有效。这样可避免 uiWorkletRuntime_.reset()
|
|
274
|
+
// → HadesGC::finalizeAll() 在上下文可能已失效后触发
|
|
275
|
+
// ~ShadowNodeFamily → ~InstanceHandle 崩溃(0730 复现变体根因)。
|
|
276
|
+
//
|
|
277
|
+
// UI runtime 为 LockableRuntime(supportsLocking=true),每个 JSI 操作
|
|
278
|
+
// 自动加锁 runtimeMutex_(recursive_mutex),从主线程调用 gc() 会阻塞
|
|
279
|
+
// 等待 UI 线程完成当前 worklet 后执行,不会死锁。
|
|
280
|
+
#if JS_RUNTIME_HERMES
|
|
281
|
+
if (uiWorkletRuntime_) {
|
|
282
|
+
try {
|
|
283
|
+
auto &uiRuntime = uiWorkletRuntime_->getJSIRuntime();
|
|
284
|
+
auto gc = uiRuntime.global().getPropertyAsFunction(uiRuntime, "gc");
|
|
285
|
+
gc.call(uiRuntime);
|
|
286
|
+
} catch (const std::exception &) {
|
|
287
|
+
// gc() 调用失败不应阻止后续析构流程
|
|
288
|
+
} catch (...) {
|
|
289
|
+
// 忽略未知异常,保证析构不因 GC 失败而 terminate
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
#endif // JS_RUNTIME_HERMES
|
|
293
|
+
|
|
294
|
+
// GC 之后再注销 hooks:确保 GC 回收 ShadowNodeWrapper 时
|
|
295
|
+
// UIManager(及 ComponentDescriptorRegistry)仍存活
|
|
296
|
+
commitHook_.reset();
|
|
297
|
+
mountHook_.reset();
|
|
298
|
+
LOG(WARNING) << "[RNOH_REA_TEARDOWN_V1] stage=fabric_hooks_removed";
|
|
299
|
+
uiManager_.reset();
|
|
259
300
|
#endif // RCT_NEW_ARCH_ENABLED
|
|
301
|
+
LOG(WARNING) << "[RNOH_REA_TEARDOWN_V1] stage=ui_runtime_reset_begin";
|
|
260
302
|
uiWorkletRuntime_.reset();
|
|
303
|
+
LOG(WARNING) << "[RNOH_REA_TEARDOWN_V1] stage=proxy_dtor_complete";
|
|
261
304
|
}
|
|
262
305
|
|
|
263
306
|
void ReanimatedModuleProxy::scheduleOnUI(
|
|
@@ -622,6 +665,7 @@ void ReanimatedModuleProxy::cleanupSensors() {
|
|
|
622
665
|
void ReanimatedModuleProxy::markNodeAsRemovable(
|
|
623
666
|
jsi::Runtime &rt,
|
|
624
667
|
const jsi::Value &shadowNodeWrapper) {
|
|
668
|
+
auto lock = propsRegistry_->createLock();
|
|
625
669
|
auto shadowNode = shadowNodeFromValue(rt, shadowNodeWrapper);
|
|
626
670
|
propsRegistry_->markNodeAsRemovable(shadowNode);
|
|
627
671
|
}
|
|
@@ -629,6 +673,7 @@ void ReanimatedModuleProxy::markNodeAsRemovable(
|
|
|
629
673
|
void ReanimatedModuleProxy::unmarkNodeAsRemovable(
|
|
630
674
|
jsi::Runtime &rt,
|
|
631
675
|
const jsi::Value &viewTag) {
|
|
676
|
+
auto lock = propsRegistry_->createLock();
|
|
632
677
|
propsRegistry_->unmarkNodeAsRemovable(viewTag.asNumber());
|
|
633
678
|
}
|
|
634
679
|
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
import { RNOHLogger, Tag, UITurboModule, UITurboModuleContext } from "@rnoh/react-native-openharmony/ts";
|
|
6
6
|
import { Animator, AnimatorResult, window } from '@kit.ArkUI';
|
|
7
7
|
import { KeyboardState } from "./AnimationManager";
|
|
8
|
+
import deviceInfo from '@ohos.deviceInfo';
|
|
9
|
+
import { accessibility } from '@kit.AccessibilityKit';
|
|
8
10
|
|
|
9
11
|
export class ReanimatedModule extends UITurboModule {
|
|
10
12
|
static NAME = "ReanimatedModule"
|
|
@@ -24,7 +26,13 @@ export class ReanimatedModule extends UITurboModule {
|
|
|
24
26
|
|
|
25
27
|
public async subscribeKeyBordListeners(isStatusBarTranslucent: boolean, isNavigationBarTranslucent: boolean) {
|
|
26
28
|
//ignore isStatusBarTranslucent - those are Android only
|
|
27
|
-
|
|
29
|
+
let windowInstance: window.Window;
|
|
30
|
+
try {
|
|
31
|
+
windowInstance = await window.getLastWindow(this.ctx.uiAbilityContext);
|
|
32
|
+
} catch (e: ESObject) {
|
|
33
|
+
this.logger.error(`subscribeKeyBordListeners failed: ${e?.message ?? e}`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
28
36
|
const navIndicatorArea = windowInstance.getWindowAvoidArea(
|
|
29
37
|
window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR
|
|
30
38
|
);
|
|
@@ -91,7 +99,13 @@ export class ReanimatedModule extends UITurboModule {
|
|
|
91
99
|
}
|
|
92
100
|
|
|
93
101
|
public async unsubscribeKeyBordListeners() {
|
|
94
|
-
|
|
102
|
+
let windowInstance: window.Window;
|
|
103
|
+
try {
|
|
104
|
+
windowInstance = await window.getLastWindow(this.ctx.uiAbilityContext);
|
|
105
|
+
} catch (e: ESObject) {
|
|
106
|
+
this.logger.error(`unsubscribeKeyBordListeners failed: ${e?.message ?? e}`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
95
109
|
windowInstance.off('keyboardHeightChange')
|
|
96
110
|
if (this.currentAnimator) {
|
|
97
111
|
this.currentAnimator.onFrame = null;
|
|
@@ -120,4 +134,15 @@ export class ReanimatedModule extends UITurboModule {
|
|
|
120
134
|
}
|
|
121
135
|
return isLayoutFullScreen;
|
|
122
136
|
}
|
|
137
|
+
|
|
138
|
+
public isReducedMotionEnabled(): boolean {
|
|
139
|
+
try {
|
|
140
|
+
if (deviceInfo.sdkApiVersion >= 23) {
|
|
141
|
+
return (accessibility as ESObject).isAnimationReduceEnabledSync();
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {
|
|
144
|
+
this.logger.warn(`isReducedMotionEnabled failed: ${JSON.stringify(e)}`);
|
|
145
|
+
}
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
123
148
|
}
|
package/harmony/reanimated.har
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"alias": "react-native-reanimated",
|
|
5
5
|
"redirectInternalImports": true
|
|
6
6
|
},
|
|
7
|
-
"version": "3.18.
|
|
8
|
-
"description": "",
|
|
7
|
+
"version": "3.18.4-beta.2",
|
|
8
|
+
"description": "More powerful alternative to Animated library for React Native.",
|
|
9
9
|
"main": "lib/index.js",
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "tsc",
|
|
@@ -46,6 +46,20 @@
|
|
|
46
46
|
"lib",
|
|
47
47
|
"harmony",
|
|
48
48
|
"src",
|
|
49
|
-
"./harmony.tar.gz"
|
|
50
|
-
|
|
49
|
+
"./harmony.tar.gz",
|
|
50
|
+
"CHANGELOG.md",
|
|
51
|
+
"!build"
|
|
52
|
+
],
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public",
|
|
55
|
+
"registry": "https://registry.npmjs.org/"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://gitcode.com/CPF-RN/rntpc_react-native-reanimated",
|
|
58
|
+
"bugs": {
|
|
59
|
+
"url": "https://gitcode.com/CPF-RN/rntpc_react-native-reanimated/issues"
|
|
60
|
+
},
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "https://gitcode.com/CPF-RN/rntpc_react-native-reanimated.git"
|
|
64
|
+
}
|
|
51
65
|
}
|