@rejourneyco/react-native 1.0.0
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/build.gradle.kts +135 -0
- package/android/consumer-rules.pro +10 -0
- package/android/proguard-rules.pro +1 -0
- package/android/src/main/AndroidManifest.xml +15 -0
- package/android/src/main/java/com/rejourney/RejourneyModuleImpl.kt +2981 -0
- package/android/src/main/java/com/rejourney/capture/ANRHandler.kt +206 -0
- package/android/src/main/java/com/rejourney/capture/ActivityTracker.kt +98 -0
- package/android/src/main/java/com/rejourney/capture/CaptureEngine.kt +1553 -0
- package/android/src/main/java/com/rejourney/capture/CaptureHeuristics.kt +375 -0
- package/android/src/main/java/com/rejourney/capture/CrashHandler.kt +153 -0
- package/android/src/main/java/com/rejourney/capture/MotionEvent.kt +215 -0
- package/android/src/main/java/com/rejourney/capture/SegmentUploader.kt +512 -0
- package/android/src/main/java/com/rejourney/capture/VideoEncoder.kt +773 -0
- package/android/src/main/java/com/rejourney/capture/ViewHierarchyScanner.kt +633 -0
- package/android/src/main/java/com/rejourney/capture/ViewSerializer.kt +286 -0
- package/android/src/main/java/com/rejourney/core/Constants.kt +117 -0
- package/android/src/main/java/com/rejourney/core/Logger.kt +93 -0
- package/android/src/main/java/com/rejourney/core/Types.kt +124 -0
- package/android/src/main/java/com/rejourney/lifecycle/SessionLifecycleService.kt +162 -0
- package/android/src/main/java/com/rejourney/network/DeviceAuthManager.kt +747 -0
- package/android/src/main/java/com/rejourney/network/HttpClientProvider.kt +16 -0
- package/android/src/main/java/com/rejourney/network/NetworkMonitor.kt +272 -0
- package/android/src/main/java/com/rejourney/network/UploadManager.kt +1363 -0
- package/android/src/main/java/com/rejourney/network/UploadWorker.kt +492 -0
- package/android/src/main/java/com/rejourney/privacy/PrivacyMask.kt +645 -0
- package/android/src/main/java/com/rejourney/touch/GestureClassifier.kt +233 -0
- package/android/src/main/java/com/rejourney/touch/KeyboardTracker.kt +158 -0
- package/android/src/main/java/com/rejourney/touch/TextInputTracker.kt +181 -0
- package/android/src/main/java/com/rejourney/touch/TouchInterceptor.kt +591 -0
- package/android/src/main/java/com/rejourney/utils/EventBuffer.kt +284 -0
- package/android/src/main/java/com/rejourney/utils/OEMDetector.kt +154 -0
- package/android/src/main/java/com/rejourney/utils/PerfTiming.kt +235 -0
- package/android/src/main/java/com/rejourney/utils/Telemetry.kt +297 -0
- package/android/src/main/java/com/rejourney/utils/WindowUtils.kt +84 -0
- package/android/src/newarch/java/com/rejourney/RejourneyModule.kt +187 -0
- package/android/src/newarch/java/com/rejourney/RejourneyPackage.kt +40 -0
- package/android/src/oldarch/java/com/rejourney/RejourneyModule.kt +218 -0
- package/android/src/oldarch/java/com/rejourney/RejourneyPackage.kt +23 -0
- package/ios/Capture/RJANRHandler.h +42 -0
- package/ios/Capture/RJANRHandler.m +328 -0
- package/ios/Capture/RJCaptureEngine.h +275 -0
- package/ios/Capture/RJCaptureEngine.m +2062 -0
- package/ios/Capture/RJCaptureHeuristics.h +80 -0
- package/ios/Capture/RJCaptureHeuristics.m +903 -0
- package/ios/Capture/RJCrashHandler.h +46 -0
- package/ios/Capture/RJCrashHandler.m +313 -0
- package/ios/Capture/RJMotionEvent.h +183 -0
- package/ios/Capture/RJMotionEvent.m +183 -0
- package/ios/Capture/RJPerformanceManager.h +100 -0
- package/ios/Capture/RJPerformanceManager.m +373 -0
- package/ios/Capture/RJPixelBufferDownscaler.h +42 -0
- package/ios/Capture/RJPixelBufferDownscaler.m +85 -0
- package/ios/Capture/RJSegmentUploader.h +146 -0
- package/ios/Capture/RJSegmentUploader.m +778 -0
- package/ios/Capture/RJVideoEncoder.h +247 -0
- package/ios/Capture/RJVideoEncoder.m +1036 -0
- package/ios/Capture/RJViewControllerTracker.h +73 -0
- package/ios/Capture/RJViewControllerTracker.m +508 -0
- package/ios/Capture/RJViewHierarchyScanner.h +215 -0
- package/ios/Capture/RJViewHierarchyScanner.m +1464 -0
- package/ios/Capture/RJViewSerializer.h +119 -0
- package/ios/Capture/RJViewSerializer.m +498 -0
- package/ios/Core/RJConstants.h +124 -0
- package/ios/Core/RJConstants.m +88 -0
- package/ios/Core/RJLifecycleManager.h +85 -0
- package/ios/Core/RJLifecycleManager.m +308 -0
- package/ios/Core/RJLogger.h +61 -0
- package/ios/Core/RJLogger.m +211 -0
- package/ios/Core/RJTypes.h +176 -0
- package/ios/Core/RJTypes.m +66 -0
- package/ios/Core/Rejourney.h +64 -0
- package/ios/Core/Rejourney.mm +2495 -0
- package/ios/Network/RJDeviceAuthManager.h +94 -0
- package/ios/Network/RJDeviceAuthManager.m +967 -0
- package/ios/Network/RJNetworkMonitor.h +68 -0
- package/ios/Network/RJNetworkMonitor.m +267 -0
- package/ios/Network/RJRetryManager.h +73 -0
- package/ios/Network/RJRetryManager.m +325 -0
- package/ios/Network/RJUploadManager.h +267 -0
- package/ios/Network/RJUploadManager.m +2296 -0
- package/ios/Privacy/RJPrivacyMask.h +163 -0
- package/ios/Privacy/RJPrivacyMask.m +922 -0
- package/ios/Rejourney.h +63 -0
- package/ios/Touch/RJGestureClassifier.h +130 -0
- package/ios/Touch/RJGestureClassifier.m +333 -0
- package/ios/Touch/RJTouchInterceptor.h +169 -0
- package/ios/Touch/RJTouchInterceptor.m +772 -0
- package/ios/Utils/RJEventBuffer.h +112 -0
- package/ios/Utils/RJEventBuffer.m +358 -0
- package/ios/Utils/RJGzipUtils.h +33 -0
- package/ios/Utils/RJGzipUtils.m +89 -0
- package/ios/Utils/RJKeychainManager.h +48 -0
- package/ios/Utils/RJKeychainManager.m +111 -0
- package/ios/Utils/RJPerfTiming.h +209 -0
- package/ios/Utils/RJPerfTiming.m +264 -0
- package/ios/Utils/RJTelemetry.h +92 -0
- package/ios/Utils/RJTelemetry.m +320 -0
- package/ios/Utils/RJWindowUtils.h +66 -0
- package/ios/Utils/RJWindowUtils.m +133 -0
- package/lib/commonjs/NativeRejourney.js +40 -0
- package/lib/commonjs/components/Mask.js +79 -0
- package/lib/commonjs/index.js +1381 -0
- package/lib/commonjs/sdk/autoTracking.js +1259 -0
- package/lib/commonjs/sdk/constants.js +151 -0
- package/lib/commonjs/sdk/errorTracking.js +199 -0
- package/lib/commonjs/sdk/index.js +50 -0
- package/lib/commonjs/sdk/metricsTracking.js +204 -0
- package/lib/commonjs/sdk/navigation.js +151 -0
- package/lib/commonjs/sdk/networkInterceptor.js +412 -0
- package/lib/commonjs/sdk/utils.js +363 -0
- package/lib/commonjs/types/expo-router.d.js +2 -0
- package/lib/commonjs/types/index.js +2 -0
- package/lib/module/NativeRejourney.js +38 -0
- package/lib/module/components/Mask.js +72 -0
- package/lib/module/index.js +1284 -0
- package/lib/module/sdk/autoTracking.js +1233 -0
- package/lib/module/sdk/constants.js +145 -0
- package/lib/module/sdk/errorTracking.js +189 -0
- package/lib/module/sdk/index.js +12 -0
- package/lib/module/sdk/metricsTracking.js +187 -0
- package/lib/module/sdk/navigation.js +143 -0
- package/lib/module/sdk/networkInterceptor.js +401 -0
- package/lib/module/sdk/utils.js +342 -0
- package/lib/module/types/expo-router.d.js +2 -0
- package/lib/module/types/index.js +2 -0
- package/lib/typescript/NativeRejourney.d.ts +147 -0
- package/lib/typescript/components/Mask.d.ts +39 -0
- package/lib/typescript/index.d.ts +117 -0
- package/lib/typescript/sdk/autoTracking.d.ts +204 -0
- package/lib/typescript/sdk/constants.d.ts +120 -0
- package/lib/typescript/sdk/errorTracking.d.ts +32 -0
- package/lib/typescript/sdk/index.d.ts +9 -0
- package/lib/typescript/sdk/metricsTracking.d.ts +58 -0
- package/lib/typescript/sdk/navigation.d.ts +33 -0
- package/lib/typescript/sdk/networkInterceptor.d.ts +47 -0
- package/lib/typescript/sdk/utils.d.ts +148 -0
- package/lib/typescript/types/index.d.ts +624 -0
- package/package.json +102 -0
- package/rejourney.podspec +21 -0
- package/src/NativeRejourney.ts +165 -0
- package/src/components/Mask.tsx +80 -0
- package/src/index.ts +1459 -0
- package/src/sdk/autoTracking.ts +1373 -0
- package/src/sdk/constants.ts +134 -0
- package/src/sdk/errorTracking.ts +231 -0
- package/src/sdk/index.ts +11 -0
- package/src/sdk/metricsTracking.ts +232 -0
- package/src/sdk/navigation.ts +157 -0
- package/src/sdk/networkInterceptor.ts +440 -0
- package/src/sdk/utils.ts +369 -0
- package/src/types/expo-router.d.ts +7 -0
- package/src/types/index.ts +739 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJConstants.h
|
|
3
|
+
// Rejourney
|
|
4
|
+
//
|
|
5
|
+
// SDK-wide constants and configuration defaults.
|
|
6
|
+
// This file contains all magic numbers and configuration values
|
|
7
|
+
// used throughout the Rejourney SDK.
|
|
8
|
+
//
|
|
9
|
+
// Video Capture Model:
|
|
10
|
+
// - H.264 video segments at 1 FPS
|
|
11
|
+
// - JSON view hierarchy snapshots
|
|
12
|
+
// - Motion events for gesture reconstruction
|
|
13
|
+
//
|
|
14
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
15
|
+
// you may not use this file except in compliance with the License.
|
|
16
|
+
// You may obtain a copy of the License at
|
|
17
|
+
//
|
|
18
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
19
|
+
//
|
|
20
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
21
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
22
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
23
|
+
// See the License for the specific language governing permissions and
|
|
24
|
+
// limitations under the License.
|
|
25
|
+
//
|
|
26
|
+
// Copyright (c) 2026 Rejourney
|
|
27
|
+
//
|
|
28
|
+
|
|
29
|
+
#import <Foundation/Foundation.h>
|
|
30
|
+
|
|
31
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
32
|
+
|
|
33
|
+
#pragma mark - SDK Version
|
|
34
|
+
|
|
35
|
+
/// Current SDK version string
|
|
36
|
+
FOUNDATION_EXTERN NSString *const RJSDKVersion;
|
|
37
|
+
|
|
38
|
+
#pragma mark - Capture Configuration (Video Model)
|
|
39
|
+
|
|
40
|
+
/// Default capture scale factor (0.35 = 35% of original size for video)
|
|
41
|
+
FOUNDATION_EXTERN const CGFloat RJDefaultCaptureScale;
|
|
42
|
+
|
|
43
|
+
#pragma mark - Motion Event Configuration
|
|
44
|
+
|
|
45
|
+
/// Minimum interval between motion events (0.016 = 60 FPS motion capture)
|
|
46
|
+
FOUNDATION_EXTERN const NSTimeInterval RJDefaultMotionEventInterval;
|
|
47
|
+
|
|
48
|
+
/// Minimum velocity to record scroll motion (points/second)
|
|
49
|
+
FOUNDATION_EXTERN const CGFloat RJMotionVelocityThreshold;
|
|
50
|
+
|
|
51
|
+
/// Scroll distance threshold for motion events (points)
|
|
52
|
+
FOUNDATION_EXTERN const CGFloat RJDefaultScrollThreshold;
|
|
53
|
+
|
|
54
|
+
/// Time after last scroll event to consider scroll ended (seconds)
|
|
55
|
+
FOUNDATION_EXTERN const NSTimeInterval RJScrollEndDelay;
|
|
56
|
+
|
|
57
|
+
#pragma mark - Memory Thresholds
|
|
58
|
+
|
|
59
|
+
/// Memory warning threshold in bytes (100MB)
|
|
60
|
+
FOUNDATION_EXTERN const NSUInteger RJMemoryWarningThresholdBytes;
|
|
61
|
+
|
|
62
|
+
/// Maximum frame data bytes to keep in memory (2MB)
|
|
63
|
+
FOUNDATION_EXTERN const NSUInteger RJMaxFrameBytesInMemory;
|
|
64
|
+
|
|
65
|
+
/// Default maximum frames to keep in memory
|
|
66
|
+
FOUNDATION_EXTERN const NSInteger RJDefaultMaxFramesInMemory;
|
|
67
|
+
|
|
68
|
+
#pragma mark - Performance Thresholds
|
|
69
|
+
|
|
70
|
+
/// Battery level threshold for low-power mode (15%)
|
|
71
|
+
FOUNDATION_EXTERN const float RJLowBatteryThreshold;
|
|
72
|
+
|
|
73
|
+
/// Maximum consecutive captures before cooldown
|
|
74
|
+
FOUNDATION_EXTERN const NSInteger RJMaxConsecutiveCaptures;
|
|
75
|
+
|
|
76
|
+
/// Cooldown duration after max consecutive captures (seconds)
|
|
77
|
+
FOUNDATION_EXTERN const NSTimeInterval RJCaptureCooldownSeconds;
|
|
78
|
+
|
|
79
|
+
#pragma mark - Upload Configuration
|
|
80
|
+
|
|
81
|
+
/// Batch upload interval in seconds
|
|
82
|
+
FOUNDATION_EXTERN const NSTimeInterval RJBatchUploadInterval;
|
|
83
|
+
|
|
84
|
+
/// Initial upload delay for short sessions (seconds)
|
|
85
|
+
FOUNDATION_EXTERN const NSTimeInterval RJInitialUploadDelay;
|
|
86
|
+
|
|
87
|
+
/// Network request timeout (seconds)
|
|
88
|
+
FOUNDATION_EXTERN const NSTimeInterval RJNetworkRequestTimeout;
|
|
89
|
+
|
|
90
|
+
/// Network resource timeout (seconds)
|
|
91
|
+
FOUNDATION_EXTERN const NSTimeInterval RJNetworkResourceTimeout;
|
|
92
|
+
|
|
93
|
+
#pragma mark - Session Configuration
|
|
94
|
+
|
|
95
|
+
/// Background duration threshold for new session (seconds)
|
|
96
|
+
FOUNDATION_EXTERN const NSTimeInterval RJBackgroundSessionTimeout;
|
|
97
|
+
|
|
98
|
+
#pragma mark - Gesture Detection
|
|
99
|
+
|
|
100
|
+
/// Maximum time between taps for double-tap detection (milliseconds)
|
|
101
|
+
FOUNDATION_EXTERN const NSTimeInterval RJDoubleTapMaxInterval;
|
|
102
|
+
|
|
103
|
+
/// Maximum distance between taps for double-tap detection (points)
|
|
104
|
+
FOUNDATION_EXTERN const CGFloat RJDoubleTapMaxDistance;
|
|
105
|
+
|
|
106
|
+
/// Minimum duration for long press detection (milliseconds)
|
|
107
|
+
FOUNDATION_EXTERN const NSTimeInterval RJLongPressMinDuration;
|
|
108
|
+
|
|
109
|
+
/// Force touch threshold (normalized force value)
|
|
110
|
+
FOUNDATION_EXTERN const CGFloat RJForceTouchThreshold;
|
|
111
|
+
|
|
112
|
+
/// Minimum distance for swipe gesture detection (points)
|
|
113
|
+
FOUNDATION_EXTERN const CGFloat RJSwipeMinDistance;
|
|
114
|
+
|
|
115
|
+
/// Minimum distance for pinch gesture detection (points)
|
|
116
|
+
FOUNDATION_EXTERN const CGFloat RJPinchMinDistance;
|
|
117
|
+
|
|
118
|
+
/// Minimum distance change percentage for pinch detection
|
|
119
|
+
FOUNDATION_EXTERN const CGFloat RJPinchMinChangePercent;
|
|
120
|
+
|
|
121
|
+
/// Minimum rotation angle for rotation gesture detection (degrees)
|
|
122
|
+
FOUNDATION_EXTERN const CGFloat RJRotationMinAngle;
|
|
123
|
+
|
|
124
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJConstants.m
|
|
3
|
+
// Rejourney
|
|
4
|
+
//
|
|
5
|
+
// SDK-wide constants implementation.
|
|
6
|
+
//
|
|
7
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
// you may not use this file except in compliance with the License.
|
|
9
|
+
// You may obtain a copy of the License at
|
|
10
|
+
//
|
|
11
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
//
|
|
13
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
// See the License for the specific language governing permissions and
|
|
17
|
+
// limitations under the License.
|
|
18
|
+
//
|
|
19
|
+
// Copyright (c) 2026 Rejourney
|
|
20
|
+
//
|
|
21
|
+
|
|
22
|
+
#import "RJConstants.h"
|
|
23
|
+
|
|
24
|
+
#pragma mark - SDK Version
|
|
25
|
+
|
|
26
|
+
NSString *const RJSDKVersion = @"1.0.0";
|
|
27
|
+
|
|
28
|
+
#pragma mark - Capture Configuration Defaults (Video Model)
|
|
29
|
+
|
|
30
|
+
const CGFloat RJDefaultCaptureScale = 0.35;
|
|
31
|
+
|
|
32
|
+
#pragma mark - Motion Event Configuration
|
|
33
|
+
|
|
34
|
+
const NSTimeInterval RJDefaultMotionEventInterval = 0.016;
|
|
35
|
+
|
|
36
|
+
const CGFloat RJMotionVelocityThreshold = 10.0;
|
|
37
|
+
|
|
38
|
+
const CGFloat RJDefaultScrollThreshold = 5.0;
|
|
39
|
+
|
|
40
|
+
const NSTimeInterval RJScrollEndDelay = 0.15;
|
|
41
|
+
|
|
42
|
+
#pragma mark - Memory Thresholds
|
|
43
|
+
|
|
44
|
+
const NSUInteger RJMemoryWarningThresholdBytes = 100 * 1024 * 1024;
|
|
45
|
+
|
|
46
|
+
const NSUInteger RJMaxFrameBytesInMemory = 4 * 1024 * 1024;
|
|
47
|
+
|
|
48
|
+
const NSInteger RJDefaultMaxFramesInMemory = 20;
|
|
49
|
+
|
|
50
|
+
#pragma mark - Performance Thresholds
|
|
51
|
+
|
|
52
|
+
const float RJLowBatteryThreshold = 0.15f;
|
|
53
|
+
|
|
54
|
+
const NSInteger RJMaxConsecutiveCaptures = 5;
|
|
55
|
+
|
|
56
|
+
const NSTimeInterval RJCaptureCooldownSeconds = 1.0;
|
|
57
|
+
|
|
58
|
+
#pragma mark - Upload Configuration
|
|
59
|
+
|
|
60
|
+
const NSTimeInterval RJBatchUploadInterval = 5.0;
|
|
61
|
+
|
|
62
|
+
const NSTimeInterval RJInitialUploadDelay = 1.0;
|
|
63
|
+
|
|
64
|
+
const NSTimeInterval RJNetworkRequestTimeout = 60.0;
|
|
65
|
+
|
|
66
|
+
const NSTimeInterval RJNetworkResourceTimeout = 120.0;
|
|
67
|
+
|
|
68
|
+
#pragma mark - Session Configuration
|
|
69
|
+
|
|
70
|
+
const NSTimeInterval RJBackgroundSessionTimeout = 60.0;
|
|
71
|
+
|
|
72
|
+
#pragma mark - Gesture Detection
|
|
73
|
+
|
|
74
|
+
const NSTimeInterval RJDoubleTapMaxInterval = 300.0;
|
|
75
|
+
|
|
76
|
+
const CGFloat RJDoubleTapMaxDistance = 50.0;
|
|
77
|
+
|
|
78
|
+
const NSTimeInterval RJLongPressMinDuration = 500.0;
|
|
79
|
+
|
|
80
|
+
const CGFloat RJForceTouchThreshold = 2.0;
|
|
81
|
+
|
|
82
|
+
const CGFloat RJSwipeMinDistance = 50.0;
|
|
83
|
+
|
|
84
|
+
const CGFloat RJPinchMinDistance = 30.0;
|
|
85
|
+
|
|
86
|
+
const CGFloat RJPinchMinChangePercent = 0.20;
|
|
87
|
+
|
|
88
|
+
const CGFloat RJRotationMinAngle = 15.0;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJLifecycleManager.h
|
|
3
|
+
// Rejourney
|
|
4
|
+
//
|
|
5
|
+
// App lifecycle and keyboard event handling.
|
|
6
|
+
//
|
|
7
|
+
// Copyright (c) 2026 Rejourney
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
#import <Foundation/Foundation.h>
|
|
11
|
+
#import <UIKit/UIKit.h>
|
|
12
|
+
|
|
13
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
14
|
+
|
|
15
|
+
/// Delegate for lifecycle events
|
|
16
|
+
@protocol RJLifecycleManagerDelegate <NSObject>
|
|
17
|
+
@optional
|
|
18
|
+
- (void)lifecycleManagerDidEnterBackground;
|
|
19
|
+
- (void)lifecycleManagerWillTerminate;
|
|
20
|
+
- (void)lifecycleManagerDidBecomeActive;
|
|
21
|
+
- (void)lifecycleManagerDidResignActive;
|
|
22
|
+
- (void)lifecycleManagerKeyboardDidShow:(CGRect)keyboardFrame;
|
|
23
|
+
- (void)lifecycleManagerKeyboardWillHide:(NSInteger)keyPressCount;
|
|
24
|
+
- (void)lifecycleManagerTextDidChange;
|
|
25
|
+
- (void)lifecycleManagerSessionDidTimeout:(NSTimeInterval)backgroundDuration;
|
|
26
|
+
@end
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Manages app lifecycle events and keyboard notifications.
|
|
30
|
+
*/
|
|
31
|
+
@interface RJLifecycleManager : NSObject
|
|
32
|
+
|
|
33
|
+
/// Delegate for lifecycle events
|
|
34
|
+
@property(nonatomic, weak, nullable) id<RJLifecycleManagerDelegate> delegate;
|
|
35
|
+
|
|
36
|
+
/// Whether the keyboard is currently visible
|
|
37
|
+
@property(nonatomic, readonly) BOOL isKeyboardVisible;
|
|
38
|
+
|
|
39
|
+
/// Current keyboard frame
|
|
40
|
+
@property(nonatomic, readonly) CGRect keyboardFrame;
|
|
41
|
+
|
|
42
|
+
/// Whether recording is currently active (set by owner)
|
|
43
|
+
@property(nonatomic, assign) BOOL isRecording;
|
|
44
|
+
|
|
45
|
+
/// Whether the app is currently in background
|
|
46
|
+
@property(nonatomic, readonly) BOOL isInBackground;
|
|
47
|
+
|
|
48
|
+
/// Time when app entered background (epoch seconds), 0 if not in background
|
|
49
|
+
@property(nonatomic, readonly) NSTimeInterval backgroundEntryTime;
|
|
50
|
+
|
|
51
|
+
/// Total background time in milliseconds for the current session
|
|
52
|
+
@property(nonatomic, readonly) NSTimeInterval totalBackgroundTimeMs;
|
|
53
|
+
|
|
54
|
+
/// Background session timeout threshold in seconds
|
|
55
|
+
@property(nonatomic, assign) NSTimeInterval backgroundTimeoutThreshold;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Start observing lifecycle and keyboard notifications.
|
|
59
|
+
*/
|
|
60
|
+
- (void)startObserving;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Stop observing notifications.
|
|
64
|
+
*/
|
|
65
|
+
- (void)stopObserving;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Reset background time tracking for a new session.
|
|
69
|
+
*/
|
|
70
|
+
- (void)resetBackgroundTime;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Mark that an external URL was opened.
|
|
74
|
+
*/
|
|
75
|
+
- (void)markExternalURLOpened:(NSString *)urlScheme;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check and clear external URL opened flag.
|
|
79
|
+
*/
|
|
80
|
+
- (BOOL)consumeExternalURLOpenedWithScheme:
|
|
81
|
+
(NSString *_Nullable *_Nullable)scheme;
|
|
82
|
+
|
|
83
|
+
@end
|
|
84
|
+
|
|
85
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJLifecycleManager.m
|
|
3
|
+
// Rejourney
|
|
4
|
+
//
|
|
5
|
+
// App lifecycle and keyboard event handling implementation.
|
|
6
|
+
//
|
|
7
|
+
// BACKGROUND TIMEOUT LOGIC:
|
|
8
|
+
// -------------------------
|
|
9
|
+
// When app returns from background:
|
|
10
|
+
// 1. Calculate how long we were in background
|
|
11
|
+
// 2. If < 60s: Add to accumulated background time, resume session normally
|
|
12
|
+
// 3. If >= 60s: Signal timeout to delegate with the background duration
|
|
13
|
+
// The delegate (Rejourney.mm) will:
|
|
14
|
+
// a) End the old session with total background time (including this period)
|
|
15
|
+
// b) Start a new session with fresh state
|
|
16
|
+
//
|
|
17
|
+
// Copyright (c) 2026 Rejourney
|
|
18
|
+
//
|
|
19
|
+
|
|
20
|
+
#import "RJLifecycleManager.h"
|
|
21
|
+
#import "RJConstants.h"
|
|
22
|
+
#import "RJLogger.h"
|
|
23
|
+
|
|
24
|
+
#pragma mark - Private Interface
|
|
25
|
+
|
|
26
|
+
@interface RJLifecycleManager ()
|
|
27
|
+
|
|
28
|
+
@property(nonatomic, assign) BOOL keyboardVisible;
|
|
29
|
+
@property(nonatomic, assign) CGRect currentKeyboardFrame;
|
|
30
|
+
@property(nonatomic, assign) NSInteger keyPressCount;
|
|
31
|
+
|
|
32
|
+
@property(nonatomic, assign) BOOL inBackground;
|
|
33
|
+
@property(nonatomic, assign) NSTimeInterval backgroundEntryTime;
|
|
34
|
+
@property(nonatomic, assign) NSTimeInterval accumulatedBackgroundTimeMs;
|
|
35
|
+
|
|
36
|
+
@property(nonatomic, assign) BOOL didOpenExternalURL;
|
|
37
|
+
@property(nonatomic, copy, nullable) NSString *lastOpenedURLScheme;
|
|
38
|
+
|
|
39
|
+
@end
|
|
40
|
+
|
|
41
|
+
#pragma mark - Implementation
|
|
42
|
+
|
|
43
|
+
@implementation RJLifecycleManager
|
|
44
|
+
|
|
45
|
+
#pragma mark - Initialization
|
|
46
|
+
|
|
47
|
+
- (instancetype)init {
|
|
48
|
+
self = [super init];
|
|
49
|
+
if (self) {
|
|
50
|
+
_keyboardVisible = NO;
|
|
51
|
+
_currentKeyboardFrame = CGRectZero;
|
|
52
|
+
_keyPressCount = 0;
|
|
53
|
+
_inBackground = NO;
|
|
54
|
+
_backgroundEntryTime = 0;
|
|
55
|
+
_accumulatedBackgroundTimeMs = 0;
|
|
56
|
+
_backgroundTimeoutThreshold = RJBackgroundSessionTimeout;
|
|
57
|
+
_isRecording = NO;
|
|
58
|
+
_didOpenExternalURL = NO;
|
|
59
|
+
}
|
|
60
|
+
return self;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
- (void)dealloc {
|
|
64
|
+
[self stopObserving];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#pragma mark - Public Properties
|
|
68
|
+
|
|
69
|
+
- (BOOL)isKeyboardVisible {
|
|
70
|
+
return _keyboardVisible;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
- (CGRect)keyboardFrame {
|
|
74
|
+
return _currentKeyboardFrame;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
- (BOOL)isInBackground {
|
|
78
|
+
return _inBackground;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
- (NSTimeInterval)backgroundEntryTime {
|
|
82
|
+
return _backgroundEntryTime;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
- (NSTimeInterval)totalBackgroundTimeMs {
|
|
86
|
+
return _accumulatedBackgroundTimeMs;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#pragma mark - Observation Lifecycle
|
|
90
|
+
|
|
91
|
+
- (void)startObserving {
|
|
92
|
+
RJLogInfo(@"[RJ-LIFECYCLE] startObserving called (isRecording=%@)",
|
|
93
|
+
self.isRecording ? @"YES" : @"NO");
|
|
94
|
+
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
|
95
|
+
|
|
96
|
+
// Keyboard notifications
|
|
97
|
+
[center addObserver:self
|
|
98
|
+
selector:@selector(keyboardWillShow:)
|
|
99
|
+
name:UIKeyboardWillShowNotification
|
|
100
|
+
object:nil];
|
|
101
|
+
[center addObserver:self
|
|
102
|
+
selector:@selector(keyboardWillHide:)
|
|
103
|
+
name:UIKeyboardWillHideNotification
|
|
104
|
+
object:nil];
|
|
105
|
+
|
|
106
|
+
// App lifecycle notifications
|
|
107
|
+
[center addObserver:self
|
|
108
|
+
selector:@selector(appDidEnterBackground:)
|
|
109
|
+
name:UIApplicationDidEnterBackgroundNotification
|
|
110
|
+
object:nil];
|
|
111
|
+
[center addObserver:self
|
|
112
|
+
selector:@selector(appWillTerminate:)
|
|
113
|
+
name:UIApplicationWillTerminateNotification
|
|
114
|
+
object:nil];
|
|
115
|
+
[center addObserver:self
|
|
116
|
+
selector:@selector(appWillResignActive:)
|
|
117
|
+
name:UIApplicationWillResignActiveNotification
|
|
118
|
+
object:nil];
|
|
119
|
+
[center addObserver:self
|
|
120
|
+
selector:@selector(appDidBecomeActive:)
|
|
121
|
+
name:UIApplicationDidBecomeActiveNotification
|
|
122
|
+
object:nil];
|
|
123
|
+
|
|
124
|
+
// Text change notifications
|
|
125
|
+
[center addObserver:self
|
|
126
|
+
selector:@selector(textDidChange:)
|
|
127
|
+
name:UITextFieldTextDidChangeNotification
|
|
128
|
+
object:nil];
|
|
129
|
+
[center addObserver:self
|
|
130
|
+
selector:@selector(textDidChange:)
|
|
131
|
+
name:UITextViewTextDidChangeNotification
|
|
132
|
+
object:nil];
|
|
133
|
+
|
|
134
|
+
RJLogInfo(@"[RJ-LIFECYCLE] Lifecycle manager started observing all notifications");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
- (void)stopObserving {
|
|
138
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
139
|
+
RJLogDebug(@"Lifecycle manager stopped observing");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#pragma mark - State Management
|
|
143
|
+
|
|
144
|
+
- (void)resetBackgroundTime {
|
|
145
|
+
RJLogInfo(@"[RJ-LIFECYCLE] resetBackgroundTime called (was %.0fms)", self.accumulatedBackgroundTimeMs);
|
|
146
|
+
self.accumulatedBackgroundTimeMs = 0;
|
|
147
|
+
self.inBackground = NO;
|
|
148
|
+
self.backgroundEntryTime = 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
- (void)markExternalURLOpened:(NSString *)urlScheme {
|
|
152
|
+
self.didOpenExternalURL = YES;
|
|
153
|
+
self.lastOpenedURLScheme = urlScheme;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
- (BOOL)consumeExternalURLOpenedWithScheme:(NSString *_Nullable *_Nullable)scheme {
|
|
157
|
+
if (!self.didOpenExternalURL) {
|
|
158
|
+
return NO;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (scheme) {
|
|
162
|
+
*scheme = self.lastOpenedURLScheme;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
self.didOpenExternalURL = NO;
|
|
166
|
+
self.lastOpenedURLScheme = nil;
|
|
167
|
+
return YES;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
#pragma mark - Keyboard Handling
|
|
171
|
+
|
|
172
|
+
- (void)keyboardWillShow:(NSNotification *)notification {
|
|
173
|
+
self.keyboardVisible = YES;
|
|
174
|
+
self.currentKeyboardFrame =
|
|
175
|
+
[notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
|
176
|
+
|
|
177
|
+
if (self.isRecording) {
|
|
178
|
+
if ([self.delegate
|
|
179
|
+
respondsToSelector:@selector(lifecycleManagerKeyboardDidShow:)]) {
|
|
180
|
+
[self.delegate lifecycleManagerKeyboardDidShow:self.currentKeyboardFrame];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
- (void)keyboardWillHide:(NSNotification *)notification {
|
|
186
|
+
if (self.isRecording && self.keyPressCount > 0) {
|
|
187
|
+
if ([self.delegate
|
|
188
|
+
respondsToSelector:@selector(lifecycleManagerKeyboardWillHide:)]) {
|
|
189
|
+
[self.delegate lifecycleManagerKeyboardWillHide:self.keyPressCount];
|
|
190
|
+
}
|
|
191
|
+
self.keyPressCount = 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
self.keyboardVisible = NO;
|
|
195
|
+
self.currentKeyboardFrame = CGRectZero;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
- (void)textDidChange:(NSNotification *)notification {
|
|
199
|
+
if (self.isRecording) {
|
|
200
|
+
self.keyPressCount++;
|
|
201
|
+
if ([self.delegate
|
|
202
|
+
respondsToSelector:@selector(lifecycleManagerTextDidChange)]) {
|
|
203
|
+
[self.delegate lifecycleManagerTextDidChange];
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
#pragma mark - App Lifecycle
|
|
209
|
+
|
|
210
|
+
- (void)appWillResignActive:(NSNotification *)notification {
|
|
211
|
+
if (self.isRecording) {
|
|
212
|
+
if ([self.delegate
|
|
213
|
+
respondsToSelector:@selector(lifecycleManagerDidResignActive)]) {
|
|
214
|
+
[self.delegate lifecycleManagerDidResignActive];
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
- (void)appDidEnterBackground:(NSNotification *)notification {
|
|
220
|
+
RJLogInfo(@"[RJ-LIFECYCLE] appDidEnterBackground (isRecording=%@)",
|
|
221
|
+
self.isRecording ? @"YES" : @"NO");
|
|
222
|
+
|
|
223
|
+
// Always track background entry time, even if not recording
|
|
224
|
+
// This allows us to detect timeout when session was ended while in background
|
|
225
|
+
self.inBackground = YES;
|
|
226
|
+
self.backgroundEntryTime = [[NSDate date] timeIntervalSince1970];
|
|
227
|
+
|
|
228
|
+
if (!self.isRecording) {
|
|
229
|
+
RJLogInfo(@"[RJ-LIFECYCLE] Not recording - just tracking background time");
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
RJLogInfo(@"[RJ-LIFECYCLE] Calling lifecycleManagerDidEnterBackground delegate");
|
|
234
|
+
if ([self.delegate
|
|
235
|
+
respondsToSelector:@selector(lifecycleManagerDidEnterBackground)]) {
|
|
236
|
+
[self.delegate lifecycleManagerDidEnterBackground];
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
- (void)appWillTerminate:(NSNotification *)notification {
|
|
241
|
+
if ([self.delegate
|
|
242
|
+
respondsToSelector:@selector(lifecycleManagerWillTerminate)]) {
|
|
243
|
+
[self.delegate lifecycleManagerWillTerminate];
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
- (void)appDidBecomeActive:(NSNotification *)notification {
|
|
248
|
+
NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
|
|
249
|
+
BOOL wasInBackground = self.inBackground && self.backgroundEntryTime > 0;
|
|
250
|
+
NSTimeInterval backgroundDurationSec = 0;
|
|
251
|
+
|
|
252
|
+
if (wasInBackground) {
|
|
253
|
+
backgroundDurationSec = currentTime - self.backgroundEntryTime;
|
|
254
|
+
RJLogInfo(@"[RJ-LIFECYCLE] Returned from background after %.1fs (isRecording=%@)",
|
|
255
|
+
backgroundDurationSec, self.isRecording ? @"YES" : @"NO");
|
|
256
|
+
} else {
|
|
257
|
+
RJLogInfo(@"[RJ-LIFECYCLE] appDidBecomeActive - was NOT in background");
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Reset background tracking state
|
|
261
|
+
self.inBackground = NO;
|
|
262
|
+
self.backgroundEntryTime = 0;
|
|
263
|
+
|
|
264
|
+
// Handle the case where we weren't recording (session already ended)
|
|
265
|
+
if (!self.isRecording) {
|
|
266
|
+
// If we were in background long enough, signal that a new session should start
|
|
267
|
+
if (wasInBackground && backgroundDurationSec >= self.backgroundTimeoutThreshold) {
|
|
268
|
+
RJLogInfo(@"[RJ-LIFECYCLE] Was not recording, background >= %.0fs - signaling for new session start",
|
|
269
|
+
self.backgroundTimeoutThreshold);
|
|
270
|
+
if ([self.delegate respondsToSelector:@selector(lifecycleManagerSessionDidTimeout:)]) {
|
|
271
|
+
[self.delegate lifecycleManagerSessionDidTimeout:backgroundDurationSec];
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// We ARE recording - handle background return
|
|
278
|
+
if (wasInBackground) {
|
|
279
|
+
NSTimeInterval bgDurationMs = backgroundDurationSec * 1000;
|
|
280
|
+
|
|
281
|
+
if (backgroundDurationSec >= self.backgroundTimeoutThreshold) {
|
|
282
|
+
// TIMEOUT CASE: End old session, start new one
|
|
283
|
+
// Add this background duration to accumulated time BEFORE signaling timeout
|
|
284
|
+
// so the old session gets the correct total background time
|
|
285
|
+
self.accumulatedBackgroundTimeMs += bgDurationMs;
|
|
286
|
+
RJLogInfo(@"[RJ-LIFECYCLE] TIMEOUT: Added %.0fms, total background=%.0fms - signaling session restart",
|
|
287
|
+
bgDurationMs, self.accumulatedBackgroundTimeMs);
|
|
288
|
+
|
|
289
|
+
if ([self.delegate respondsToSelector:@selector(lifecycleManagerSessionDidTimeout:)]) {
|
|
290
|
+
[self.delegate lifecycleManagerSessionDidTimeout:backgroundDurationSec];
|
|
291
|
+
}
|
|
292
|
+
// Note: The delegate's handleSessionTimeout will read totalBackgroundTimeMs
|
|
293
|
+
// and then call resetBackgroundTime for the new session
|
|
294
|
+
} else {
|
|
295
|
+
// SHORT BACKGROUND: Just accumulate and resume
|
|
296
|
+
self.accumulatedBackgroundTimeMs += bgDurationMs;
|
|
297
|
+
RJLogInfo(@"[RJ-LIFECYCLE] Short background: Added %.0fms, total=%.0fms - resuming session",
|
|
298
|
+
bgDurationMs, self.accumulatedBackgroundTimeMs);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Call didBecomeActive for normal resume handling (video capture, etc.)
|
|
303
|
+
if ([self.delegate respondsToSelector:@selector(lifecycleManagerDidBecomeActive)]) {
|
|
304
|
+
[self.delegate lifecycleManagerDidBecomeActive];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
@end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//
|
|
2
|
+
// RJLogger.h
|
|
3
|
+
// Rejourney
|
|
4
|
+
//
|
|
5
|
+
// Centralized logging utility for the Rejourney SDK.
|
|
6
|
+
// Provides consistent log formatting and level-based filtering.
|
|
7
|
+
//
|
|
8
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
9
|
+
// you may not use this file except in compliance with the License.
|
|
10
|
+
// You may obtain a copy of the License at
|
|
11
|
+
//
|
|
12
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
13
|
+
//
|
|
14
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
15
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
+
// See the License for the specific language governing permissions and
|
|
18
|
+
// limitations under the License.
|
|
19
|
+
//
|
|
20
|
+
// Copyright (c) 2026 Rejourney
|
|
21
|
+
//
|
|
22
|
+
|
|
23
|
+
#import <Foundation/Foundation.h>
|
|
24
|
+
|
|
25
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
26
|
+
|
|
27
|
+
typedef NS_ENUM(NSInteger, RJLogLevel) {
|
|
28
|
+
RJLogLevelDebug = 0,
|
|
29
|
+
RJLogLevelInfo = 1,
|
|
30
|
+
RJLogLevelWarning = 2,
|
|
31
|
+
RJLogLevelError = 3,
|
|
32
|
+
RJLogLevelSilent = 4
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
@interface RJLogger : NSObject
|
|
36
|
+
|
|
37
|
+
@property(class, nonatomic, assign) RJLogLevel minimumLogLevel;
|
|
38
|
+
@property(class, nonatomic, assign) BOOL includeTimestamps;
|
|
39
|
+
@property(class, nonatomic, assign) BOOL debugMode;
|
|
40
|
+
|
|
41
|
+
+ (void)debug:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
|
|
42
|
+
+ (void)info:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
|
|
43
|
+
+ (void)warning:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
|
|
44
|
+
+ (void)error:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
|
|
45
|
+
+ (void)logWithLevel:(RJLogLevel)level
|
|
46
|
+
format:(NSString *)format, ... NS_FORMAT_FUNCTION(2, 3);
|
|
47
|
+
+ (void)logInitSuccess:(NSString *)version;
|
|
48
|
+
+ (void)logInitFailure:(NSString *)reason;
|
|
49
|
+
+ (void)logSessionStart:(NSString *)sessionId;
|
|
50
|
+
+ (void)logSessionEnd:(NSString *)sessionId;
|
|
51
|
+
+ (void)setDebugMode:(BOOL)enabled;
|
|
52
|
+
|
|
53
|
+
@end
|
|
54
|
+
|
|
55
|
+
#define RJLogDebug(fmt, ...) [RJLogger debug:fmt, ##__VA_ARGS__]
|
|
56
|
+
#define RJLogInfo(fmt, ...) [RJLogger info:fmt, ##__VA_ARGS__]
|
|
57
|
+
#define RJLogWarning(fmt, ...) [RJLogger warning:fmt, ##__VA_ARGS__]
|
|
58
|
+
#define RJLogError(fmt, ...) [RJLogger error:fmt, ##__VA_ARGS__]
|
|
59
|
+
#define RJLogPerf(fmt, ...) [RJLogger info:fmt, ##__VA_ARGS__]
|
|
60
|
+
|
|
61
|
+
NS_ASSUME_NONNULL_END
|