Fix deep link handling regression

This commit is contained in:
franzap
2026-04-08 12:31:23 -03:00
parent 130559baf0
commit d3687ff308
5 changed files with 20 additions and 21 deletions
-1
View File
@@ -25,7 +25,6 @@
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
+1 -1
View File
@@ -284,7 +284,7 @@ final appInitializationProvider = FutureProvider<void>((ref) async {
final backgroundService = ref.read(backgroundUpdateServiceProvider); final backgroundService = ref.read(backgroundUpdateServiceProvider);
unawaited(backgroundService.initialize()); unawaited(backgroundService.initialize());
unawaited(ref.read(deepLinkServiceProvider).initialize()); await ref.read(deepLinkServiceProvider).initialize();
await _attemptAutoSignIn(ref); await _attemptAutoSignIn(ref);
}); });
+3 -5
View File
@@ -13,7 +13,6 @@ import 'package:zapstore/screens/search_screen.dart';
import 'package:zapstore/screens/updates_screen.dart'; import 'package:zapstore/screens/updates_screen.dart';
import 'package:zapstore/screens/profile_screen.dart'; import 'package:zapstore/screens/profile_screen.dart';
import 'package:zapstore/services/package_manager/package_manager.dart'; import 'package:zapstore/services/package_manager/package_manager.dart';
import 'package:zapstore/services/deep_link_resolver.dart';
import 'package:zapstore/services/updates_service.dart'; import 'package:zapstore/services/updates_service.dart';
/// Root paths for each navigation branch (used for back navigation handling) /// Root paths for each navigation branch (used for back navigation handling)
@@ -117,10 +116,9 @@ final routerProvider = Provider<GoRouter>((ref) {
final router = GoRouter( final router = GoRouter(
navigatorKey: rootNavigatorKey, navigatorKey: rootNavigatorKey,
initialLocation: '/search', initialLocation: '/search',
// Intercept deep link URIs that GoRouter cannot match as paths. onException: (context, state, router) {
// This fires before any route is rendered, eliminating the GoException router.go('/search');
// flash when the app is launched via market:// or https://zapstore.dev. },
redirect: (context, state) => resolveDeepLinkPath(state.uri),
routes: [ routes: [
// Single stateful shell route that handles everything // Single stateful shell route that handles everything
StatefulShellRoute.indexedStack( StatefulShellRoute.indexedStack(
+8 -8
View File
@@ -4,28 +4,28 @@ import 'package:flutter/foundation.dart';
/// the URI is not a recognized deep link. /// the URI is not a recognized deep link.
/// ///
/// Handles: /// Handles:
/// - `https://zapstore.dev/apps/{id}` /// - `https://zapstore.dev/apps/{id}` (full URI from app_links)
/// - `/apps/{id}` (path-only, as seen by GoRouter's onException)
/// - `market://details?id=com.example.app` /// - `market://details?id=com.example.app`
/// - `market://search?q=search+query` /// - `market://search?q=search+query`
String? resolveDeepLinkPath(Uri uri) { String? resolveDeepLinkPath(Uri uri) {
// https://zapstore.dev/apps/<id> // https://zapstore.dev/apps/<id> OR bare /apps/<id> from GoRouter
if (uri.scheme == 'https' && if (uri.pathSegments.length == 2 && uri.pathSegments[0] == 'apps') {
uri.host == 'zapstore.dev' && final isFullUri = uri.scheme == 'https' && uri.host == 'zapstore.dev';
uri.pathSegments.length == 2 && final isBarePath = uri.host.isEmpty;
uri.pathSegments[0] == 'apps') { if (isFullUri || isBarePath) {
final id = uri.pathSegments[1]; final id = uri.pathSegments[1];
if (id.isNotEmpty) { if (id.isNotEmpty) {
debugPrint('App link: app ID = $id');
return '/search/app/$id'; return '/search/app/$id';
} }
} }
}
// market://details?id=com.example.app (Google Play-style intents) // market://details?id=com.example.app (Google Play-style intents)
if (uri.scheme == 'market') { if (uri.scheme == 'market') {
if (uri.host == 'details' || uri.path == '/details') { if (uri.host == 'details' || uri.path == '/details') {
final id = uri.queryParameters['id']; final id = uri.queryParameters['id'];
if (id != null && id.isNotEmpty) { if (id != null && id.isNotEmpty) {
debugPrint('Market intent: app ID = $id');
return '/search/app/$id'; return '/search/app/$id';
} }
} }
+5 -3
View File
@@ -22,13 +22,15 @@ class DeepLinkService {
/// Initialize the service - call once after app is ready. /// Initialize the service - call once after app is ready.
/// ///
/// The initial launch URI is not re-processed here because GoRouter's /// Handles both the cold-launch URI (the link that opened the app) and
/// top-level redirect already maps it to the correct path before any /// links received while the app is already running.
/// screen renders. Only links received while the app is running are handled.
Future<void> initialize() async { Future<void> initialize() async {
if (_initialized) return; if (_initialized) return;
_initialized = true; _initialized = true;
final initialUri = await _appLinks.getInitialLink();
_handleUri(initialUri);
_subscription = _appLinks.uriLinkStream.listen(_handleUri); _subscription = _appLinks.uriLinkStream.listen(_handleUri);
} }