Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2a16222
chore(sample_app): replace Sentry with Firebase Crashlytics
xsahil03x May 19, 2026
032341d
chore(sample_app): leave Crashlytics Gradle plugin to flutterfire con…
xsahil03x May 19, 2026
d8a8845
chore(sample_app): run flutterfire configure for Crashlytics
xsahil03x May 19, 2026
9c774a3
chore(sample_app): regenerate iOS Pods after Sentry removal
xsahil03x May 19, 2026
4dad8f3
chore(sample_app): floor Android compileSdk at 36 for firebase_crashl…
xsahil03x May 19, 2026
1e37279
chore(sample_app): let embedder surface platform errors in debug
xsahil03x May 19, 2026
7ddafad
style(sample_app): blank line after early-return guard in onError
xsahil03x May 19, 2026
02d92b3
chore(sample_app): default Crashlytics collection off in native config
xsahil03x May 19, 2026
e27bd06
chore(sample_app): tweak Crashlytics gate comments
xsahil03x May 19, 2026
cdae974
Merge branch 'master' into chore/replace-sentry-with-firebase
xsahil03x May 19, 2026
7961ea5
chore(sample_app): melos format firebase_options.dart
xsahil03x May 19, 2026
489bb35
ci(sample_app): install flutterfire_cli before iOS build
xsahil03x May 19, 2026
a926c7a
chore(sample_app): drop dSYM upload run-script phase
xsahil03x May 19, 2026
a10ac87
ci(sample_app): upload iOS dSYMs to Crashlytics in distribution lanes
xsahil03x May 19, 2026
b484ee6
ci(sample_app): handle SPM Crashlytics in upload_crashlytics_symbols
xsahil03x May 19, 2026
04363eb
ci(sample_app): disable Swift Package Manager integration on iOS/macOS
xsahil03x May 19, 2026
604ccb7
ci(sample_app): propagate DEVELOPMENT_TEAM to SPM packages on archive
xsahil03x May 19, 2026
5b37891
ci(sample_app): force manual code-sign style for SPM packages
xsahil03x May 19, 2026
9f1d473
Revert "ci(sample_app): force manual code-sign style for SPM packages"
xsahil03x May 19, 2026
07ec98f
ci(repo): move legacy_version_analyze path filter to job level
xsahil03x May 19, 2026
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
29 changes: 21 additions & 8 deletions .github/workflows/legacy_version_analyze.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,42 @@ on:
push:
branches:
- master
paths:
- 'packages/**'
- '.github/workflows/legacy_version_analyze.yml'
pull_request:
branches:
- master
paths:
- 'packages/**'
- '.github/workflows/legacy_version_analyze.yml'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
# Detect whether anything that affects legacy analysis was touched in this
# PR. Path filtering at the job level (instead of `on.paths`) means a
# skipped `analyze_legacy_versions` reports as `success` to branch
# protection — see
# https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks
changes:
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.filter.outputs.packages }}
steps:
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
packages:
- 'packages/**'
- '.github/workflows/legacy_version_analyze.yml'

# Does a sanity check that packages at least pass analysis on the N-1
# versions of Flutter stable if the package claims to support that version.
# This is to minimize accidentally making changes that break old versions
# (which we don't commit to supporting, but don't want to actively break)
# without updating the constraints.
analyze_legacy_versions:
needs: changes
if: needs.changes.outputs.packages == 'true' && github.event.pull_request.draft == false
timeout-minutes: 15
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- name: "Git Checkout"
Expand All @@ -48,4 +61,4 @@ jobs:
cache-key: flutter-:os:-:channel:-:version:-:arch:-:hash:-${{ hashFiles('**/pubspec.lock') }}

- name: 📊 Analyze and test packages
uses: ./.github/actions/package_analysis
uses: ./.github/actions/package_analysis
2 changes: 1 addition & 1 deletion melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ command:
equatable: ^2.0.5
ezanimation: ^0.6.0
firebase_core: ^3.0.0
firebase_crashlytics: ^4.0.0
firebase_messaging: ^15.0.0
file_picker: ^10.1.2
file_selector: ^1.0.3
Expand Down Expand Up @@ -75,7 +76,6 @@ command:
record: ">=5.2.0 <7.0.0"
responsive_builder: ^0.7.0
rxdart: ^0.28.0
sentry_flutter: ^8.3.0
share_plus: ">=11.0.0 <13.0.0"
shimmer: ^3.0.0
sqlite3_flutter_libs: ^0.5.26
Expand Down
1 change: 1 addition & 0 deletions sample_app/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id "com.android.application"
// START: FlutterFire Configuration
id "com.google.gms.google-services"
id 'com.google.firebase.crashlytics'
// END: FlutterFire Configuration
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
Expand Down
72 changes: 36 additions & 36 deletions sample_app/android/app/google-services.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,42 +94,6 @@
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:674907137625:android:07c76802bbfd5654d7f348",
"android_client_info": {
"package_name": "com.sampleapp.rnpushtest"
}
},
"oauth_client": [
{
"client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "674907137625-2a06km2oshvi7e9m52v95a30u0ek36up.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.getstream.expotiktokapp"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:674907137625:android:c02fbdcc683148e1d7f348",
Expand Down Expand Up @@ -706,6 +670,42 @@
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:674907137625:android:cba499ae72f6ee4bd7f348",
"android_client_info": {
"package_name": "io.getstream.reactnative.sampleapp"
Comment thread
xsahil03x marked this conversation as resolved.
}
},
"oauth_client": [
{
"client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyBArS4RH7lUn3xbD-jhzWl5hVWZhliRgY0"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "674907137625-o5iqvv6dtmljtn069b5djv19ad9a7js0.apps.googleusercontent.com",
"client_type": 3
},
{
"client_id": "674907137625-2a06km2oshvi7e9m52v95a30u0ek36up.apps.googleusercontent.com",
"client_type": 2,
"ios_info": {
"bundle_id": "io.getstream.expotiktokapp"
}
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:674907137625:android:e20ff8f1ccbf76e4d7f348",
Expand Down
6 changes: 6 additions & 0 deletions sample_app/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,11 @@
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />

<!-- Disable Crashlytics collection by default; re-enabled at runtime
for non-debug builds. -->
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="false" />
</application>
</manifest>
3 changes: 1 addition & 2 deletions sample_app/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ subprojects {
android.namespace = project.group
}

// Align the compileSdkVersion with Flutter's compileSdkVersion, but
// pin a floor of 36 so AAR metadata checks pass for transitive
// Pin a floor of 36 so AAR metadata checks pass for transitive
// dependencies that require it until Flutter's bundled
// compileSdkVersion catches up.
android.compileSdkVersion = Math.max(flutter.compileSdkVersion, 36)
Expand Down
1 change: 1 addition & 0 deletions sample_app/android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ plugins {
id "com.android.application" version "8.12.2" apply false
// START: FlutterFire Configuration
id "com.google.gms.google-services" version "4.4.3" apply false
id "com.google.firebase.crashlytics" version "2.8.1" apply false
// END: FlutterFire Configuration
id "org.jetbrains.kotlin.android" version "2.1.20" apply false
}
Expand Down
14 changes: 10 additions & 4 deletions sample_app/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -268,14 +268,18 @@
"${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework",
"${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCoreExtension/FirebaseCoreExtension.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseCrashlytics/FirebaseCrashlytics.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop.framework",
"${BUILT_PRODUCTS_DIR}/FirebaseSessions/FirebaseSessions.framework",
"${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework",
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
"${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework",
"${BUILT_PRODUCTS_DIR}/PromisesSwift/Promises.framework",
"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
"${BUILT_PRODUCTS_DIR}/Sentry/Sentry.framework",
"${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework",
"${BUILT_PRODUCTS_DIR}/audio_session/audio_session.framework",
"${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework",
Expand All @@ -296,7 +300,6 @@
"${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework",
"${BUILT_PRODUCTS_DIR}/photo_manager/photo_manager.framework",
"${BUILT_PRODUCTS_DIR}/record_ios/record_ios.framework",
"${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework",
"${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework",
"${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework",
"${BUILT_PRODUCTS_DIR}/sqflite_darwin/sqflite_darwin.framework",
Expand All @@ -311,14 +314,18 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreExtension.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCrashlytics.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseRemoteConfigInterop.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseSessions.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Promises.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sentry.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/audio_session.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework",
Expand All @@ -339,7 +346,6 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/photo_manager.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/record_ios.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sentry_flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite_darwin.framework",
Expand Down
2 changes: 2 additions & 0 deletions sample_app/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>FirebaseCrashlyticsCollectionEnabled</key>
<false/>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppleMusicUsageDescription</key>
Expand Down
9 changes: 5 additions & 4 deletions sample_app/lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import 'dart:async';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
Expand All @@ -21,7 +22,6 @@ import 'package:sample_app/state/init_data.dart';
import 'package:sample_app/utils/app_config.dart';
import 'package:sample_app/utils/local_notification_observer.dart';
import 'package:sample_app/utils/localizations.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_localizations/stream_chat_localizations.dart';
import 'package:stream_chat_persistence/stream_chat_persistence.dart';
Expand Down Expand Up @@ -245,11 +245,12 @@ final chatPersistentClient = StreamChatPersistenceClient(
void _sampleAppLogHandler(LogRecord record) async {
if (kDebugMode) StreamChatClient.defaultLogHandler(record);

// report errors to sentry.io
// report errors to Firebase Crashlytics
if (record.error != null || record.stackTrace != null) {
await Sentry.captureException(
await FirebaseCrashlytics.instance.recordError(
record.error,
stackTrace: record.stackTrace,
record.stackTrace,
reason: record.message,
);
}
}
Expand Down
2 changes: 0 additions & 2 deletions sample_app/lib/firebase_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@ class DefaultFirebaseOptions {
storageBucket: 'stream-chat-internal.appspot.com',
androidClientId:
'674907137625-0aa50j6b2i35ef9c52lsbk1v16otl492.apps.googleusercontent.com',
iosClientId:
'674907137625-p3msks3snq0h22l7ekpqcf0frr0vt8mg.apps.googleusercontent.com',
iosBundleId: 'io.getstream.streamChatV1',
);
}
61 changes: 27 additions & 34 deletions sample_app/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,53 +1,46 @@
import 'dart:async';

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:sample_app/app.dart';
import 'package:sample_app/firebase_options.dart';
import 'package:sample_app/utils/app_config.dart';
import 'package:sentry_flutter/sentry_flutter.dart';

Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();

// Initialize Firebase before wiring Crashlytics handlers so the error
// reporters have a live Firebase app to talk to.
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);

// Avoid sending Crashlytics reports for crashes that happen during local
// development; reports still flow in release/profile builds.
if (!kDebugMode) {
await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);
}

/// Captures errors reported by the Flutter framework.
FlutterError.onError = (FlutterErrorDetails details) {
if (kDebugMode) {
// In development mode, simply print to console.
FlutterError.dumpErrorToConsole(details);
} else {
// In production mode, report to the application zone to report to sentry.
Zone.current.handleUncaughtError(details.exception, details.stack!);
// In production mode, report the framework error to Crashlytics as fatal
// so it surfaces alongside native crashes.
FirebaseCrashlytics.instance.recordFlutterFatalError(details);
}
};

/// Captures errors reported by the native environment, including native iOS
/// and Android code.
Future<void> reportError(dynamic error, StackTrace stackTrace) async {
// Print the exception to the console.
if (kDebugMode) {
// Print the full stacktrace in debug mode.
print(stackTrace);
return;
} else {
// Send the Exception and Stacktrace to sentry in Production mode.
await Sentry.captureException(error, stackTrace: stackTrace);
}
}
/// Captures errors reported by the platform dispatcher, including async
/// errors thrown outside the Flutter framework (e.g. from native iOS and
/// Android code via platform channels).
PlatformDispatcher.instance.onError = (error, stack) {
// In debug, return false so the embedder logs the error and the IDE can
// break on it. In release, hand it to Crashlytics and mark it handled.
if (kDebugMode) return false;

/// Runs the app wrapped in a [Zone] that captures errors and sends them to
/// sentry.
runZonedGuarded(
() async {
WidgetsFlutterBinding.ensureInitialized();

// Wait for Sentry and Firebase to initialize before running the app.
await Future.wait([
SentryFlutter.init((options) => options.dsn = sentryDsn),
Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform),
]);
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true;
};
Comment thread
coderabbitai[bot] marked this conversation as resolved.

runApp(const StreamChatSampleApp());
},
reportError,
);
runApp(const StreamChatSampleApp());
}
3 changes: 0 additions & 3 deletions sample_app/lib/utils/app_config.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import 'package:stream_chat_flutter/stream_chat_flutter.dart';

const sentryDsn =
'https://6381ef88de4140db8f5e25ab37e0f08c@o1213503.ingest.sentry.io/6352870';

const kDefaultStreamApiKey = 'kv7mcsxr24p8';

final defaultUsers = <String, User>{
Expand Down
Loading
Loading