newrelic / newrelic-flutter-agent

New Relic agent SDK for Flutter hybrid mobile apps
Apache License 2.0
6 stars 12 forks source link

New Relic package's NewRelicNavigationObserver is conflicting with the Go Router package. #110

Open ashiq-mvp opened 5 days ago

ashiq-mvp commented 5 days ago

`The following NoSuchMethodError was thrown building InheritedGoRouter(goRouter: Instance of 'GoRouter'):

Class 'RouteSettings' has no instance getter 'key'. Receiver: Instance of 'RouteSettings' Tried calling: key

When the exception was thrown, this was the stack:

0 Object.noSuchMethod (dart:core-patch/object_patch.dart:38:5)

object_patch.dart:38

1 NewRelicNavigationObserver._addGoRouterBreadcrumb (package:newrelic_mobile/newrelic_navigation_observer.dart:84:32)

2 NewRelicNavigationObserver.didPush (package:newrelic_mobile/newrelic_navigation_observer.dart:45:9)

newrelic_navigation_observer.dart:45

3 _NavigatorPushObservation.notify (package:flutter/src/widgets/navigator.dart:3471:14)

navigator.dart:3471

4 List.forEach (dart:core-patch/growable_array.dart:417:8)

growable_array.dart:417

5 NavigatorState._flushObserverNotifications (package:flutter/src/widgets/navigator.dart:4445:27)

navigator.dart:4445

6 NavigatorState._flushHistoryUpdates (package:flutter/src/widgets/navigator.dart:4407:5)

7 NavigatorState._updatePages (package:flutter/src/widgets/navigator.dart:4270:5)

navigator.dart:4270

8 NavigatorState.didUpdateWidget (package:flutter/src/widgets/navigator.dart:3911:7)

navigator.dart:3911

9 StatefulElement.update (package:flutter/src/widgets/framework.dart:5789:55)

framework.dart:5789

10 Element.updateChild (package:flutter/src/widgets/framework.dart:3941:15)

framework.dart:3941

11 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5642:16)

framework.dart:5642

12 Element.rebuild (package:flutter/src/widgets/framework.dart:5333:7)

13 ProxyElement.update (package:flutter/src/widgets/framework.dart:5946:5)

framework.dart:5946

14 Element.updateChild (package:flutter/src/widgets/framework.dart:3941:15)

framework.dart:3941

15 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5642:16)

framework.dart:5642

16 Element.rebuild (package:flutter/src/widgets/framework.dart:5333:7)

framework.dart:5333

17 ProxyElement.update (package:flutter/src/widgets/framework.dart:5946:5)`

I'm encountering this issue only in projects using Go Router, specifically after adding observers: [observer, NewRelicNavigationObserver()].

This is an urgent issue: the app keeps displaying a grey screen, which is affecting its functionality. Could you please investigate this as soon as possible? @ndesai-newrelic

ndesai-newrelic commented 5 days ago

@ashiq-mvp can you provide sample app where we can reproduce the issue?

ashiq-mvp commented 4 days ago

Package Version: newrelic_mobile: 1.0.9

Main:

void main() {
  runZonedGuarded(() async {
    WidgetsFlutterBinding.ensureInitialized();
    FlutterError.onError = NewrelicMobile.onError;
    final config = Config(
      accessToken: _getAppToken(),
      analyticsEventEnabled: true,
      networkErrorRequestEnabled: true,
      networkRequestEnabled: true,
      crashReportingEnabled: true,
      interactionTracingEnabled: true,
      httpResponseBodyCaptureEnabled: true,
      loggingEnabled: true,
      webViewInstrumentation: true,
      printStatementAsEventsEnabled: true,
      httpInstrumentationEnabled: true,
    );
    await NewrelicMobile.instance.startAgent(config);
    runApp(const MyApp());
  }, (error, stackTrace) {
    NewrelicMobile.instance.recordError(error, stackTrace);
  });
}

MyApp:

MaterialApp.router(
                title: "Araby AI",
                routerConfig: appRoute.router,
                debugShowCheckedModeBanner: false,
                builder: (context, child) {
                  final mediaQueryData = MediaQuery.of(context);
                  debugPrint(mediaQueryData.size.width.toString());
                  debugPrint(mediaQueryData.size.height.toString());
                  return MediaQuery(
                      data: mediaQueryData.copyWith(
                          textScaler: TextScaler.linear(
                              mediaQueryData.size.height > 932 ||
                                      mediaQueryData.size.width > 470
                                  ? 0.6
                                  : 1.0)),
                      child: child!);
                })

Route:

class AppRoute {
  static FirebaseAnalytics analytics = FirebaseAnalytics.instance;
  static FirebaseAnalyticsObserver observer =
      FirebaseAnalyticsObserver(analytics: analytics);
  final GoRouter router = GoRouter(
    initialLocation: "/splash_screen",
    observers: [observer, NewRelicNavigationObserver()],
    redirect: (context, state) {
      switch (InternetAvailabilityConfig.showNoInternetPage()) {
        case true:
          InternetAvailabilityConfig.prevRoute = state.matchedLocation;
          return NoInternetPage.routeName;
        case false:
          return InternetAvailabilityConfig.prevRoute;
        default:
          return null;
      }
    },
    refreshListenable: RefreshStream(
        InternetAvailabilityConfig.internetAvailabilityCubit.stream),
    routes: [
      GoRoute(
        name: SplashScreen.routeName,
        path: SplashScreen.routeName,
        builder: (context, state) => const SplashScreen(),
      ),
      GoRoute(
        path: NoInternetPage.routeName,
        builder: (context, state) => const NoInternetPage(),
      ),
      GoRoute(
        name: SelectLanguageScreen.routeName,
        path: SelectLanguageScreen.routeName,
        builder: (context, state) => const SelectLanguageScreen(),
      ),
      GoRoute(
          name: LoginRegisterScreen.routeName,
          path: LoginRegisterScreen.routeName,
          builder: (context, state) => const LoginRegisterScreen(),
          routes: [
            GoRoute(
              name: SignInScreen.routeName,
              path: SignInScreen.routeName,
              builder: (context, state) => const SignInScreen(),
              // routes: forgotPassRouteList
            ),
            GoRoute(
              name: RegisterScreen.routeName,
              path: RegisterScreen.routeName,
              builder: (context, state) => const RegisterScreen(),
            ),
          ]),
      GoRoute(
          name: HomeScreen.routeName,
          path: HomeScreen.routeName,
          builder: (context, state) => AppConfig.isNew
              ? const ChatScreen(backButton: true, fromBtmNavBar: false)
              : const HomeScreen(),
          routes: [
            GoRoute(
              name: ChatHomeScreen.routeName,
              path: ChatHomeScreen.routeName,
              builder: (context, state) => const ChatHomeScreen(),
            ),
            GoRoute(
              name: MainImageGenScreen.routeName,
              path: MainImageGenScreen.routeName,
              builder: (context, state) => const MainImageGenScreen(),
            ),
            GoRoute(
              name: ProfileScreen.routeName,
              path: ProfileScreen.routeName,
              builder: (context, state) => const ProfileScreen(),
            ),
            GoRoute(
              name: EditProfileScreen.routeName,
              path: EditProfileScreen.routeName,
              builder: (context, state) => const EditProfileScreen(),
            ),
            GoRoute(
              name: ManagePlan.routeName,
              path: ManagePlan.routeName,
              builder: (context, state) => const ManagePlan(),
            ),
            GoRoute(
              name: AccountSettings.routeName,
              path: AccountSettings.routeName,
              builder: (context, state) => const AccountSettings(),
            ),
            GoRoute(
              name: PlansScreen.routeName,
              path: PlansScreen.routeName,
              builder: (context, state) => const PlansScreen(),
            ),
            GoRoute(
              name: WriteNowScreen.routeName,
              path: WriteNowScreen.routeName,
              builder: (context, state) => const WriteNowScreen(),
            ),
            GoRoute(
              name: RichTextEditor.routeName,
              path: RichTextEditor.routeName,
              builder: (context, state) => const RichTextEditor(),
            ),
            GoRoute(
              name: TextToAudioScreen.routeName,
              path: TextToAudioScreen.routeName,
              builder: (context, state) => const TextToAudioScreen(),
            ),
            GoRoute(
              name: MainHistoryScreen.routeName,
              path: MainHistoryScreen.routeName,
              builder: (context, state) => const MainHistoryScreen(),
            ),
          ]),
    ],
  );
}

Hi, I'm sorry, but I can't share the full code of my app because the issue is occurring in a live project, not a test project. However, I'll provide the relevant code snippet along with the version of New Relic I'm using. Thank you for understanding.

Note: I have downgraded the New Relic version to a specific one because I'm encountering this issuehttps://github.com/newrelic/newrelic-flutter-agent/issues/109 in the newer versions. @ndesai-newrelic

ndesai-newrelic commented 1 day ago

@ashiq-mvp this is not very useful, we have our test Go router app where we are unable to reproduce the issue.