Skip to content

Commit 3989f26

Browse files
committed
feat: implement automatic crash reporting
1 parent 29f7d1a commit 3989f26

File tree

29 files changed

+673
-210
lines changed

29 files changed

+673
-210
lines changed

.github/workflows/test-flutter.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,27 @@ jobs:
2727
- name: Set up Flutter
2828
uses: ./.github/actions/setup-flutter
2929

30+
- name: Check version consistency
31+
run: |
32+
# Extract version from pubspec.yaml
33+
PUBSPEC_VERSION=$(grep '^version:' pubspec.yaml | sed 's/version: //' | tr -d ' ')
34+
35+
# Extract version from lib/version.dart
36+
VERSION_DART=$(grep 'const String nativebrikFlutterSdkVersion' lib/version.dart | sed "s/.*'\(.*\)'.*/\1/")
37+
38+
echo "pubspec.yaml version: $PUBSPEC_VERSION"
39+
echo "lib/version.dart version: $VERSION_DART"
40+
41+
if [ "$PUBSPEC_VERSION" != "$VERSION_DART" ]; then
42+
echo "Error: Version mismatch between pubspec.yaml ($PUBSPEC_VERSION) and lib/version.dart ($VERSION_DART)"
43+
echo "Please run 'make bump-version VERSION=x.y.z' to update both versions consistently"
44+
exit 1
45+
fi
46+
47+
echo "Version consistency check passed"
48+
49+
- name: Run tests
50+
run: flutter test
51+
3052
- name: Validate package
3153
run: dart pub publish --dry-run

CHANGELOG.md

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,46 @@
1+
## 0.14.0
2+
3+
- **Breaking Change**: Crash reporting is now automatic
4+
- Crash reporting is enabled by default when you initialize `NativebrikBridge`
5+
- Manual crash reporting setup is no longer needed
6+
- `NativebrikCrashReport` class is deprecated and will be removed in a future version
7+
- To opt-out: `NativebrikBridge("PROJECT_ID", trackCrashes: false)`
8+
9+
- **Migration Guide**:
10+
- **Before**:
11+
```dart
12+
void main() {
13+
runZonedGuarded(() {
14+
WidgetsFlutterBinding.ensureInitialized();
15+
NativebrikBridge("PROJECT_ID");
16+
FlutterError.onError = (errorDetails) {
17+
NativebrikCrashReport.instance.recordFlutterError(errorDetails);
18+
};
19+
PlatformDispatcher.instance.onError = (error, stack) {
20+
NativebrikCrashReport.instance.recordPlatformError(error, stack);
21+
return true;
22+
};
23+
runApp(const MyApp());
24+
}, (error, stack) {
25+
NativebrikCrashReport.instance.recordPlatformError(error, stack);
26+
});
27+
}
28+
```
29+
- **After**:
30+
```dart
31+
void main() {
32+
WidgetsFlutterBinding.ensureInitialized();
33+
NativebrikBridge("PROJECT_ID"); // Crash tracking enabled by default
34+
runApp(const MyApp());
35+
}
36+
```
37+
38+
- Update Dependencies
39+
- iOS: Nubrick 0.13.0 → 0.14.1
40+
- Android: Nubrick 0.8.0 → 0.8.2
41+
- Removed Yoga dependency (cleaner dependency tree)
42+
- Added stack_trace package for improved crash report parsing
43+
144
## 0.13.1
245
346
- Enhance tooltip feature
@@ -10,13 +53,8 @@
1053
- io.nubrick:nubrick to 0.8.1
1154
- Nubrick to 0.14.0
1255
13-
1456
## 0.12.0
1557
16-
- Update iOS dependencies
17-
- Bump version to 0.13.0
18-
- Restore CocoaPods support
19-
2058
## 0.11.0
2159
2260
- Update Dependencies

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ reinstall-android:
2323
define bump_version
2424
@NEW_VERSION=$$(echo "$(VERSION)" | awk -F. '{print $(1)}') && \
2525
sed -i '' "s/^version: .*/version: $$NEW_VERSION/" pubspec.yaml && \
26+
sed -i '' "s/const String nativebrikFlutterSdkVersion = '.*'/const String nativebrikFlutterSdkVersion = '$$NEW_VERSION'/" lib/version.dart && \
2627
echo "\n## $$NEW_VERSION\n\n- " >> CHANGELOG.md;
2728
make install
2829
endef

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ android {
5858
}
5959

6060
dependencies {
61-
implementation 'io.nubrick:nubrick:0.8.1'
61+
implementation 'io.nubrick:nubrick:0.8.2'
6262
implementation 'androidx.activity:activity-compose:1.8.2'
6363
testImplementation 'org.jetbrains.kotlin:kotlin-test'
6464
testImplementation 'org.mockito:mockito-core:5.0.0'

android/src/main/kotlin/com/nativebrik/flutter/nativebrik_bridge/Manager.kt

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package com.nativebrik.flutter.nativebrik_bridge
22

33
import android.content.Context
4+
import io.nubrick.nubrick.FlutterBridgeApi
45
import io.nubrick.nubrick.NubrickClient
56
import io.nubrick.nubrick.__DO_NOT_USE_THIS_INTERNAL_BRIDGE
7+
import io.nubrick.nubrick.data.ExceptionRecord
68
import io.nubrick.nubrick.data.NotFoundException
9+
import io.nubrick.nubrick.data.StackFrame
10+
import io.nubrick.nubrick.data.TrackCrashEvent
711
import io.flutter.plugin.platform.PlatformView
812
import io.flutter.plugin.platform.PlatformViewFactory
913
import io.flutter.plugin.common.StandardMessageCodec
@@ -25,6 +29,7 @@ import kotlinx.coroutines.launch
2529

2630
internal data class ConfigEntity(val variant: RemoteConfigVariant?, val experimentId: String?)
2731

32+
@OptIn(FlutterBridgeApi::class)
2833
internal class NativebrikBridgeManager(private val binaryMessenger: BinaryMessenger) {
2934
private var nativebrikClient: NubrickClient? = null
3035
private var bridgeClient: __DO_NOT_USE_THIS_INTERNAL_BRIDGE? = null
@@ -214,12 +219,54 @@ internal class NativebrikBridgeManager(private val binaryMessenger: BinaryMessen
214219
}
215220

216221
/**
217-
* Records a crash with the given throwable.
222+
* Records exceptions from Flutter.
218223
*
219-
* This method forwards the throwable to the Nativebrik SDK for crash reporting.
224+
* This method constructs a crash event and forwards it to the Nativebrik SDK for crash reporting
225+
* with platform set to "flutter".
220226
*/
221-
fun recordCrash(throwable: Throwable) {
222-
this.nativebrikClient?.experiment?.record(throwable)
227+
fun recordFlutterExceptions(exceptionsList: List<Map<String, Any?>>, flutterSdkVersion: String?) {
228+
try {
229+
val exceptions = exceptionsList.mapNotNull { exceptionMap ->
230+
try {
231+
val type = exceptionMap["type"] as? String
232+
val message = exceptionMap["message"] as? String
233+
val callStacksList = exceptionMap["callStacks"] as? List<*>
234+
235+
val callStacks = callStacksList?.mapNotNull { frameMap ->
236+
try {
237+
val frame = frameMap as? Map<*, *>
238+
StackFrame(
239+
fileName = frame?.get("fileName") as? String,
240+
className = frame?.get("className") as? String,
241+
methodName = frame?.get("methodName") as? String,
242+
lineNumber = (frame?.get("lineNumber") as? Number)?.toInt()
243+
)
244+
} catch (e: Exception) {
245+
null
246+
}
247+
}
248+
249+
ExceptionRecord(
250+
type = type,
251+
message = message,
252+
callStacks = callStacks
253+
)
254+
} catch (e: Exception) {
255+
null
256+
}
257+
}
258+
259+
if (exceptions.isNotEmpty()) {
260+
val crashEvent = TrackCrashEvent(
261+
exceptions = exceptions,
262+
platform = "flutter",
263+
flutterSdkVersion = flutterSdkVersion
264+
)
265+
this.nativebrikClient?.experiment?.sendFlutterCrash(crashEvent)
266+
}
267+
} catch (e: Exception) {
268+
// Silently fail to avoid causing crashes in error reporting
269+
}
223270
}
224271
}
225272

android/src/main/kotlin/com/nativebrik/flutter/nativebrik_bridge/NativebrikBridgePlugin.kt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -200,17 +200,22 @@ class NativebrikBridgePlugin: FlutterPlugin, MethodCallHandler {
200200
}
201201
"recordCrash" -> {
202202
try {
203-
val errorData = call.arguments as Map<*, *>
204-
val exception = errorData["exception"] as String
205-
val stackTrace = errorData["stack"] as String
203+
val errorData = call.arguments as? Map<*, *>
204+
if (errorData == null) {
205+
result.error("CRASH_REPORT_ERROR", "Invalid error data format", null)
206+
return
207+
}
206208

207-
// Create a throwable with the Flutter error information
208-
val throwable = Throwable(exception).apply {
209-
this.stackTrace = parseStackTraceElements(stackTrace)
209+
val exceptionsList = errorData["exceptions"] as? List<*>
210+
if (exceptionsList == null) {
211+
result.error("CRASH_REPORT_ERROR", "Missing exceptions list", null)
212+
return
210213
}
211214

212-
// Record the crash using the Nativebrik SDK
213-
this.manager.recordCrash(throwable)
215+
val exceptions = exceptionsList.mapNotNull { it as? Map<*, *> }
216+
.map { it.mapKeys { entry -> entry.key.toString() } }
217+
val flutterSdkVersion = errorData["flutterSdkVersion"] as? String
218+
this.manager.recordFlutterExceptions(exceptions, flutterSdkVersion)
214219
result.success("ok")
215220
} catch (e: Exception) {
216221
result.error("CRASH_REPORT_ERROR", "Failed to record crash: ${e.message}", null)

e2e/ios/Flutter/AppFrameworkInfo.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@
2121
<key>CFBundleVersion</key>
2222
<string>1.0</string>
2323
<key>MinimumOSVersion</key>
24-
<string>12.0</string>
24+
<string>13.0</string>
2525
</dict>
2626
</plist>

e2e/ios/Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Uncomment this line to define a global platform for your project
2-
# platform :ios, '12.0'
2+
# platform :ios, '13.0'
33

44
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
55
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

e2e/ios/Podfile.lock

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
PODS:
22
- Flutter (1.0.0)
3+
- nativebrik_bridge (0.0.1):
4+
- Flutter
5+
- Nubrick (= 0.14.1)
6+
- Nubrick (0.14.1)
37

48
DEPENDENCIES:
59
- Flutter (from `Flutter`)
10+
- nativebrik_bridge (from `.symlinks/plugins/nativebrik_bridge/ios`)
11+
12+
SPEC REPOS:
13+
trunk:
14+
- Nubrick
615

716
EXTERNAL SOURCES:
817
Flutter:
918
:path: Flutter
1019

1120
SPEC CHECKSUMS:
12-
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
21+
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
22+
nativebrik_bridge: 07c281be5ad485adf32670ccd554e9e839e4cf7c
23+
Nubrick: 4d4a94ddcc67597abea0552deedeff817ac4bc96
1324

14-
PODFILE CHECKSUM: 4305caec6b40dde0ae97be1573c53de1882a07e5
25+
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e
1526

1627
COCOAPODS: 1.16.2

e2e/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@
444444
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
445445
GCC_WARN_UNUSED_FUNCTION = YES;
446446
GCC_WARN_UNUSED_VARIABLE = YES;
447-
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
447+
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
448448
MTL_ENABLE_DEBUG_INFO = NO;
449449
SDKROOT = iphoneos;
450450
SUPPORTED_PLATFORMS = iphoneos;
@@ -579,7 +579,7 @@
579579
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
580580
GCC_WARN_UNUSED_FUNCTION = YES;
581581
GCC_WARN_UNUSED_VARIABLE = YES;
582-
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
582+
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
583583
MTL_ENABLE_DEBUG_INFO = YES;
584584
ONLY_ACTIVE_ARCH = YES;
585585
SDKROOT = iphoneos;
@@ -630,7 +630,7 @@
630630
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
631631
GCC_WARN_UNUSED_FUNCTION = YES;
632632
GCC_WARN_UNUSED_VARIABLE = YES;
633-
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
633+
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
634634
MTL_ENABLE_DEBUG_INFO = NO;
635635
SDKROOT = iphoneos;
636636
SUPPORTED_PLATFORMS = iphoneos;

0 commit comments

Comments
 (0)