Flutter Deep Linking
Asked Answered
R

6

11

According to the Flutter's official deep linking page, we do not require any plugin or native Android/iOS code for handling deep links.

But it doesn't really tell us how we can get the data from that link. I'm talking from coding perspective. Sure, they have written in there that:

enter image description here

But this does not tell me where should I write what code to actually get the complete link. I've looked for examples/tutorials but I'm unable to find anything that is not using a plugin for handling deep linking.

Right now, all I've done is add <intent-filter> tags in AndroidManifest.xml file and on clicking the link, my app has started to show up. But I don't know how to extract data from that link.

Is there anyone who can guide me here? Thanks in advance.

Rhines answered 22/6, 2021 at 9:57 Comment(0)
A
2

You need platform specific code to handle deep linking. If you follow link mention in documention, you will find complete example.

private val CHANNEL = "poc.deeplink.flutter.dev/channel"
private var startString: String? = null
override fun configureFlutterEngine(@NonNull flutterEngine:FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)

MethodChannel(flutterEngine.dartExecutor, CHANNEL).setMethodCallHandler { call, result ->
    if (call.method == "initialLink") {
        if (startString != null) {
            result.success(startString)
        }
    }
 }
}


override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)

   val intent = getIntent()
   startString = intent.data?.toString()
}

Flutter Code:

class DeepLinkBloc extends Bloc {

 //Event Channel creation
static const stream = const 
EventChannel('poc.deeplink.flutter.dev/events');

//Method channel creation
static const platform = const 
MethodChannel('poc.deeplink.flutter.dev/channel');

 StreamController<String> _stateController = StreamController();

 Stream<String> get state => _stateController.stream;

 Sink<String> get stateSink => _stateController.sink;


//Adding the listener into contructor
DeepLinkBloc() {
  //Checking application start by deep link
  startUri().then(_onRedirected);
  //Checking broadcast stream, if deep link was clicked in opened appication

  stream.receiveBroadcastStream().listen((d) => _onRedirected(d));
}


_onRedirected(String uri) {
  // Here can be any uri analysis, checking tokens etc, if it’s necessary
  // Throw deep link URI into the BloC's stream
  stateSink.add(uri);
}


  @override
  void dispose() {
    _stateController.close();
  }


  Future<String> startUri() async {
    try {
      return platform.invokeMethod('initialLink');
    } on PlatformException catch (e) {
      return "Failed to Invoke: '${e.message}'.";
    }
  }
}

Follow this link for more detail.

https://medium.com/flutter-community/deep-links-and-flutter-applications-how-to-handle-them-properly-8c9865af9283

Altocumulus answered 22/6, 2021 at 11:21 Comment(1)
If you read this flutter.dev/docs/development/ui/navigation/… you will find out that plugin based method is different than the one I'm questioning about. I don't want to use plugins, I want to use the default deep link handling, the one provided by Flutter.Rhines
S
1

The Flutter way to do that, assuming you've already made the steps in the guide you posted, is to create a onGenerateRoute and/or onGenerateInitialRoutes handlers in your MaterialApp so that these handlers deals with the routes passed or pushed by the framework according to the described behaviors. You can even create an expected named route coming from a deeplink on the routes property of MaterialApp, even though I believe the dynamic generation of routes is more appropriate due to the dynamic nature of deeplinking, specially if you're dealing with "authentication needed content" inside your app.

Sneed answered 24/12, 2021 at 2:55 Comment(0)
A
0

Or, if you don't want to pass trough the platform specific code, you could use firebase dynamic links. That would allow to easily listen to links coming from both platforms and you also get the advantage that your link would bring up the store listing page if the user doesn't have the app installed.

I've written a full example here: https://gbaccetta.medium.com/flutter-deep-linking-with-firebase-dynamic-links-and-bloc-architecture-660f0517fbc2

Ashtray answered 6/8, 2021 at 17:21 Comment(0)
P
0

Do for android as said in the web page: "Add a metadata tag and intent filter to AndroidManifest.xml inside the tag with the ".MainActivity" name". Do what required for ios too.

Then use onGenerateRoute in the usual way in MaterialApp, don't use "routes:". For example:

      onGenerateRoute: (settings) {
    print("settings.name " + settings.name.toString());

    if (settings.name == '/') return MaterialPageRoute(builder: (_) => ScreenStart());

    return MaterialPageRoute(builder: (_) => ScreenUnknown());
  },

Then to simulate I did: cd /Users/Utente/AppData/Local/Android/Sdk/platform-tools

adb shell

am start -W -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "http://theaddressichoosed.com/helloworld?byebye"

And print("settings.name " + settings.name.toString()); printed settings.name /helloworld?byebye

Porett answered 27/12, 2021 at 19:36 Comment(0)
F
0

After spending some time on this, here's my take using the Navigator 2 API. It also shows how to perform query and path arguments parsing. Hope it will save someone the time I spent researching this.

Obviously you also need to edit your platform-specific build files (such as AndroidManifest.xml for Android) as shown in the Flutter Deep Linking page.

A special note for Android 12 and above: you'll also need to securely approve the app's domain in the Google Play Developer Console for deep linking to work.

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) => MaterialApp(
        initialRoute: '/',
        routes: {
          '/': (context) => HomeScaffold(),
          '/route1': (context) => const RouteOneScaffold(),
          '/route2': (context) => const RouteTwoScaffold(),
          // Other routes which don't need any sort of query parsing
        },
        onGenerateRoute: (settings) {
          // This is executed to determine which route to follow if no adequate entry is found in the `routes` array above.
          // Here we can parse path and query parameters as we like.
          final fullRoute = settings.name;
          if (fullRoute == null) {
            return null;
          }
          final routeData = Uri.tryParse(fullRoute);
          if (routeData == null) {
            return null;
          }
          final pathParameters = routeData.pathSegments;
          final queryParameters = routeData.queryParameters;
          // Here you can write your route handling logic
          return MaterialPageRoute(builder: (context) => RouteThreeScaffold(pathParameters,queryParameters));
        },
      );

}
Flatfooted answered 12/10, 2022 at 13:46 Comment(0)
T
0

Instead of adding native code to extract values from the link, you can use this flutter package to extract value

AppLinks appLinks = AppLinks();
StreamSubscription<Uri>? linkSubscription;
 linkSubscription = appLinks.uriLinkStream.listen((uri) {
  //write your code to extract value from the URI
});
Teets answered 23/5, 2024 at 15:10 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.