Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.firebase.crashlytics.internal.Logger;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
Expand All @@ -34,9 +35,11 @@

/** FlutterFirebaseCrashlyticsPlugin */
public class FlutterFirebaseCrashlyticsPlugin
implements FlutterFirebasePlugin, FlutterPlugin, MethodCallHandler {
implements FlutterFirebasePlugin, FlutterPlugin, MethodCallHandler, EventChannel.StreamHandler {
public static final String TAG = "FLTFirebaseCrashlytics";
private MethodChannel channel;
private EventChannel testEventChannel;
private EventChannel.EventSink testEventSink;

private static final String FIREBASE_CRASHLYTICS_COLLECTION_ENABLED =
"firebase_crashlytics_collection_enabled";
Expand All @@ -46,6 +49,9 @@ private void initInstance(BinaryMessenger messenger) {
channel = new MethodChannel(messenger, channelName);
channel.setMethodCallHandler(this);
FlutterFirebasePluginRegistry.registerPlugin(channelName, this);
testEventChannel =
new EventChannel(messenger, "plugins.flutter.io/firebase_crashlytics_test_stream");
testEventChannel.setStreamHandler(this);
}

@Override
Expand All @@ -59,6 +65,10 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
channel = null;
}
if (testEventChannel != null) {
testEventChannel.setStreamHandler(null);
testEventChannel = null;
}
}

private Task<Map<String, Object>> checkForUnsentReports() {
Expand Down Expand Up @@ -134,6 +144,7 @@ private Task<Map<String, Object>> didCrashOnPreviousExecution() {

private Task<Void> recordError(final Map<String, Object> arguments) {
TaskCompletionSource<Void> taskCompletionSource = new TaskCompletionSource<>();
Handler mainHandler = new Handler(Looper.getMainLooper());

cachedThreadPool.execute(
() -> {
Expand All @@ -160,8 +171,10 @@ private Task<Void> recordError(final Map<String, Object> arguments) {

Exception exception;
if (reason != null) {
final String crashlyticsErrorReason = "thrown " + reason;
mainHandler.post(() -> testEventSink.success(crashlyticsErrorReason));
// Set a "reason" (to match iOS) to show where the exception was thrown.
crashlytics.setCustomKey(Constants.FLUTTER_ERROR_REASON, "thrown " + reason);
crashlytics.setCustomKey(Constants.FLUTTER_ERROR_REASON, crashlyticsErrorReason);
exception =
new FlutterError(dartExceptionMessage + ". " + "Error thrown " + reason + ".");
} else {
Expand Down Expand Up @@ -466,4 +479,14 @@ public Task<Void> didReinitializeFirebaseCore() {

return taskCompletionSource.getTask();
}

@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
testEventSink = events;
}

@Override
public void onCancel(Object arguments) {
testEventSink = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#endif

NSString *const kFLTFirebaseCrashlyticsChannelName = @"plugins.flutter.io/firebase_crashlytics";
NSString *const kFLTFirebaseCrashlyticsTestChannelName =
@"plugins.flutter.io/firebase_crashlytics_test_stream";

// Argument Keys
NSString *const kCrashlyticsArgumentException = @"exception";
Expand All @@ -34,6 +36,11 @@
NSString *const kCrashlyticsArgumentUnsentReports = @"unsentReports";
NSString *const kCrashlyticsArgumentDidCrashOnPreviousExecution = @"didCrashOnPreviousExecution";

@interface FLTFirebaseCrashlyticsPlugin () <FlutterStreamHandler>
@property(nonatomic, strong) FlutterEventChannel *testEventChannel;
@property(nonatomic, strong) FlutterEventSink testEventSink;
@end

@implementation FLTFirebaseCrashlyticsPlugin

#pragma mark - FlutterPlugin
Expand Down Expand Up @@ -61,6 +68,10 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
binaryMessenger:[registrar messenger]];
FLTFirebaseCrashlyticsPlugin *instance = [FLTFirebaseCrashlyticsPlugin sharedInstance];
[registrar addMethodCallDelegate:instance channel:channel];
instance.testEventChannel =
[FlutterEventChannel eventChannelWithName:kFLTFirebaseCrashlyticsTestChannelName
binaryMessenger:[registrar messenger]];
[instance.testEventChannel setStreamHandler:instance];
}

- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)flutterResult {
Expand Down Expand Up @@ -126,10 +137,13 @@ - (void)recordError:(id)arguments withMethodCallResult:(FLTFirebaseMethodCallRes
}

if (![reason isEqual:[NSNull null]]) {
reason = [NSString stringWithFormat:@"%@. Error thrown %@.", dartExceptionMessage, reason];
NSString *crashlyticsErrorReason = [NSString stringWithFormat:@"thrown %@", reason];

self.testEventSink(crashlyticsErrorReason);
// Log additional custom value to match Android.
[[FIRCrashlytics crashlytics] setCustomValue:[NSString stringWithFormat:@"thrown %@", reason]
forKey:@"flutter_error_reason"];
reason = [NSString stringWithFormat:@"%@. Error thrown %@.", dartExceptionMessage, reason];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a test to test the output? and make sure it matches between the platforms?

} else {
reason = dartExceptionMessage;
}
Expand Down Expand Up @@ -247,4 +261,15 @@ - (NSString *_Nonnull)flutterChannelName {
return kFLTFirebaseCrashlyticsChannelName;
}

- (FlutterError *_Nullable)onCancelWithArguments:(id _Nullable)arguments {
self.testEventSink = nil;
return nil;
}

- (FlutterError *_Nullable)onListenWithArguments:(id _Nullable)arguments
eventSink:(nonnull FlutterEventSink)events {
self.testEventSink = events;
return nil;
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:tests/firebase_options.dart';
import '../e2e_test.dart';
import 'dart:async';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
Expand Down Expand Up @@ -98,6 +101,31 @@ void main() {
);
},
);

test(
'should have consistent error reason format',
() async {
const eventChannel = EventChannel('plugins.flutter.io/firebase_crashlytics_test_stream');
final eventStream = eventChannel.receiveBroadcastStream();

final completer = Completer<String>();

eventStream.listen((event) {
print('Received event: $event');
completer.complete(event.toString());
});

await FirebaseCrashlytics.instance.recordError(
'foo exception',
StackTrace.fromString('during testing'),
reason: 'foo reason',
);

final event = await completer.future;
expect(event, 'thrown foooo reason');
},
skip: kIsWeb || defaultTargetPlatform == TargetPlatform.macOS || !isCI,
);
});

group('log', () {
Expand Down
Loading