The article discusses implementing Flutter deep linking using Firebase Dynamic Links within a Bloc architecture framework, emphasizing layer independence and handling various user authentication scenarios.
Abstract
The author of the article addresses the challenge of integrating Firebase Dynamic Links for deep linking in a Flutter application while adhering to clean architecture principles using the Bloc library. The article provides a practical guide on structuring the app to handle deep links for users who are not authenticated, those who authenticate after the app is launched via a deep link, and when the app is running in the foreground or background. The approach involves creating a dedicated DeepLinkBloc to manage a FirebaseDynamicLinksRepository, ensuring that the logic layer remains independent of Firebase-specific dependencies. The author also demonstrates how to use helper packages like freezed and auto_route to simplify the code and describes the implementation of a repository and bloc to manage deep link states and events. The article concludes with an example of how to listen for deep links in the UserDashboardPage after user authentication and navigate to the appropriate content using Navigator 2.0.
Opinions
The author considers deep linking, especially with Firebase Dynamic Links, as a key feature to promote apps, drive traffic, and increase user engagement.
The use of the Bloc library by Felix Angelov is highly recommended for separating the logic, data, and presentation layers of the app.
The author emphasizes the importance of not hesitating to ask questions or seek clarification on parts of the implementation that may be unclear.
FirebaseDynamicLinks listeners are transformed into streams to better integrate with Bloc architecture.
The article suggests that maintaining a clean and structured codebase is crucial, and packages like flutter_bloc, get_it, freezed, and auto_route can significantly ease development efforts.
The author invites feedback on the tutorial and encourages support for their work through a 'buy me a coffee' link.
A recommendation is made for an AI service, ZAI.chat, as a cost-effective alternative to ChatGPT Plus (GPT-4), highlighting its capabilities and a special offer.
Flutter Deep Linking with Firebase Dynamic Links and Bloc architecture
While building my new app, I stumbled upon a gap in practical examples (for production purposes) on how to implement firebase dynamic links and deep linking in general when using bloc architecture.
Deep Linking and clean architecture consideration
I consider that deep linking, especially powered app by firebase dynamic links, is key to promote your app, drive traffic and increase engagement. In general they are used to streamline the user toward a specific content in your app.
When building an app it is important to try and separate the logic, layer, the data layer and the presentation layer. For that I’m using the great bloc library by Felix Angelov.
Initialization and firebase setup
The point of this article isn’t to show how to use and configure firebase dynamic links. If you need help with that, this is well documented on the flutter fire documentation here (steps 1 to 5 for android and iOS). Also I’ll use lots of concepts as a given and make use of few helper packages to simplify the code:
So please, do not hesitate to comment if you have any question or if you do not understand part of the implementation.
Set up the problem
In this article I’ll show you how I’ve structured my app to achieve layer independency and solve these 3 situations :
User NOT authenticated ->in this case we should consume the deep link, but wait for authentification
User authenticated after app has been launched trough a deep link -> in this case we should retrieve the link after the authentification
App is running (foreground or background) -> we should keep listening to deep links.
My approach
Main.dart: App and blocs initializations
My approach was to build a DeepLinkBloc dedicated to initialize and orchestrate a FirebaseDynamicLinksRepository. In this way the bloc (logic layer) will be independent of any firebase dependency (in case you would like to use another provider).
Also, the bloc will be provided at the top of our widget tree, alongside the AuthBloc (in charge of handling the authentification state). In this way the presentation layer will be able to access the bloc anywhere in your app.
The MaterialApp will listen to the AuthBloc at the top level of our application and be en charge to show the login page vs user dashboard page depending on the authentification status.
Thus this is my main.dart file:
DeepLinkRepository
the deep link repository will simply be a wrapper to make our logic layer independent from any Firebase reference.
Also FirebaseDynamicLinks use listeners callback to the onLink method to notify about a new links. In order to better plug into the bloc architecture, we will transform this listener into a stream to be consumed by our DeepLinkBloc.
For the sake of simplicity the createDynamicLink in this example is not implemented. I left the method declaration because it is often used in the official firebase documentation.
NOTE 1: I added a helper to close the stream that we will use for the deeplinks.
NOTE 2: I kept the getLinks and getInitialLink independents. It will be the bloc to initialize them in the correct order (getInitialLink has to be called after setting up the getLinks listener as per firebase documentation).
DeepLinkBloc
the deep link bloc will be quite straightforward.
We will have 3 different state:
Initial -> the bloc has not been initialized yet
Ready -> the bloc has been initialized and is ready to receive links
LinkPending -> a deep link has been used and needs processing
Therefore it’s pretty straightforward to deduce that these 3 events will allow to switch between states:
InitDeepLinking -> to get our bloc to the Ready state
AddPendingLink -> to notify that a new deep link has been received
ConsumePendingLink -> to go back to the Ready state
Finally the content of our bloc:
UserDashboardPage
Finally we will listen to change for the DeepLink bloc in the UserDashboardState. This is because we want to handle links only after the user is authenticated.
The BlocListener is the first element of the page. if the state is LinkPending, we will use the pushNamed method from the navigator 2.0 (which is used by auto_route) and notify the bloc that the link has been consumed.
Conclusion
And that’s it ! Navigator 2.0 support path navigation.
So if the link behind your dynamic link is something like https://deeplinkapp.com/user/book/the_doors_of_stone the state.link.path will return the /user/book/the_doors_of_stone path and route for the detail page of the The Door of Stone book from Patrick Rothfuss will show up (if it will ever be released LOL).
Here it is how the book details route is declared:
and the UserBookDetailsPage:
Thanks !!
I hope this will help you in your app developments and let you save some time as well as maybe teach you something! Never neglect to write to write your code in a clean and structured way. Clean architecture is just a design pattern but not the only one. Packages such as flutter_bloc, get_it, freezed, or auto_route may really make your life easier, so do not hesitate to use them.
I’m just starting to write down tutorials and articles about development, and this is one of my first posts, so please feel free to comment on it (any feedback is welcome) or support me by buying me a coffee.