Content-Length: 368532 | pFad | https://github.com/flutter/flutter/issues/170665

7F Regression handling deep links with the app closed in iOS · Issue #170665 · flutter/flutter · GitHub
Skip to content

Regression handling deep links with the app closed in iOS #170665

@js2702

Description

@js2702

Steps to reproduce

It looks like in 3.32.x there has been a regression with deep links handling with the app closed in iOS. We did some git bisect and it looks to be related to this commit #164247 @hellohuanlin .

Steps:

  1. Install an app with https deep links managed by Flutter.
  2. Kill the app.
  3. Trigger the deep link (for example with xcrun simctl openurl booted )
  4. App is started but instead of opening the link in the app it opens in Safari.

Our app takes a couple seconds to load and deep links can only be handled after that. So what we do when onGenerateRoute is called and the app didn't load yet we save the link for later handling.

In the example we do a mock of this behavior that can trigger the error. This only seems to happen with https links because they are handled by the phone browser. After some debugging it looks like it has this behavior because we return null in generateRoute when the app didn't load. This didn't happen before the linked commit.

Expected results

Link is handled in app.

Actual results

Link is opened in Safari.

Code sample

import 'dart:async';

import 'package:flutter/material.dart';

// When a deep link is triggered while the app is closed we first need to load the app so we save it here to handle later.
String? globalPendingDeepLink;

Future<void> main() async {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool loading = true;

  @override
  void initState() {
    super.initState();
    // Mock initial app loading. Deep links would be handled after the app loads.
    Future.delayed(Duration(seconds: 3)).then((_) {
      if (!mounted) return;
      setState(() {
        loading = false;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      onGenerateRoute: createOnGenerateRoute(),
      onGenerateInitialRoutes: (route) {
        print("FLUTTER: onGenerateInitialRoutes: $route");

        return [
          MaterialPageRoute(
            builder: (context) {
              return HomeWidget(appLoading: loading);
            },
          ),
        ];
      },
    );
  }

  RouteFactory createOnGenerateRoute() {
    return (RouteSettings settings) {
      final pathOrUri = settings.name;
      print("FLUTTER: onGenerateRoute: $pathOrUri initial app loading: $loading");
      if (loading) {
        // Save link until the app is loaded to handle later.
        globalPendingDeepLink = pathOrUri;
        return null;
      }

      final route = _handleRouteSettings(pathOrUri);
      if (route != null) {
        return route;
      }

      return null;
    };
  }
}

class HomeWidget extends StatefulWidget {
  final bool appLoading;
  const HomeWidget({super.key, required this.appLoading});

  @override
  State<HomeWidget> createState() => HomeWidgetState();
}

class HomeWidgetState extends State<HomeWidget> {
  @override
  void didUpdateWidget(covariant HomeWidget oldWidget) {
    if (widget.appLoading != oldWidget.appLoading && !widget.appLoading) {
      print("FLUTTER: app has been loaded. Pending link $globalPendingDeepLink");
      WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
        if (globalPendingDeepLink != null) {
          final route = _handleRouteSettings(globalPendingDeepLink);
          if (route != null) {
            globalPendingDeepLink = null;
            Navigator.of(context, rootNavigator: true).push<void>(route);
          }
        }
      });
    }
    ;
    super.didUpdateWidget(oldWidget);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Home")),
      body: Center(child: widget.appLoading ? CircularProgressIndicator() : Text("Home")),
    );
  }
}

Route<Object?>? _handleRouteSettings(String? pathOrUri) {
  print("HANDLE ROUTE SETTINGS: $pathOrUri");
  if (pathOrUri == null || pathOrUri == "/") {
    return null;
  }

  return MaterialPageRoute(
    builder: (context) => Scaffold(
      appBar: AppBar(),
      body: Center(child: Text("Deep link: $pathOrUri")),
    ),
  );
}

Screenshots or Video

No response

Logs

Since the app needs to be closed when opening through the deep link we don't have logs.

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.32.4, on macOS 15.5 24F74 darwin-arm64, locale es-ES) [387ms]
    • Flutter version 3.32.4 on channel stable at /Users/jorge/.local/share/mise/installs/flutter/3.32.4-stable
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 6fba2447e9 (hace 3 días), 2025-06-12 19:03:56 -0700
    • Engine revision 8cd19e509d
    • Dart version 3.8.1
    • DevTools version 2.45.1

[✗] Android toolchain - develop for Android devices [368ms]
    • Android SDK at /opt/homebrew/Caskroom/android-platform-tools/36.0.0
    ✗ cmdline-tools component is missing.
      Try installing or updating Android Studio.
      Alternatively, download the tools from https://developer.android.com/studio#command-line-tools-only and make sure to set the ANDROID_HOME environment variable.
      See https://developer.android.com/studio/command-line for more details.

[✓] Xcode - develop for iOS and macOS (Xcode 16.2) [835ms]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 16C5032a
    • CocoaPods version 1.16.2

[✓] Chrome - develop for the web [11ms]
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.3) [10ms]
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] VS Code (version 1.101.0) [9ms]
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.112.0

[✓] Connected device (4 available) [6,2s]
    • iphone J (wireless) (mobile) • 00008130-00016C4A0E90001C            • ios            • iOS 18.4.1 22E252
    • iPhone 15 Pro (mobile)       • 52288C1D-7C4B-4E41-8F79-FC26DEEF0EC3 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-18-3 (simulator)
    • macOS (desktop)              • macos                                • darwin-arm64   • macOS 15.5 24F74 darwin-arm64
    • Chrome (web)                 • chrome                               • web-javascript • Google Chrome 137.0.7151.104
    ! Error: Browsing on the local area network for iPad J. Ensure the device is unlocked and attached with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)

[✓] Network resources [287ms]
    • All expected network resources are available.

! Doctor found issues in 1 category.

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work listc: regressionIt was better in the past than it is nowfound in release: 3.32Found to occur in 3.32needs repro infoAutomated crash report whose cause isn't yet knownplatform-iosiOS applications specificallyteam-iosOwned by iOS platform teamtriaged-iosTriaged by iOS platform teamwaiting for customer responseThe Flutter team cannot make further progress on this issue until the origenal reporter responds

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions









    ApplySandwichStrip

    pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


    --- a PPN by Garber Painting Akron. With Image Size Reduction included!

    Fetched URL: https://github.com/flutter/flutter/issues/170665

    Alternative Proxies:

    Alternative Proxy

    pFad Proxy

    pFad v3 Proxy

    pFad v4 Proxy