@onekeyfe/react-native-perf-stats 3.0.35 → 3.0.37
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/android/src/main/java/com/margelo/nitro/reactnativeperfstats/PerfStatsInitProvider.kt +11 -4
- package/android/src/main/java/com/margelo/nitro/reactnativeperfstats/ReactNativePerfStats.kt +333 -24
- package/ios/ReactNativePerfStats.swift +360 -15
- package/lib/module/index.js +77 -5
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/ReactNativePerfStats.nitro.d.ts +109 -1
- package/lib/typescript/src/ReactNativePerfStats.nitro.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +31 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_MemoryWarningEvent.hpp +79 -0
- package/nitrogen/generated/android/c++/JHybridReactNativePerfStatsSpec.cpp +24 -0
- package/nitrogen/generated/android/c++/JHybridReactNativePerfStatsSpec.hpp +3 -0
- package/nitrogen/generated/android/c++/JMemoryWarningEvent.hpp +66 -0
- package/nitrogen/generated/android/c++/JMemoryWarningLevel.hpp +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativeperfstats/Func_void_MemoryWarningEvent.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativeperfstats/HybridReactNativePerfStatsSpec.kt +17 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativeperfstats/MemoryWarningEvent.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativeperfstats/MemoryWarningLevel.kt +21 -0
- package/nitrogen/generated/android/reactnativeperfstatsOnLoad.cpp +2 -0
- package/nitrogen/generated/ios/ReactNativePerfStats-Swift-Cxx-Bridge.cpp +8 -0
- package/nitrogen/generated/ios/ReactNativePerfStats-Swift-Cxx-Bridge.hpp +37 -0
- package/nitrogen/generated/ios/ReactNativePerfStats-Swift-Cxx-Umbrella.hpp +7 -0
- package/nitrogen/generated/ios/c++/HybridReactNativePerfStatsSpecSwift.hpp +27 -0
- package/nitrogen/generated/ios/swift/Func_void_MemoryWarningEvent.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridReactNativePerfStatsSpec.swift +3 -0
- package/nitrogen/generated/ios/swift/HybridReactNativePerfStatsSpec_cxx.swift +39 -0
- package/nitrogen/generated/ios/swift/MemoryWarningEvent.swift +58 -0
- package/nitrogen/generated/ios/swift/MemoryWarningLevel.swift +40 -0
- package/nitrogen/generated/shared/c++/HybridReactNativePerfStatsSpec.cpp +3 -0
- package/nitrogen/generated/shared/c++/HybridReactNativePerfStatsSpec.hpp +7 -0
- package/nitrogen/generated/shared/c++/MemoryWarningEvent.hpp +84 -0
- package/nitrogen/generated/shared/c++/MemoryWarningLevel.hpp +76 -0
- package/package.json +1 -1
- package/src/ReactNativePerfStats.nitro.ts +114 -1
- package/src/index.tsx +90 -5
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
// Forward declarations of C++ defined types
|
|
11
11
|
// Forward declaration of `HybridReactNativePerfStatsSpec` to properly resolve imports.
|
|
12
12
|
namespace margelo::nitro::reactnativeperfstats { class HybridReactNativePerfStatsSpec; }
|
|
13
|
+
// Forward declaration of `MemoryWarningEvent` to properly resolve imports.
|
|
14
|
+
namespace margelo::nitro::reactnativeperfstats { struct MemoryWarningEvent; }
|
|
15
|
+
// Forward declaration of `MemoryWarningLevel` to properly resolve imports.
|
|
16
|
+
namespace margelo::nitro::reactnativeperfstats { enum class MemoryWarningLevel; }
|
|
13
17
|
// Forward declaration of `PerfSample` to properly resolve imports.
|
|
14
18
|
namespace margelo::nitro::reactnativeperfstats { struct PerfSample; }
|
|
15
19
|
|
|
@@ -19,6 +23,8 @@ namespace ReactNativePerfStats { class HybridReactNativePerfStatsSpec_cxx; }
|
|
|
19
23
|
|
|
20
24
|
// Include C++ defined types
|
|
21
25
|
#include "HybridReactNativePerfStatsSpec.hpp"
|
|
26
|
+
#include "MemoryWarningEvent.hpp"
|
|
27
|
+
#include "MemoryWarningLevel.hpp"
|
|
22
28
|
#include "PerfSample.hpp"
|
|
23
29
|
#include <NitroModules/Promise.hpp>
|
|
24
30
|
#include <NitroModules/PromiseHolder.hpp>
|
|
@@ -89,6 +95,28 @@ namespace margelo::nitro::reactnativeperfstats::bridge::swift {
|
|
|
89
95
|
return Func_void_std__exception_ptr_Wrapper(std::move(value));
|
|
90
96
|
}
|
|
91
97
|
|
|
98
|
+
// pragma MARK: std::function<void(const MemoryWarningEvent& /* event */)>
|
|
99
|
+
/**
|
|
100
|
+
* Specialized version of `std::function<void(const MemoryWarningEvent&)>`.
|
|
101
|
+
*/
|
|
102
|
+
using Func_void_MemoryWarningEvent = std::function<void(const MemoryWarningEvent& /* event */)>;
|
|
103
|
+
/**
|
|
104
|
+
* Wrapper class for a `std::function<void(const MemoryWarningEvent& / * event * /)>`, this can be used from Swift.
|
|
105
|
+
*/
|
|
106
|
+
class Func_void_MemoryWarningEvent_Wrapper final {
|
|
107
|
+
public:
|
|
108
|
+
explicit Func_void_MemoryWarningEvent_Wrapper(std::function<void(const MemoryWarningEvent& /* event */)>&& func): _function(std::make_unique<std::function<void(const MemoryWarningEvent& /* event */)>>(std::move(func))) {}
|
|
109
|
+
inline void call(MemoryWarningEvent event) const noexcept {
|
|
110
|
+
_function->operator()(event);
|
|
111
|
+
}
|
|
112
|
+
private:
|
|
113
|
+
std::unique_ptr<std::function<void(const MemoryWarningEvent& /* event */)>> _function;
|
|
114
|
+
} SWIFT_NONCOPYABLE;
|
|
115
|
+
Func_void_MemoryWarningEvent create_Func_void_MemoryWarningEvent(void* NON_NULL swiftClosureWrapper) noexcept;
|
|
116
|
+
inline Func_void_MemoryWarningEvent_Wrapper wrap_Func_void_MemoryWarningEvent(Func_void_MemoryWarningEvent value) noexcept {
|
|
117
|
+
return Func_void_MemoryWarningEvent_Wrapper(std::move(value));
|
|
118
|
+
}
|
|
119
|
+
|
|
92
120
|
// pragma MARK: std::shared_ptr<HybridReactNativePerfStatsSpec>
|
|
93
121
|
/**
|
|
94
122
|
* Specialized version of `std::shared_ptr<HybridReactNativePerfStatsSpec>`.
|
|
@@ -118,5 +146,14 @@ namespace margelo::nitro::reactnativeperfstats::bridge::swift {
|
|
|
118
146
|
inline Result_std__shared_ptr_Promise_PerfSample___ create_Result_std__shared_ptr_Promise_PerfSample___(const std::exception_ptr& error) noexcept {
|
|
119
147
|
return Result<std::shared_ptr<Promise<PerfSample>>>::withError(error);
|
|
120
148
|
}
|
|
149
|
+
|
|
150
|
+
// pragma MARK: Result<double>
|
|
151
|
+
using Result_double_ = Result<double>;
|
|
152
|
+
inline Result_double_ create_Result_double_(double value) noexcept {
|
|
153
|
+
return Result<double>::withValue(std::move(value));
|
|
154
|
+
}
|
|
155
|
+
inline Result_double_ create_Result_double_(const std::exception_ptr& error) noexcept {
|
|
156
|
+
return Result<double>::withError(error);
|
|
157
|
+
}
|
|
121
158
|
|
|
122
159
|
} // namespace margelo::nitro::reactnativeperfstats::bridge::swift
|
|
@@ -10,15 +10,22 @@
|
|
|
10
10
|
// Forward declarations of C++ defined types
|
|
11
11
|
// Forward declaration of `HybridReactNativePerfStatsSpec` to properly resolve imports.
|
|
12
12
|
namespace margelo::nitro::reactnativeperfstats { class HybridReactNativePerfStatsSpec; }
|
|
13
|
+
// Forward declaration of `MemoryWarningEvent` to properly resolve imports.
|
|
14
|
+
namespace margelo::nitro::reactnativeperfstats { struct MemoryWarningEvent; }
|
|
15
|
+
// Forward declaration of `MemoryWarningLevel` to properly resolve imports.
|
|
16
|
+
namespace margelo::nitro::reactnativeperfstats { enum class MemoryWarningLevel; }
|
|
13
17
|
// Forward declaration of `PerfSample` to properly resolve imports.
|
|
14
18
|
namespace margelo::nitro::reactnativeperfstats { struct PerfSample; }
|
|
15
19
|
|
|
16
20
|
// Include C++ defined types
|
|
17
21
|
#include "HybridReactNativePerfStatsSpec.hpp"
|
|
22
|
+
#include "MemoryWarningEvent.hpp"
|
|
23
|
+
#include "MemoryWarningLevel.hpp"
|
|
18
24
|
#include "PerfSample.hpp"
|
|
19
25
|
#include <NitroModules/Promise.hpp>
|
|
20
26
|
#include <NitroModules/Result.hpp>
|
|
21
27
|
#include <exception>
|
|
28
|
+
#include <functional>
|
|
22
29
|
#include <memory>
|
|
23
30
|
|
|
24
31
|
// C++ helpers for Swift
|
|
@@ -14,9 +14,16 @@ namespace ReactNativePerfStats { class HybridReactNativePerfStatsSpec_cxx; }
|
|
|
14
14
|
|
|
15
15
|
// Forward declaration of `PerfSample` to properly resolve imports.
|
|
16
16
|
namespace margelo::nitro::reactnativeperfstats { struct PerfSample; }
|
|
17
|
+
// Forward declaration of `MemoryWarningEvent` to properly resolve imports.
|
|
18
|
+
namespace margelo::nitro::reactnativeperfstats { struct MemoryWarningEvent; }
|
|
19
|
+
// Forward declaration of `MemoryWarningLevel` to properly resolve imports.
|
|
20
|
+
namespace margelo::nitro::reactnativeperfstats { enum class MemoryWarningLevel; }
|
|
17
21
|
|
|
18
22
|
#include "PerfSample.hpp"
|
|
19
23
|
#include <NitroModules/Promise.hpp>
|
|
24
|
+
#include "MemoryWarningEvent.hpp"
|
|
25
|
+
#include <functional>
|
|
26
|
+
#include "MemoryWarningLevel.hpp"
|
|
20
27
|
|
|
21
28
|
#include "ReactNativePerfStats-Swift-Cxx-Umbrella.hpp"
|
|
22
29
|
|
|
@@ -100,6 +107,26 @@ namespace margelo::nitro::reactnativeperfstats {
|
|
|
100
107
|
std::rethrow_exception(__result.error());
|
|
101
108
|
}
|
|
102
109
|
}
|
|
110
|
+
inline double addMemoryWarningListener(const std::function<void(const MemoryWarningEvent& /* event */)>& callback) override {
|
|
111
|
+
auto __result = _swiftPart.addMemoryWarningListener(callback);
|
|
112
|
+
if (__result.hasError()) [[unlikely]] {
|
|
113
|
+
std::rethrow_exception(__result.error());
|
|
114
|
+
}
|
|
115
|
+
auto __value = std::move(__result.value());
|
|
116
|
+
return __value;
|
|
117
|
+
}
|
|
118
|
+
inline void removeMemoryWarningListener(double id) override {
|
|
119
|
+
auto __result = _swiftPart.removeMemoryWarningListener(std::forward<decltype(id)>(id));
|
|
120
|
+
if (__result.hasError()) [[unlikely]] {
|
|
121
|
+
std::rethrow_exception(__result.error());
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
inline void cleanupNativeCaches() override {
|
|
125
|
+
auto __result = _swiftPart.cleanupNativeCaches();
|
|
126
|
+
if (__result.hasError()) [[unlikely]] {
|
|
127
|
+
std::rethrow_exception(__result.error());
|
|
128
|
+
}
|
|
129
|
+
}
|
|
103
130
|
|
|
104
131
|
private:
|
|
105
132
|
ReactNativePerfStats::HybridReactNativePerfStatsSpec_cxx _swiftPart;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// Func_void_MemoryWarningEvent.swift
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
import NitroModules
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Wraps a Swift `(_ event: MemoryWarningEvent) -> Void` as a class.
|
|
13
|
+
* This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`.
|
|
14
|
+
*/
|
|
15
|
+
public final class Func_void_MemoryWarningEvent {
|
|
16
|
+
public typealias bridge = margelo.nitro.reactnativeperfstats.bridge.swift
|
|
17
|
+
|
|
18
|
+
private let closure: (_ event: MemoryWarningEvent) -> Void
|
|
19
|
+
|
|
20
|
+
public init(_ closure: @escaping (_ event: MemoryWarningEvent) -> Void) {
|
|
21
|
+
self.closure = closure
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@inline(__always)
|
|
25
|
+
public func call(event: MemoryWarningEvent) -> Void {
|
|
26
|
+
self.closure(event)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Casts this instance to a retained unsafe raw pointer.
|
|
31
|
+
* This acquires one additional strong reference on the object!
|
|
32
|
+
*/
|
|
33
|
+
@inline(__always)
|
|
34
|
+
public func toUnsafe() -> UnsafeMutableRawPointer {
|
|
35
|
+
return Unmanaged.passRetained(self).toOpaque()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Casts an unsafe pointer to a `Func_void_MemoryWarningEvent`.
|
|
40
|
+
* The pointer has to be a retained opaque `Unmanaged<Func_void_MemoryWarningEvent>`.
|
|
41
|
+
* This removes one strong reference from the object!
|
|
42
|
+
*/
|
|
43
|
+
@inline(__always)
|
|
44
|
+
public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_void_MemoryWarningEvent {
|
|
45
|
+
return Unmanaged<Func_void_MemoryWarningEvent>.fromOpaque(pointer).takeRetainedValue()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -20,6 +20,9 @@ public protocol HybridReactNativePerfStatsSpec_protocol: HybridObject {
|
|
|
20
20
|
func hideOverlay() throws -> Void
|
|
21
21
|
func sample() throws -> Promise<PerfSample>
|
|
22
22
|
func setJsFpsHint(fps: Double) throws -> Void
|
|
23
|
+
func addMemoryWarningListener(callback: @escaping (_ event: MemoryWarningEvent) -> Void) throws -> Double
|
|
24
|
+
func removeMemoryWarningListener(id: Double) throws -> Void
|
|
25
|
+
func cleanupNativeCaches() throws -> Void
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
public extension HybridReactNativePerfStatsSpec_protocol {
|
|
@@ -190,4 +190,43 @@ open class HybridReactNativePerfStatsSpec_cxx {
|
|
|
190
190
|
return bridge.create_Result_void_(__exceptionPtr)
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
|
+
|
|
194
|
+
@inline(__always)
|
|
195
|
+
public final func addMemoryWarningListener(callback: bridge.Func_void_MemoryWarningEvent) -> bridge.Result_double_ {
|
|
196
|
+
do {
|
|
197
|
+
let __result = try self.__implementation.addMemoryWarningListener(callback: { () -> (MemoryWarningEvent) -> Void in
|
|
198
|
+
let __wrappedFunction = bridge.wrap_Func_void_MemoryWarningEvent(callback)
|
|
199
|
+
return { (__event: MemoryWarningEvent) -> Void in
|
|
200
|
+
__wrappedFunction.call(__event)
|
|
201
|
+
}
|
|
202
|
+
}())
|
|
203
|
+
let __resultCpp = __result
|
|
204
|
+
return bridge.create_Result_double_(__resultCpp)
|
|
205
|
+
} catch (let __error) {
|
|
206
|
+
let __exceptionPtr = __error.toCpp()
|
|
207
|
+
return bridge.create_Result_double_(__exceptionPtr)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@inline(__always)
|
|
212
|
+
public final func removeMemoryWarningListener(id: Double) -> bridge.Result_void_ {
|
|
213
|
+
do {
|
|
214
|
+
try self.__implementation.removeMemoryWarningListener(id: id)
|
|
215
|
+
return bridge.create_Result_void_()
|
|
216
|
+
} catch (let __error) {
|
|
217
|
+
let __exceptionPtr = __error.toCpp()
|
|
218
|
+
return bridge.create_Result_void_(__exceptionPtr)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@inline(__always)
|
|
223
|
+
public final func cleanupNativeCaches() -> bridge.Result_void_ {
|
|
224
|
+
do {
|
|
225
|
+
try self.__implementation.cleanupNativeCaches()
|
|
226
|
+
return bridge.create_Result_void_()
|
|
227
|
+
} catch (let __error) {
|
|
228
|
+
let __exceptionPtr = __error.toCpp()
|
|
229
|
+
return bridge.create_Result_void_(__exceptionPtr)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
193
232
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// MemoryWarningEvent.swift
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
import NitroModules
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Represents an instance of `MemoryWarningEvent`, backed by a C++ struct.
|
|
13
|
+
*/
|
|
14
|
+
public typealias MemoryWarningEvent = margelo.nitro.reactnativeperfstats.MemoryWarningEvent
|
|
15
|
+
|
|
16
|
+
public extension MemoryWarningEvent {
|
|
17
|
+
private typealias bridge = margelo.nitro.reactnativeperfstats.bridge.swift
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Create a new instance of `MemoryWarningEvent`.
|
|
21
|
+
*/
|
|
22
|
+
init(level: MemoryWarningLevel, rss: Double, timestamp: Double) {
|
|
23
|
+
self.init(level, rss, timestamp)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var level: MemoryWarningLevel {
|
|
27
|
+
@inline(__always)
|
|
28
|
+
get {
|
|
29
|
+
return self.__level
|
|
30
|
+
}
|
|
31
|
+
@inline(__always)
|
|
32
|
+
set {
|
|
33
|
+
self.__level = newValue
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var rss: Double {
|
|
38
|
+
@inline(__always)
|
|
39
|
+
get {
|
|
40
|
+
return self.__rss
|
|
41
|
+
}
|
|
42
|
+
@inline(__always)
|
|
43
|
+
set {
|
|
44
|
+
self.__rss = newValue
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
var timestamp: Double {
|
|
49
|
+
@inline(__always)
|
|
50
|
+
get {
|
|
51
|
+
return self.__timestamp
|
|
52
|
+
}
|
|
53
|
+
@inline(__always)
|
|
54
|
+
set {
|
|
55
|
+
self.__timestamp = newValue
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// MemoryWarningLevel.swift
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Represents the JS union `MemoryWarningLevel`, backed by a C++ enum.
|
|
10
|
+
*/
|
|
11
|
+
public typealias MemoryWarningLevel = margelo.nitro.reactnativeperfstats.MemoryWarningLevel
|
|
12
|
+
|
|
13
|
+
public extension MemoryWarningLevel {
|
|
14
|
+
/**
|
|
15
|
+
* Get a MemoryWarningLevel for the given String value, or
|
|
16
|
+
* return `nil` if the given value was invalid/unknown.
|
|
17
|
+
*/
|
|
18
|
+
init?(fromString string: String) {
|
|
19
|
+
switch string {
|
|
20
|
+
case "low":
|
|
21
|
+
self = .low
|
|
22
|
+
case "critical":
|
|
23
|
+
self = .critical
|
|
24
|
+
default:
|
|
25
|
+
return nil
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get the String value this MemoryWarningLevel represents.
|
|
31
|
+
*/
|
|
32
|
+
var stringValue: String {
|
|
33
|
+
switch self {
|
|
34
|
+
case .low:
|
|
35
|
+
return "low"
|
|
36
|
+
case .critical:
|
|
37
|
+
return "critical"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -20,6 +20,9 @@ namespace margelo::nitro::reactnativeperfstats {
|
|
|
20
20
|
prototype.registerHybridMethod("hideOverlay", &HybridReactNativePerfStatsSpec::hideOverlay);
|
|
21
21
|
prototype.registerHybridMethod("sample", &HybridReactNativePerfStatsSpec::sample);
|
|
22
22
|
prototype.registerHybridMethod("setJsFpsHint", &HybridReactNativePerfStatsSpec::setJsFpsHint);
|
|
23
|
+
prototype.registerHybridMethod("addMemoryWarningListener", &HybridReactNativePerfStatsSpec::addMemoryWarningListener);
|
|
24
|
+
prototype.registerHybridMethod("removeMemoryWarningListener", &HybridReactNativePerfStatsSpec::removeMemoryWarningListener);
|
|
25
|
+
prototype.registerHybridMethod("cleanupNativeCaches", &HybridReactNativePerfStatsSpec::cleanupNativeCaches);
|
|
23
26
|
});
|
|
24
27
|
}
|
|
25
28
|
|
|
@@ -15,9 +15,13 @@
|
|
|
15
15
|
|
|
16
16
|
// Forward declaration of `PerfSample` to properly resolve imports.
|
|
17
17
|
namespace margelo::nitro::reactnativeperfstats { struct PerfSample; }
|
|
18
|
+
// Forward declaration of `MemoryWarningEvent` to properly resolve imports.
|
|
19
|
+
namespace margelo::nitro::reactnativeperfstats { struct MemoryWarningEvent; }
|
|
18
20
|
|
|
19
21
|
#include "PerfSample.hpp"
|
|
20
22
|
#include <NitroModules/Promise.hpp>
|
|
23
|
+
#include "MemoryWarningEvent.hpp"
|
|
24
|
+
#include <functional>
|
|
21
25
|
|
|
22
26
|
namespace margelo::nitro::reactnativeperfstats {
|
|
23
27
|
|
|
@@ -56,6 +60,9 @@ namespace margelo::nitro::reactnativeperfstats {
|
|
|
56
60
|
virtual void hideOverlay() = 0;
|
|
57
61
|
virtual std::shared_ptr<Promise<PerfSample>> sample() = 0;
|
|
58
62
|
virtual void setJsFpsHint(double fps) = 0;
|
|
63
|
+
virtual double addMemoryWarningListener(const std::function<void(const MemoryWarningEvent& /* event */)>& callback) = 0;
|
|
64
|
+
virtual void removeMemoryWarningListener(double id) = 0;
|
|
65
|
+
virtual void cleanupNativeCaches() = 0;
|
|
59
66
|
|
|
60
67
|
protected:
|
|
61
68
|
// Hybrid Setup
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// MemoryWarningEvent.hpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#if __has_include(<NitroModules/JSIConverter.hpp>)
|
|
11
|
+
#include <NitroModules/JSIConverter.hpp>
|
|
12
|
+
#else
|
|
13
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
14
|
+
#endif
|
|
15
|
+
#if __has_include(<NitroModules/NitroDefines.hpp>)
|
|
16
|
+
#include <NitroModules/NitroDefines.hpp>
|
|
17
|
+
#else
|
|
18
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
19
|
+
#endif
|
|
20
|
+
#if __has_include(<NitroModules/JSIHelpers.hpp>)
|
|
21
|
+
#include <NitroModules/JSIHelpers.hpp>
|
|
22
|
+
#else
|
|
23
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
// Forward declaration of `MemoryWarningLevel` to properly resolve imports.
|
|
27
|
+
namespace margelo::nitro::reactnativeperfstats { enum class MemoryWarningLevel; }
|
|
28
|
+
|
|
29
|
+
#include "MemoryWarningLevel.hpp"
|
|
30
|
+
|
|
31
|
+
namespace margelo::nitro::reactnativeperfstats {
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A struct which can be represented as a JavaScript object (MemoryWarningEvent).
|
|
35
|
+
*/
|
|
36
|
+
struct MemoryWarningEvent {
|
|
37
|
+
public:
|
|
38
|
+
MemoryWarningLevel level SWIFT_PRIVATE;
|
|
39
|
+
double rss SWIFT_PRIVATE;
|
|
40
|
+
double timestamp SWIFT_PRIVATE;
|
|
41
|
+
|
|
42
|
+
public:
|
|
43
|
+
MemoryWarningEvent() = default;
|
|
44
|
+
explicit MemoryWarningEvent(MemoryWarningLevel level, double rss, double timestamp): level(level), rss(rss), timestamp(timestamp) {}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
} // namespace margelo::nitro::reactnativeperfstats
|
|
48
|
+
|
|
49
|
+
namespace margelo::nitro {
|
|
50
|
+
|
|
51
|
+
// C++ MemoryWarningEvent <> JS MemoryWarningEvent (object)
|
|
52
|
+
template <>
|
|
53
|
+
struct JSIConverter<margelo::nitro::reactnativeperfstats::MemoryWarningEvent> final {
|
|
54
|
+
static inline margelo::nitro::reactnativeperfstats::MemoryWarningEvent fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
55
|
+
jsi::Object obj = arg.asObject(runtime);
|
|
56
|
+
return margelo::nitro::reactnativeperfstats::MemoryWarningEvent(
|
|
57
|
+
JSIConverter<margelo::nitro::reactnativeperfstats::MemoryWarningLevel>::fromJSI(runtime, obj.getProperty(runtime, "level")),
|
|
58
|
+
JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, "rss")),
|
|
59
|
+
JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, "timestamp"))
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::reactnativeperfstats::MemoryWarningEvent& arg) {
|
|
63
|
+
jsi::Object obj(runtime);
|
|
64
|
+
obj.setProperty(runtime, "level", JSIConverter<margelo::nitro::reactnativeperfstats::MemoryWarningLevel>::toJSI(runtime, arg.level));
|
|
65
|
+
obj.setProperty(runtime, "rss", JSIConverter<double>::toJSI(runtime, arg.rss));
|
|
66
|
+
obj.setProperty(runtime, "timestamp", JSIConverter<double>::toJSI(runtime, arg.timestamp));
|
|
67
|
+
return obj;
|
|
68
|
+
}
|
|
69
|
+
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
70
|
+
if (!value.isObject()) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
jsi::Object obj = value.getObject(runtime);
|
|
74
|
+
if (!nitro::isPlainObject(runtime, obj)) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (!JSIConverter<margelo::nitro::reactnativeperfstats::MemoryWarningLevel>::canConvert(runtime, obj.getProperty(runtime, "level"))) return false;
|
|
78
|
+
if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, "rss"))) return false;
|
|
79
|
+
if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, "timestamp"))) return false;
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
} // namespace margelo::nitro
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// MemoryWarningLevel.hpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © 2026 Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#if __has_include(<NitroModules/NitroHash.hpp>)
|
|
11
|
+
#include <NitroModules/NitroHash.hpp>
|
|
12
|
+
#else
|
|
13
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
14
|
+
#endif
|
|
15
|
+
#if __has_include(<NitroModules/JSIConverter.hpp>)
|
|
16
|
+
#include <NitroModules/JSIConverter.hpp>
|
|
17
|
+
#else
|
|
18
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
19
|
+
#endif
|
|
20
|
+
#if __has_include(<NitroModules/NitroDefines.hpp>)
|
|
21
|
+
#include <NitroModules/NitroDefines.hpp>
|
|
22
|
+
#else
|
|
23
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
namespace margelo::nitro::reactnativeperfstats {
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* An enum which can be represented as a JavaScript union (MemoryWarningLevel).
|
|
30
|
+
*/
|
|
31
|
+
enum class MemoryWarningLevel {
|
|
32
|
+
LOW SWIFT_NAME(low) = 0,
|
|
33
|
+
CRITICAL SWIFT_NAME(critical) = 1,
|
|
34
|
+
} CLOSED_ENUM;
|
|
35
|
+
|
|
36
|
+
} // namespace margelo::nitro::reactnativeperfstats
|
|
37
|
+
|
|
38
|
+
namespace margelo::nitro {
|
|
39
|
+
|
|
40
|
+
// C++ MemoryWarningLevel <> JS MemoryWarningLevel (union)
|
|
41
|
+
template <>
|
|
42
|
+
struct JSIConverter<margelo::nitro::reactnativeperfstats::MemoryWarningLevel> final {
|
|
43
|
+
static inline margelo::nitro::reactnativeperfstats::MemoryWarningLevel fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
44
|
+
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, arg);
|
|
45
|
+
switch (hashString(unionValue.c_str(), unionValue.size())) {
|
|
46
|
+
case hashString("low"): return margelo::nitro::reactnativeperfstats::MemoryWarningLevel::LOW;
|
|
47
|
+
case hashString("critical"): return margelo::nitro::reactnativeperfstats::MemoryWarningLevel::CRITICAL;
|
|
48
|
+
default: [[unlikely]]
|
|
49
|
+
throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum MemoryWarningLevel - invalid value!");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::reactnativeperfstats::MemoryWarningLevel arg) {
|
|
53
|
+
switch (arg) {
|
|
54
|
+
case margelo::nitro::reactnativeperfstats::MemoryWarningLevel::LOW: return JSIConverter<std::string>::toJSI(runtime, "low");
|
|
55
|
+
case margelo::nitro::reactnativeperfstats::MemoryWarningLevel::CRITICAL: return JSIConverter<std::string>::toJSI(runtime, "critical");
|
|
56
|
+
default: [[unlikely]]
|
|
57
|
+
throw std::invalid_argument("Cannot convert MemoryWarningLevel to JS - invalid value: "
|
|
58
|
+
+ std::to_string(static_cast<int>(arg)) + "!");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
62
|
+
if (!value.isString()) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, value);
|
|
66
|
+
switch (hashString(unionValue.c_str(), unionValue.size())) {
|
|
67
|
+
case hashString("low"):
|
|
68
|
+
case hashString("critical"):
|
|
69
|
+
return true;
|
|
70
|
+
default:
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
} // namespace margelo::nitro
|
package/package.json
CHANGED
|
@@ -13,19 +13,56 @@ export interface PerfSample {
|
|
|
13
13
|
/**
|
|
14
14
|
* UI thread frame rate, frames per second over the last 1 s window.
|
|
15
15
|
* Measured on the platform's main thread via Choreographer (Android)
|
|
16
|
-
* or CADisplayLink (iOS). `0` until at least one window has elapsed
|
|
16
|
+
* or CADisplayLink (iOS). `0` until at least one window has elapsed
|
|
17
|
+
* **and the sampler is running** — the underlying frame monitor only
|
|
18
|
+
* runs between `start()` and `stop()`, so one-shot `sample()` calls
|
|
19
|
+
* issued outside that window always report `0` here.
|
|
17
20
|
*/
|
|
18
21
|
uiFps: number;
|
|
19
22
|
/**
|
|
20
23
|
* JS thread frame rate, frames per second reported by the JS-side
|
|
21
24
|
* `requestAnimationFrame` ticker (see `startJsFpsTracker`). `0` if
|
|
22
25
|
* the tracker has not been started or no hint has been received yet.
|
|
26
|
+
* Same caveat as `uiFps`: one-shot `sample()` calls issued before
|
|
27
|
+
* `start()` (or after `stop()`) report `0` here.
|
|
23
28
|
*/
|
|
24
29
|
jsFps: number;
|
|
25
30
|
/** Wall-clock timestamp (ms since unix epoch) when the sample was taken. */
|
|
26
31
|
timestamp: number;
|
|
27
32
|
}
|
|
28
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Severity of a system-emitted memory pressure event, normalised across
|
|
36
|
+
* platforms.
|
|
37
|
+
*
|
|
38
|
+
* - `low`: Android `TRIM_MEMORY_RUNNING_MODERATE` /
|
|
39
|
+
* `TRIM_MEMORY_RUNNING_LOW`. iOS does not emit this level (iOS only
|
|
40
|
+
* fires the critical warning), so JS code should treat the absence of
|
|
41
|
+
* `low` events on iOS as expected, not a missing signal.
|
|
42
|
+
* - `critical`: iOS `UIApplicationDidReceiveMemoryWarningNotification`;
|
|
43
|
+
* Android `TRIM_MEMORY_RUNNING_CRITICAL` or `onLowMemory()`. Indicates
|
|
44
|
+
* the OS is about to start killing background apps (Android) or the
|
|
45
|
+
* app itself (iOS jetsam). Subscribers should drop everything that
|
|
46
|
+
* can be rebuilt on demand.
|
|
47
|
+
*/
|
|
48
|
+
export type MemoryWarningLevel = 'low' | 'critical';
|
|
49
|
+
|
|
50
|
+
export interface MemoryWarningEvent {
|
|
51
|
+
level: MemoryWarningLevel;
|
|
52
|
+
/**
|
|
53
|
+
* Process RSS in bytes at the moment the warning fired. `0` if the
|
|
54
|
+
* lookup failed.
|
|
55
|
+
*
|
|
56
|
+
* On iOS the primary source is `phys_footprint`; if that fails, the
|
|
57
|
+
* fallback path reads `resident_size`, which is semantically smaller
|
|
58
|
+
* and noisier. The two values are not directly comparable, so treat
|
|
59
|
+
* unexpected magnitude differences across reports cautiously.
|
|
60
|
+
*/
|
|
61
|
+
rss: number;
|
|
62
|
+
/** Wall-clock timestamp (ms since unix epoch). */
|
|
63
|
+
timestamp: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
29
66
|
export interface ReactNativePerfStats
|
|
30
67
|
extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> {
|
|
31
68
|
/**
|
|
@@ -78,4 +115,80 @@ export interface ReactNativePerfStats
|
|
|
78
115
|
* than calling this directly.
|
|
79
116
|
*/
|
|
80
117
|
setJsFpsHint(fps: number): void;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Subscribe to OS-emitted memory pressure events.
|
|
121
|
+
*
|
|
122
|
+
* - iOS: `UIApplicationDidReceiveMemoryWarningNotification`, mapped to
|
|
123
|
+
* `critical`. Fires on the main thread.
|
|
124
|
+
* - Android: `ComponentCallbacks2.onTrimMemory` filtered to
|
|
125
|
+
* `TRIM_MEMORY_RUNNING_*` (foreground process pressure), plus
|
|
126
|
+
* `onLowMemory()` as `critical`. Fires on the main thread.
|
|
127
|
+
*
|
|
128
|
+
* The native listener is registered process-wide on first call and
|
|
129
|
+
* survives `stop()` — memory pressure is independent of the perf
|
|
130
|
+
* sampler being active. Callbacks are invoked on the JS thread.
|
|
131
|
+
*
|
|
132
|
+
* **Always pair this with `removeMemoryWarningListener`** (e.g. in a
|
|
133
|
+
* React effect cleanup): the callback closure is retained for the life
|
|
134
|
+
* of the subscription, and forgetting to remove leaks every object the
|
|
135
|
+
* closure transitively captures — typically the React component instance
|
|
136
|
+
* that registered it. This matters in dev too: the native listener
|
|
137
|
+
* table is a process-wide singleton that **does not clear on RN
|
|
138
|
+
* reload**, so a Fast-Refresh / dev reload that drops the JS realm
|
|
139
|
+
* without first calling `removeMemoryWarningListener` will leave the
|
|
140
|
+
* pre-reload callback in the table, pointing at a dead JS context.
|
|
141
|
+
* The cleanest fix is the same effect-cleanup pattern.
|
|
142
|
+
*
|
|
143
|
+
* The relative order in which subscribed callbacks fire for a single
|
|
144
|
+
* event is **not guaranteed** — iOS iterates a hash dictionary, Android
|
|
145
|
+
* iterates a LinkedHashMap, and either may change. Don't take a
|
|
146
|
+
* cross-listener dependency.
|
|
147
|
+
*
|
|
148
|
+
* Dispatch: when a warning arrives, the native module walks all
|
|
149
|
+
* registered callbacks **serially on the main thread** before each
|
|
150
|
+
* one hops to the JS thread. Cost scales with the number of
|
|
151
|
+
* subscribers — keep N small (single-digit) and avoid registering one
|
|
152
|
+
* listener per render-tree branch.
|
|
153
|
+
*
|
|
154
|
+
* Side effects of the warning itself (before your callback fires):
|
|
155
|
+
* - **iOS** runs the same reclaim path as `cleanupNativeCaches`,
|
|
156
|
+
* which drops the process-wide `URLCache.shared`, the WK HTTP /
|
|
157
|
+
* AppCache / Service-Worker stores, and triggers a libmalloc
|
|
158
|
+
* pressure relief. If any code path in the app depends on
|
|
159
|
+
* URLCache for offline HTTP content, or on a Service Worker for
|
|
160
|
+
* offline WebView fallback, that state is dropped here — don't
|
|
161
|
+
* register this listener if either is load-bearing.
|
|
162
|
+
* - **Android** runs `Runtime.gc()` on every warning (LOW and
|
|
163
|
+
* CRITICAL). ART treats it as a hint.
|
|
164
|
+
*
|
|
165
|
+
* Returns an opaque id; pass it to `removeMemoryWarningListener` to
|
|
166
|
+
* unsubscribe.
|
|
167
|
+
*/
|
|
168
|
+
addMemoryWarningListener(callback: (event: MemoryWarningEvent) => void): number;
|
|
169
|
+
|
|
170
|
+
/** Unsubscribe a previously-registered memory warning listener. No-op for unknown ids. */
|
|
171
|
+
removeMemoryWarningListener(id: number): void;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Trigger the same native reclaim path the OS memory-warning observer
|
|
175
|
+
* runs, on demand. Use when the JS layer has reason to believe pressure
|
|
176
|
+
* is building before the OS posts a warning (e.g. backgrounding, a
|
|
177
|
+
* heavy route transition, jotai cache invalidation, post-import).
|
|
178
|
+
*
|
|
179
|
+
* - **iOS** clears `URLCache.shared` (process-wide HTTP response cache;
|
|
180
|
+
* any consumer that relies on URLCache for offline content loses
|
|
181
|
+
* it until the next request) and the WK HTTP / AppCache / Service-
|
|
182
|
+
* Worker stores (auth-related cookies / localStorage / IndexedDB
|
|
183
|
+
* are preserved). Then dispatches `malloc_zone_pressure_relief` on
|
|
184
|
+
* a background queue — the call returns to JS immediately, but the
|
|
185
|
+
* zone walk that actually frees pages can take 100-500 ms.
|
|
186
|
+
* - **Android** asks ART to GC via `Runtime.gc()` (hint only; the
|
|
187
|
+
* runtime decides whether to honour it). Returns quickly.
|
|
188
|
+
*
|
|
189
|
+
* Cheap on Android, cheap-to-return on iOS (heavy work runs async).
|
|
190
|
+
* Pair with `forceGarbageCollection()` if you also want the JS engine
|
|
191
|
+
* to participate.
|
|
192
|
+
*/
|
|
193
|
+
cleanupNativeCaches(): void;
|
|
81
194
|
}
|