24

Why does it throw an error and give me the link is empty even though the link exists? And when I use launch (url) alone, the link opens without any problems.

enter image description here

 String StateUrl = 'View App' ;
 var url = 'https://www.youtube.com/watch?v=-k0IXjCHObw' ;
body: Column(
        children: [
          Text(StateUrl),
          Center(
            child: ElevatedButton.icon(
                onPressed: () async{
                  try {
                    await canLaunch(url) ?
                    await launch(url):
                    throw 'Error';
                  } catch(e){
                    setState(() {
                      StateUrl = e.toString() ;
                    });
                  }
                },
                icon: const Icon(FontAwesomeIcons.link),
                label:  const Text('View Url')
            ),
          ),
        ],
      ),

Performing hot reload:

D/EGL_emulation(17669): app_time_stats: avg=17852.65ms min=658.78ms max=35046.52ms count=2 I/UrlLauncher(17669): component name for https://www.youtube.com/watch?v=-k0IXjCHObw is null D/EGL_emulation(17669): app_time_stats: avg=8279.72ms min=8279.72ms max=8279.72ms count=1

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Mohammad alqannas
  • 335
  • 1
  • 6
  • 12

14 Answers14

41

You have to add <queries> elements to your AndroidManifest.xml file. more info

Xoltawn
  • 1,445
  • 1
  • 11
  • 17
16

With link can handle via other app like youtube, spreadsheets, document...

from android 11 (API 30) and above you must add this permission to AndroidManifest.xml

<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />

UPDATE: with QUERY_ALL_PACKAGES, you will need to explain to Google Play side when you publish the app.

To avoid that, you need to query what you need: package,intent...

please refer: https://developer.android.com/training/package-visibility/declaring

  • 2
    This solution works, but when you publish on Google Play, it produce a permission problem that you have to manage it before they let you publish the app. Better solution for @JRJR. You can add this in your manifest for https schema: – Sami Issa Mar 07 '23 at 10:33
13

try using await launch(url); instead of if (await canLaunch(url)) { print("launching $url"); await launch(url); } else { throw 'Could not launch maps'; } it seems theres a problem with canLaunch(url) function

JRJR
  • 141
  • 2
7

Don't use canLaunch with videos URL, just use try/catch.

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Esraa Hamada
  • 121
  • 1
  • 5
3

If you come here looking for why your email link (mailto:email@example.com) doesn't work, then try this out.

Don't call canLaunch for mailto links - use it only for http and https!

Since I have both http(s) and mailto links in my app, I use the try-catch block.

Here is the full function:

class UrlHandler {
  /// Attempts to open the given [url] in in-app browser. Returns `true` after successful opening, `false` otherwise.
  static Future<bool> open(String url) async {
    try {
      await launch(
        url,
        enableJavaScript: true,
      );
      return true;
    } catch (e) {
      log(e.toString());
      return false;
    }
  }
}
Aleksandar
  • 3,558
  • 1
  • 39
  • 42
1

for me the solution is to copy and paste

<!-- Provide required visibility configuration for API level 30 and above -->
<queries>
  <!-- If your app checks for SMS support -->
  <intent>
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="sms" />
  </intent>
  <!-- If your app checks for call support -->
  <intent>
    <action android:name="android.intent.action.VIEW" />
    <data android:scheme="tel" />
  </intent>
</queries>

from official packages docs but the problem is that the package removed the next lines from code snippet

<intent>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="https" />
</intent>

so add them first to the

0

Try is like this:

try {
  if(await canLaunch(url)) await launch(url):
   } catch(e){
   setState(() {
   StateUrl = e.toString() ;
    });
throw e;}
},
Huthaifa Muayyad
  • 11,321
  • 3
  • 17
  • 49
0

You can use this code, it works for me:

_launchURL() async {
  const url = 'https://en.wikipedia.org/wiki/Body_mass_index';
  if (await launch(url)) {
    await canLaunch(url);
  } else {
    throw 'Could not launch $url';
  }
}

and use this _launchURL() function in onPressed();

desertnaut
  • 57,590
  • 26
  • 140
  • 166
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 28 '22 at 07:42
0

I also had the same problem. The solution was so set an intent in the android manifest file. If this is done, the canLaunch() call will not fail, cause you allow the android system to query this url.

<queries>
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <data  android:scheme="https" android:host="youtube.com" />
    </intent>
</queries>

For comparison, the url launcher now prints following text to the console:

I/UrlLauncher( 2628): component name for <your youtube link> is {com.google.android.youtube/com.google.android.youtube.UrlActivity}

Further if you set the launchMode to LaunchMode.externalApplication the youtube app will launch, if installed.

Also Google updates his PolicyBytes and I think using

<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />

or

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

might lead to app rejects, if you can not explain in detail why you need to use those permissions.

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Ma G
  • 25
  • 4
0

The url_launcher requires a Uri object to be passed instead of a string. Add a Uri.parse

String StateUrl = 'View App' ;
 var url = 'https://www.youtube.com/watch?v=-k0IXjCHObw' ;
body: Column(
        children: [
          Text(StateUrl),
          Center(
            child: ElevatedButton.icon(
                onPressed: () async{
                  try {
                    Uri uri = Uri.parse(url);
                    await canLaunch(uri) ?
                    await launch(uri):
                    throw 'Error';
                  } catch(e){
                    setState(() {
                      StateUrl = e.toString() ;
                    });
                  }
                },
                icon: const Icon(FontAwesomeIcons.link),
                label:  const Text('View Url')
            ),
          ),
        ],
      ),
0

I just used this and it worked...(nb:Dec 2022)

if (!await launchUrl(url)) {
    throw 'Could not launch $url';
  }
Hez
  • 315
  • 2
  • 7
0

My suggestion is to add "http://" or "https://" before your url String. It works for me.

0

canLaunch(url) was the problem and try catch could not catch the exception in my case so I used onError method.

                launchUrl(Uri.parse(url)).onError(
                  (error, stackTrace) {
                    print("Url is not valid!");
                    return false;
                  },
                );
-1

Try using await launch(url); instead of

if (await canLaunch(url)) {
    print("launching $url"); 
    await launch(url);
} 
else { 
    throw 'Could not launch maps'; 
}

It seems theres a problem with canLaunch(url) function

Thank you for this Solution :)

EliaTolin
  • 526
  • 3
  • 15