diff --git a/lib/.env.dart.example b/lib/.env.dart.example index 260b8ff03..f3d1dd34a 100644 --- a/lib/.env.dart.example +++ b/lib/.env.dart.example @@ -1,5 +1,4 @@ class Config { - static const String PLATFORM = 'web'; static const String API_SECRET = 'secret'; static const String SENTRY_DNS = 'dns'; diff --git a/lib/data/repositories/auth_repository.dart b/lib/data/repositories/auth_repository.dart index f9877b8b1..a72b629ca 100644 --- a/lib/data/repositories/auth_repository.dart +++ b/lib/data/repositories/auth_repository.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:core'; +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:invoiceninja_flutter/.env.dart'; @@ -33,7 +34,7 @@ class AuthRepository { 'last_name': lastName, 'terms_of_service': true, 'privacy_policy': true, - 'token_name': '${Config.PLATFORM.toLowerCase()}-client', + 'token_name': _tokenName, }; if ((url ?? '').isEmpty) { @@ -91,7 +92,7 @@ class AuthRepository { Future addCompany({String token}) async { final data = { - 'token_name': '${Config.PLATFORM.toLowerCase()}-client', + 'token_name': _tokenName, }; return webClient.post('/companies', token, data: json.encode(data)); @@ -128,4 +129,7 @@ class AuthRepository { return serializers.deserializeWith(LoginResponse.serializer, response); } + + String get _tokenName => + kIsWeb ? 'web' : Platform.isAndroid ? 'android' : 'ios'; } diff --git a/lib/main.dart b/lib/main.dart index f70bd3f14..ecfc30fae 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -45,6 +45,7 @@ import 'package:invoiceninja_flutter/ui/settings/tax_settings_vm.dart'; import 'package:invoiceninja_flutter/utils/colors.dart'; import 'package:invoiceninja_flutter/utils/localization.dart'; import 'package:invoiceninja_flutter/utils/platforms.dart'; +import 'package:invoiceninja_flutter/utils/sentry.dart'; import 'package:local_auth/local_auth.dart'; import 'package:redux/redux.dart'; import 'package:redux_logging/redux_logging.dart'; @@ -77,16 +78,11 @@ import 'package:invoiceninja_flutter/redux/company_gateway/company_gateway_middl void main({bool isTesting = false}) async { WidgetsFlutterBinding.ensureInitialized(); - //final packageInfo = await PackageInfo.fromPlatform(); final SentryClient _sentry = Config.SENTRY_DNS.isEmpty ? null : SentryClient( dsn: Config.SENTRY_DNS, - environmentAttributes: Event( - //release: packageInfo.version, - release: kAppVersion, - environment: Config.PLATFORM, - )); + environmentAttributes: await getSentryEvent()); final store = Store(appReducer, initialState: await _initialState(isTesting), @@ -121,35 +117,29 @@ void main({bool isTesting = false}) async { ), ])); - Future _reportError(dynamic error, dynamic stackTrace) async { - print('Caught error: $error'); - if (kDebugMode) { - print(stackTrace); - return; - } else { - _sentry.captureException( - exception: error, - stackTrace: stackTrace, - ); - } - } - if (_sentry == null) { runApp(InvoiceNinjaApp(store: store)); } else { runZoned>(() async { runApp(InvoiceNinjaApp(store: store)); - }, onError: (dynamic error, dynamic stackTrace) { - if (store.state.reportErrors) { - _reportError(error, stackTrace); + }, onError: (dynamic exception, dynamic stackTrace) async { + if (kDebugMode) { + print(stackTrace); + } else if (store.state.reportErrors) { + final event = await getSentryEvent( + state: store.state, + exception: exception, + stackTrace: stackTrace, + ); + _sentry.capture(event: event); } }); } FlutterError.onError = (FlutterErrorDetails details) { - if (kDebugMode || !store.state.reportErrors) { + if (kDebugMode) { FlutterError.dumpErrorToConsole(details); - } else { + } else if (store.state.reportErrors) { Zone.current.handleUncaughtError(details.exception, details.stack); } }; diff --git a/lib/utils/sentry.dart b/lib/utils/sentry.dart new file mode 100644 index 000000000..ec7e3fe44 --- /dev/null +++ b/lib/utils/sentry.dart @@ -0,0 +1,64 @@ +import 'dart:io'; + +import 'package:device_info/device_info.dart'; +import 'package:flutter/foundation.dart'; +import 'package:invoiceninja_flutter/constants.dart'; +import 'package:invoiceninja_flutter/redux/app/app_state.dart'; +import 'package:sentry/sentry.dart'; + +Future getSentryEvent( + {AppState state, dynamic exception, dynamic stackTrace}) async { + OperatingSystem os; + Device device; + + if (kIsWeb) { + // TODO track web info + os = OperatingSystem( + name: 'Web', + ); + } else { + //final packageInfo = await PackageInfo.fromPlatform(); + final deviceInfo = DeviceInfoPlugin(); + + if (Platform.isAndroid) { + final androidInfo = await deviceInfo.androidInfo; + os = OperatingSystem( + name: 'Android', + version: androidInfo.version.release, + ); + device = Device( + model: androidInfo.model, + manufacturer: androidInfo.manufacturer, + modelId: androidInfo.product, + ); + } else if (Platform.isIOS) { + final iosInfo = await deviceInfo.iosInfo; + os = OperatingSystem( + name: iosInfo.systemName, + version: iosInfo.systemVersion, + ); + device = Device( + model: iosInfo.utsname.machine, + manufacturer: 'Apple', + family: iosInfo.model, + ); + } + } + + return Event( + release: kAppVersion, + //release: packageInfo.version, + environment: state.isHosted ? 'Hosted' : 'Selfhosted', + stackTrace: stackTrace, + exception: exception, + contexts: Contexts( + operatingSystem: os, + device: device, + app: App( + version: kAppVersion, + //name: packageInfo.appName, + //version: packageInfo.version, + //build: packageInfo.buildNumber, + )), + ); +} diff --git a/pubspec.lock b/pubspec.lock index 2912c65ee..13b5a4e9f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -190,6 +190,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.3" + device_info: + dependency: "direct main" + description: + name: device_info + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.2+1" extended_image: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7dadd2eac..0396d5036 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,6 +43,7 @@ dependencies: flutter_typeahead: ^1.8.0 flutter_share: ^1.0.2+1 package_info: ^0.4.0+16 + device_info: ^0.4.2+1 #quick_actions: ^0.2.1 dev_dependencies: