iOS deep links are not working when app comes from a terminated state using the `Authenticator` pre-built widget.
Description
I just finished setting up my app's deep link structure as per the Flutter documentation and it all works well except for the iOS launch of deep links when using the Authenticator pre-built widget.
The Android version of my code works just fine and even when app is terminated it opens the deep link as expected, the issue only occurs in iOS when the app comes from a terminated state. I attach two videos of what I'm talking about:
https://github.com/user-attachments/assets/c16dca92-a222-4c78-bbd1-09571cae1b49
https://github.com/user-attachments/assets/d6e2838b-da37-4956-a9e3-eea389bfadc8
The first video uses the Authenticator pre-built widget as outlined in the code that appears next to the simulator, here you can see that deep link doesn't work when app comes from terminated state, when app is already launched it works just fine. The second video uses the bare-bone MaterialApp widget as seen in the code next to the simulator and in this case the app coming from a terminated state properly handles the deep link.
In the video that doesn't use
Authenticatorthe first screen is different (no stores are displayed) becuase my API requires an authenticated user, not because anything else changed in the code.
In the first video it is clearly seen that the terminated app doesn't handle deep links correctly, the first time you open this it just stays in the home page (the "/" route) without navigating to the complete path. In the second video it is clear that the deep link works as intended, taking the user to the complete path (the "/help" route).
I was wondering if this is a known issue or if there is some clear problem with my implementation. The complete structure of my main.dart file is the following:
// Dart libraries
import 'dart:convert';
// External libraries
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:amplify_api/amplify_api.dart';
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_analytics_pinpoint/amplify_analytics_pinpoint.dart';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:go_router/go_router.dart';
import 'package:amplify_authenticator/amplify_authenticator.dart';
// Utilities
import 'package:pey/utils/rest_api_manager.dart';
import 'package:pey/routes.dart';
// Components
import 'package:pey/components/main/splash_screen.dart';
import 'package:pey/components/main/initialization_error.dart';
// Models
import 'package:pey/models/cart.dart';
import 'package:pey/models/store.dart';
// Configs
import 'package:pey/configs/amplify.dart';
Future<void> configureAmplify() async {
try {
if (Amplify.isConfigured) {
safePrint("Amplify is already configured 🎉");
return;
}
await Amplify.addPlugins([
AmplifyAnalyticsPinpoint(),
AmplifyAuthCognito(),
AmplifyAPI(),
]);
await Amplify.configure(jsonEncode(amplifyConfig));
safePrint("Successfully configured Amplify 🎉");
} on Exception catch (e) {
safePrint('An error occurred configuring Amplify: $e');
rethrow;
}
}
Future<void> configureStripe() async {
String merchantId = "merchant.com.pey";
try {
final publishableKey = await RestApi.fetchStripePublishableKey();
Stripe.publishableKey = publishableKey;
Stripe.merchantIdentifier = merchantId;
await Stripe.instance.applySettings();
safePrint("Successfully configured Stripe 🎉");
} catch (e) {
safePrint('An error occurred configuring Stripe: $e');
rethrow;
}
}
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const InitializationWrapper());
}
class InitializationWrapper extends StatefulWidget {
const InitializationWrapper({super.key});
@override
State<InitializationWrapper> createState() => _InitializationWrapperState();
}
class _InitializationWrapperState extends State<InitializationWrapper> {
late Future<void> _initializationFuture;
final GoRouter _router = router;
@override
void initState() {
super.initState();
_initializationFuture = _initialize();
}
Future<void> _initialize() async {
await configureAmplify();
await configureStripe();
}
void _retryInitialization() {
setState(() {
_initializationFuture = _initialize();
});
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initializationFuture,
builder: (context, snapshot) {
if (snapshot.hasError) {
return MaterialApp(
home: InitializationError(
error: snapshot.error?.toString(),
onRetry: _retryInitialization,
),
);
}
if (snapshot.connectionState == ConnectionState.done) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => CartModel()),
ChangeNotifierProvider(create: (context) => StoreModel())
],
child: Authenticator(
child: MaterialApp.router(
routerConfig: _router,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF0067F1),
primary: const Color(0xFF0067F1),
),
useMaterial3: true,
),
builder: Authenticator.builder(),
),
),
);
}
return const MaterialApp(
home: SplashScreen(),
);
},
);
}
}
I was trying to narrow down the causes of failure given this GitHub issue which stated that conditional statements when launching the MaterialApp caused issues; this turned out to be true and it seems the culprit right now is Authenticator. I first want to fix the Authenticator which clearly causes the issue and then see if my other conditions (SplashScreen and InitializationError) also affect the deep link behavior. In the video examples I showed above the Widget build(BuildContext context) { ... } used the simplified versions of the code that appear in the videos.
This issue in the Flutter repo goes deep into the functionality of deep links in iOS when app comes from a terminated state.
Categories
- [ ] Analytics
- [ ] API (REST)
- [ ] API (GraphQL)
- [X] Auth
- [X] Authenticator
- [ ] DataStore
- [ ] Notifications (Push)
- [ ] Storage
Steps to Reproduce
Already explained in the description, try to configure flutter deep links with an app that uses Amplify's pre-built Authenticator widget.
Screenshots
No response
Platforms
- [X] iOS
- [ ] Android
- [ ] Web
- [ ] macOS
- [ ] Windows
- [ ] Linux
Flutter Version
3.24.3
Amplify Flutter Version
^2.0.0
Deployment Method
AWS CDK
Schema
No response
Hi @ramon-san, thank you for taking the time to raise this issue as well as the extraordinary detail in describing the problem. We will investigate this issue and get back to you when we have an update.
Hi @ramon-san, I have been able to reproduce this issue. It will be tracked as a bug and I will report back to this issue when we have a fix.
Hello, was wondering if there is any ETA on this bug fix. Accessing specific areas of the app through a QR code is core functionality of what I'm building so a fix to this bug would be huge. If the time to fix this will be very long (more than a month) please let me know so that I start building a personalized Auth solution that doesn't cause this issue.
Hi @ramon-san, we currently do not have a ETA on the fix for this. We will post any updates we have here as we can.