From e369a771152293c5754434350be84674c3e6df57 Mon Sep 17 00:00:00 2001 From: Tommy Date: Sun, 30 Apr 2023 00:07:43 -0400 Subject: [PATCH] Migrate to Firebase for crash logs & analytics (#263) * Remove Sentry Flutter * Install and configure firebase * Install and configure firebase crashlytics * Install firebase performance monitoring * Install firebase analytics * Remove Sentry from github actions * Update iOS configs * Update setting toggle for firebase --- .github/workflows/gh-release.yml | 3 +- .github/workflows/store-release.yml | 5 +- android/app/google-services.json | 46 ++++ ios/Podfile.lock | 217 ++++++++++++++++-- ios/Runner.xcodeproj/project.pbxproj | 25 +- ios/Runner/GoogleService-Info.plist | 34 +++ ios/Runner/Info.plist | 4 +- ios/firebase_app_id_file.json | 7 + lib/constants.dart | 3 - lib/firebase_options.dart | 69 ++++++ lib/main.dart | 23 +- lib/screens/onboarding/onboarding_setup.dart | 26 ++- lib/screens/settings/other_settings.dart | 26 ++- lib/screens/settings/stores/auth_store.dart | 25 +- .../settings/stores/settings_store.dart | 8 +- .../settings/stores/settings_store.g.dart | 24 +- pubspec.lock | 112 +++++++-- pubspec.yaml | 5 +- 18 files changed, 551 insertions(+), 111 deletions(-) create mode 100644 android/app/google-services.json create mode 100644 ios/Runner/GoogleService-Info.plist create mode 100644 ios/firebase_app_id_file.json create mode 100644 lib/firebase_options.dart diff --git a/.github/workflows/gh-release.yml b/.github/workflows/gh-release.yml index 2ef10db1..483b78af 100644 --- a/.github/workflows/gh-release.yml +++ b/.github/workflows/gh-release.yml @@ -16,7 +16,6 @@ jobs: KEY_FILE_PATH: android/key.properties CLIENT_ID: ${{ secrets.CLIENT_ID }} SECRET: ${{ secrets.SECRET }} - SENTRY_DSN: ${{ secrets.SENTRY_DSN }} steps: - name: Checkout Frosty repo uses: actions/checkout@v3 @@ -49,7 +48,7 @@ jobs: # Build the APK with the environment variables and move/rename it. - name: Build for Android run: | - flutter build apk --dart-define CLIENT_ID=$CLIENT_ID --dart-define SECRET=$SECRET --dart-define SENTRY_DSN=$SENTRY_DSN + flutter build apk --dart-define CLIENT_ID=$CLIENT_ID --dart-define SECRET=$SECRET mv build/app/outputs/flutter-apk/app-release.apk frosty-${{ github.ref_name }}.apk # Create a draft release on GitHub. diff --git a/.github/workflows/store-release.yml b/.github/workflows/store-release.yml index 4ff5a47a..1182ce23 100644 --- a/.github/workflows/store-release.yml +++ b/.github/workflows/store-release.yml @@ -13,7 +13,6 @@ env: BUNDLE_GEMFILE: ${{ github.workspace }}/android/Gemfile CLIENT_ID: ${{ secrets.CLIENT_ID }} SECRET: ${{ secrets.SECRET }} - SENTRY_DSN: ${{ secrets.SENTRY_DSN }} jobs: android: name: Build and release Frosty on Android @@ -63,7 +62,7 @@ jobs: # Build the Android app bundle (AAB) and pass the environment variables. - name: Build the Android AAB - run: flutter build appbundle --dart-define CLIENT_ID=$CLIENT_ID --dart-define SECRET=$SECRET --dart-define SENTRY_DSN=$SENTRY_DSN + run: flutter build appbundle --dart-define CLIENT_ID=$CLIENT_ID --dart-define SECRET=$SECRET # Deploy to the play store with fastlane. - name: Deploy with fastlane @@ -96,7 +95,7 @@ jobs: # Setup the iOS project with environment variables without signing (building and signing will happen in fastlane). - name: Config the iOS build - run: flutter build ios --no-codesign --config-only --dart-define CLIENT_ID=$CLIENT_ID --dart-define SECRET=$SECRET --dart-define SENTRY_DSN=$SENTRY_DSN + run: flutter build ios --no-codesign --config-only --dart-define CLIENT_ID=$CLIENT_ID --dart-define SECRET=$SECRET # Sign, build the app, and deploy to app store with fastlane. - name: Sign, build, and release with fastlane diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 00000000..32317f65 --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,46 @@ +{ + "project_info": { + "project_number": "403282332389", + "project_id": "frosty-128de", + "storage_bucket": "frosty-128de.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:403282332389:android:a7ff237168bad4c30be20c", + "android_client_info": { + "package_name": "com.tommychow.frosty" + } + }, + "oauth_client": [ + { + "client_id": "403282332389-4ml1piauu7mtvu628ik8dujcgv8gf72r.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyANmrDMKr9clsyh_7NyHpux4JNeMSXjJyk" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "403282332389-4ml1piauu7mtvu628ik8dujcgv8gf72r.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "403282332389-gst8k8gl71a7vrhf5k69nl8pnsq19rg8.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "com.tommychow.frosty" + } + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3ec31430..d5608b35 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,6 +1,99 @@ PODS: - device_info_plus (0.0.1): - Flutter + - Firebase/Analytics (10.7.0): + - Firebase/Core + - Firebase/Core (10.7.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 10.7.0) + - Firebase/CoreOnly (10.7.0): + - FirebaseCore (= 10.7.0) + - Firebase/Crashlytics (10.7.0): + - Firebase/CoreOnly + - FirebaseCrashlytics (~> 10.7.0) + - Firebase/Performance (10.7.0): + - Firebase/CoreOnly + - FirebasePerformance (~> 10.7.0) + - firebase_analytics (10.2.1): + - Firebase/Analytics (= 10.7.0) + - firebase_core + - Flutter + - firebase_core (2.10.0): + - Firebase/CoreOnly (= 10.7.0) + - Flutter + - firebase_crashlytics (3.1.2): + - Firebase/Crashlytics (= 10.7.0) + - firebase_core + - Flutter + - firebase_performance (0.9.1-1): + - Firebase/Performance (= 10.7.0) + - firebase_core + - Flutter + - FirebaseABTesting (10.9.0): + - FirebaseCore (~> 10.0) + - FirebaseAnalytics (10.7.0): + - FirebaseAnalytics/AdIdSupport (= 10.7.0) + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.8) + - GoogleUtilities/MethodSwizzler (~> 7.8) + - GoogleUtilities/Network (~> 7.8) + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseAnalytics/AdIdSupport (10.7.0): + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleAppMeasurement (= 10.7.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.8) + - GoogleUtilities/MethodSwizzler (~> 7.8) + - GoogleUtilities/Network (~> 7.8) + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseCore (10.7.0): + - FirebaseCoreInternal (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/Logger (~> 7.8) + - FirebaseCoreExtension (10.9.0): + - FirebaseCore (~> 10.0) + - FirebaseCoreInternal (10.9.0): + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseCrashlytics (10.7.0): + - FirebaseCore (~> 10.5) + - FirebaseInstallations (~> 10.0) + - FirebaseSessions (~> 10.5) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.8) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesObjC (~> 2.1) + - FirebaseInstallations (10.9.0): + - FirebaseCore (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/UserDefaults (~> 7.8) + - PromisesObjC (~> 2.1) + - FirebasePerformance (10.7.0): + - FirebaseCore (~> 10.5) + - FirebaseInstallations (~> 10.0) + - FirebaseRemoteConfig (~> 10.0) + - FirebaseSessions (~> 10.5) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/ISASwizzler (~> 7.8) + - GoogleUtilities/MethodSwizzler (~> 7.8) + - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseRemoteConfig (10.9.0): + - FirebaseABTesting (~> 10.0) + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseSessions (10.9.0): + - FirebaseCore (~> 10.5) + - FirebaseCoreExtension (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.10) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesSwift (~> 2.1) - Flutter (1.0.0) - flutter_native_splash (0.0.1): - Flutter @@ -9,15 +102,63 @@ PODS: - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) + - GoogleAppMeasurement (10.7.0): + - GoogleAppMeasurement/AdIdSupport (= 10.7.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.8) + - GoogleUtilities/MethodSwizzler (~> 7.8) + - GoogleUtilities/Network (~> 7.8) + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleAppMeasurement/AdIdSupport (10.7.0): + - GoogleAppMeasurement/WithoutAdIdSupport (= 10.7.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.8) + - GoogleUtilities/MethodSwizzler (~> 7.8) + - GoogleUtilities/Network (~> 7.8) + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleAppMeasurement/WithoutAdIdSupport (10.7.0): + - GoogleUtilities/AppDelegateSwizzler (~> 7.8) + - GoogleUtilities/MethodSwizzler (~> 7.8) + - GoogleUtilities/Network (~> 7.8) + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - nanopb (< 2.30910.0, >= 2.30908.0) + - GoogleDataTransport (9.2.2): + - GoogleUtilities/Environment (~> 7.7) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/AppDelegateSwizzler (7.11.1): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.11.1): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/ISASwizzler (7.11.1) + - GoogleUtilities/Logger (7.11.1): + - GoogleUtilities/Environment + - GoogleUtilities/MethodSwizzler (7.11.1): + - GoogleUtilities/Logger + - GoogleUtilities/Network (7.11.1): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.11.1)" + - GoogleUtilities/Reachability (7.11.1): + - GoogleUtilities/Logger + - GoogleUtilities/UserDefaults (7.11.1): + - GoogleUtilities/Logger + - nanopb (2.30909.0): + - nanopb/decode (= 2.30909.0) + - nanopb/encode (= 2.30909.0) + - nanopb/decode (2.30909.0) + - nanopb/encode (2.30909.0) - package_info_plus (0.4.5): - Flutter - - path_provider_ios (0.0.1): - - Flutter - - Sentry/HybridSDK (7.31.5) - - sentry_flutter (0.0.1): + - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - - Sentry/HybridSDK (= 7.31.5) + - PromisesObjC (2.2.0) + - PromisesSwift (2.2.0): + - PromisesObjC (= 2.2.0) - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -33,12 +174,15 @@ PODS: DEPENDENCIES: - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) + - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`) + - firebase_performance (from `.symlinks/plugins/firebase_performance/ios`) - Flutter (from `Flutter`) - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) - - sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) @@ -47,12 +191,36 @@ DEPENDENCIES: SPEC REPOS: trunk: + - Firebase + - FirebaseABTesting + - FirebaseAnalytics + - FirebaseCore + - FirebaseCoreExtension + - FirebaseCoreInternal + - FirebaseCrashlytics + - FirebaseInstallations + - FirebasePerformance + - FirebaseRemoteConfig + - FirebaseSessions - FMDB - - Sentry + - GoogleAppMeasurement + - GoogleDataTransport + - GoogleUtilities + - nanopb + - PromisesObjC + - PromisesSwift EXTERNAL SOURCES: device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" + firebase_analytics: + :path: ".symlinks/plugins/firebase_analytics/ios" + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_crashlytics: + :path: ".symlinks/plugins/firebase_crashlytics/ios" + firebase_performance: + :path: ".symlinks/plugins/firebase_performance/ios" Flutter: :path: Flutter flutter_native_splash: @@ -61,10 +229,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_secure_storage/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_ios: - :path: ".symlinks/plugins/path_provider_ios/ios" - sentry_flutter: - :path: ".symlinks/plugins/sentry_flutter/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/ios" sqflite: @@ -78,17 +244,36 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed + Firebase: 0219acf760880eeec8ce479895bd7767466d9f81 + firebase_analytics: e8e294333de66e5429d4aac365966281b4dbfb7d + firebase_core: 18d44f087248303a4a8f05d0099a000c46e3c77a + firebase_crashlytics: 621d91c0c5752e8219f8fe05a4d1e76394f4896a + firebase_performance: 7dd98298ea2f19f480efd59ccbfcad3972ced984 + FirebaseABTesting: 005b70969e2817e2a1e631e8dba29134a04c0622 + FirebaseAnalytics: f8133442ee6f8512e28ff19e62ce15398bfaeace + FirebaseCore: e317665b9d744727a97e623edbbed009320afdd7 + FirebaseCoreExtension: d3e9bba2930a8033042112397cd9f006a1bb203d + FirebaseCoreInternal: d2b4acb827908e72eca47a9fd896767c3053921e + FirebaseCrashlytics: 35fdd1a433b31e28adcf5c8933f4c526691a1e0b + FirebaseInstallations: c58489c9caacdbf27d1da60891a87318e20218e0 + FirebasePerformance: 8281bbaf08aad194001018b932115b7d58a6f00b + FirebaseRemoteConfig: 5ea5834e8c518f377bf1af2d97ebd611914ebf2d + FirebaseSessions: 44a6782502eb279a214d4adca20891353278760c Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + GoogleAppMeasurement: fe17c92a32207dd5cdd4e8d742767f2da74857f6 + GoogleDataTransport: 8378d1fa8ac49753ea6ce70d65a7cb70ce5f66e6 + GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749 + nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e - path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 - Sentry: 4c9babff9034785067c896fd580b1f7de44da020 - sentry_flutter: d3dad547d3db4918a8051a5ef738cc195c427b4b + path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852 + PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef + PromisesSwift: cf9eb58666a43bbe007302226e510b16c1e10959 shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 - url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de + url_launcher_ios: ae1517e5e344f5544fb090b079e11f399dfbe4d2 wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 60a55a33..fbac3150 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -139,6 +139,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 34CC65D58A1948B306772884 /* [CP] Embed Pods Frameworks */, + 233686724150C819037C8B0B /* [firebase_crashlytics] Crashlytics Upload Symbols */, ); buildRules = ( ); @@ -219,6 +220,26 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 233686724150C819037C8B0B /* [firebase_crashlytics] Crashlytics Upload Symbols */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}\"", + "\"$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)\"", + ); + name = "[firebase_crashlytics] Crashlytics Upload Symbols"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$PODS_ROOT/FirebaseCrashlytics/upload-symbols\" --flutter-project \"$PROJECT_DIR/firebase_app_id_file.json\" "; + }; 34CC65D58A1948B306772884 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -238,6 +259,7 @@ }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -252,6 +274,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist new file mode 100644 index 00000000..1ee88e10 --- /dev/null +++ b/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,34 @@ + + + + + CLIENT_ID + 403282332389-gst8k8gl71a7vrhf5k69nl8pnsq19rg8.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.403282332389-gst8k8gl71a7vrhf5k69nl8pnsq19rg8 + API_KEY + AIzaSyBu9PAnTdUBS5M13WaiP7-JtUd6D6LtzCE + GCM_SENDER_ID + 403282332389 + PLIST_VERSION + 1 + BUNDLE_ID + com.tommychow.frosty + PROJECT_ID + frosty-128de + STORAGE_BUCKET + frosty-128de.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:403282332389:ios:0fc3f8c3d4e80c8b0be20c + + \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 4a9c1625..2f78432e 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -54,5 +54,7 @@ CADisableMinimumFrameDurationOnPhone - + UIApplicationSupportsIndirectInputEvents + + diff --git a/ios/firebase_app_id_file.json b/ios/firebase_app_id_file.json new file mode 100644 index 00000000..4860d1d1 --- /dev/null +++ b/ios/firebase_app_id_file.json @@ -0,0 +1,7 @@ +{ + "file_generated_by": "FlutterFire CLI", + "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", + "GOOGLE_APP_ID": "1:403282332389:ios:0fc3f8c3d4e80c8b0be20c", + "FIREBASE_PROJECT_ID": "frosty-128de", + "GCM_SENDER_ID": "403282332389" +} \ No newline at end of file diff --git a/lib/constants.dart b/lib/constants.dart index 88600eaa..68c67376 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -4,9 +4,6 @@ const clientId = String.fromEnvironment('CLIENT_ID'); /// Twitch API client secret. const secret = String.fromEnvironment('SECRET'); -/// The tracesSampleRate for sentry crash reporting. -const sampleRate = 0.2; - /// BTTV emotes with zero width to allow for overlaying other emotes. const zeroWidthEmotes = [ 'SoSnowy', diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart new file mode 100644 index 00000000..5349f973 --- /dev/null +++ b/lib/firebase_options.dart @@ -0,0 +1,69 @@ +// File generated by FlutterFire CLI. +// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for web - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyANmrDMKr9clsyh_7NyHpux4JNeMSXjJyk', + appId: '1:403282332389:android:a7ff237168bad4c30be20c', + messagingSenderId: '403282332389', + projectId: 'frosty-128de', + storageBucket: 'frosty-128de.appspot.com', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyBu9PAnTdUBS5M13WaiP7-JtUd6D6LtzCE', + appId: '1:403282332389:ios:0fc3f8c3d4e80c8b0be20c', + messagingSenderId: '403282332389', + projectId: 'frosty-128de', + storageBucket: 'frosty-128de.appspot.com', + iosClientId: '403282332389-gst8k8gl71a7vrhf5k69nl8pnsq19rg8.apps.googleusercontent.com', + iosBundleId: 'com.tommychow.frosty', + ); +} diff --git a/lib/main.dart b/lib/main.dart index 29f2159b..437f2259 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,9 @@ import 'dart:convert'; import 'dart:io'; import 'package:device_preview/device_preview.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -9,7 +12,7 @@ import 'package:frosty/apis/bttv_api.dart'; import 'package:frosty/apis/ffz_api.dart'; import 'package:frosty/apis/seventv_api.dart'; import 'package:frosty/apis/twitch_api.dart'; -import 'package:frosty/constants.dart'; +import 'package:frosty/firebase_options.dart'; import 'package:frosty/screens/home/home.dart'; import 'package:frosty/screens/onboarding/onboarding_intro.dart'; import 'package:frosty/screens/settings/stores/auth_store.dart'; @@ -17,7 +20,6 @@ import 'package:frosty/screens/settings/stores/settings_store.dart'; import 'package:http/http.dart'; import 'package:mobx/mobx.dart'; import 'package:provider/provider.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() async { @@ -46,11 +48,18 @@ void main() async { // Create a MobX reaction that will save the settings on disk every time they are changed. autorun((_) => prefs.setString('settings', jsonEncode(settingsStore))); - // Initialize Sentry for crash reporting if enabled. - if (settingsStore.sendCrashLogs) { - await SentryFlutter.init( - (options) => options.tracesSampleRate = sampleRate); - } + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); + + // Pass all uncaught "fatal" errors from the framework to Crashlytics + FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError; + + // Pass all uncaught asynchronous errors that aren't handled by the Flutter framework to Crashlytics + PlatformDispatcher.instance.onError = (error, stack) { + FirebaseCrashlytics.instance.recordError(error, stack, fatal: true); + return true; + }; /// Initialize API services with a common client. /// This will prevent every request from creating a new client instance. diff --git a/lib/screens/onboarding/onboarding_setup.dart b/lib/screens/onboarding/onboarding_setup.dart index d2387f0b..56526f58 100644 --- a/lib/screens/onboarding/onboarding_setup.dart +++ b/lib/screens/onboarding/onboarding_setup.dart @@ -1,13 +1,14 @@ +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; +import 'package:firebase_performance/firebase_performance.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:frosty/constants.dart'; import 'package:frosty/screens/onboarding/onboarding_scaffold.dart'; import 'package:frosty/screens/onboarding/onboarding_welcome.dart'; import 'package:frosty/screens/settings/stores/settings_store.dart'; import 'package:frosty/screens/settings/widgets/settings_list_select.dart'; import 'package:frosty/screens/settings/widgets/settings_list_switch.dart'; import 'package:provider/provider.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; class OnboardingSetup extends StatelessWidget { const OnboardingSetup({Key? key}) : super(key: key); @@ -32,18 +33,19 @@ class OnboardingSetup extends StatelessWidget { ThemeType.values[themeNames.indexOf(newTheme)], ), SettingsListSwitch( - title: 'Send anonymous crash logs', + title: 'Share crash logs and analytics', subtitle: const Text( - 'Help improve Frosty by sending anonymous crash logs through Sentry.io.'), - value: settingsStore.sendCrashLogs, + 'Help improve Frosty by sending anonymous crash logs and analytics through Firebase.'), + value: settingsStore.shareCrashLogsAndAnalytics, onChanged: (newValue) { - if (newValue == true) { - SentryFlutter.init( - (options) => options.tracesSampleRate = sampleRate); - } else { - Sentry.close(); - } - settingsStore.sendCrashLogs = newValue; + settingsStore.shareCrashLogsAndAnalytics = newValue; + + FirebaseCrashlytics.instance + .setCrashlyticsCollectionEnabled(newValue); + FirebaseAnalytics.instance + .setAnalyticsCollectionEnabled(newValue); + FirebasePerformance.instance + .setPerformanceCollectionEnabled(newValue); }, ), ], diff --git a/lib/screens/settings/other_settings.dart b/lib/screens/settings/other_settings.dart index 77d57106..43f027a9 100644 --- a/lib/screens/settings/other_settings.dart +++ b/lib/screens/settings/other_settings.dart @@ -1,9 +1,11 @@ +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; +import 'package:firebase_performance/firebase_performance.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:frosty/constants.dart'; import 'package:frosty/screens/settings/stores/settings_store.dart'; import 'package:frosty/screens/settings/widgets/settings_list_switch.dart'; import 'package:frosty/widgets/alert_message.dart'; @@ -11,7 +13,6 @@ import 'package:frosty/widgets/button.dart'; import 'package:frosty/widgets/dialog.dart'; import 'package:frosty/widgets/list_tile.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; class OtherSettings extends StatefulWidget { @@ -127,18 +128,19 @@ class _OtherSettingsState extends State { ), Observer( builder: (_) => SettingsListSwitch( - title: 'Send anonymous crash logs', + title: 'Share crash logs and analytics', subtitle: const Text( - 'Help improve Frosty by sending anonymous crash logs through Sentry.io.'), - value: widget.settingsStore.sendCrashLogs, + 'Help improve Frosty by sending anonymous crash logs and analytics through Firebase.'), + value: widget.settingsStore.shareCrashLogsAndAnalytics, onChanged: (newValue) { - if (newValue == true) { - SentryFlutter.init( - (options) => options.tracesSampleRate = sampleRate); - } else { - Sentry.close(); - } - widget.settingsStore.sendCrashLogs = newValue; + widget.settingsStore.shareCrashLogsAndAnalytics = newValue; + + FirebaseCrashlytics.instance + .setCrashlyticsCollectionEnabled(newValue); + FirebaseAnalytics.instance + .setAnalyticsCollectionEnabled(newValue); + FirebasePerformance.instance + .setPerformanceCollectionEnabled(newValue); }, ), ), diff --git a/lib/screens/settings/stores/auth_store.dart b/lib/screens/settings/stores/auth_store.dart index 76f225ab..6358bd91 100644 --- a/lib/screens/settings/stores/auth_store.dart +++ b/lib/screens/settings/stores/auth_store.dart @@ -9,7 +9,6 @@ import 'package:frosty/screens/settings/stores/user_store.dart'; import 'package:frosty/widgets/button.dart'; import 'package:frosty/widgets/dialog.dart'; import 'package:mobx/mobx.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:webview_flutter/webview_flutter.dart'; part 'auth_store.g.dart'; @@ -180,13 +179,7 @@ abstract class AuthBase with Store { } _error = null; - } catch (e, stackTrace) { - // If auth initialization failed, log the error to Sentry. - await Sentry.captureException( - e, - stackTrace: stackTrace, - ); - + } catch (e) { debugPrint(e.toString()); _error = e.toString(); } @@ -211,13 +204,7 @@ abstract class AuthBase with Store { // Set the login status to logged in. if (user.details != null) _isLoggedIn = true; - } catch (e, stackTrace) { - // If login failed, log the error to Sentry. - await Sentry.captureException( - e, - stackTrace: stackTrace, - ); - + } catch (e) { debugPrint('Login failed due to $e'); } } @@ -246,13 +233,7 @@ abstract class AuthBase with Store { _isLoggedIn = false; debugPrint('Successfully logged out'); - } catch (e, stackTrace) { - // If logout failed, log the error to Sentry. - await Sentry.captureException( - e, - stackTrace: stackTrace, - ); - + } catch (e) { debugPrint(e.toString()); } } diff --git a/lib/screens/settings/stores/settings_store.dart b/lib/screens/settings/stores/settings_store.dart index 7818716e..2751a3f1 100644 --- a/lib/screens/settings/stores/settings_store.dart +++ b/lib/screens/settings/stores/settings_store.dart @@ -259,15 +259,15 @@ abstract class _SettingsStoreBase with Store { } // * Other settings - static const defaultSendCrashLogs = true; + static const defaultShareCrashLogsAndAnalytics = true; - @JsonKey(defaultValue: defaultSendCrashLogs) + @JsonKey(defaultValue: defaultShareCrashLogsAndAnalytics) @observable - var sendCrashLogs = defaultSendCrashLogs; + var shareCrashLogsAndAnalytics = defaultShareCrashLogsAndAnalytics; @action void resetOtherSettings() { - sendCrashLogs = defaultSendCrashLogs; + shareCrashLogsAndAnalytics = defaultShareCrashLogsAndAnalytics; } // * Global configs diff --git a/lib/screens/settings/stores/settings_store.g.dart b/lib/screens/settings/stores/settings_store.g.dart index c197d246..ffc5b425 100644 --- a/lib/screens/settings/stores/settings_store.g.dart +++ b/lib/screens/settings/stores/settings_store.g.dart @@ -50,7 +50,8 @@ SettingsStore _$SettingsStoreFromJson(Map json) => (json['fullScreenChatOverlayOpacity'] as num?)?.toDouble() ?? 0.5 ..chatOnlyPreventSleep = json['chatOnlyPreventSleep'] as bool? ?? false ..autocomplete = json['autocomplete'] as bool? ?? true - ..sendCrashLogs = json['sendCrashLogs'] as bool? ?? true + ..shareCrashLogsAndAnalytics = + json['shareCrashLogsAndAnalytics'] as bool? ?? true ..fullScreen = json['fullScreen'] as bool? ?? false ..fullScreenChatOverlay = json['fullScreenChatOverlay'] as bool? ?? false; @@ -87,7 +88,7 @@ Map _$SettingsStoreToJson(SettingsStore instance) => 'fullScreenChatOverlayOpacity': instance.fullScreenChatOverlayOpacity, 'chatOnlyPreventSleep': instance.chatOnlyPreventSleep, 'autocomplete': instance.autocomplete, - 'sendCrashLogs': instance.sendCrashLogs, + 'shareCrashLogsAndAnalytics': instance.shareCrashLogsAndAnalytics, 'fullScreen': instance.fullScreen, 'fullScreenChatOverlay': instance.fullScreenChatOverlay, }; @@ -608,19 +609,20 @@ mixin _$SettingsStore on _SettingsStoreBase, Store { }); } - late final _$sendCrashLogsAtom = - Atom(name: '_SettingsStoreBase.sendCrashLogs', context: context); + late final _$shareCrashLogsAndAnalyticsAtom = Atom( + name: '_SettingsStoreBase.shareCrashLogsAndAnalytics', context: context); @override - bool get sendCrashLogs { - _$sendCrashLogsAtom.reportRead(); - return super.sendCrashLogs; + bool get shareCrashLogsAndAnalytics { + _$shareCrashLogsAndAnalyticsAtom.reportRead(); + return super.shareCrashLogsAndAnalytics; } @override - set sendCrashLogs(bool value) { - _$sendCrashLogsAtom.reportWrite(value, super.sendCrashLogs, () { - super.sendCrashLogs = value; + set shareCrashLogsAndAnalytics(bool value) { + _$shareCrashLogsAndAnalyticsAtom + .reportWrite(value, super.shareCrashLogsAndAnalytics, () { + super.shareCrashLogsAndAnalytics = value; }); } @@ -759,7 +761,7 @@ chatWidth: ${chatWidth}, fullScreenChatOverlayOpacity: ${fullScreenChatOverlayOpacity}, chatOnlyPreventSleep: ${chatOnlyPreventSleep}, autocomplete: ${autocomplete}, -sendCrashLogs: ${sendCrashLogs}, +shareCrashLogsAndAnalytics: ${shareCrashLogsAndAnalytics}, fullScreen: ${fullScreen}, fullScreenChatOverlay: ${fullScreenChatOverlay} '''; diff --git a/pubspec.lock b/pubspec.lock index ab64604e..21f1ab82 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "52.0.0" + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: "6a0ad72b2bcdb461749e40c01c478212a78db848dfcb2f10f2a461988bc5fb29" + url: "https://pub.dev" + source: hosted + version: "1.1.1" analyzer: dependency: transitive description: @@ -281,6 +289,94 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.4" + firebase_analytics: + dependency: "direct main" + description: + name: firebase_analytics + sha256: "2d8f475f79658a8e1865ee8a9e2e8eea70de5e487e3a646d9073dc3d1520d3e8" + url: "https://pub.dev" + source: hosted + version: "10.2.1" + firebase_analytics_platform_interface: + dependency: transitive + description: + name: firebase_analytics_platform_interface + sha256: a667807edbcd3f5a6336275a21c8802de8f98f0a91b8c97abb76119b142aa91d + url: "https://pub.dev" + source: hosted + version: "3.4.1" + firebase_analytics_web: + dependency: transitive + description: + name: firebase_analytics_web + sha256: "907285030d59570d7c1a8d721912db990957ab9b87736e50a9457491c16bcffe" + url: "https://pub.dev" + source: hosted + version: "0.5.2+1" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "239e4ac688674a7e7b5476fd16b0d8e2b5a453d464f32091af3ce1df4ebb7316" + url: "https://pub.dev" + source: hosted + version: "2.10.0" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: "0df0a064ab0cad7f8836291ca6f3272edd7b83ad5b3540478ee46a0849d8022b" + url: "https://pub.dev" + source: hosted + version: "4.6.0" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: "347351a8f0518f3343d79a9a0690fa67ad232fc32e2ea270677791949eac792b" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + firebase_crashlytics: + dependency: "direct main" + description: + name: firebase_crashlytics + sha256: "02ce958507138d938b4611e3a4910667a44b969b0c20a810bbc97bbf967ba0d7" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + firebase_crashlytics_platform_interface: + dependency: transitive + description: + name: firebase_crashlytics_platform_interface + sha256: b9c7b8498c877a2901ad323fc92c10f672be1597bc82d08f121f6228f321a7e0 + url: "https://pub.dev" + source: hosted + version: "3.4.1" + firebase_performance: + dependency: "direct main" + description: + name: firebase_performance + sha256: "14f4d1e89e757f0aa1dec83c13ca390bbd728aca1ccc3ad19e6a23e2710f45b7" + url: "https://pub.dev" + source: hosted + version: "0.9.1+1" + firebase_performance_platform_interface: + dependency: transitive + description: + name: firebase_performance_platform_interface + sha256: "0914a49c4ca2cc74ac4c7fde719f280896b4c1d1bbe5fa72e059da0803cbc493" + url: "https://pub.dev" + source: hosted + version: "0.1.2+1" + firebase_performance_web: + dependency: transitive + description: + name: firebase_performance_web + sha256: "8192e4e112e9e09d2c9bbc8ab51d7c4e34ea618d15452d0ecfa6141e8babbd40" + url: "https://pub.dev" + source: hosted + version: "0.1.2+1" fixnum: dependency: transitive description: @@ -789,22 +885,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.27.7" - sentry: - dependency: transitive - description: - name: sentry - sha256: c64db3444237ff747c5a68f5214897bcb078de248785d0d816e3c55ab94dd71d - url: "https://pub.dev" - source: hosted - version: "6.19.0" - sentry_flutter: - dependency: "direct main" - description: - name: sentry_flutter - sha256: a76cf5180d571535fb8fc3bf10358ab385d78134fcf652d0e03ba7741525ab09 - url: "https://pub.dev" - source: hosted - version: "6.19.0" shared_preferences: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 92466024..c1d6908c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,7 +45,6 @@ dependencies: mobx: ^2.0.7+4 flutter_mobx: ^2.0.0 shared_preferences: ^2.0.8 - sentry_flutter: ^6.2.2 tuple: ^2.0.0 flutter_svg: ^1.0.0 url_launcher: ^6.0.17 @@ -59,6 +58,10 @@ dependencies: simple_pip_mode: git: url: https://github.com/tommyxchow/simple_pip_mode_flutter + firebase_core: ^2.10.0 + firebase_crashlytics: ^3.1.2 + firebase_performance: ^0.9.1+1 + firebase_analytics: ^10.2.1 dev_dependencies: flutter_test: