react-native-stallion 2.3.0-alpha.4 → 2.3.0-alpha.5

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.
Files changed (97) hide show
  1. package/android/build.gradle +25 -0
  2. package/android/src/main/cpp/CMakeLists.txt +19 -0
  3. package/android/src/main/cpp/stallion_signal_handler.cpp +62 -0
  4. package/android/src/main/java/com/stallion/Stallion.java +0 -2
  5. package/android/src/main/java/com/stallion/StallionModule.java +37 -1
  6. package/android/src/main/java/com/stallion/events/StallionEventConstants.java +1 -0
  7. package/android/src/main/java/com/stallion/events/StallionEventManager.java +23 -15
  8. package/android/src/main/java/com/stallion/networkmanager/StallionFileDownloader.java +8 -5
  9. package/android/src/main/java/com/stallion/networkmanager/StallionSyncHandler.java +18 -1
  10. package/android/src/main/java/com/stallion/storage/StallionMeta.java +52 -1
  11. package/android/src/main/java/com/stallion/storage/StallionStateManager.java +22 -1
  12. package/android/src/main/java/com/stallion/utils/StallionDeviceInfo.java +83 -0
  13. package/android/src/main/java/com/stallion/utils/StallionExceptionHandler.java +84 -7
  14. package/ios/Stallion.xcodeproj/project.pbxproj +6 -0
  15. package/ios/main/Stallion.swift +20 -0
  16. package/ios/main/StallionConstants.swift +1 -0
  17. package/ios/main/StallionDeviceInfo.swift +105 -0
  18. package/ios/main/StallionEventHandler.m +3 -1
  19. package/ios/main/StallionExceptionHandler.h +1 -0
  20. package/ios/main/StallionExceptionHandler.mm +293 -0
  21. package/ios/main/StallionFileDownloader.swift +9 -1
  22. package/ios/main/StallionMeta.h +11 -0
  23. package/ios/main/StallionMeta.m +76 -1
  24. package/ios/main/StallionSlotManager.m +1 -1
  25. package/ios/main/StallionSyncHandler.swift +14 -2
  26. package/package.json +1 -1
  27. package/react-native-stallion.podspec +22 -0
  28. package/src/main/components/modules/listing/components/BundleCardInfoSection.js +1 -1
  29. package/src/main/components/modules/listing/components/styles/index.js +18 -13
  30. package/src/main/components/modules/listing/components/styles/index.js.map +1 -1
  31. package/src/main/components/modules/listing/index.js +15 -15
  32. package/src/main/components/modules/listing/index.js.map +1 -1
  33. package/src/main/components/modules/listing/styles.js +2 -1
  34. package/src/main/components/modules/listing/styles.js.map +1 -1
  35. package/src/main/components/modules/login/index.js +8 -5
  36. package/src/main/components/modules/login/index.js.map +1 -1
  37. package/src/main/components/modules/login/styles/index.js +10 -4
  38. package/src/main/components/modules/login/styles/index.js.map +1 -1
  39. package/src/main/components/modules/modal/StallionModal.js +2 -2
  40. package/src/main/components/modules/modal/StallionModal.js.map +1 -1
  41. package/src/main/components/modules/prod/prod.js +5 -4
  42. package/src/main/components/modules/prod/prod.js.map +1 -1
  43. package/src/main/components/modules/prod/styles/index.js +7 -4
  44. package/src/main/components/modules/prod/styles/index.js.map +1 -1
  45. package/src/main/constants/appConstants.js +1 -0
  46. package/src/main/constants/appConstants.js.map +1 -1
  47. package/src/main/state/actionCreators/useUpdateMetaActions.js +2 -2
  48. package/src/main/state/actionCreators/useUpdateMetaActions.js.map +1 -1
  49. package/src/main/state/index.js +5 -3
  50. package/src/main/state/index.js.map +1 -1
  51. package/src/main/state/reducers/updateMetaReducer.js +8 -0
  52. package/src/main/state/reducers/updateMetaReducer.js.map +1 -1
  53. package/src/main/state/useStallionEvents.js +27 -4
  54. package/src/main/state/useStallionEvents.js.map +1 -1
  55. package/src/main/utils/ErrorBoundary.js +35 -9
  56. package/src/main/utils/ErrorBoundary.js.map +1 -1
  57. package/src/main/utils/crashState.js +16 -0
  58. package/src/main/utils/crashState.js.map +1 -0
  59. package/src/main/utils/useStallionUpdate.js +2 -2
  60. package/src/main/utils/useStallionUpdate.js.map +1 -1
  61. package/src/main/utils/withStallion.js +4 -2
  62. package/src/main/utils/withStallion.js.map +1 -1
  63. package/src/types/updateMeta.types.js +1 -0
  64. package/src/types/updateMeta.types.js.map +1 -1
  65. package/types/main/components/modules/listing/components/styles/index.d.ts +9 -4
  66. package/types/main/components/modules/listing/components/styles/index.d.ts.map +1 -1
  67. package/types/main/components/modules/listing/index.d.ts.map +1 -1
  68. package/types/main/components/modules/listing/styles.d.ts +1 -0
  69. package/types/main/components/modules/listing/styles.d.ts.map +1 -1
  70. package/types/main/components/modules/login/index.d.ts.map +1 -1
  71. package/types/main/components/modules/login/styles/index.d.ts +6 -0
  72. package/types/main/components/modules/login/styles/index.d.ts.map +1 -1
  73. package/types/main/components/modules/prod/prod.d.ts.map +1 -1
  74. package/types/main/components/modules/prod/styles/index.d.ts +5 -2
  75. package/types/main/components/modules/prod/styles/index.d.ts.map +1 -1
  76. package/types/main/constants/appConstants.d.ts +2 -0
  77. package/types/main/constants/appConstants.d.ts.map +1 -1
  78. package/types/main/index.d.ts +1 -1
  79. package/types/main/state/actionCreators/useUpdateMetaActions.d.ts.map +1 -1
  80. package/types/main/state/index.d.ts +4 -1
  81. package/types/main/state/index.d.ts.map +1 -1
  82. package/types/main/state/reducers/updateMetaReducer.d.ts +1 -0
  83. package/types/main/state/reducers/updateMetaReducer.d.ts.map +1 -1
  84. package/types/main/state/useStallionEvents.d.ts +4 -2
  85. package/types/main/state/useStallionEvents.d.ts.map +1 -1
  86. package/types/main/utils/ErrorBoundary.d.ts +1 -1
  87. package/types/main/utils/ErrorBoundary.d.ts.map +1 -1
  88. package/types/main/utils/crashState.d.ts +4 -0
  89. package/types/main/utils/crashState.d.ts.map +1 -0
  90. package/types/main/utils/useStallionUpdate.d.ts.map +1 -1
  91. package/types/main/utils/withStallion.d.ts +2 -1
  92. package/types/main/utils/withStallion.d.ts.map +1 -1
  93. package/types/types/updateMeta.types.d.ts +7 -2
  94. package/types/types/updateMeta.types.d.ts.map +1 -1
  95. package/types/types/utils.types.d.ts +1 -1
  96. package/types/types/utils.types.d.ts.map +1 -1
  97. package/ios/main/StallionExceptionHandler.m +0 -184
@@ -0,0 +1,83 @@
1
+ package com.stallion.utils;
2
+
3
+ import android.os.Build;
4
+
5
+ import com.stallion.storage.StallionConfig;
6
+
7
+ import org.json.JSONObject;
8
+
9
+ import java.util.Locale;
10
+ import java.util.TimeZone;
11
+
12
+ public class StallionDeviceInfo {
13
+
14
+ /**
15
+ * Sample JSON contract for deviceMeta
16
+ * {
17
+ * "osName": "Android",
18
+ * "osVersion": "14",
19
+ * "sdkInt": 34,
20
+ * "manufacturer": "Google",
21
+ * "brand": "google",
22
+ * "model": "Pixel 7",
23
+ * "device": "panther",
24
+ * "product": "panther",
25
+ * "hardware": "panther",
26
+ * "locale": "en-US",
27
+ * "localeLanguage": "en",
28
+ * "localeCountry": "US",
29
+ * "timezone": "America/Los_Angeles",
30
+ * "timezoneOffsetMinutes": -420,
31
+ * "isEmulator": false,
32
+ * "projectId": "<project-id>",
33
+ * "uid": "<device-uid>",
34
+ * "appVersion": "1.2.3"
35
+ * }
36
+ */
37
+ public static JSONObject getDeviceMetaJson(StallionConfig config) {
38
+ JSONObject json = new JSONObject();
39
+ try {
40
+ json.put("osName", "Android");
41
+ json.put("osVersion", Build.VERSION.RELEASE != null ? Build.VERSION.RELEASE : "");
42
+ json.put("sdkInt", Build.VERSION.SDK_INT);
43
+ json.put("manufacturer", Build.MANUFACTURER != null ? Build.MANUFACTURER : "");
44
+ json.put("brand", Build.BRAND != null ? Build.BRAND : "");
45
+ json.put("model", Build.MODEL != null ? Build.MODEL : "");
46
+ json.put("device", Build.DEVICE != null ? Build.DEVICE : "");
47
+ json.put("product", Build.PRODUCT != null ? Build.PRODUCT : "");
48
+ json.put("hardware", Build.HARDWARE != null ? Build.HARDWARE : "");
49
+ Locale defaultLocale = Locale.getDefault();
50
+ json.put("locale", defaultLocale != null ? defaultLocale.toLanguageTag() : "");
51
+ json.put("localeLanguage", defaultLocale != null ? defaultLocale.getLanguage() : "");
52
+ json.put("localeCountry", defaultLocale != null ? defaultLocale.getCountry() : "");
53
+ TimeZone tz = TimeZone.getDefault();
54
+ json.put("timezone", tz != null ? tz.getID() : "");
55
+ json.put("timezoneOffsetMinutes", tz != null ? (tz.getOffset(System.currentTimeMillis()) / 60000) : 0);
56
+ json.put("isEmulator", isProbablyEmulator());
57
+ if (config != null) {
58
+ json.put("projectId", config.getProjectId());
59
+ json.put("uid", config.getUid());
60
+ json.put("appVersion", config.getAppVersion());
61
+ }
62
+ } catch (Exception ignored) { }
63
+ return json;
64
+ }
65
+
66
+ private static boolean isProbablyEmulator() {
67
+ String fingerprint = Build.FINGERPRINT;
68
+ String model = Build.MODEL;
69
+ String manufacturer = Build.MANUFACTURER;
70
+ String brand = Build.BRAND;
71
+ String device = Build.DEVICE;
72
+ String product = Build.PRODUCT;
73
+
74
+ if (fingerprint != null && (fingerprint.startsWith("generic") || fingerprint.startsWith("unknown"))) return true;
75
+ if (model != null && (model.contains("google_sdk") || model.contains("Emulator") || model.contains("Android SDK built for x86"))) return true;
76
+ if (manufacturer != null && manufacturer.contains("Genymotion")) return true;
77
+ if (brand != null && brand.startsWith("generic") && device != null && device.startsWith("generic")) return true;
78
+ if (product != null && product.equals("google_sdk")) return true;
79
+ return false;
80
+ }
81
+ }
82
+
83
+
@@ -15,6 +15,8 @@ public class StallionExceptionHandler {
15
15
  private static Thread _exceptionThread;
16
16
  private static Throwable _exceptionThrowable;
17
17
  private static boolean isErrorBoundaryInitialized = false;
18
+ private static boolean isNativeSignalsInitialized = false;
19
+ private static boolean hasProcessedNativeCrashMarker = false;
18
20
 
19
21
  public static void initErrorBoundary() {
20
22
  if (isErrorBoundaryInitialized) {
@@ -44,6 +46,17 @@ public class StallionExceptionHandler {
44
46
  continueExceptionFlow();
45
47
  }
46
48
  });
49
+
50
+ // Initialize native signal handler once and process any prior crash marker
51
+ try {
52
+ if (!isNativeSignalsInitialized) {
53
+ System.loadLibrary("stallion-crash");
54
+ String filesDir = StallionStateManager.getInstance().getStallionConfig().getFilesDirectory();
55
+ initNativeSignalHandler(filesDir);
56
+ isNativeSignalsInitialized = true;
57
+ }
58
+ processNativeCrashMarkerIfPresent();
59
+ } catch (Throwable ignored) {}
47
60
  }
48
61
 
49
62
  private static void emitException(String stackTraceString, String releaseHash, boolean isAutoRollback, boolean isProd) {
@@ -52,13 +65,13 @@ public class StallionExceptionHandler {
52
65
  syncErrorPayload.put("meta", stackTraceString);
53
66
  syncErrorPayload.put("releaseHash", releaseHash);
54
67
  syncErrorPayload.put("isAutoRollback", Boolean.toString(isAutoRollback));
68
+ StallionEventManager.getInstance().sendEvent(
69
+ isProd ?
70
+ StallionEventConstants.NativeProdEventTypes.EXCEPTION_PROD.toString()
71
+ : StallionEventConstants.NativeStageEventTypes.EXCEPTION_STAGE.toString(),
72
+ syncErrorPayload
73
+ );
55
74
  } catch (Exception ignored) { }
56
- StallionEventManager.getInstance().sendEvent(
57
- isProd ?
58
- StallionEventConstants.NativeProdEventTypes.EXCEPTION_PROD.toString()
59
- : StallionEventConstants.NativeStageEventTypes.EXCEPTION_STAGE.toString(),
60
- syncErrorPayload
61
- );
62
75
  }
63
76
 
64
77
  private static void handleProdState(String stackTraceString, StallionStateManager stateManager) {
@@ -83,7 +96,9 @@ public class StallionExceptionHandler {
83
96
  // Emit exception event
84
97
  emitException(stackTraceString, currentStageHash, isAutoRollback, false);
85
98
 
86
- StallionSlotManager.rollbackStage();
99
+ if(isAutoRollback) {
100
+ StallionSlotManager.rollbackStage();
101
+ }
87
102
 
88
103
  continueExceptionFlow();
89
104
  }
@@ -93,4 +108,66 @@ public class StallionExceptionHandler {
93
108
  _androidUncaughtExceptionHandler.uncaughtException(_exceptionThread, _exceptionThrowable);
94
109
  }
95
110
  }
111
+
112
+ private static void processNativeCrashMarkerIfPresent() {
113
+ try {
114
+ if (hasProcessedNativeCrashMarker) { return; }
115
+ String filesDir = StallionStateManager.getInstance().getStallionConfig().getFilesDirectory();
116
+ java.io.File marker = new java.io.File(filesDir + "/stallion_crash.marker");
117
+ if (marker.exists()) {
118
+ StringBuilder sb = new StringBuilder();
119
+ try (java.io.BufferedReader br = new java.io.BufferedReader(new java.io.FileReader(marker))) {
120
+ String line;
121
+ while ((line = br.readLine()) != null) {
122
+ sb.append(line);
123
+ }
124
+ }
125
+
126
+ String jsonContent = sb.toString();
127
+ String stackTraceString = "";
128
+ boolean isAutoRollback = false;
129
+
130
+ try {
131
+ // Parse JSON from previous crash
132
+ JSONObject crashMarker = new JSONObject(jsonContent);
133
+ stackTraceString = crashMarker.optString("crashLog", "");
134
+ // Use the autoRollback flag that was determined at crash time (previous session)
135
+ isAutoRollback = crashMarker.optBoolean("isAutoRollback", false);
136
+ } catch (org.json.JSONException e) {
137
+ // Fallback for old format (non-JSON)
138
+ stackTraceString = jsonContent;
139
+ // Default to true for old format (conservative approach)
140
+ isAutoRollback = true;
141
+ }
142
+
143
+ if (stackTraceString.length() > 900) {
144
+ stackTraceString = stackTraceString.substring(0, 900) + "...";
145
+ }
146
+
147
+ StallionStateManager stateManager = StallionStateManager.getInstance();
148
+ StallionMetaConstants.SwitchState switchState = stateManager.stallionMeta.getSwitchState();
149
+ if (switchState == StallionMetaConstants.SwitchState.PROD) {
150
+ String currentHash = stateManager.stallionMeta.getHashAtCurrentProdSlot();
151
+ // Use isAutoRollback from previous crash, not current session state
152
+ emitException(stackTraceString, currentHash, isAutoRollback, true);
153
+ if (isAutoRollback) {
154
+ StallionSlotManager.rollbackProd(true, stackTraceString);
155
+ }
156
+ } else if (switchState == StallionMetaConstants.SwitchState.STAGE) {
157
+ String currentStageHash = stateManager.stallionMeta.getStageNewHash();
158
+ // Use isAutoRollback from previous crash, not current session state
159
+ emitException(stackTraceString, currentStageHash, isAutoRollback, false);
160
+ if (isAutoRollback) {
161
+ StallionSlotManager.rollbackStage();
162
+ }
163
+ }
164
+
165
+ // delete marker
166
+ StallionFileManager.deleteFileOrFolderSilently(marker);
167
+ hasProcessedNativeCrashMarker = true;
168
+ }
169
+ } catch (Exception ignored) {}
170
+ }
171
+
172
+ private static native void initNativeSignalHandler(String filesDir);
96
173
  }
@@ -9,6 +9,7 @@
9
9
  /* Begin PBXBuildFile section */
10
10
  5E555C0D2413F4C50049A1A2 /* Stallion.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* Stallion.m */; };
11
11
  F4FF95D7245B92E800C19C63 /* Stallion.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* Stallion.swift */; };
12
+ F4FF95DA245B92EB00C19C63 /* StallionDeviceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D9245B92EB00C19C63 /* StallionDeviceInfo.swift */; };
12
13
  /* End PBXBuildFile section */
13
14
 
14
15
  /* Begin PBXCopyFilesBuildPhase section */
@@ -28,6 +29,8 @@
28
29
  B3E7B5891CC2AC0600A0062D /* Stallion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Stallion.m; sourceTree = "<group>"; };
29
30
  F4FF95D5245B92E700C19C63 /* Stallion-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Stallion-Bridging-Header.h"; sourceTree = "<group>"; };
30
31
  F4FF95D6245B92E800C19C63 /* Stallion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stallion.swift; sourceTree = "<group>"; };
32
+ F4FF95D7245B92E900C19C63 /* StallionVersion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "StallionVersion.h"; sourceTree = "<group>"; };
33
+ F4FF95D9245B92EB00C19C63 /* StallionDeviceInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StallionDeviceInfo.swift"; sourceTree = "<group>"; };
31
34
  /* End PBXFileReference section */
32
35
 
33
36
  /* Begin PBXFrameworksBuildPhase section */
@@ -53,8 +56,10 @@
53
56
  isa = PBXGroup;
54
57
  children = (
55
58
  F4FF95D6245B92E800C19C63 /* Stallion.swift */,
59
+ F4FF95D9245B92EB00C19C63 /* StallionDeviceInfo.swift */,
56
60
  B3E7B5891CC2AC0600A0062D /* Stallion.m */,
57
61
  F4FF95D5245B92E700C19C63 /* Stallion-Bridging-Header.h */,
62
+ F4FF95D7245B92E900C19C63 /* StallionVersion.h */,
58
63
  134814211AA4EA7D00B7C361 /* Products */,
59
64
  );
60
65
  sourceTree = "<group>";
@@ -117,6 +122,7 @@
117
122
  buildActionMask = 2147483647;
118
123
  files = (
119
124
  F4FF95D7245B92E800C19C63 /* Stallion.swift in Sources */,
125
+ F4FF95DA245B92EB00C19C63 /* StallionDeviceInfo.swift in Sources */,
120
126
  B3E7B58A1CC2AC0600A0062D /* Stallion.m in Sources */,
121
127
  );
122
128
  runOnlyForDeploymentPostprocessing = 0;
@@ -30,6 +30,14 @@ class Stallion: RCTEventEmitter {
30
30
  @objc func onLaunch(_ launchData: String) {
31
31
  stallionStateManager.isMounted = true
32
32
  checkPendingDownloads()
33
+ let currentReleaseHash = stallionStateManager.stallionMeta.getHashAtCurrentProdSlot()
34
+ if let currentReleaseHash = currentReleaseHash {
35
+ if !currentReleaseHash.isEmpty && stallionStateManager.stallionMeta.getSuccessfulLaunchCount(currentReleaseHash) == 0 {
36
+ emitInstallEvent(currentReleaseHash)
37
+ }
38
+ stallionStateManager.stallionMeta.markSuccessfulLaunch(currentReleaseHash)
39
+ stallionStateManager.syncStallionMeta()
40
+ }
33
41
  }
34
42
 
35
43
  private func checkPendingDownloads() {
@@ -153,5 +161,17 @@ class Stallion: RCTEventEmitter {
153
161
  RCTTriggerReloadCommandListeners("Stallion: Restart")
154
162
  }
155
163
  }
164
+
165
+ private func emitInstallEvent(_ releaseHash: String) {
166
+ let eventPayload: [String: Any] = [
167
+ "releaseHash": releaseHash
168
+ ]
169
+
170
+ Stallion.sendEventToRn(
171
+ eventName: StallionConstants.NativeEventTypesProd.INSTALLED_PROD,
172
+ eventBody: eventPayload as NSDictionary,
173
+ shouldCache: false
174
+ )
175
+ }
156
176
  }
157
177
 
@@ -34,6 +34,7 @@ class StallionConstants {
34
34
  static let SecretKey = "secretKey"
35
35
  }
36
36
  static let PROGRESS_EVENT_THRESHOLD: Float = 0.05;
37
+ static let PROGRESS_THROTTLE_INTERVAL_MS: TimeInterval = 0.3; // 300ms
37
38
 
38
39
  static let PROD_DIRECTORY = "StallionProd"
39
40
  static let STAGE_DIRECTORY = "StallionStage"
@@ -0,0 +1,105 @@
1
+ //
2
+ // StallionDeviceInfo.swift
3
+ // react-native-stallion
4
+ //
5
+ // Created by Thor963 on 29/01/25.
6
+ //
7
+
8
+ import Foundation
9
+ import UIKit
10
+
11
+ class StallionDeviceInfo {
12
+
13
+ /**
14
+ * Sample JSON contract for deviceMeta
15
+ * {
16
+ * "osName": "iOS",
17
+ * "osVersion": "17.2",
18
+ * "sdkInt": 17,
19
+ * "manufacturer": "Apple",
20
+ * "brand": "Apple",
21
+ * "model": "iPhone 15 Pro",
22
+ * "device": "iPhone16,1",
23
+ * "product": "iPhone16,1",
24
+ * "hardware": "iPhone16,1",
25
+ * "locale": "en-US",
26
+ * "localeLanguage": "en",
27
+ * "localeCountry": "US",
28
+ * "timezone": "America/Los_Angeles",
29
+ * "timezoneOffsetMinutes": -420,
30
+ * "isEmulator": false,
31
+ * "projectId": "<project-id>",
32
+ * "uid": "<device-uid>",
33
+ * "appVersion": "1.2.3"
34
+ * }
35
+ */
36
+ static func getDeviceMetaJson(_ config: StallionConfig?) -> [String: Any] {
37
+ var json: [String: Any] = [:]
38
+
39
+ // OS Information
40
+ json["osName"] = "iOS"
41
+ json["osVersion"] = UIDevice.current.systemVersion
42
+ json["sdkInt"] = Int(UIDevice.current.systemVersion.components(separatedBy: ".").first ?? "0") ?? 0
43
+
44
+ // Device Information
45
+ json["manufacturer"] = "Apple"
46
+ json["brand"] = "Apple"
47
+ json["model"] = getDeviceModel()
48
+ json["device"] = getDeviceIdentifier()
49
+ json["product"] = getDeviceIdentifier()
50
+ json["hardware"] = getDeviceIdentifier()
51
+
52
+ // Locale Information
53
+ let locale = Locale.current
54
+ json["locale"] = locale.identifier
55
+ json["localeLanguage"] = locale.languageCode ?? ""
56
+ json["localeCountry"] = locale.regionCode ?? ""
57
+
58
+ // Timezone Information
59
+ let timezone = TimeZone.current
60
+ json["timezone"] = timezone.identifier
61
+ json["timezoneOffsetMinutes"] = timezone.secondsFromGMT() / 60
62
+
63
+ // Emulator Detection
64
+ json["isEmulator"] = isProbablyEmulator()
65
+
66
+ // Config Information
67
+ if let config = config {
68
+ json["projectId"] = config.projectId ?? ""
69
+ json["uid"] = config.uid ?? ""
70
+ json["appVersion"] = config.appVersion ?? ""
71
+ }
72
+
73
+ return json
74
+ }
75
+
76
+ private static func getDeviceModel() -> String {
77
+ var systemInfo = utsname()
78
+ uname(&systemInfo)
79
+ let modelCode = withUnsafePointer(to: &systemInfo.machine) {
80
+ $0.withMemoryRebound(to: CChar.self, capacity: 1) {
81
+ ptr in String.init(validatingUTF8: ptr)
82
+ }
83
+ }
84
+ return modelCode ?? "Unknown"
85
+ }
86
+
87
+ private static func getDeviceIdentifier() -> String {
88
+ var systemInfo = utsname()
89
+ uname(&systemInfo)
90
+ let identifier = withUnsafePointer(to: &systemInfo.machine) {
91
+ $0.withMemoryRebound(to: CChar.self, capacity: 1) {
92
+ ptr in String.init(validatingUTF8: ptr)
93
+ }
94
+ }
95
+ return identifier ?? "Unknown"
96
+ }
97
+
98
+ private static func isProbablyEmulator() -> Bool {
99
+ #if targetEnvironment(simulator)
100
+ return true
101
+ #else
102
+ return false
103
+ #endif
104
+ }
105
+ }
@@ -7,6 +7,7 @@
7
7
 
8
8
  #import "StallionEventHandler.h"
9
9
  #import "StallionStateManager.h"
10
+ #import "StallionVersion.h"
10
11
 
11
12
  #import <React/RCTBridge.h>
12
13
  #import <React/RCTEventDispatcher.h>
@@ -15,7 +16,7 @@
15
16
  static NSString *const STALLION_NATIVE_EVENT_NAME = @"STALLION_NATIVE_EVENT";
16
17
  static NSString *const EVENTS_KEY = @"stored_events";
17
18
  static NSInteger const MAX_BATCH_COUNT_SIZE = 9;
18
- static NSInteger const MAX_EVENT_STORAGE_LIMIT = 20;
19
+ static NSInteger const MAX_EVENT_STORAGE_LIMIT = 60;
19
20
 
20
21
  @implementation StallionEventHandler
21
22
 
@@ -45,6 +46,7 @@ static NSInteger const MAX_EVENT_STORAGE_LIMIT = 20;
45
46
  mutablePayload[@"platform"] = @"ios";
46
47
  mutablePayload[@"appVersion"] = appVersion;
47
48
  mutablePayload[@"uid"] = uid;
49
+ mutablePayload[@"sdkVersion"] = STALLION_SDK_VERSION;
48
50
  // Store event locally
49
51
  [self storeEventLocally:uniqueId eventPayload:mutablePayload];
50
52
  }
@@ -12,6 +12,7 @@ NS_ASSUME_NONNULL_BEGIN
12
12
  @interface StallionExceptionHandler : NSObject
13
13
 
14
14
  + (void)initExceptionHandler;
15
+ + (void)initJavaScriptExceptionHandler;
15
16
 
16
17
  @end
17
18