appambit 0.1.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.
Files changed (52) hide show
  1. package/Appambit.podspec +22 -0
  2. package/LICENSE +20 -0
  3. package/README.md +191 -0
  4. package/android/build.gradle +78 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/com/appambit/AppambitAnalyticsModule.kt +56 -0
  8. package/android/src/main/java/com/appambit/AppambitCrashesModule.kt +90 -0
  9. package/android/src/main/java/com/appambit/AppambitModule.kt +22 -0
  10. package/android/src/main/java/com/appambit/AppambitPackage.kt +42 -0
  11. package/ios/AppAmbitAnalytics.h +5 -0
  12. package/ios/AppAmbitAnalytics.mm +45 -0
  13. package/ios/AppAmbitCrashes.h +5 -0
  14. package/ios/AppAmbitCrashes.mm +80 -0
  15. package/ios/AppAmbitSDKWrapper.swift +79 -0
  16. package/ios/Appambit.h +13 -0
  17. package/ios/Appambit.mm +17 -0
  18. package/lib/module/NativeAppambitAnalytics.js +5 -0
  19. package/lib/module/NativeAppambitAnalytics.js.map +1 -0
  20. package/lib/module/NativeAppambitCore.js +5 -0
  21. package/lib/module/NativeAppambitCore.js.map +1 -0
  22. package/lib/module/NativeAppambitCrashes.js +5 -0
  23. package/lib/module/NativeAppambitCrashes.js.map +1 -0
  24. package/lib/module/index.js +99 -0
  25. package/lib/module/index.js.map +1 -0
  26. package/lib/module/package.json +1 -0
  27. package/lib/typescript/appambit_test_app/src/App.d.ts +2 -0
  28. package/lib/typescript/appambit_test_app/src/App.d.ts.map +1 -0
  29. package/lib/typescript/appambit_test_app/src/components/CustomButton.d.ts +8 -0
  30. package/lib/typescript/appambit_test_app/src/components/CustomButton.d.ts.map +1 -0
  31. package/lib/typescript/appambit_test_app/src/components/CustomInput.d.ts +10 -0
  32. package/lib/typescript/appambit_test_app/src/components/CustomInput.d.ts.map +1 -0
  33. package/lib/typescript/appambit_test_app/src/screens/AnalyticsScreen.d.ts +2 -0
  34. package/lib/typescript/appambit_test_app/src/screens/AnalyticsScreen.d.ts.map +1 -0
  35. package/lib/typescript/appambit_test_app/src/screens/CrashesScreen.d.ts +2 -0
  36. package/lib/typescript/appambit_test_app/src/screens/CrashesScreen.d.ts.map +1 -0
  37. package/lib/typescript/appambit_test_app/src/utils/uuid.d.ts +2 -0
  38. package/lib/typescript/appambit_test_app/src/utils/uuid.d.ts.map +1 -0
  39. package/lib/typescript/package.json +1 -0
  40. package/lib/typescript/src/NativeAppambitAnalytics.d.ts +14 -0
  41. package/lib/typescript/src/NativeAppambitAnalytics.d.ts.map +1 -0
  42. package/lib/typescript/src/NativeAppambitCore.d.ts +7 -0
  43. package/lib/typescript/src/NativeAppambitCore.d.ts.map +1 -0
  44. package/lib/typescript/src/NativeAppambitCrashes.d.ts +23 -0
  45. package/lib/typescript/src/NativeAppambitCrashes.d.ts.map +1 -0
  46. package/lib/typescript/src/index.d.ts +24 -0
  47. package/lib/typescript/src/index.d.ts.map +1 -0
  48. package/package.json +164 -0
  49. package/src/NativeAppambitAnalytics.ts +14 -0
  50. package/src/NativeAppambitCore.ts +7 -0
  51. package/src/NativeAppambitCrashes.ts +23 -0
  52. package/src/index.tsx +138 -0
@@ -0,0 +1,22 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "Appambit"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported }
14
+ s.source = { :git => "https://github.com/AppAmbit/appambit-sdk-react-native.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = "ios/**/*.{h,m,mm,cpp,swift}"
17
+ s.private_header_files = "ios/**/*.h"
18
+
19
+ s.dependency 'AppAmbitSdk', '~> 0.1.0'
20
+
21
+ install_modules_dependencies(s)
22
+ end
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 AppAmbit
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # AppAmbit React Native SDK
2
+
3
+ **Track. Debug. Distribute.**
4
+ **AppAmbit: track, debug, and distribute your apps from one dashboard.**
5
+
6
+ Lightweight SDK for analytics, events, logging, crashes, and offline support. Simple setup, minimal overhead.
7
+
8
+ > Full product docs live here: **[docs.appambit.com](https://docs.appambit.com)**
9
+
10
+ ---
11
+
12
+ ## Contents
13
+
14
+ * [Features](#features)
15
+ * [Requirements](#requirements)
16
+ * [Install](#install)
17
+ * [Quickstart](#quickstart)
18
+ * [Usage](#usage)
19
+ * [Release Distribution](#release-distribution)
20
+ * [Privacy and Data](#privacy-and-data)
21
+ * [Troubleshooting](#troubleshooting)
22
+ * [Contributing](#contributing)
23
+ * [Versioning](#versioning)
24
+ * [Security](#security)
25
+ * [License](#license)
26
+
27
+ ---
28
+
29
+ ## Features
30
+
31
+ * Session analytics with automatic lifecycle tracking
32
+ * Event tracking with custom properties
33
+ * Error logging for quick diagnostics
34
+ * Crash capture with stack traces and threads
35
+ * Offline support with batching, retry, and queue
36
+ * Create multiple app profiles for staging and production
37
+ * Small footprint
38
+
39
+ ---
40
+
41
+ ## Requirements
42
+
43
+ - Node >= 20
44
+ - Yarn >=3.6.1
45
+ - **Android SDK with:**
46
+ - Android 5.0+
47
+ - compileSdkVersion 34
48
+ - targetSdkVersion 34
49
+ - minSdkVersion 21
50
+ - **iOS SDK with:**
51
+ - Xcode 15+ (for iOS)
52
+ - macOS 13+
53
+
54
+ ---
55
+
56
+
57
+ ## Install
58
+
59
+ ### NPM
60
+
61
+ Add the package to your React Native project:
62
+
63
+ ```bash
64
+ npm install appambit
65
+ # or specify version
66
+ npm install appambit@0.1.0
67
+ ```
68
+ ---
69
+
70
+ ## Quickstart
71
+
72
+ Initialize the SDK with your **API key**.
73
+
74
+ ### Javascript
75
+
76
+ ```javascript
77
+ export default function App() {
78
+ useEffect(() => {
79
+ start("<YOUR-APPKEY>");
80
+ }, []);
81
+ }
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Android App Requirements
87
+
88
+ Add these permissions to your `AndroidManifest.xml`:
89
+
90
+ ```xml
91
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
92
+ <uses-permission android:name="android.permission.INTERNET" />
93
+ ```
94
+
95
+ ---
96
+
97
+ ## Usage
98
+
99
+ * **Session activity** – automatically tracks user session starts, stops, and durations
100
+ * **Track events** – send structured events with custom properties
101
+
102
+ ```javascript
103
+ trackEvent("ButtonClicked", {"Count": "41"})
104
+ ```
105
+ * **Logs**: add structured log messages for debugging
106
+
107
+ ```javascript
108
+ try {
109
+ throw new Error();
110
+ } catch (e) {
111
+ logError(
112
+ { stack: e.stack,
113
+ exception: e,
114
+ classFqn: e.constructor.name,
115
+ properties: {"user_id": "1"} },
116
+ );
117
+ }
118
+ ```
119
+ * **Crash Reporting**: uncaught crashes are automatically captured and uploaded on next launch
120
+
121
+ ---
122
+
123
+ ## Release Distribution
124
+
125
+ Upload your APK, AAB, or IPA directly to your AppAmbit dashboard.
126
+ Distribute release builds through:
127
+ * Direct install links
128
+ * Email distribution
129
+ * Environment-specific channels
130
+
131
+ ---
132
+
133
+ ## Privacy and Data
134
+
135
+ * The SDK batches and transmits data efficiently
136
+ * You control what is sent — avoid secrets or sensitive PII
137
+ * Supports compliance with Google Play policies
138
+
139
+ For details, see the docs: **[docs.appambit.com](https://docs.appambit.com)**
140
+
141
+ ---
142
+
143
+ ## Troubleshooting
144
+
145
+ * **No data in dashboard** → check API key, endpoint, and network access
146
+ * **React Native dependency not resolving** → run `npm install` or `yarn install` and verify again
147
+ * **Crash not appearing** → crashes are sent on next launch
148
+
149
+ ---
150
+
151
+ ## Contributing
152
+
153
+ We welcome issues and pull requests.
154
+
155
+ * Fork the repo
156
+ * Create a feature branch
157
+ * Add tests where applicable
158
+ * Open a PR with a clear summary
159
+
160
+ Please follow React Native API design guidelines and document public APIs.
161
+
162
+ ---
163
+
164
+ ## Versioning
165
+
166
+ Semantic Versioning (`MAJOR.MINOR.PATCH`) is used.
167
+
168
+ * Breaking changes → **major**
169
+ * New features → **minor**
170
+ * Fixes → **patch**
171
+
172
+ ---
173
+
174
+ ## Security
175
+
176
+ If you find a security issue, please contact us at **[hello@appambit.com](mailto:hello@appambit.com)** rather than opening a public issue.
177
+
178
+ ---
179
+
180
+ ## License
181
+
182
+ Open source under the terms described in the [LICENSE](./LICENSE) file.
183
+
184
+ ---
185
+
186
+ ## Links
187
+
188
+ * **Docs**: [docs.appambit.com](https://docs.appambit.com)
189
+ * **Dashboard**: [appambit.com](https://appambit.com)
190
+ * **Discord**: [discord.gg](https://discord.gg/nJyetYue2s)
191
+ * **Examples**: Sample React Native test app included in repo.
@@ -0,0 +1,78 @@
1
+ buildscript {
2
+ ext.getExtOrDefault = {name ->
3
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['Appambit_' + name]
4
+ }
5
+
6
+ repositories {
7
+ google()
8
+ mavenCentral()
9
+ }
10
+
11
+ dependencies {
12
+ classpath "com.android.tools.build:gradle:8.7.2"
13
+ // noinspection DifferentKotlinGradleVersion
14
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
15
+ }
16
+ }
17
+
18
+
19
+ apply plugin: "com.android.library"
20
+ apply plugin: "kotlin-android"
21
+
22
+ apply plugin: "com.facebook.react"
23
+
24
+ def getExtOrIntegerDefault(name) {
25
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Appambit_" + name]).toInteger()
26
+ }
27
+
28
+ android {
29
+ namespace "com.appambit"
30
+
31
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
32
+
33
+ defaultConfig {
34
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
35
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
36
+ }
37
+
38
+ buildFeatures {
39
+ buildConfig true
40
+ }
41
+
42
+ buildTypes {
43
+ release {
44
+ minifyEnabled false
45
+ }
46
+ }
47
+
48
+ lintOptions {
49
+ disable "GradleCompatible"
50
+ }
51
+
52
+ compileOptions {
53
+ sourceCompatibility JavaVersion.VERSION_1_8
54
+ targetCompatibility JavaVersion.VERSION_1_8
55
+ }
56
+
57
+ sourceSets {
58
+ main {
59
+ java.srcDirs += [
60
+ "generated/java",
61
+ "generated/jni"
62
+ ]
63
+ }
64
+ }
65
+ }
66
+
67
+ repositories {
68
+ mavenCentral()
69
+ google()
70
+ }
71
+
72
+ def kotlin_version = getExtOrDefault("kotlinVersion")
73
+
74
+ dependencies {
75
+ implementation "com.facebook.react:react-android"
76
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
77
+ implementation "com.appambit:appambit:0.1.0"
78
+ }
@@ -0,0 +1,5 @@
1
+ Appambit_kotlinVersion=2.0.21
2
+ Appambit_minSdkVersion=21
3
+ Appambit_targetSdkVersion=34
4
+ Appambit_compileSdkVersion=35
5
+ Appambit_ndkVersion=27.1.12297006
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,56 @@
1
+ package com.appambit
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+ import com.facebook.react.bridge.ReadableMapKeySetIterator
5
+ import com.facebook.react.bridge.ReadableMap as RNReadableMap
6
+
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.facebook.react.module.annotations.ReactModule
9
+ import com.appambit.sdk.Analytics
10
+
11
+ @ReactModule(name = AppambitAnalyticsModule.NAME)
12
+ class AppambitAnalyticsModule(reactContext: ReactApplicationContext) :
13
+ NativeAppambitAnalyticsSpec(reactContext) {
14
+
15
+ override fun getName(): String {
16
+ return NAME
17
+ }
18
+
19
+ override fun setUserId(userId: String?) {
20
+ Analytics.setUserId(userId)
21
+ }
22
+
23
+ override fun setUserEmail(userEmail: String?) {
24
+ Analytics.setUserEmail(userEmail)
25
+ }
26
+
27
+ override fun clearToken() {
28
+ Analytics.clearToken()
29
+ }
30
+
31
+ override fun startSession() {
32
+ Analytics.startSession()
33
+ }
34
+
35
+ override fun endSession() {
36
+ Analytics.endSession()
37
+ }
38
+
39
+ override fun enableManualSession() {
40
+ Analytics.enableManualSession()
41
+ }
42
+
43
+ override fun trackEvent(eventTitle: String, properties: ReadableMap?) {
44
+ val props: MutableMap<String, String>? = properties?.toHashMap()
45
+ ?.mapValues { it.value.toString() }
46
+ ?.toMutableMap()
47
+ Analytics.trackEvent(eventTitle, props)
48
+ }
49
+ override fun generateTestEvent() {
50
+ Analytics.generateTestEvent()
51
+ }
52
+
53
+ companion object {
54
+ const val NAME = "AppAmbitAnalytics"
55
+ }
56
+ }
@@ -0,0 +1,90 @@
1
+ package com.appambit
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+ import com.facebook.react.bridge.ReadableMapKeySetIterator
5
+ import com.facebook.react.bridge.ReadableMap as RNReadableMap
6
+ import com.facebook.react.bridge.Promise
7
+ import com.facebook.react.bridge.ReactMethod
8
+
9
+ import com.facebook.react.bridge.ReactApplicationContext
10
+ import com.facebook.react.module.annotations.ReactModule
11
+ import com.appambit.sdk.Crashes
12
+ @ReactModule(name = AppambitCrashesModule.NAME)
13
+ class AppambitCrashesModule(reactContext: ReactApplicationContext) :
14
+ NativeAppambitCrashesSpec(reactContext) {
15
+
16
+ override fun getName(): String {
17
+ return NAME
18
+ }
19
+
20
+ @ReactMethod
21
+ override fun didCrashInLastSession(promise: Promise) {
22
+ try {
23
+ val crashed = Crashes.didCrashInLastSession()
24
+ promise.resolve(crashed)
25
+ } catch (e: Exception) {
26
+ promise.reject("DID_CRASH_ERROR", e)
27
+ }
28
+ }
29
+
30
+ override fun generateTestCrash() {
31
+ Thread {
32
+ Crashes.generateTestCrash()
33
+ }.start()
34
+ }
35
+
36
+ override fun logErrorMessage(message: String, properties: ReadableMap?) {
37
+
38
+ val props: MutableMap<String, String> = properties?.toHashMap()
39
+ ?.mapValues { it.value.toString() }
40
+ ?.toMutableMap() ?: mutableMapOf()
41
+
42
+ Crashes.logError(message, props)
43
+ }
44
+
45
+ override fun logError(errorMap: ReadableMap) {
46
+ val map = errorMap.toHashMap()
47
+
48
+ val message = map["message"]?.toString() ?: "Unknown error"
49
+ val stack = map["stack"]?.toString()
50
+ val classFqn = map["classFqn"]?.toString()
51
+ val fileName = map["fileName"]?.toString()
52
+
53
+ val lineNumber = try {
54
+ when (val lineNum = map["lineNumber"]) {
55
+ is Number -> lineNum.toInt()
56
+ is String -> lineNum.toIntOrNull()
57
+ else -> null
58
+ }
59
+ } catch (e: Exception) {
60
+ null
61
+ }
62
+
63
+ val properties: Map<String, String> =
64
+ ((map["properties"] as? Map<*, *>)?.map { (k, v) ->
65
+ k.toString() to v.toString()
66
+ }?.toMap()) ?: emptyMap()
67
+
68
+ val finalProperties = properties.toMutableMap()
69
+
70
+ val exception = Exception(message)
71
+
72
+ if (!stack.isNullOrEmpty()) {
73
+ val stackTraceElements: Array<StackTraceElement> = stack.lines().map { line ->
74
+ StackTraceElement(
75
+ classFqn,
76
+ line,
77
+ fileName,
78
+ lineNumber ?: 0
79
+ )
80
+ }.toTypedArray()
81
+
82
+ exception.stackTrace = stackTraceElements
83
+ }
84
+ Crashes.logError(exception, finalProperties.toMap())
85
+ }
86
+
87
+ companion object {
88
+ const val NAME = "AppAmbitCrashes"
89
+ }
90
+ }
@@ -0,0 +1,22 @@
1
+ package com.appambit
2
+
3
+ import com.facebook.react.bridge.ReactApplicationContext
4
+ import com.facebook.react.module.annotations.ReactModule
5
+ import com.appambit.sdk.AppAmbit
6
+
7
+ @ReactModule(name = AppambitModule.NAME)
8
+ class AppambitModule(reactContext: ReactApplicationContext) :
9
+ NativeAppambitCoreSpec(reactContext) {
10
+
11
+ override fun getName(): String {
12
+ return NAME
13
+ }
14
+
15
+ override fun start(appkey: String) {
16
+ AppAmbit.start(reactApplicationContext, appkey)
17
+ }
18
+
19
+ companion object {
20
+ const val NAME = "AppAmbitCore"
21
+ }
22
+ }
@@ -0,0 +1,42 @@
1
+ package com.appambit
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+ import java.util.HashMap
9
+
10
+ class AppambitPackage : BaseReactPackage() {
11
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
12
+ return when (name) {
13
+ AppambitModule.NAME -> AppambitModule(reactContext)
14
+ AppambitCrashesModule.NAME -> AppambitCrashesModule(reactContext)
15
+ AppambitAnalyticsModule.NAME -> AppambitAnalyticsModule(reactContext)
16
+ else -> null
17
+ }
18
+ }
19
+
20
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
21
+ return ReactModuleInfoProvider {
22
+ val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
23
+
24
+ fun addInfo(name: String) {
25
+ moduleInfos[name] = ReactModuleInfo(
26
+ name,
27
+ name,
28
+ false,
29
+ false,
30
+ false,
31
+ true
32
+ )
33
+ }
34
+
35
+ addInfo(AppambitModule.NAME)
36
+ addInfo(AppambitCrashesModule.NAME)
37
+ addInfo(AppambitAnalyticsModule.NAME)
38
+
39
+ moduleInfos
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,5 @@
1
+ #import <AppambitSpec/AppambitSpec.h>
2
+
3
+ @interface AppAmbitAnalytics : NSObject <NativeAppambitAnalyticsSpec>
4
+
5
+ @end
@@ -0,0 +1,45 @@
1
+ #import "Appambit.h"
2
+ #import <Appambit-Swift.h>
3
+
4
+ @implementation AppAmbitAnalytics
5
+ RCT_EXPORT_MODULE(AppAmbitAnalytics);
6
+
7
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
8
+ (const facebook::react::ObjCTurboModule::InitParams &)params
9
+ {
10
+ return std::make_shared<facebook::react::NativeAppambitAnalyticsSpecJSI>(params);
11
+ }
12
+
13
+ - (void)clearToken {
14
+ [AppAmbitSdkWrapper clearToken];
15
+ }
16
+
17
+ - (void)enableManualSession {
18
+ [AppAmbitSdkWrapper enableManualSession];
19
+ }
20
+
21
+ - (void)startSession {
22
+ [AppAmbitSdkWrapper startSession];
23
+ }
24
+
25
+ - (void)endSession {
26
+ [AppAmbitSdkWrapper endSession];
27
+ }
28
+
29
+ - (void)generateTestEvent {
30
+ [AppAmbitSdkWrapper generateTestEvent];
31
+ }
32
+
33
+ - (void)setUserEmail:(nonnull NSString *)email {
34
+ [AppAmbitSdkWrapper setUserEmailWithUserEmail:email];
35
+ }
36
+
37
+ - (void)setUserId:(nonnull NSString *)userId {
38
+ [AppAmbitSdkWrapper setUserIdWithUserId:userId];
39
+ }
40
+
41
+ - (void)trackEvent:(nonnull NSString *)eventTitle properties:(nonnull NSDictionary *)properties {
42
+ [AppAmbitSdkWrapper trackEventWithEventTitle:eventTitle properties:properties];
43
+ }
44
+
45
+ @end
@@ -0,0 +1,5 @@
1
+ #import <AppambitSpec/AppambitSpec.h>
2
+
3
+ @interface AppAmbitCrashes : NSObject <NativeAppambitCrashesSpec>
4
+
5
+ @end
@@ -0,0 +1,80 @@
1
+ #import "Appambit.h"
2
+ #import <Appambit-Swift.h>
3
+
4
+ @implementation AppAmbitCrashes
5
+ RCT_EXPORT_MODULE(AppAmbitCrashes);
6
+
7
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
8
+ (const facebook::react::ObjCTurboModule::InitParams &)params
9
+ {
10
+ return std::make_shared<facebook::react::NativeAppambitCrashesSpecJSI>(params);
11
+ }
12
+
13
+ - (void)didCrashInLastSession:(RCTPromiseResolveBlock)resolve
14
+ reject:(RCTPromiseRejectBlock)reject {
15
+ [AppAmbitSdkWrapper didCrashInLastSessionWithCompletion:^(BOOL crashed) {
16
+ resolve(@(crashed));
17
+ }];
18
+ }
19
+
20
+ - (void)generateTestCrash {
21
+ [AppAmbitSdkWrapper generateTestCrash];
22
+ }
23
+
24
+ - (void)logErrorMessage:(nonnull NSString *)errorTitle properties:(nonnull NSDictionary *)properties {
25
+ [AppAmbitSdkWrapper logErrorWithMessage:errorTitle properties:properties];
26
+ }
27
+
28
+ - (void)logError:(JS::NativeAppambitCrashes::ErrorPayload &)payload {
29
+
30
+ NSString *rawMessage = payload.message();
31
+ NSString *stack = payload.stack();
32
+ NSString *classFqn = payload.classFqn() ?: @"JSException";
33
+ NSString *fileName = payload.fileName();
34
+ NSNumber *lineNumber = payload.lineNumber().has_value()
35
+ ? @(payload.lineNumber().value())
36
+ : nil;
37
+
38
+ NSDictionary *rawProps = nil;
39
+ if ([payload.properties() isKindOfClass:[NSDictionary class]]) {
40
+ rawProps = (NSDictionary *)payload.properties();
41
+ }
42
+
43
+ NSString *derivedMessage = @"JS Error";
44
+ if (stack && stack.length > 0) {
45
+ NSArray *lines = [stack componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
46
+ if (lines.count > 0) {
47
+ derivedMessage = lines.firstObject;
48
+ }
49
+ }
50
+
51
+ NSString *finalMessage = (rawMessage && ![rawMessage isEqualToString:@"{}"] && rawMessage.length > 0)
52
+ ? rawMessage
53
+ : derivedMessage;
54
+
55
+ NSMutableDictionary<NSString*, NSString*> *properties = [NSMutableDictionary dictionary];
56
+ if (rawProps) {
57
+ [rawProps enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
58
+ properties[key] = [value description];
59
+ }];
60
+ }
61
+
62
+ NSMutableDictionary *userInfo = [@{
63
+ NSLocalizedDescriptionKey: finalMessage,
64
+ @"classFqn": classFqn ?: @"Unknown"
65
+ } mutableCopy];
66
+
67
+ if (stack) userInfo[@"stackTrace"] = stack;
68
+ if (fileName) userInfo[@"fileName"] = fileName;
69
+ if (lineNumber) userInfo[@"lineNumber"] = lineNumber;
70
+ if (properties.count > 0) userInfo[@"properties"] = properties;
71
+
72
+ NSError *error = [NSError errorWithDomain:@"com.appambit.react.error"
73
+ code:-1
74
+ userInfo:userInfo];
75
+
76
+ [AppAmbitSdkWrapper logErrorWithException:error properties:properties];
77
+ }
78
+
79
+
80
+ @end