-
Notifications
You must be signed in to change notification settings - Fork 275
Description
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:
authentication_video.mov
noauthentication_video.mov
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)
- Auth
- 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
- iOS
- Android
- Web
- macOS
- Windows
- Linux
Flutter Version
3.24.3
Amplify Flutter Version
^2.0.0
Deployment Method
AWS CDK
Schema
No response