Skip to content

Commit ea92a2c

Browse files
Merge branch 'dev' into release
2 parents 187857d + 6a91375 commit ea92a2c

16 files changed

Lines changed: 621 additions & 24 deletions

File tree

android/app/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ plugins {
1111
id("com.android.application")
1212
id("kotlin-android")
1313
id("com.google.gms.google-services")
14+
id("com.google.firebase.crashlytics")
1415
id("dev.flutter.flutter-gradle-plugin")
1516
}
1617

@@ -71,6 +72,7 @@ repositories {
7172
dependencies {
7273
implementation(platform("com.google.firebase:firebase-bom:34.4.0"))
7374
implementation("com.google.firebase:firebase-analytics")
75+
implementation("com.google.firebase:firebase-crashlytics")
7476
implementation("com.google.android.ump:user-messaging-platform:3.1.0")
7577

7678
// Android TV support

android/app/src/main/kotlin/com/defyx/defyx/MainActivity.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ class MainActivity : FlutterActivity() {
5757

5858
EventChannel(flutterEngine.dartExecutor.binaryMessenger, "com.defyx.progress_events")
5959
.setStreamHandler(ProgressStreamHandler())
60+
61+
EventChannel(flutterEngine.dartExecutor.binaryMessenger, "com.defyx.crash_events")
62+
.setStreamHandler(CrashStreamHandler())
6063
}
6164
private fun grantNotificationPermission() {
6265
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
@@ -451,3 +454,35 @@ class ProgressStreamHandler : EventChannel.StreamHandler, ProgressListener {
451454
CoroutineScope(Dispatchers.Main).launch { eventSink?.success(msg) }
452455
}
453456
}
457+
458+
class CrashStreamHandler : EventChannel.StreamHandler {
459+
460+
private var eventSink: EventChannel.EventSink? = null
461+
462+
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
463+
this.eventSink = events
464+
465+
// Register crash callback with Go library
466+
Android.setCrashCallback(object : android.CrashListener {
467+
override fun onCrash(functionName: String, errorMessage: String, stackTrace: String) {
468+
// Forward crash info to Flutter via event channel
469+
CoroutineScope(Dispatchers.Main).launch {
470+
eventSink?.success(
471+
mapOf(
472+
"functionName" to functionName,
473+
"errorMessage" to errorMessage,
474+
"stackTrace" to stackTrace,
475+
"platform" to "android"
476+
)
477+
)
478+
}
479+
}
480+
})
481+
}
482+
483+
override fun onCancel(arguments: Any?) {
484+
this.eventSink = null
485+
// Optionally unregister callback
486+
Android.setCrashCallback(null)
487+
}
488+
}

android/settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ plugins {
2121
id("com.android.application") version "8.9.1" apply false
2222
// START: FlutterFire Configuration
2323
id("com.google.gms.google-services") version("4.3.15") apply false
24+
id("com.google.firebase.crashlytics") version "3.0.2" apply false
2425
// END: FlutterFire Configuration
2526
id("org.jetbrains.kotlin.android") version "2.1.21" apply false
2627
}

ios/Podfile.lock

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,20 @@ PODS:
4646
- Flutter
4747
- Firebase/CoreOnly (12.4.0):
4848
- FirebaseCore (~> 12.4.0)
49+
- Firebase/Crashlytics (12.4.0):
50+
- Firebase/CoreOnly
51+
- FirebaseCrashlytics (~> 12.4.0)
4952
- firebase_analytics (12.0.4):
5053
- firebase_core
5154
- FirebaseAnalytics (= 12.4.0)
5255
- Flutter
5356
- firebase_core (4.2.1):
5457
- Firebase/CoreOnly (= 12.4.0)
5558
- Flutter
59+
- firebase_crashlytics (5.0.5):
60+
- Firebase/Crashlytics (= 12.4.0)
61+
- firebase_core
62+
- Flutter
5663
- FirebaseAnalytics (12.4.0):
5764
- FirebaseAnalytics/Default (= 12.4.0)
5865
- FirebaseCore (~> 12.4.0)
@@ -75,13 +82,34 @@ PODS:
7582
- FirebaseCoreInternal (~> 12.4.0)
7683
- GoogleUtilities/Environment (~> 8.1)
7784
- GoogleUtilities/Logger (~> 8.1)
85+
- FirebaseCoreExtension (12.4.0):
86+
- FirebaseCore (~> 12.4.0)
7887
- FirebaseCoreInternal (12.4.0):
7988
- "GoogleUtilities/NSData+zlib (~> 8.1)"
89+
- FirebaseCrashlytics (12.4.0):
90+
- FirebaseCore (~> 12.4.0)
91+
- FirebaseInstallations (~> 12.4.0)
92+
- FirebaseRemoteConfigInterop (~> 12.4.0)
93+
- FirebaseSessions (~> 12.4.0)
94+
- GoogleDataTransport (~> 10.1)
95+
- GoogleUtilities/Environment (~> 8.1)
96+
- nanopb (~> 3.30910.0)
97+
- PromisesObjC (~> 2.4)
8098
- FirebaseInstallations (12.4.0):
8199
- FirebaseCore (~> 12.4.0)
82100
- GoogleUtilities/Environment (~> 8.1)
83101
- GoogleUtilities/UserDefaults (~> 8.1)
84102
- PromisesObjC (~> 2.4)
103+
- FirebaseRemoteConfigInterop (12.4.0)
104+
- FirebaseSessions (12.4.0):
105+
- FirebaseCore (~> 12.4.0)
106+
- FirebaseCoreExtension (~> 12.4.0)
107+
- FirebaseInstallations (~> 12.4.0)
108+
- GoogleDataTransport (~> 10.1)
109+
- GoogleUtilities/Environment (~> 8.1)
110+
- GoogleUtilities/UserDefaults (~> 8.1)
111+
- nanopb (~> 3.30910.0)
112+
- PromisesSwift (~> 2.1)
85113
- Flutter (1.0.0)
86114
- flutter_native_splash (2.4.3):
87115
- Flutter
@@ -122,6 +150,9 @@ PODS:
122150
- GoogleUtilities/Network (~> 8.1)
123151
- "GoogleUtilities/NSData+zlib (~> 8.1)"
124152
- nanopb (~> 3.30910.0)
153+
- GoogleDataTransport (10.1.0):
154+
- nanopb (~> 3.30910.0)
155+
- PromisesObjC (~> 2.4)
125156
- GoogleUserMessagingPlatform (3.0.0)
126157
- GoogleUtilities/AppDelegateSwizzler (8.1.0):
127158
- GoogleUtilities/Environment
@@ -161,6 +192,8 @@ PODS:
161192
- Flutter
162193
- FlutterMacOS
163194
- PromisesObjC (2.4.0)
195+
- PromisesSwift (2.4.0):
196+
- PromisesObjC (= 2.4.0)
164197
- SDWebImage (5.21.7):
165198
- SDWebImage/Core (= 5.21.7)
166199
- SDWebImage/Core (5.21.7)
@@ -187,6 +220,7 @@ DEPENDENCIES:
187220
- file_picker (from `.symlinks/plugins/file_picker/ios`)
188221
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
189222
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
223+
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
190224
- Flutter (from `Flutter`)
191225
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
192226
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
@@ -208,15 +242,21 @@ SPEC REPOS:
208242
- Firebase
209243
- FirebaseAnalytics
210244
- FirebaseCore
245+
- FirebaseCoreExtension
211246
- FirebaseCoreInternal
247+
- FirebaseCrashlytics
212248
- FirebaseInstallations
249+
- FirebaseRemoteConfigInterop
250+
- FirebaseSessions
213251
- Google-Mobile-Ads-SDK
214252
- GoogleAdsOnDeviceConversion
215253
- GoogleAppMeasurement
254+
- GoogleDataTransport
216255
- GoogleUserMessagingPlatform
217256
- GoogleUtilities
218257
- nanopb
219258
- PromisesObjC
259+
- PromisesSwift
220260
- SDWebImage
221261
- SwiftyGif
222262

@@ -237,6 +277,8 @@ EXTERNAL SOURCES:
237277
:path: ".symlinks/plugins/firebase_analytics/ios"
238278
firebase_core:
239279
:path: ".symlinks/plugins/firebase_core/ios"
280+
firebase_crashlytics:
281+
:path: ".symlinks/plugins/firebase_crashlytics/ios"
240282
Flutter:
241283
:path: Flutter
242284
flutter_native_splash:
@@ -274,10 +316,15 @@ SPEC CHECKSUMS:
274316
Firebase: f07b15ae5a6ec0f93713e30b923d9970d144af3e
275317
firebase_analytics: 67fbdd9f3c04e55048024f3da21cfc36f05e56cf
276318
firebase_core: f1aafb21c14f497e5498f7ffc4dc63cbb52b2594
319+
firebase_crashlytics: c039028126cb45e32f4c217aa392408b0963d081
277320
FirebaseAnalytics: 0fc2b20091f0ddd21bf73397cf8f0eb5346dc24f
278321
FirebaseCore: bb595f3114953664e3c1dc032f008a244147cfd3
322+
FirebaseCoreExtension: 7e1f7118ee970e001a8013719fb90950ee5e0018
279323
FirebaseCoreInternal: d7f5a043c2cd01a08103ab586587c1468047bca6
324+
FirebaseCrashlytics: a6ece278a837c7e88de2d9b5da0a3542f2342395
280325
FirebaseInstallations: ae9f4902cb5bf1d0c5eaa31ec1f4e5495a0714e2
326+
FirebaseRemoteConfigInterop: 1e31ec72b89c9924367c59bfb5ec9ab60d1d6766
327+
FirebaseSessions: ba7c7a7ca8696a8d540eb3fe3800fbe98c79786d
281328
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
282329
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
283330
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
@@ -286,12 +333,14 @@ SPEC CHECKSUMS:
286333
google_mobile_ads: 535223588a6791b7a3cc3513a1bc7b89d12f3e62
287334
GoogleAdsOnDeviceConversion: e03a386840803ea7eef3fd22a061930142c039c1
288335
GoogleAppMeasurement: 1e718274b7e015cefd846ac1fcf7820c70dc017d
336+
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
289337
GoogleUserMessagingPlatform: f8d0cdad3ca835406755d0a69aa634f00e76d576
290338
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
291339
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
292340
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
293341
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
294342
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
343+
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
295344
SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf
296345
sensors_plus: 6a11ed0c2e1d0bd0b20b4029d3bad27d96e0c65b
297346
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb

ios/Runner/AppDelegate.swift

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,14 @@ import Flutter
3232
let progressHandler = ProgressStreamHandler()
3333
progressChannel.setStreamHandler(progressHandler)
3434

35+
let crashChannel = FlutterEventChannel(
36+
name: "com.defyx.crash_events",
37+
binaryMessenger: controller.binaryMessenger)
38+
let crashHandler = CrashStreamHandler()
39+
crashChannel.setStreamHandler(crashHandler)
40+
3541
getLogs(progressHandler)
42+
getCrashes(crashHandler)
3643
}
3744

3845
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
@@ -63,6 +70,32 @@ import Flutter
6370
defaults.synchronize()
6471
}
6572
}
73+
74+
func getCrashes(_ crashHandler: CrashStreamHandler) {
75+
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
76+
guard let defaults = UserDefaults(suiteName: "group.de.unboundtech.defyxvpn"),
77+
var crashes = defaults.array(forKey: "go_crashes") as? [[String: String]],
78+
!crashes.isEmpty
79+
else { return }
80+
81+
let crashesToSend = crashes
82+
83+
for crash in crashesToSend {
84+
crashHandler.send(crash)
85+
}
86+
87+
var currentCrashes = defaults.array(forKey: "go_crashes") as? [[String: String]] ?? []
88+
89+
if currentCrashes.count >= crashesToSend.count {
90+
currentCrashes.removeFirst(crashesToSend.count)
91+
} else {
92+
currentCrashes.removeAll()
93+
}
94+
95+
defaults.set(currentCrashes, forKey: "go_crashes")
96+
defaults.synchronize()
97+
}
98+
}
6699
}
67100

68101
class ProgressStreamHandler: NSObject, FlutterStreamHandler {
@@ -105,3 +138,23 @@ class StatusStreamHandler: NSObject, FlutterStreamHandler {
105138
return nil
106139
}
107140
}
141+
142+
class CrashStreamHandler: NSObject, FlutterStreamHandler {
143+
private var eventSink: FlutterEventSink?
144+
145+
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink)
146+
-> FlutterError?
147+
{
148+
self.eventSink = events
149+
return nil
150+
}
151+
152+
func onCancel(withArguments arguments: Any?) -> FlutterError? {
153+
self.eventSink = nil
154+
return nil
155+
}
156+
157+
func send(_ crashInfo: [String: String]) {
158+
eventSink?(crashInfo)
159+
}
160+
}

ios/Runner/VPNPlugin.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ class VpnPlugin: VpnStatusDelegate {
1717
VpnService.shared.statusDelegate = self
1818
let progressStream = ProgressStreamHandlerIOS()
1919
IosSetProgressListener(progressStream)
20+
21+
// Set up crash callback
22+
let crashHandler = CrashStreamHandlerIOS()
23+
IosSetCrashCallback(crashHandler)
2024
}
2125

2226
// MARK: - Event Sink
@@ -438,3 +442,33 @@ class ProgressStreamHandlerIOS: NSObject, IosProgressListenerProtocol {
438442
}
439443
}
440444
}
445+
446+
class CrashStreamHandlerIOS: NSObject, IosCrashListenerProtocol {
447+
func onCrash(_ functionName: String?, errorMessage: String?, stackTrace: String?) {
448+
// Store crash info in UserDefaults for main app to retrieve
449+
if let defaults = UserDefaults(suiteName: "group.de.unboundtech.defyxvpn") {
450+
var crashes = defaults.array(forKey: "go_crashes") as? [[String: String]] ?? []
451+
452+
let crashInfo: [String: String] = [
453+
"functionName": functionName ?? "unknown",
454+
"errorMessage": errorMessage ?? "unknown",
455+
"stackTrace": stackTrace ?? "",
456+
"platform": "ios",
457+
"timestamp": ISO8601DateFormatter().string(from: Date())
458+
]
459+
460+
crashes.append(crashInfo)
461+
462+
// Keep only last 100 crashes to avoid excessive storage
463+
if crashes.count > 100 {
464+
crashes = Array(crashes.suffix(100))
465+
}
466+
467+
defaults.set(crashes, forKey: "go_crashes")
468+
defaults.synchronize()
469+
470+
// Also log to console for debugging
471+
print("🔥 Go panic recovered: \(functionName ?? "unknown") - \(errorMessage ?? "unknown")")
472+
}
473+
}
474+
}

0 commit comments

Comments
 (0)