Skip to content

Commit

Permalink
🔀 Merge pull request #6 from catoverse/feature/cloud-logger
Browse files Browse the repository at this point in the history
App Analytics
  • Loading branch information
algokun committed Jun 24, 2021
2 parents 7dd2d8b + 74799af commit 6925f35
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 58 deletions.
2 changes: 2 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ if (flutterVersionName == null) {

apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

Expand Down Expand Up @@ -79,4 +80,5 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation platform('com.google.firebase:firebase-bom:28.0.1')
implementation 'com.google.firebase:firebase-analytics-ktx'
implementation 'com.google.firebase:firebase-crashlytics-ktx'
}
1 change: 1 addition & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.8'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.0'
}
}

Expand Down
7 changes: 5 additions & 2 deletions lib/app/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:feed/core/services/environment_service.dart';
import 'package:feed/core/services/explode_service.dart';
import 'package:feed/core/services/key_storage_service.dart';
import 'package:feed/firebase/analytics.dart';
import 'package:feed/firebase/crashlytics.dart';
import 'package:feed/firebase/dynamic_links.dart';
import 'package:feed/core/services/hive_service/hive_service.dart';
import 'package:feed/core/services/hive_service/hive_service_impl.dart';
Expand All @@ -27,7 +28,6 @@ import 'package:stacked_firebase_auth/stacked_firebase_auth.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:stacked/stacked_annotations.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';

import 'injection.dart';

/// The @StackedApp annotation generates
Expand Down Expand Up @@ -93,8 +93,11 @@ import 'injection.dart';
LazySingleton(classType: FeedService),
LazySingleton(classType: DynamicLinksService),
LazySingleton(classType: AnalyticsService),
LazySingleton(
classType: CrashlyticsService,
resolveUsing: CrashlyticsService.getInstance),
],
logger: StackedLogger(),
logger: StackedLogger(loggerOutputs: [CrashlyticsOutput]),
)
class AppSetup {
/** Serves no purpose besides having an annotation attached to it */
Expand Down
2 changes: 2 additions & 0 deletions lib/app/app.locator.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 3 additions & 8 deletions lib/app/app.logger.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions lib/core/services/environment_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ class EnvironmentService {

/// Returns the value associated with the key
String getValue(String key, {bool verbose = false}) {
final value = env[key] ?? NoKey;
final value = dotenv.env[key] ?? NoKey;
if (verbose) log.v('key:$key value:$value');
return value;
}

static Future<EnvironmentService> getInstance() async {
print('Load environment');
await load(fileName: ".env");
await dotenv.load(fileName: ".env");
print('Environement loaded');
return Future.value(EnvironmentService());
}
Expand Down
3 changes: 3 additions & 0 deletions lib/core/services/user_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:feed/core/models/app_models.dart';

import 'package:feed/core/services/hive_service/hive_service.dart';
import 'package:feed/core/services/key_storage_service.dart';
import 'package:feed/firebase/analytics.dart';
import 'package:feed/remote/api/api_service.dart';
import 'package:feed/remote/client.dart';
import 'package:stacked_firebase_auth/stacked_firebase_auth.dart';
Expand All @@ -15,6 +16,7 @@ class UserService {
final _apiService = locator<APIService>();
final _remoteClient = locator<RemoteClient>();
final _hiveService = locator<HiveService>();
final _crashlytics = locator<AnalyticsService>();
final _authService = locator<FirebaseAuthenticationService>();

User? _loggedInUser;
Expand Down Expand Up @@ -89,6 +91,7 @@ class UserService {

_loggedInUser = authUser;
_remoteClient.updateToken(newToken: authUser.token);
_crashlytics.setUserIdentifier(currentUser.id);

return true;
}
Expand Down
41 changes: 41 additions & 0 deletions lib/firebase/analytics.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,50 @@
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_analytics/observer.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/foundation.dart';

class AnalyticsService {
final FirebaseAnalytics _analytics = FirebaseAnalytics();

FirebaseAnalyticsObserver getAnalyticsObserver() =>
FirebaseAnalyticsObserver(analytics: _analytics);

Future logAppOpen() async {
if (kReleaseMode) {
await _analytics.logAppOpen();
}
}

void logLogin() {
if (kReleaseMode) {
_analytics.logLogin(loginMethod: 'google');
}
}

Future logShare(String itemId,
{String contentType = 'Post', String method = 'in_app_share'}) async {
if (kReleaseMode) {
await _analytics.logShare(
contentType: contentType,
itemId: itemId,
method: method,
);
}
}

Future logEvent(String name, {Map<String, dynamic> params = const {}}) async {
if (kReleaseMode) {
await _analytics.logEvent(
name: name,
parameters: params,
);
}
}

void setUserIdentifier(String userId) {
if (kReleaseMode) {
FirebaseCrashlytics.instance.setUserIdentifier(userId);
_analytics.setUserId(userId);
}
}
}
73 changes: 73 additions & 0 deletions lib/firebase/crashlytics.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';

class CrashlyticsService {
static CrashlyticsService? _instance;

static CrashlyticsService getInstance() {
if (_instance == null) {
_instance = CrashlyticsService._(FirebaseCrashlytics.instance);
}

return _instance!;
}

final FirebaseCrashlytics _crashlyticsService;
CrashlyticsService._(
this._crashlyticsService,
);

void recordFlutterErrorToCrashlytics(FlutterErrorDetails details) {
_crashlyticsService.recordFlutterError(details);
}

Future logToCrashlytics(
Level level, List<String> lines, StackTrace stacktrace,
{required bool logwarnings}) async {
if (level == Level.error || level == Level.wtf) {
await _crashlyticsService.recordError(
lines.join('\n'),
stacktrace,
printDetails: true,
fatal: true,
);
}
if (level == Level.warning && logwarnings) {
await _crashlyticsService.recordError(
lines.join('\n'),
stacktrace,
printDetails: true,
);
}
if (level == Level.info || level == Level.verbose || level == Level.debug) {
await _crashlyticsService.log(lines.join('\n'));
}
}

Future setCustomKeysToTrack(String key, dynamic value) async {
await _crashlyticsService.setCustomKey(key, value);
}

// Be very careful when you excute this code it will crash the app
// So, be sure to remove it after usage
void crashApp() {
_crashlyticsService.crash();
}
}

class CrashlyticsOutput extends LogOutput {
final bool logWarnings;
CrashlyticsOutput({this.logWarnings = false});

@override
void output(OutputEvent event) {
try {
CrashlyticsService.getInstance().logToCrashlytics(
event.level, event.lines, StackTrace.current,
logwarnings: logWarnings);
} catch (e) {
print('CRASHLYTICS FAILED: $e');
}
}
}
11 changes: 7 additions & 4 deletions lib/ui/base/auth_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import 'package:feed/app/app.logger.dart';
import 'package:feed/app/app.router.dart';
import 'package:feed/core/enums/bottom_sheet.dart';
import 'package:feed/core/services/user_service.dart';
import 'package:feed/firebase/analytics.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';

abstract class AuthenticationViewModel extends BaseViewModel {
final BottomSheetService _bottomSheetService = locator<BottomSheetService>();
final SnackbarService _snackbarService = locator<SnackbarService>();
final NavigationService _navigationService = locator<NavigationService>();
final UserService _userService = locator<UserService>();
final _bottomSheetService = locator<BottomSheetService>();
final _snackbarService = locator<SnackbarService>();
final _navigationService = locator<NavigationService>();
final _userService = locator<UserService>();
final _analytics = locator<AnalyticsService>();
final _log = getLogger("Authentication ViewModel");

Future showConstraint({
Expand Down Expand Up @@ -61,6 +63,7 @@ abstract class AuthenticationViewModel extends BaseViewModel {
_log.i(
"User Login Successful : Logged in user: ${_userService.currentUser}");
isProfileExists = await _userService.isUserProfileExists();
_analytics.logLogin();

setBusy(false);

Expand Down
Loading

0 comments on commit 6925f35

Please sign in to comment.