@rejourneyco/react-native 1.0.0 → 1.0.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/README.md +29 -0
- package/android/src/main/java/com/rejourney/RejourneyModuleImpl.kt +47 -30
- package/android/src/main/java/com/rejourney/capture/CaptureEngine.kt +25 -1
- package/android/src/main/java/com/rejourney/capture/CaptureHeuristics.kt +70 -32
- package/android/src/main/java/com/rejourney/core/Constants.kt +4 -4
- package/android/src/newarch/java/com/rejourney/RejourneyModule.kt +14 -0
- package/android/src/oldarch/java/com/rejourney/RejourneyModule.kt +9 -0
- package/ios/Capture/RJCaptureEngine.m +72 -34
- package/ios/Capture/RJCaptureHeuristics.h +7 -5
- package/ios/Capture/RJCaptureHeuristics.m +138 -112
- package/ios/Capture/RJVideoEncoder.m +0 -26
- package/ios/Core/Rejourney.mm +64 -102
- package/ios/Utils/RJPerfTiming.m +0 -5
- package/ios/Utils/RJWindowUtils.m +0 -1
- package/lib/commonjs/components/Mask.js +1 -6
- package/lib/commonjs/index.js +12 -101
- package/lib/commonjs/sdk/autoTracking.js +55 -353
- package/lib/commonjs/sdk/constants.js +2 -13
- package/lib/commonjs/sdk/errorTracking.js +1 -29
- package/lib/commonjs/sdk/metricsTracking.js +3 -24
- package/lib/commonjs/sdk/navigation.js +3 -42
- package/lib/commonjs/sdk/networkInterceptor.js +7 -49
- package/lib/commonjs/sdk/utils.js +0 -5
- package/lib/module/components/Mask.js +1 -6
- package/lib/module/index.js +11 -105
- package/lib/module/sdk/autoTracking.js +55 -354
- package/lib/module/sdk/constants.js +2 -13
- package/lib/module/sdk/errorTracking.js +1 -29
- package/lib/module/sdk/index.js +0 -2
- package/lib/module/sdk/metricsTracking.js +3 -24
- package/lib/module/sdk/navigation.js +3 -42
- package/lib/module/sdk/networkInterceptor.js +7 -49
- package/lib/module/sdk/utils.js +0 -5
- package/lib/typescript/NativeRejourney.d.ts +2 -0
- package/lib/typescript/sdk/autoTracking.d.ts +5 -6
- package/lib/typescript/types/index.d.ts +0 -1
- package/package.json +11 -3
- package/src/NativeRejourney.ts +4 -0
- package/src/components/Mask.tsx +0 -3
- package/src/index.ts +11 -88
- package/src/sdk/autoTracking.ts +72 -331
- package/src/sdk/constants.ts +13 -13
- package/src/sdk/errorTracking.ts +1 -17
- package/src/sdk/index.ts +0 -2
- package/src/sdk/metricsTracking.ts +5 -33
- package/src/sdk/navigation.ts +8 -29
- package/src/sdk/networkInterceptor.ts +9 -33
- package/src/sdk/utils.ts +0 -5
- package/src/types/index.ts +0 -29
|
@@ -61,6 +61,7 @@ typedef struct {
|
|
|
61
61
|
@property(nonatomic, assign) NSInteger generation;
|
|
62
62
|
@property(nonatomic, strong, nullable) RJViewHierarchyScanResult *scanResult;
|
|
63
63
|
@property(nonatomic, copy, nullable) NSString *layoutSignature;
|
|
64
|
+
@property(nonatomic, assign) RJCaptureImportance importance;
|
|
64
65
|
|
|
65
66
|
@end
|
|
66
67
|
|
|
@@ -168,6 +169,8 @@ typedef struct {
|
|
|
168
169
|
@property(nonatomic, assign) CFRunLoopObserverRef runLoopObserver;
|
|
169
170
|
@property(nonatomic, assign) BOOL runLoopCapturePending;
|
|
170
171
|
|
|
172
|
+
@property(nonatomic, assign) BOOL isWarmingUp;
|
|
173
|
+
|
|
171
174
|
@end
|
|
172
175
|
|
|
173
176
|
#pragma mark - Implementation
|
|
@@ -300,6 +303,7 @@ typedef struct {
|
|
|
300
303
|
_isShuttingDown = NO;
|
|
301
304
|
_uiReadyForCapture = NO;
|
|
302
305
|
_framesSinceHierarchy = 0;
|
|
306
|
+
_isWarmingUp = NO;
|
|
303
307
|
|
|
304
308
|
[self applyDefaultConfiguration];
|
|
305
309
|
|
|
@@ -494,7 +498,38 @@ typedef struct {
|
|
|
494
498
|
|
|
495
499
|
- (void)appDidBecomeActive:(NSNotification *)notification {
|
|
496
500
|
self.isInBackground = NO;
|
|
497
|
-
|
|
501
|
+
|
|
502
|
+
// DEFENSIVE FIX: Warmup period
|
|
503
|
+
// When returning from background, the view hierarchy and layout may not be
|
|
504
|
+
// stable immediately. This can cause privacy masks to be drawn in the wrong
|
|
505
|
+
// position relative to the content (race condition). We impose a short
|
|
506
|
+
// "warmup" period where we skip capture to allow AutoLayout to settle.
|
|
507
|
+
self.isWarmingUp = YES;
|
|
508
|
+
|
|
509
|
+
// Clear stale caches to force fresh scan
|
|
510
|
+
if (self.lastCapturedPixelBuffer) {
|
|
511
|
+
CVPixelBufferRelease(self.lastCapturedPixelBuffer);
|
|
512
|
+
self.lastCapturedPixelBuffer = NULL;
|
|
513
|
+
}
|
|
514
|
+
self.lastMaskScanResult = nil;
|
|
515
|
+
self.lastSafeMaskScanResult = nil;
|
|
516
|
+
|
|
517
|
+
RJLogDebug(@"CaptureEngine: App became active - starting warmup (0.2s)");
|
|
518
|
+
|
|
519
|
+
__weak typeof(self) weakSelf = self;
|
|
520
|
+
dispatch_after(
|
|
521
|
+
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)),
|
|
522
|
+
dispatch_get_main_queue(), ^{
|
|
523
|
+
__strong typeof(weakSelf) strongSelf = weakSelf;
|
|
524
|
+
if (!strongSelf)
|
|
525
|
+
return;
|
|
526
|
+
|
|
527
|
+
strongSelf.isWarmingUp = NO;
|
|
528
|
+
RJLogDebug(@"CaptureEngine: Warmup complete - resuming capture");
|
|
529
|
+
|
|
530
|
+
// Trigger an immediate capture check
|
|
531
|
+
[strongSelf captureVideoFrame];
|
|
532
|
+
});
|
|
498
533
|
}
|
|
499
534
|
|
|
500
535
|
#pragma mark - System Monitoring
|
|
@@ -1087,14 +1122,31 @@ typedef struct {
|
|
|
1087
1122
|
}
|
|
1088
1123
|
|
|
1089
1124
|
- (void)captureVideoFrame {
|
|
1125
|
+
[self captureVideoFrameWithImportance:RJCaptureImportanceLow reason:@"timer"];
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
- (void)captureVideoFrameWithImportance:(RJCaptureImportance)importance
|
|
1129
|
+
reason:(NSString *)reason {
|
|
1090
1130
|
if (!self.internalIsRecording || self.isShuttingDown)
|
|
1091
1131
|
return;
|
|
1132
|
+
|
|
1133
|
+
if (self.isWarmingUp) {
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// Critical events (like navigation) should bypass UI ready checks if
|
|
1138
|
+
// possible, but we still need a valid UI.
|
|
1092
1139
|
if (!self.uiReadyForCapture) {
|
|
1093
1140
|
if (self.framesSinceSessionStart % 60 == 0)
|
|
1094
1141
|
RJLogDebug(@"Skipping capture: UI not ready");
|
|
1095
1142
|
return;
|
|
1096
1143
|
}
|
|
1097
|
-
|
|
1144
|
+
|
|
1145
|
+
// Critical events override paused state
|
|
1146
|
+
BOOL isCritical = (importance == RJCaptureImportanceCritical ||
|
|
1147
|
+
importance == RJCaptureImportanceHigh);
|
|
1148
|
+
if (self.internalPerformanceLevel == RJPerformanceLevelPaused &&
|
|
1149
|
+
!isCritical) {
|
|
1098
1150
|
static NSInteger pauseSkipCount = 0;
|
|
1099
1151
|
if (++pauseSkipCount % 60 == 0)
|
|
1100
1152
|
RJLogDebug(@"Skipping capture: Performance Paused");
|
|
@@ -1109,12 +1161,19 @@ typedef struct {
|
|
|
1109
1161
|
|
|
1110
1162
|
RJCapturePendingCapture *pending = [[RJCapturePendingCapture alloc] init];
|
|
1111
1163
|
pending.wantedAt = now;
|
|
1164
|
+
pending.importance = importance;
|
|
1165
|
+
|
|
1112
1166
|
NSTimeInterval grace = self.captureHeuristics.captureGraceSeconds;
|
|
1113
1167
|
if (self.captureHeuristics.animationBlocking ||
|
|
1114
1168
|
self.captureHeuristics.scrollActive ||
|
|
1115
1169
|
self.captureHeuristics.keyboardAnimating) {
|
|
1116
1170
|
grace = MIN(grace, 0.3);
|
|
1117
1171
|
}
|
|
1172
|
+
|
|
1173
|
+
if (isCritical) {
|
|
1174
|
+
grace = MIN(grace, 0.1);
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1118
1177
|
pending.deadline = now + grace;
|
|
1119
1178
|
pending.timestamp = [self currentTimestamp];
|
|
1120
1179
|
pending.generation = ++self.pendingCaptureGeneration;
|
|
@@ -1207,7 +1266,8 @@ typedef struct {
|
|
|
1207
1266
|
RJCaptureHeuristicsDecision *decision = [self.captureHeuristics
|
|
1208
1267
|
decisionForSignature:pending.layoutSignature
|
|
1209
1268
|
now:now
|
|
1210
|
-
hasLastFrame:(self.lastCapturedPixelBuffer != NULL)
|
|
1269
|
+
hasLastFrame:(self.lastCapturedPixelBuffer != NULL)
|
|
1270
|
+
importance:pending.importance];
|
|
1211
1271
|
|
|
1212
1272
|
if (decision.action == RJCaptureHeuristicsActionRenderNow && !fullScan) {
|
|
1213
1273
|
RJ_TIME_START_NAMED(viewScan);
|
|
@@ -1241,7 +1301,8 @@ typedef struct {
|
|
|
1241
1301
|
decision = [self.captureHeuristics
|
|
1242
1302
|
decisionForSignature:pending.layoutSignature
|
|
1243
1303
|
now:now
|
|
1244
|
-
hasLastFrame:(self.lastCapturedPixelBuffer != NULL)
|
|
1304
|
+
hasLastFrame:(self.lastCapturedPixelBuffer != NULL)
|
|
1305
|
+
importance:pending.importance];
|
|
1245
1306
|
}
|
|
1246
1307
|
|
|
1247
1308
|
if (decision.action == RJCaptureHeuristicsActionDefer && fullScan) {
|
|
@@ -1342,7 +1403,10 @@ typedef struct {
|
|
|
1342
1403
|
}
|
|
1343
1404
|
self.pendingDefensiveCaptureTime = 0;
|
|
1344
1405
|
self.lastIntentTime = CACurrentMediaTime();
|
|
1345
|
-
|
|
1406
|
+
// Defensive capture triggered by heuristics (e.g.
|
|
1407
|
+
// navigation) is High importance
|
|
1408
|
+
[self captureVideoFrameWithImportance:RJCaptureImportanceHigh
|
|
1409
|
+
reason:reason];
|
|
1346
1410
|
});
|
|
1347
1411
|
}
|
|
1348
1412
|
|
|
@@ -1662,7 +1726,6 @@ typedef struct {
|
|
|
1662
1726
|
}
|
|
1663
1727
|
|
|
1664
1728
|
if (self.internalPerformanceLevel == RJPerformanceLevelMinimal) {
|
|
1665
|
-
// Minimal mode trades quality for speed
|
|
1666
1729
|
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
|
|
1667
1730
|
CGContextSetShouldAntialias(context, false);
|
|
1668
1731
|
CGContextSetAllowsAntialiasing(context, false);
|
|
@@ -1672,17 +1735,13 @@ typedef struct {
|
|
|
1672
1735
|
CGContextSetAllowsAntialiasing(context, true);
|
|
1673
1736
|
}
|
|
1674
1737
|
|
|
1675
|
-
// Set up context transform (flip for UIKit coordinates)
|
|
1676
1738
|
CGContextScaleCTM(context, contextScale, -contextScale);
|
|
1677
1739
|
CGContextTranslateCTM(context, 0, -sizePoints.height);
|
|
1678
1740
|
|
|
1679
|
-
// Optimization #9: Fast Memset Clear (White = 0xFF)
|
|
1680
|
-
// Much faster than CGContextFillRect
|
|
1681
1741
|
memset(baseAddress, 0xFF, bytesPerRow * height);
|
|
1682
1742
|
|
|
1683
1743
|
UIGraphicsPushContext(context);
|
|
1684
1744
|
|
|
1685
|
-
// ===== RENDERING: ALWAYS USE drawViewHierarchyInRect =====
|
|
1686
1745
|
RJ_TIME_START_NAMED(render);
|
|
1687
1746
|
BOOL didDraw = NO;
|
|
1688
1747
|
@try {
|
|
@@ -1703,10 +1762,6 @@ typedef struct {
|
|
|
1703
1762
|
return NULL;
|
|
1704
1763
|
}
|
|
1705
1764
|
|
|
1706
|
-
// Recalculate effective scale so consumers (PrivacyMask) know the real
|
|
1707
|
-
// mapping Used by caller to pass to applyToPixelBuffer Note: we don't need to
|
|
1708
|
-
// return it, caller has it.
|
|
1709
|
-
|
|
1710
1765
|
return pixelBuffer;
|
|
1711
1766
|
}
|
|
1712
1767
|
|
|
@@ -1746,9 +1801,6 @@ typedef struct {
|
|
|
1746
1801
|
}
|
|
1747
1802
|
|
|
1748
1803
|
- (NSTimeInterval)currentTimestamp {
|
|
1749
|
-
// Always use wall clock time for session timestamps
|
|
1750
|
-
// CACurrentMediaTime optimization removed - it causes drift after
|
|
1751
|
-
// background periods The ~1ms overhead is acceptable for 1fps capture
|
|
1752
1804
|
return [[NSDate date] timeIntervalSince1970] * 1000.0;
|
|
1753
1805
|
}
|
|
1754
1806
|
|
|
@@ -1760,8 +1812,6 @@ typedef struct {
|
|
|
1760
1812
|
endTime:(NSTimeInterval)endTime
|
|
1761
1813
|
frameCount:(NSInteger)frameCount {
|
|
1762
1814
|
|
|
1763
|
-
// Ensure we are on our own encoding queue to protect hierarchySnapshots
|
|
1764
|
-
// and maintain thread safety (callback comes from VideoEncoder queue)
|
|
1765
1815
|
dispatch_async(self.encodingQueue, ^{
|
|
1766
1816
|
RJLogDebug(@"CaptureEngine: videoEncoderDidFinishSegment: %@ (%ld frames, "
|
|
1767
1817
|
@"%.1fs), sessionId=%@",
|
|
@@ -1803,9 +1853,6 @@ typedef struct {
|
|
|
1803
1853
|
|
|
1804
1854
|
[self uploadCurrentHierarchySnapshots];
|
|
1805
1855
|
|
|
1806
|
-
// NUCLEAR FIX: Do NOT call startSegmentWithSize here!
|
|
1807
|
-
// The encoder's appendFrame method will auto-start a segment with the
|
|
1808
|
-
// correct PIXEL dimensions when the next frame is captured.
|
|
1809
1856
|
if (self.internalIsRecording && !self.isShuttingDown) {
|
|
1810
1857
|
RJLogDebug(
|
|
1811
1858
|
@"CaptureEngine: Segment finished, auto-start new on next frame");
|
|
@@ -1843,10 +1890,8 @@ typedef struct {
|
|
|
1843
1890
|
|
|
1844
1891
|
RJLogInfo(@"CaptureEngine: Pausing video capture (sync=%d)", synchronous);
|
|
1845
1892
|
|
|
1846
|
-
// Reset capture-in-progress flag immediately to prevent stuck state
|
|
1847
1893
|
self.captureInProgress = NO;
|
|
1848
1894
|
|
|
1849
|
-
// Invalidate timer synchronously if in sync mode
|
|
1850
1895
|
if (synchronous) {
|
|
1851
1896
|
[self teardownDisplayLink];
|
|
1852
1897
|
} else {
|
|
@@ -1856,7 +1901,7 @@ typedef struct {
|
|
|
1856
1901
|
}
|
|
1857
1902
|
|
|
1858
1903
|
if (self.internalVideoEncoder) {
|
|
1859
|
-
self.internalIsRecording = NO;
|
|
1904
|
+
self.internalIsRecording = NO;
|
|
1860
1905
|
|
|
1861
1906
|
if (synchronous) {
|
|
1862
1907
|
void (^finishSync)(void) = ^{
|
|
@@ -1895,19 +1940,15 @@ typedef struct {
|
|
|
1895
1940
|
return;
|
|
1896
1941
|
}
|
|
1897
1942
|
|
|
1898
|
-
// Set recording back to YES to allow captureVideoFrame to proceed
|
|
1899
1943
|
self.internalIsRecording = YES;
|
|
1900
1944
|
|
|
1901
1945
|
RJLogInfo(@"CaptureEngine: Resuming video capture");
|
|
1902
1946
|
|
|
1903
|
-
// Reset capture state to ensure clean resumption
|
|
1904
|
-
// These flags may have been left in an inconsistent state when going to
|
|
1905
|
-
// background
|
|
1906
1947
|
self.captureInProgress = NO;
|
|
1907
|
-
self.lastIntentTime = 0;
|
|
1948
|
+
self.lastIntentTime = 0;
|
|
1908
1949
|
|
|
1909
1950
|
self.internalPerformanceLevel =
|
|
1910
|
-
RJPerformanceLevelNormal;
|
|
1951
|
+
RJPerformanceLevelNormal;
|
|
1911
1952
|
|
|
1912
1953
|
self.pendingCapture = nil;
|
|
1913
1954
|
self.pendingCaptureGeneration = 0;
|
|
@@ -1926,7 +1967,6 @@ typedef struct {
|
|
|
1926
1967
|
if (window && self.internalVideoEncoder) {
|
|
1927
1968
|
RJLogInfo(@"CaptureEngine: Resuming capture...");
|
|
1928
1969
|
|
|
1929
|
-
// Use the optimized Display Link
|
|
1930
1970
|
[self setupDisplayLink];
|
|
1931
1971
|
|
|
1932
1972
|
} else {
|
|
@@ -1943,14 +1983,12 @@ typedef struct {
|
|
|
1943
1983
|
if (!self.internalIsRecording)
|
|
1944
1984
|
return;
|
|
1945
1985
|
|
|
1946
|
-
// Force update if screen changed
|
|
1947
1986
|
if (![screenName isEqualToString:self.currentScreenName]) {
|
|
1948
1987
|
NSTimeInterval now = CACurrentMediaTime();
|
|
1949
1988
|
self.currentScreenName = screenName;
|
|
1950
1989
|
RJLogDebug(@"Navigation to screen: %@ (forcing layout refresh)",
|
|
1951
1990
|
screenName);
|
|
1952
1991
|
|
|
1953
|
-
// Force layout change detection on next frame
|
|
1954
1992
|
[self.captureHeuristics invalidateSignature];
|
|
1955
1993
|
[self.captureHeuristics recordNavigationEventAtTime:now];
|
|
1956
1994
|
self.lastSerializedSignature = nil;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#import <Foundation/Foundation.h>
|
|
11
11
|
#import <UIKit/UIKit.h>
|
|
12
12
|
|
|
13
|
+
#import "../Core/RJTypes.h"
|
|
13
14
|
#import "RJViewHierarchyScanner.h"
|
|
14
15
|
|
|
15
16
|
NS_ASSUME_NONNULL_BEGIN
|
|
@@ -59,7 +60,7 @@ typedef NS_ENUM(NSInteger, RJCaptureHeuristicsReason) {
|
|
|
59
60
|
- (void)recordMapInteractionAtTime:(NSTimeInterval)time;
|
|
60
61
|
- (void)recordNavigationEventAtTime:(NSTimeInterval)time;
|
|
61
62
|
- (void)recordRenderedSignature:(nullable NSString *)signature
|
|
62
|
-
|
|
63
|
+
atTime:(NSTimeInterval)time;
|
|
63
64
|
|
|
64
65
|
- (void)updateWithScanResult:(RJViewHierarchyScanResult *)scanResult
|
|
65
66
|
window:(UIWindow *)window
|
|
@@ -68,10 +69,11 @@ typedef NS_ENUM(NSInteger, RJCaptureHeuristicsReason) {
|
|
|
68
69
|
- (void)updateWithStabilityProbeForWindow:(UIWindow *)window
|
|
69
70
|
now:(NSTimeInterval)now;
|
|
70
71
|
|
|
71
|
-
- (RJCaptureHeuristicsDecision *)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
- (RJCaptureHeuristicsDecision *)
|
|
73
|
+
decisionForSignature:(nullable NSString *)signature
|
|
74
|
+
now:(NSTimeInterval)now
|
|
75
|
+
hasLastFrame:(BOOL)hasLastFrame
|
|
76
|
+
importance:(RJCaptureImportance)importance;
|
|
75
77
|
|
|
76
78
|
+ (NSString *)stringForReason:(RJCaptureHeuristicsReason)reason;
|
|
77
79
|
|