I want to execute a function when the Flutter app starts - flutter

I want to send an ID to the server and receive json when the app is launched.
Flow
1.Start my app (Show splash screen)
2.Json request to server
3.If there is data, display page1. If not, display page2

it seems you my need to get a bit more learning about Flutter, my sugest is to start with this one only 10 euros will give you base from where will be easier to learn the rest, that said, to get a databse i'm using this code:
//lib/services/networking_service.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class NetworkHelper {
final String json;
final url = 'HERE YOU CAN PUT YOUR API URL';
NetworkHelper(this.json);
Map<String, String> headers = {
"Content-type": "application/x-www-form-urlencoded"
};
Future getData(BuildContext context) async {
http.Response response = await http.post(url, body: json, headers: headers);
if (response.statusCode == 200) {
Map<String, dynamic> decodedResp = jsonDecode(response.body);
print(decodedResp);
return decodedResp;
} else {
print(response.statusCode);
return null;
}
}
}
You can call it from your main like this:
static getCategories(BuildContext context) async {
String json =
'q={"f":"listCategories","Store_id":"$storeId","LANG":"$lang","UID":"$uid"}';
//THIS json VARIABLE IS WHERE YOU NEED TO PUT YOUR API CALL LĂ“GIC TO GET THAT ID, I LEAVE THIS FOR YOUR BETTER UNDERSTANDING
NetworkHelper networkHelper = NetworkHelper(json);
var decodedResp = await networkHelper.getData(context);
final CategoriesModel respData = CategoriesModel.fromJson(decodedResp);
print(respData);
//HERE YOU MAY RETURN O STORE IN PROVIDER YOUR RESPONSE AND SEND THE USER TO THE PAGE YOU CONSIDER
}
If you need more help I'm happy to help, but consider taking the course o learn a bit more, it will be lots more easy and enjoyable after.

use SchedulerBinding it runs when page is opened and widgets are build.
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
// your code after page opens,splash keeps open until work is done
});
}

#override
void initState() {
super.initState();
Timer(
Duration(seconds: 3),// you can do your stuff here when splash screen run
() => Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (BuildContext context) => LoginScreen())));}
and please put this code into the spalsh screen

Related

How can I get user information after successful login and show ir inn a drawer?

List item
I'm trying to get information after storing information from successful login and displaying that information in a UserAccountsDrawerHeader.
But without using a future builder or list builder.
example:: accountName:Text("info name from database")
how could that be done?
help would be greatly appreciated.
code:
-- Services--
Future <List>InfoCabeceraDrawer() async{
Map<String, String> headers = {
'Content-Type':'application/json;charset=UTF-8',
'Charset':'utf-8'
};
var Url= Uri.parse("http://");
final response = await http.get((Url),headers: headers);
print(response.body);
return productDrawerFromJson(response.body);
}
--- Model--
List productCabeceraDrawerFromJson(String str) => List<CabeceraDrawerModel>.from(json.decode(str).map((x) => CabeceraDrawerModel.fromJson(x)));// con esto hago el get
class CabeceraDrawerModel{
String UsuarioPk;
String FotoUsuario;
String CorreoUsuario;
String NombreUsuario;
CabeceraDrawerModel({this.UsuarioPk,this.FotoUsuario,this.NombreUsuario,this.CorreoUsuario});
factory CabeceraDrawerModel.fromJson(Map<String, dynamic> parsedJson){
return CabeceraDrawerModel(
UsuarioPk: parsedJson['Usu'],
FotoUsuario:parsedJson['im'],
NombreUsuario: parsedJson['Usuar'],
CorreoUsuario:parsedJson['Usuario_C']
);
}
}
-- front--
#override
void initState() {
super.initState();
}
UserAccountsDrawerHeader(
accountName: Text("show information data base"),
accountEmail:Text(""),
),
You can use one of the State management approaches that Flutter mentioned here.

How do I ensure a specific execution order when forced to use Dart async/await

I am writing a basic programme to teach myself Dart/Flutter. Part of the programme uses the http.dart package to get some data and the http.get command returns a Future value. In order to unpack this value, I need to use an await command, which then changes the execution order of my code. I cannot work out how to preserve the intended execution order whilst using async/await. I am new to this, so appreciate that I am probably missing something obvious.
Code example 1 below uses async/await through a series of functions. This approach gives more or less the correct output order (other than the end of main()), but would mean (I think) that I would need to have an async build() method, which is not valid in Flutter.
// Cascading async methods with local variables and await statements
import 'dart:async';
import 'dart:math';
import 'package:http/http.dart' as http;
void main(List<String> arguments) {
print('Main: start.');
_build();
print('Main: end.');
}
// Draw some stuff, make some decisions
void _build() async {
print('build: Before getName.');
String name = await _getName();
print('build: After getName.');
}
// Get some data, make some decisions
Future<String> _getName() async {
print('getName: before getData');
String name = await _getData();
print('getName: after getData');
double val = Random().nextDouble();
if (val < 0.5) {
print('getName: returning body.data');
return name;
} else {
print('getName: returning Bob');
return 'Bob';
}
}
// Get the data via an http request
Future<String> _getData() async {
print('getData: Before http get.');
final data = await http.get(Uri.parse('http://www.google.co.uk'));
print('getData: After http get.');
return data.body;
}
The output from this is (I have truncated the html data that is returned):
Main: start.
build: Before getName.
getName: before getData
getData: Before http get.
Main: end.
getData: After http get.
getName: after getData
getName: returning body.data
build: After getName. Name is: <html data>
The second code example below uses a global variable to capture data in the _getName() method so that I can avoid using async/await in the build() method. This does not give the correct execution order or the correct output.
// Use global variable to receive awaited data and avoid cascading async methods
import 'dart:async';
import 'dart:math';
import 'package:http/http.dart' as http;
String name = "";
void main(List<String> arguments) {
print('Main: start.');
_build();
print('Main: end.');
}
// Draw some stuff, make some decisions
void _build() {
print('build: Before getName.');
_getName();
print('build: After getName. Name is: $name');
}
// Get some data, make some decisions
Future<void> _getName() async {
print('getName: before getData');
String data = await _getData();
print('getName: after getData');
double val = Random().nextDouble();
if (val < 0.5) {
print('getName: setting name = body.data');
name = data;
} else {
print('getName: setting name = Bob');
name = 'Bob';
}
return;
}
// Get the data via an http request
Future<String> _getData() async {
print('getData: Before http get.');
final data = await http.get(Uri.parse('http://www.google.co.uk'));
print('getData: After http get.');
return data.body;
}
The output from this code is shown below. Note that the build() method completed before _getData and _getName and the name printed in build() is empty in the 5th row.
Main: start.
build: Before getName.
getName: before getData
getData: Before http get.
build: After getName. Name is:
Main: end.
getData: After http get.
getName: after getData
getName: setting name = body.data
In the third example below, I have tried using .then to ensure that the code in each function only executes after the await command. I didn't think this would work (and it didn't) because I think I have a problem controlling the flow between functions, not a problem controlling the flow within functions, but I thought I should give it a go and I was clutching at straws by this point.
// Use global variable to avoid using await in build() method
// Use .then to ensure that method actions follow await command
import 'dart:async';
import 'dart:math';
import 'package:http/http.dart' as http;
String name = ""; // Global variable for async data return
void main(List<String> arguments) {
print('Main: start.');
_build();
print('Main: end.');
}
// Draw some stuff, make some decisions
void _build() {
print('build: Before getName.');
_getName();
print('build: After getName. Name is: $name');
}
// Get some data, make some decisions
Future<void> _getName() async {
print('getName: before getData');
await _getData().then((data) {
print('getName: after getData');
double val = Random().nextDouble();
if (val < 0.5) {
print('getName: setting name = body.data');
name = data;
} else {
print('getName: setting name = Bob');
name = 'Bob';
}
});
return;
}
// Get the data via an http request
Future<String> _getData() async {
print('getData: Before http get.');
String value = "";
await http.get(Uri.parse('http://www.google.co.uk')).then((data) {
print('getData: After http get.');
value = data.body;
});
return value;
}
The output from this code is shown below. As with the second example, the execution is not in the correct order and the name printed in the build() method is empty.
Main: start.
build: Before getName.
getName: before getData
getData: Before http get.
build: After getName. Name is:
Main: end.
getData: After http get.
getName: after getData
getName: setting name = Bob
Ideally, the output from the programme should be:
Main: start.
build: Before getName.
getName: before getData
getData: Before http get.
getData: After http get.
getName: after getData
getName: setting name = Bob
build: After getName. Name is: Bob
Main: end.
How do I write my code so that I can use the http.get method and ensure that my code executes in the order that I want? I'll just add that I have read A LOT of stackoverflow questions, flutter documentation and general help online, but not found anything that answers my question so far.
Or nothing that I understand. :D Apologies if this is a stupid question. I am a noob at this.
I should have added that this example is an simplification of the problem in a Flutter app I am writing (noughts and crosses). This is checking for a win/draw after each move, then reading data from a DB, updating the results and writing them back to the DB. It also updates the game state to show that the game is over. The problem caused by async/await is that gamestate isn't being updated whilst the functions await the data and the game continues in the "playing" state even though the game is over. Pseudo code of the programme below (this is a bit scrappy, but hopefully it illustrates the problem).
build() {
checkState(win, draw or continue?);
if (continue){
_humanMove();
_computerMove();
drawTheWidgets;
} else {
drawDifferentWidgets; // New game
}
}
void _humanMove() async {
processMove;
if (win/draw) {
await _updateResults;
updateGameState(game over);
}
}
void _computerMove() async {
processMove;
if (win/draw) {
await _updateResults;
updateGameState(game over);
}
}
results _updateResults() async {
await http.get data results in database;
updateWithResult;
await http.put data results in database;
}
You need to wait ("await") for all the function calls, see:
void main(List<String> arguments) async {
print('Main: start.');
await _build();
print('Main: end.');
}
// Draw some stuff, make some decisions
Future<void> _build() async {
print('build: Before getName.');
await _getName();
print('build: After getName. Name is: $name');
}
// Get some data, make some decisions
Future<void> _getName() async {
print('getName: before getData');
String data = await Future.delayed(const Duration(milliseconds: 500), () {
return 'x';
});
print('getName: after getData');
double val = 5;
if (val < 0.5) {
print('getName: setting name = body.data');
name = data;
} else {
print('getName: setting name = Bob');
name = 'Bob';
}
return;
}
One comment: I believe it's easier for you to learn to do this right, if you try to learn this not based on console output, but with a Flutter app. You would see that your program goes through different states that actually need time - before, during and after your http request.
In your build method of a widget, you would need to provide something to show for for each state of your program. So you actually do not wait (await) for results, but update the state based on the results. And depending on that, your build method is prepared to take the different states and show something adequate. Then async/await is quite nice.
--- adding the following in response to the clarifying comment ---
The build method of a widget is not where you put business logic of your app. Build is called whenever a widget is rebuild (if you have a http request writing in a database, it would be triggered a whole number of times!). Trying to apply the steps you wanted your app to do in your first description with the intended output on the console, I tried to write this clarifying app (and to have different states that your app passes through I included that you have to click the icon button / FloatingActionButton to trigger the process). Please have a look how the build method of the second widget deals with all the different states (it prints them to the console and shows a text - you could do more fancy stuff there of course, based on what the state of your app implies). The real "action" (changes of the state of your app) is happening elsewhere:
import 'package:flutter/material.dart';
class ExampleWidget extends StatefulWidget {
const ExampleWidget({Key? key}) : super(key: key);
#override
_ExampleWidgetState createState() => _ExampleWidgetState();
}
class _ExampleWidgetState extends State<ExampleWidget> {
String _showWhatsHappening = 'Before getName.';
Future<String> _getData() async {
setState(() {
_showWhatsHappening = 'getData: Before http get.';
});
final data = await Future.delayed(const Duration(milliseconds: 500), () {
return 'Bob';
});
setState(() {
_showWhatsHappening = 'getData: After http get.';
});
await Future.delayed(const Duration(milliseconds: 300));
return data;
}
#override
void initState() {
print('not main, but initstate: start.');
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Demo',
theme: ThemeData(brightness: Brightness.light, fontFamily: 'Example'),
home: Scaffold(
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.star_outline),
onPressed: () async {
setState(() {
_showWhatsHappening = 'before getData ';
});
final x = await _getData();
await Future.delayed(const Duration(milliseconds: 300));
setState(() {
_showWhatsHappening = 'after getData ';
});
await Future.delayed(const Duration(milliseconds: 300));
setState(() {
_showWhatsHappening = 'setting name = $x';
});
},
),
body: Center(child: ShowItWidget(showIt: _showWhatsHappening)),
),
);
}
}
class ShowItWidget extends StatelessWidget {
final String showIt;
const ShowItWidget({Key? key, required this.showIt}) : super(key: key);
#override
Widget build(BuildContext context) {
print(showIt);
return Text(showIt);
}
}
void main() {
runApp(const ExampleWidget());
}
For completeness, here is my Dart-specific solution using Streams.
// Use global variable to receive awaited data
// Use StreamController to wait for async methods to finish
import 'dart:async';
import 'dart:math';
import 'package:http/http.dart' as http;
String name = "";
StreamController streamController = StreamController.broadcast();
void main(List<String> arguments) {
print('Main: start.');
_build();
print('Main: end.');
}
// Draw some stuff, make some decisions
void _build() {
print('build: Before getName.');
_getName();
streamController.stream.listen((args) {
print('build: After getName. Name is: $name');
});
}
Future<void> _getName() async {
print('getName: before getData');
String data = await _getData();
print('getName: after getData');
double val = Random().nextDouble();
if (val < 0.5) {
print('getName: setting name = body.data');
name = data.length.toString();
} else {
print('getName: setting name = Bob');
name = 'Bob ${data.length.toString()}';
}
print('gateName. Name is $name');
streamController.add(name);
return;
}
// Get the data via an http request
Future<String> _getData() async {
print('getData: Before http get.');
final data = await http.get(Uri.parse('http://www.google.co.uk'));
print('getData: After http get.');
return data.body;
}

Flutter How to pass data from one screen to another if I need it before the BuildContext?

I want to send a request with a specific id but I can only get the id after I receive it from previous screen in the build widget
void gettingTime() async {
final response = await http.get(
Uri.parse('http://192.168.1.11/Backend/dateValide.php?id=$id'),);
print("StatusCodeDetail== ${response.statusCode}");
if (response.statusCode == 200 || response.statusCode == 201) {
setState(() {
dataListTime = json.decode(response.body); //we store the json data in a list
print("RESPONSE${response.body}");
});
}
else {
print("Error in loading from the server");
}
}
#override
void initState() {
gettingTime();
super.initState();
}
#override
Widget build(BuildContext context) {
dataMap=ModalRoute.of(context)?.settings.arguments as Map;//We recieve the data as a Map from the home screen
String id=dataMap["previousScreenData"]["ID_EXCURSION"];
Pass the id as an argument for the widget's constructor using the router
Edit: You didn't really ask a question, so I answered: "How can I pass data from one screen to another if I need it before the BuildContext is known?" Hope it helps :-)

Flutter: response variable blank in http request

I am trying to create a profile page for my flutter app
Here is a snippet
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class MyProfile extends StatefulWidget {
#override
_MyProfileState createState() => _MyProfileState();
}
class _MyProfileState extends State<MyProfile> {
bool visible=false;
var postData=List();
var jsonData;
Future accountInfo()async{
var url ='http://192.168.0.107/get_account.php';
var response= await http.get(url);
var jsonData= json.decode(response.body);
setState(() {
postData=jsonData;
});
debugPrint(jsonData);
return jsonData;
}
#override
void initState(){
super.initState();
accountInfo();
}
However, the variables postData and jsonData are returned as null.
Value of postData=[]
The API is working perfectly, tried it with postman and also tried intercepting with a proxy tool.
I am getting a valid json response body. But the values are not passed onto jsonData or postData.
When I use postData inside a text widget i get this error:-
RangeError(index): Index out of Range: no indices are valid: 0
You defined two jsonData. That may be the reason. Also, set jsonData inside setState(), too. Try this:
var jsonData;
Future accountInfo()async{
setState(() {
visible=true;
});
var url ='http://192.168.0.107/get_account.php';
var response = await http.get(url);
setState(() {
jsonData = json.decode(response.body); // Here we changed!
postData = jsonData;
});
The solution is to define jsonData as
Map<String, dynamic> jsonData= jsonDecode(response.body);

Firebase Dynamic Link is not caught by getInitialLink if app is closed and opened by that link

Programmatically generated dynamic links are not properly catched by
FirebaseDynamicLinks.instance.getInitialLink().
if the app is closed. However, if the app is open it is properly detected by the listener for new incoming dynamic links. It is not clear to me if it is a setup problem, how I generate the dynamic link.
To Reproduce
First set up Firebase for Flutter project as documented. Then to set up a dynamic link:
/// See also
/// https://firebase.google.com/docs/dynamic-links/use-cases/rewarded-referral
/// how to implement referral schemes using Firebase.
Future<ShortDynamicLink> buildDynamicLink(String userId) async {
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
final String packageName = packageInfo.packageName;
var androidParams = AndroidParameters(
packageName: packageInfo.packageName,
minimumVersion: Constants.androidVersion, // app version and not the Android OS version
);
var iosParams = IosParameters(
bundleId: packageInfo.packageName,
minimumVersion: Constants.iosVersion, // app version and not the iOS version
appStoreId: Constants.iosAppStoreId,
);
var socialMetaTagParams = SocialMetaTagParameters(
title: 'Referral Link',
description: 'Referred app signup',
);
var dynamicLinkParams = DynamicLinkParameters(
uriPrefix: 'https://xxxxxx.page.link',
link: Uri.parse('https://www.xxxxxxxxx${Constants.referralLinkPath}?${Constants.referralLinkParam}=$userId'),
androidParameters: androidParams,
iosParameters: iosParams,
socialMetaTagParameters: socialMetaTagParams,
);
return dynamicLinkParams.buildShortLink();
}
This dynamic link then can be shared with other new users.
I listen for initial links at app startup and then for new incoming links.
1) The link properly opens the app if the app is not running but the getInitialLink does not get it.
2) If the app is open the link is properly caught by the listener and all works.
Here is the very simple main.dart that I used to verify 1) that the initial link is not found with FirebaseDynamicLinks.instance.getInitialLink().
void main() async {
WidgetsFlutterBinding.ensureInitialized();
PendingDynamicLinkData linkData = await FirebaseDynamicLinks.instance.getInitialLink();
String link = linkData?.link.toString();
runApp(MyTestApp(link: link));
}
class MyTestApp extends StatelessWidget {
final String link;
MyTestApp({this.link});
#override
Widget build(BuildContext context) {
return MaterialApp(
builder: (BuildContext context, Widget child) {
return Scaffold(
body: Container(
child: Center(
child: Text('Initial dynamic Firebase link: $link')
),
),
);
}
);
}
}
Expected behavior
The link should open the app and trigger FirebaseDynamicLinks.instance.getInitialLink()..
Additional context
I hope properly configured Firebase project with Firebase console. To verify this I created a dynamic link to be used with Firebase Auth 'signup by email link' and these dynamic links are working as expected, also when the app is not open.
The point here is that the referral dynamic link that I generate programmatically is opening the app when it is closed but is then not caught by FirebaseDynamicLinks.instance.getInitialLink(), and to make things more confusing, works as expected if the app is open. In that case it is caught by the listener FirebaseDynamicLinks.instance.onLink.
I also set up the WidgetsBindingObserver in Flutter to handle that callback as required, when the app gets its focus back.
Any help is greatly appreciated. Debugging is very tricky, as you need to do it on a real device and not in the simulator. To make things worse, I did not figure out how to attach a debugger while the dynamic link opens the app. This means I am also stuck in investigating this issue further.
In The FirebaseDynamicLinks Two Methods 1) getInitialLink() 2) onLink().
If When Your App Is Open And You Click On Dynamic Link Then Will Be Call FirebaseDynamicLinks.instance.onLink(), If Your App Is Killed Or Open From PlayStore Then You Get From FirebaseDynamicLinks.instance.getInitialLink();.
First Of You Need To Initialise Instance Of FirebaseDynamicLinks.instance.
static void initDynamicLinks() async {
final PendingDynamicLinkData data =
await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null && deepLink.queryParameters != null) {
SharedPrefs.setValue("param", deepLink.queryParameters["param"]);
}
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null && deepLink.queryParameters != null) {
SharedPrefs.setValue("param", deepLink.queryParameters["param]);
}
}, onError: (OnLinkErrorException e) async {
print(e.message);
});
}
Initialize Link Listener. This works for me.
class _MainAppState extends State<MainApp> {
Future<void> initDynamicLinks() async {
print("Initial DynamicLinks");
FirebaseDynamicLinks dynamicLinks = FirebaseDynamicLinks.instance;
// Incoming Links Listener
dynamicLinks.onLink.listen((dynamicLinkData) {
final Uri uri = dynamicLinkData.link;
final queryParams = uri.queryParameters;
if (queryParams.isNotEmpty) {
print("Incoming Link :" + uri.toString());
// your code here
} else {
print("No Current Links");
// your code here
}
});
// Search for Firebase Dynamic Links
PendingDynamicLinkData? data = await dynamicLinks
.getDynamicLink(Uri.parse("https://yousite.page.link/refcode"));
final Uri uri = data!.link;
if (uri != null) {
print("Found The Searched Link: " + uri.toString());
// your code here
} else {
print("Search Link Not Found");
// your code here
}
}
Future<void> initFirebase() async {
print("Initial Firebase");
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// await Future.delayed(Duration(seconds: 3));
initDynamicLinks();
}
#override
initState() {
print("INITSTATE to INITIALIZE FIREBASE");
super.initState();
initFirebase();
}
I tried Rohit's answer and because several people face the same issue I add here some more details. I created a stateful widget that I place pretty much at the top of the widget tree just under material app:
class DynamicLinkWidget extends StatefulWidget {
final Widget child;
DynamicLinkWidget({this.child});
#override
State<StatefulWidget> createState() => DynamicLinkWidgetState();
}
class DynamicLinkWidgetState extends State<DynamicLinkWidget> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
locator.get<DynamicLinkService>().initDynamicLinks();
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(child: widget.child);
}
}
I use the getit package to inject services. The dynamic link service is roughly like this:
class DynamicLinkService {
final UserDataService userDataService;
final ValueNotifier<bool> isLoading = ValueNotifier<bool>(false);
final BehaviorSubject<DynamicLinkError> _errorController = BehaviorSubject<DynamicLinkError>();
Stream<DynamicLinkError> get errorStream => _errorController.stream;
DynamicLinkService({#required this.userDataService});
void initDynamicLinks() async {
final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
processDynamicLink(deepLink);
}
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
print('=====> incoming deep link: <${deepLink.toString()}>');
processDynamicLink(deepLink);
}
},
onError: (OnLinkErrorException error) async {
throw PlatformException(
code: error.code,
message: error.message,
details: error.details,
);
}
);
}
Future<void> processDynamicLink(Uri deepLink) async {
if (deepLink.path == Constants.referralLinkPath && deepLink.queryParameters.containsKey(Constants.referrerLinkParam)) {
var referrer = referrerFromDynamicLink(deepLink);
userDataService.processReferrer(referrer);
} else {
await FirebaseEmailSignIn.processDynamicLink(
deepLink: deepLink,
isLoading: isLoading,
onError: this.onError
);
}
}
void onError(DynamicLinkError error) {
_errorController.add(error);
}
}
You see that my app has to process two types of dynamic link, one is for email link signup, the other link is our referral link that is used to link users together and allow us to understand who introduced a new user to us. This setup works now for us. Hope it helps others too.