Flutter open deep link using package

Viewed 2364

I am using the following flutter package in order to allow my users to open the Spotify app: https://pub.dev/packages/external_app_launcher

When a user clicks a button in the application, he should navigate to Spotify Deep link. How can I implement it using the package above?

The deep link should be something like this: https://open.spotify.com/playlist/37i9dQZF1DWX5ZOsG2Ogi1?si=41c6a392cf7d4a2b

However, my current implementation is as follow:

await LaunchApp.openApp(
  androidPackageName: 'com.spotify.music',
  iosUrlScheme: 'spotify:',
);

How can I do it?

2 Answers

Your package is used to open an app not to open deep link. Deep linking is basically just opening an URL which will redirect you to its associated app if available.

So to open a deep link you should use the package url_launcher and simply launch your Spotify URL with it.

Here's a tutorial on Android:

Step 1: Add permissions to your AndroidManifest

You will need to add the permission QUERY_ALL_PACKAGES so you can verify if the Spotify application is available on the phone by using canLaunch.

  • android/app/src/debug/AndroidManifest.xml (if you want it to work on debug mode too)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.so_tests">
    <!-- Flutter needs it to communicate with the running application
         to allow setting breakpoints, to provide hot reload, etc.
    -->
    <uses-permission android:name="android.permission.INTERNET"/>

    <!-- Add this line -->
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
</manifest>
  • android/app/src/main/AndroidManifest.xml (for the release)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.so_tests">
    <uses-permission android:name="android.permission.INTERNET"/>

    <!-- Add this line -->
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
   <application
        android:label="so_tests"
        android:icon="@mipmap/ic_launcher">

        <!-- TODO: Add your Google Maps API key here -->
        <meta-data android:name="com.google.android.geo.API_KEY"
               android:value="YOUR-KEY-HERE"/>
               
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <!-- Displays an Android View that continues showing the launch screen
                 Drawable until Flutter paints its first frame, then this splash
                 screen fades out. A splash screen is useful to avoid any visual
                 gap between the end of Android's launch screen and the painting of
                 Flutter's first frame. -->
            <meta-data
              android:name="io.flutter.embedding.android.SplashScreenDrawable"
              android:resource="@drawable/launch_background"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
</manifest>

Step 2: use canLaunch and launch

Here's a basic code sample:

import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            final spotifyUrl =
                'https://open.spotify.com/playlist/37i9dQZF1DWX5ZOsG2Ogi1?si=41c6a392cf7d4a2b';

            // Check if Spotify is installed
            if (await canLaunch(spotifyUrl)) {
              // Launch the url which will open Spotify
              launch(spotifyUrl);
            }
          },
          child: Text('Open Spotify'),
        ),
      ),
    );
  }
}

IMHO that package does not support it. You can firstly learn how a native normal iOS app opens deep links. Then write down native ios (swift/objc) code. Then wrap it by simple Flutter code such that you can call it from flutter (flutter has some official doc about such cases - develop a package).

You may also try to treat https://open.spotify.com/playlist/37i9dQZF1DWX5ZOsG2Ogi1?si=41c6a392cf7d4a2b as a "normal" url, and use flutter to open it externally. Then ios may open the app instead of browser.

Related