I have order which have 4 status : preparing , pending , delivering and delivered. and when the order status changed from one to another I wanted to show a notification to the user of the change occurs.
*I have used local notifications plugin. In order page widget shown here it is triggered by a stream above that get the order from fire-base.
*That's why I supposed that each time the status will change the orderPage will be rebuild again and initstate will be recalled and send the new notification msg with new status, but that didn't happen.
Another solution was to use didchangedependency but I got no different result.
This was a missed work I know, but this is what came to my mind.
*What I exactly want is something that make me listen on the status and when changes occur a function " singleNotification" will be called to show the notification.
any Help will be appreciated.
class OrderPage extends StatefulWidget {
const OrderPage({
Key key,
#required this.order,
}) : super(key: key);
final Order order;
#override
OrderPageState createState() {
return new OrderPageState();
}
}
class OrderPageState extends State<OrderPage> {
final DateTime now = DateTime.now().toUtc().add(
Duration(seconds: 3),
);
String title = "notification";
String msg = "";
FlutterLocalNotificationsPlugin localNotificationsPlugin =
FlutterLocalNotificationsPlugin();
initializeNotifications() async {
var initializeAndroid =
AndroidInitializationSettings('#mipmap/ic_launcher');
var initializeIOS = IOSInitializationSettings();
var initSettings = InitializationSettings(initializeAndroid, initializeIOS);
await localNotificationsPlugin.initialize(initSettings);
}
Future singleNotification(
DateTime datetime, String message, String subtext, int hashcode,
{String sound}) async {
var androidChannel = AndroidNotificationDetails(
'channel-id',
'channel-name',
'channel-description',
importance: Importance.Max,
priority: Priority.Max,
);
var iosChannel = IOSNotificationDetails();
var platformChannel = NotificationDetails(androidChannel, iosChannel);
localNotificationsPlugin.schedule(
hashcode, message, subtext, datetime, platformChannel,
payload: hashcode.toString());
}
#override
void initState() {
super.initState();
getMsgState(widget.order.status);
initializeNotifications();
singleNotification(
now,
title,
msg,
98123871,
);
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
getMsgState(widget.order.status);
initializeNotifications();
singleNotification(
now,
title,
msg,
98123871,
);
}
Widget build(BuildContext context) {
return Container();
}
String getMsgState(String orderStatus) {
switch (orderStatus) {
case 'pending':
return msg = "Your order is pending";
break;
case 'preparing':
return msg = "your order is currently preparing";
break;
case 'delivering':
return msg = "your order is currently delivering";
break;
case 'delivered':
return msg = "Your order is delivered";
default:
return msg = "CustomStepState.Complete";
break;
}
}
If I understand correctly, Firebase knows when the order status is changed. And it sends a notification. And you would like to show it to the user.
You can use FCM and Firebase in-app notification. One of my project had a similar requirement whether server does the processing and the Flutter mobile app shows the status. I did the following :
Wrote a small code on the server side which calls Firebase cloud message API with user display message and data payload.
Wrote a code on Flutter mobile app side to display the notification (in the in-app style) if the app is already in the foreground.
Sample code snippet :
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
Helper.write('on message $message');
//Map data = json.decode(message);
this.scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message['aps']['alert']['body']),));
},
onResume: (Map<String, dynamic> message) async {
Helper.write('on resume $message');
},
onLaunch: (Map<String, dynamic> message) async {
Helper.write('on launch $message');
},
);
analytics.logEvent(name:'firebaseCloudMessaging_Listeners_Done',parameters:null);
}
Related
I need to verify by an ID that comes inside the data field that I received from a firebase message. How can I access this field based on the active notifications?
The point is to remove the notification once a page with that ID is opened.
This is what I have to get the notifications
page.dart
final List<ActiveNotification>? activeNotifications =
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()!
.getActiveNotifications();
that gives me the body, channelId, id, title and hascode.
While RemoteMessage message gives me a lot more stuff including a map data.
Is there a way to access this data field through the ActiveNotification?
I'm trying to do the verification with a sample on the body, but it's not a really good pratice giving the circumstances of the project.
What I receive from firebase is sent_at (date), service_id (the id I need to get to), id (other id but not so important), body, and title.
The service_id shouldn't be displayed in the notification tho, otherwise I'd get it through the notification body
Whoever answered and deleted their answer, helped my a lot. So I'm marking this as the solution because it worked. Thank you stranger.
final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
final Future<SharedPreferences> _savedNotifications =
SharedPreferences.getInstance();
_savedNotifications.then((saveNotifications) {
saveNotifications.setString(
"service_id_${message.messageId}", message.data["service_id"]);
});
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
onResumed();
break;
case AppLifecycleState.inactive:
onInactive();
break;
case AppLifecycleState.detached:
onDetached();
break;
case AppLifecycleState.paused:
onPaused();
break;
}
}
Future<String?> _getServiceId(title) async {
_savedNotifications.then((saveNotifications) => saveNotifications.reload());
return _savedNotifications.then((saveNotifications) {
_savedNotifications.then(
(value) => value.getKeys().forEach(
(element) async {
if (element.contains('service_id_')) {
String serviceId = value.get(element).toString();
}
},
),
);
});
}
void onResumed() async {
final prefs = await SharedPreferences.getInstance();
prefs.reload();
final List<ActiveNotification>? activeNotifications =
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()!
.getActiveNotifications();
for (ActiveNotification notification in activeNotifications!) {
String? serviceId = await _getServiceId(notification.title);
}
}
I am unsure on how to resolve this. I am trying to grab a specific device from an endpoint on my API.
class DeviceProfileWidget extends StatelessWidget {
final int deviceId;
DeviceProfileWidget({Key? key, required this.deviceId}) : super(key: key);
#override
Widget build(BuildContext context) {
Future<DeviceModel> device = Get.find<DeviceController>.
().getDevice(AppConstants.DEVICE_URI + deviceId.toString());
var ports = device.ports;
var port = ports.length;
print("device id is " + device.deviceId);
I can see that I am getting the data when I print my response.body in my device_api_client.dart file. However I am struggling to get this file to pass the deviceId so that I can grab a specific device. I dont want to grab the device from a filtered list, I want to hit the specific endpoint for the particular device. I can share more of my code if necessary.
Thanks in advance!
getDevice method is located here in controller file
class DeviceController extends GetxController {
final DeviceRepo deviceRepo;
DeviceController({required this.deviceRepo});
DeviceModel? _deviceModel;
DeviceModel? get device => _deviceModel;
Future<DeviceModel> getDevice(deviceURI) async {
Response response = await deviceRepo.getDevice(deviceURI);
if (response.statusCode == 200) {
_deviceModel = DeviceModel.fromJson(
response.body['device'] as Map<dynamic, dynamic>);
// print(_deviceModel);
update();
} else {
print("no data");
}
return DeviceModel(
deviceId: device!.deviceId,
publicId: device!.publicId,
label: device!.label,
temperatureImperial: device!.temperatureImperial, ports:
device!.ports);
}
}
In getDevice method please change the return to Future <DeviceModel> and return a DeviceModel from the method. Right now it's returning nothing and marked as Future<void>
You can pass it to this method by making those parameters
Future<DeviceModel> getDevice(deviceid, uri)
{
// All computation here
return DeviceModel(
//add device model details here like device ID etc
);
}
To get the deviceData use
DeviceModel deviceData = await getDevice();
I have been trying to send SMS using telephony by following the youtube tutorial https://www.youtube.com/watch?v=X4yFdl3o1Lg. However, no message is being sent despite adding the required permissions.
final SmsSendStatusListener listener = (SendStatus status) {
// Handle the status
};
final Telephony telephony = Telephony.instance;
final _formKey = GlobalKey<FormState>();
_sendSMS2() async {
bool? permissionsGranted = await telephony.requestSmsPermissions;
print(permissionsGranted); //returns true
bool? canSendSms = await telephony.isSmsCapable;
print(canSendSms); //returns true
// Get sim state
SimState simState = await telephony.simState;
print(simState); //returns SimState.READY
telephony.sendSms(to: "123456", message: "hello", statusListener: listener);
}
}
The status returns sendStatus.SENT but I don't find any message being sent.
I really need help, please.
I removed the status listener and it then worked for me
telephony.sendSms(
to: "123123",
message: "May the force be with you! From MS",
// statusListener: smsListener
)
Try to change your phone number into international format. Then put await keyword for the method. This worked even i spam it many times.
onTap: () async {
final Telephony telephony = Telephony.instance;
if (await telephony.requestPhoneAndSmsPermissions) {
await telephony.sendSms(
to: '62xxxxxxxxxxx',
message: 'From flutter',
statusListener: (s) => print(s.name),
);
}
}
screenshot
My App does the following: It runs a background Task using Flutter Workmanager which checks some values and then it throws a Notification via Flutter Local Notification. In the initialize method from FlutterLocalNotifications Plugin, i can specify a inline fuction, which should navigate to a page. Since i dont have a Builder context, i must use a Navigator Key with OnGenerateRoute to forward the user to a site. However, this doesn`t work and i don´t know why. I know that this code is useful when the app gotkilled.
Example Code
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
String initialRoute = HomePage.routeName;
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
selectedNotificationPayload = notificationAppLaunchDetails!.payload;
initialRoute = SecondPage.routeName;
}
But what to do when the app is still alive? My Project code is listed below.
Main.Dart
void main() {
WidgetsFlutterBinding.ensureInitialized();
Workmanager().initialize(callbackDispatcher, isInDebugMode: true);
Workmanager().registerPeriodicTask("1", "test",frequency: Duration(minutes: 15));
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: "/",
navigatorKey: NavigationService.navigatorKey,
onGenerateRoute: RouteGenerator.generateRoute
);
}
}
RouteGenerator.dart
class RouteGenerator {
static Route<dynamic> generateRoute(RouteSettings settings) {
final args = settings.arguments;
switch(settings.name) {
case '/first':
return MaterialPageRoute(builder: (_) => Page1(title: "First"));
case '/second':
return MaterialPageRoute(builder: (_) => Page2(title: "Second"));
case '/third':
return MaterialPageRoute(builder: (_) => Page3(title: "Third"));
case '/fourth':
return MaterialPageRoute(builder: (_) => Page4(title: "Fourth"));
}
return MaterialPageRoute(builder: (_) => Page0(title: "Root!"));
}
}
class NavigationService {
static final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
static Future<dynamic> navigateTo(String routeName) {
return navigatorKey.currentState!.pushNamed(routeName);
}
}
service.dart
class DevHttpOverrides extends HttpOverrides {
#override
HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context)
..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
}
}
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) async{
HttpOverrides.global = new DevHttpOverrides();
var url = 'https://172.16.0.100/handler.php?page=settings';
http.Response response = await http.get(Uri.parse(url));
List<dynamic> list = jsonDecode(response.body);
SharedPreferences prefs = await SharedPreferences.getInstance();
var usage = "Beides";
var checkValue = "temp_out";
var borderValueString = "14.9";
var checktype = "Grenzwert überschreiten";
var borderValueDouble;
var message = "";
if(usage != "Nur Home Widgets" && checkValue != "" && borderValueString != "" && checktype != "")
{
var value = list[0][checkValue];
if (double.tryParse(borderValueString) != null && double.tryParse(value) != null)
{
borderValueDouble = double.parse(borderValueString);
value = double.parse(value);
}
if (checktype == "Grenzwert unterschreiten")
{
if (borderValueDouble is double)
{
if (value <= borderValueDouble)
{
message = "Grenzwert unterschritten";
}
}
}
else if (checktype == "Grenzwert überschreiten")
{
if (borderValueDouble is double)
{
if (value >= borderValueDouble)
{
message = "Grenzwert überschritten";
}
}
}
else if (checktype == "Entspricht Grenzwert")
{
if (borderValueDouble == value)
{
message = "Grenzwert erreicht";
}
}
}
if(message != "")
{
FlutterLocalNotificationsPlugin flip = new FlutterLocalNotificationsPlugin();
var android = new AndroidInitializationSettings('#mipmap/ic_launcher');
var ios = new IOSInitializationSettings();
var settings = new InitializationSettings(android: android, iOS: ios);
flip.initialize(settings, onSelectNotification: (String? payload) async {
await NavigationService.navigatorKey.currentState!.push(MaterialPageRoute(builder: (context) => Page4(title: "Hello")));
});
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
'1',
'weatherstation',
'Notify when values change',
importance: Importance.max,
priority: Priority.high
);
var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics);
await flip.show(0, message,
'App öffnen für weitere Details',
platformChannelSpecifics, payload: 'Default_Sound'
);
}
return Future.value(true);
});
}
Did you find any solution for it? I'm also working on an Android application that update user data in firestore database (at interval of 15min) and send user its notification (both task happens in background using flutter workmanager_plugin). When user taps on the notification he should be navigated to the route which shows latest data from the database.
First 2 background tasks are happening successfully but when the notification is clicked nothing is happening. I'm also using GlobalKey key to get MaterialApp widget's context, so that routing Route can be pushed.
It seems like onSelectNotification property for FlutterLocalNotificationsPlugin.initialize() method don't work for workmanager plugin. I have also added a print statement inside it, but nothing get displayed in console. I thought maybe my Globalkey has some fault but when I tried it for navigating pages in non background task it was happening succesfully, similarly onSelectNotification was working perfectely for non-workmanager task.
void callbackDispatcher() {
Workmanager().executeTask((task, data) async {
if(task=='showNotification'){
FlutterLocalNotificationsPlugin notifPlugin =
FlutterLocalNotificationsPlugin();
NotificationDetails notificationDetails = NotificationDetails(
android: AndroidNotificationDetails(
'main_channel',
'Main Channel',
'Main Notification Channel',
importance: Importance.max,
priority: Priority.high,
),
);
await notifPlugin.initialize(
InitializationSettings(
android: AndroidInitializationSettings('ic_launcher')),
onSelectNotification: (String? payload) async {
print('Inside on select Route Navigator. Route= $payload');
switch (payload!) {
case 'Home':
// navigatorKey is GlobalKey
navigatorKey.currentState!
.push(MaterialPageRoute(builder: (context) => Home()));
break;
case 'Auth':
navigatorKey.currentState!
.push(MaterialPageRoute(builder: (context) => Auth()));
break;
case 'Details':
navigatorKey.currentState!
.push(MaterialPageRoute(builder: (context) => UserDetails()));
break;
}
});
await notifPlugin.show(id, title, body, notificationDetails, payload:payload);
}
return Future.value(true);
}
}
When notification is clicked. Following message should print on console: "Inside on select Route Navigator. Route= Details" and he should be navigated on the UserDetails page but nothing seems to be happening.
I solved it by reacting to two different events.
If the App starts, i check if the app was launched by a notification. This can be done in createState or initState in main.dart. This code is useful for that.
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
String initialRoute = HomePage.routeName;
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
selectedNotificationPayload = notificationAppLaunchDetails!.payload;
initialRoute = SecondPage.routeName;
}
If the app is in background and a notification launches the app again, you must use Widgets Binding Observer and react to the App Resume event. There is an article at Medium which has example code for this case. Have a look at it here.
There is one drawback when reacting to App Resume Event and using the Flutter Local notifications Plugin. The aforementioned code always delivers true once triggered by an notification, even if the app entered background state again and was resumed manually by an user. This means code for changing a page will always be called, even
if you did not click an notification. Therefore, I´m using a boolean variable to trigger the App State Resume code once. Obviously, if you enter the app via notification ,the app gets resumed and you get a second notification, the code for changing a page will not be executed. It´s a workaround, but for my case, it´s good enough.
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.