Vinaya Augusthy
Vinaya Augusthy

Reputation: 91

Flutter DeepLinking is not naviagting to app

I am using deeplinks to reset password. User will get an email from clicking reset button from email app should open. But instead it opening to browser. I am using app_links: ^6.3.3 package and I have my on routes class instead of GoRouter. I have assetlinks.json file uploaded in server and necessary parameters on manifest file.

class DeepLinkService {
 // Handles incoming links while the app is already started (foreground or               background).
  static void handleIncomingLinks() {
   log('called');
    AppLinks().uriLinkStream.listen((Uri? uri) async {
      WidgetsBinding.instance.addPostFrameCallback((_) async {
        if (uri != null) {
          debugPrint('Incoming link: $uri');
          _handleIncomingLink(uri);
        }
      });
    }, onError: (Object err) {
      FirebaseCrashlytics.instance.recordError(err, null);
      CustomLogger.error('Error handling incoming link: $err');
    });
  }

  // Handles the initial URI when the app is first started.
  static Future<void> handleInitialUri() async {
    try {
      final uri = await AppLinks().getInitialLink();
      log('$uri');
      if (uri != null) {
        WidgetsBinding.instance.addPostFrameCallback((_) async {
          debugPrint('Initial URI: $uri');
          _handleIncomingLink(uri);
        });
      }
    } on PlatformException catch (e, st) {
      FirebaseCrashlytics.instance.recordError(e, st);
      CustomLogger.error('Failed to get initial URI: $e');
    } on FormatException catch (e, st) {
      FirebaseCrashlytics.instance.recordError(e, st);
      CustomLogger.error('Malformed initial URI: $e');
    } catch (e, st) {
      FirebaseCrashlytics.instance.recordError(e, st);
      CustomLogger.error('Unknown error: $e');
    }
  }

  // Parses the incoming URI and performs navigation.
  static void _handleIncomingLink(Uri uri) {
    try {
      final token = uri.queryParameters['token'];
      if (token != null && token.isNotEmpty) {
        if (!navigatorKey.currentState!.canPop()) {
          navigatorKey.currentState!.pushNamed(
            AppRoutesNames.resetPasswordView,
            arguments: {'token': token},
          );
        }
      } else {
        CustomLogger.error('Token is missing or empty in the URI.');
      }
   } catch (e, st) {
      FirebaseCrashlytics.instance.recordError(e, st);
      CustomLogger.error('Error handling incoming link: $e');
    }
  }

>! StartUpView will take user to appropriate screens based on login status

class StartupView extends ConsumerStatefulWidget {
  const StartupView({super.key});

  @override
  ConsumerState<ConsumerStatefulWidget> createState() => _StartupViewState();
}

class _StartupViewState extends ConsumerState<StartupView> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) async {
      await ref.read(startupVMProvider).initialize();
    });
  }

  @override
  Widget build(BuildContext context) {
    DeepLinkService.handleIncomingLinks();
    DeepLinkService.handleInitialUri();

    final startupVM = ref.watch(startupVMProvider);

    if (!startupVM.isAuthStateLoaded) {
      return const Scaffold(
        body: Center(
          child: CircularProgressIndicator(),
        ),
      );
    }

    return StreamBuilder(
      stream: ref.watch(authServiceProvider).userState,
      builder: (context, snapshot) {
        if (snapshot.hasError) {
          return Center(
            child: ErrorView(),
          );
        } else if (snapshot.hasData) {
          if (ref.watch(authServiceProvider).isLogged) {
            return const LocalAuthView();
          } else if (ref.watch(authServiceProvider).isLogged &&
              !ref.watch(authServiceProvider).hasAcceptedTermsAndConditions) {
            return PrivacyPolicyView();
          } else {
            return const WelcomeView();
          }
        } else {
          return const SizedBox();
        }
      },
    );
  }
}

>! For navigation

class AppRoutesNames {
  static const String localAuthView = '/localAuthView';
  static const String deactivePage = '/deactivePage';
  static const String invitationView = '/invitationView';
  static const String homeView = '/homeView';
  static const String detailsView = '/detailView';
  static const String errorView = '/errorView';
  static const String registrationView = '/registrationView';
  static const String loginView = '/loginView';
  static const String emailOtpView = '/emailOtpView';
  static const String resetPasswordView = '/resetPasswordView';
  static const String recoverPasswordView = '/recoverPasswordView';
  static const String welcomeView = '/welcomeView';
  static const String allDoneSuccessView = "/allDoneSuccessView";
  static const String resetPasscodeView = '/resetPasscodeView';
  static const String noInternetView = '/noInternetView';
}

class AppRouter {
  Route? onGenerateRoute(RouteSettings settings) {
    switch (settings.name) {
      case AppRoutesNames.homeView:
        return MaterialPageRoute(
          builder: (context) => const HomeView(),
        );
      case AppRoutesNames.resetPasswordView:
        final args = settings.arguments as Map<String, dynamic>;
        return MaterialPageRoute(
            builder: (context) => ResetPasswordView(token: args['token']));
      default:
        return null;
    }
  }
}

//manifest -->

         <intent-filter android:autoVerify="true">
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:host=hostName />
            <data android:host=hostName" />
            <data android:scheme="https" />
        </intent-filter> 

Upvotes: 2

Views: 48

Answers (0)

Related Questions