Reputation: 457
I'm trying to use the url_launcher
plugin to open youtube videos by link but the canLaunch
function keeps throwing an error. I'm able to bypass this error only by completely removing the canLaunch
function but can't figure out what is wrong.
Code not working:
_goToVideo(YoutubeVideoData video) async {
if (await canLaunch(video.url)) {
await launch(video.url);
} else {
throw 'Could not launch ${video.url}';
}
}
Code working:
_goToVideo(YoutubeVideoData video) async {
await launch(video.url);
}
I'm not quite sure why I can't use the canLaunch
method as written in the README Example
Error:
E/flutter (12574): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: Could not launch https://www.youtube.com/watch?v=-3g5WlqJtIo
E/flutter (12574): #0 _goToVideo (package:esfandapp/widgets/newsList/videoCard.dart:71:5)
E/flutter (12574): <asynchronous suspension>
E/flutter (12574): #1 VideoCard.build.<anonymous closure> (package:esfandapp/widgets/newsList/videoCard.dart:13:20)
E/flutter (12574): #2 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:992:19)
E/flutter (12574): #3 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:1098:38)
E/flutter (12574): #4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:184:24)
E/flutter (12574): #5 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:524:11)
E/flutter (12574): #6 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:284:5)
E/flutter (12574): #7 BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:256:7)
E/flutter (12574): #8 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:158:27)
E/flutter (12574): #9 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:224:20)
E/flutter (12574): #10 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:200:22)
E/flutter (12574): #11 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:158:7)
E/flutter (12574): #12 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:104:7)
E/flutter (12574): #13 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:88:7)
E/flutter (12574): #14 _rootRunUnary (dart:async/zone.dart:1206:13)
E/flutter (12574): #15 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter (12574): #16 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter (12574): #17 _invoke1 (dart:ui/hooks.dart:267:10)
E/flutter (12574): #18 _dispatchPointerDataPacket (dart:ui/hooks.dart:176:5)
Widget using the function:
class VideoCard extends StatelessWidget {
final YoutubeVideoData video;
VideoCard({this.video});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () => _goToVideo(video),
child: Container(
child: Card(
child: Container(
child: Column(
children: [
Align(
child: Padding(
child: Text(
video.title,
style: TextStyle(
fontFamily: 'Roboto Condensed',
fontSize: 16,
),
),
padding: EdgeInsets.fromLTRB(15, 0, 15, 10),
),
alignment: Alignment.centerLeft,
),
Container(
child: Image.network(video.thumbnails[1], fit: BoxFit.cover,),
width: MediaQuery.of(context).size.width,
),
Align(
child: Container(
child: Text(
video.date.toString() + "",
style: TextStyle(
fontFamily: 'Roboto Condensed',
fontSize: 14,
fontWeight: FontWeight.w300,
),
),
padding: EdgeInsets.fromLTRB(15, 5, 15, 0),
),
alignment: Alignment.centerLeft,
),
],
),
width: MediaQuery.of(context).size.width - 32,
padding: EdgeInsets.symmetric(
horizontal: 0,
vertical: 10,
),
alignment: Alignment.center,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(25))),
),
),
);
}
}
Upvotes: 35
Views: 38488
Reputation: 97
I encountered a similar issue where my app was rejected on the Google Play Store due to the inclusion of the
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
permission in the manifest.
Here's how I resolved it:
if (await launchUrl(Uri.parse(url))) {
await launch(url);
}
else {
throw 'Could not launch $url';
}
This resolved the rejection issue and ensured my app functioned properly. Hope this helps others facing a similar challenge!
Upvotes: -1
Reputation: 6022
QUERY_ALL_PACKAGES
(not recommended)
Because Google could stop letting people use it in the future as mentioned in the official document
if you use launch any url from your app just use
<manifest package="com.example.game">
<queries>
<package android:name="com.android.chrome" />
</queries>
...
</manifest>
likewise you can add <queries>
depends on your need.
ex.
<queries>
<!-- If your app opens https URLs -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<!-- If your app makes calls -->
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<!-- If your app emails -->
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
</queries>
Upvotes: 0
Reputation: 6022
For Android Just add in your androidmanifest.xml file
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
For iOS add these in your info.plist file
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>http</string>
<string>tel</string>
<string>mailto</string>
</array>
Upvotes: 0
Reputation: 59
if (await canLaunchUrl(Uri.parse(url))) {
await launchUrl(Uri.parse(url),
mode: LaunchMode.externalApplication, );
}
Upvotes: 0
Reputation: 773
Make sure to add in the android manifest the below line
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
Don't forget about the Info.plist as well
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>http</string>
<string>tel</string>
<string>mailto</string>
</array>
Upvotes: 3
Reputation: 439
I spent nearly 2 hours to find what is wrong and after I closed the application from the recent tab and re-run the app it worked perfectly fine.
Things you might missed,
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
</queries>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>http</string>
</array>
Upvotes: 2
Reputation: 5303
For Android Use the below code in Android/main/res/AndroidManifest.xml
like the showed in the image
and here is the code
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
For IPhone ios/Runner/Info.plist
like the showed in the image
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>http</string>
<string>tel</string>
<string>mailto</string>
Upvotes: 4
Reputation: 71
If none of the above works, try adding this in the AndroidManifest.xml (main one if you have that). Add this code snipped just above the <application>
tag.
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
</queries>
Upvotes: 0
Reputation: 685
i faced same error using win and linux for android developments and solve it with these steps the idea is to add the to AndroidManifest.xml in app/src/main/AndroidManifest.xml to do so and to make it work without error you must update the gardle version so here is the steps 1-updated my gradle-wrapper.properties to gradle-6.7.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
2- updated my classpath in android/build.gradle to com.android.tools.build:gradle:4.2.1
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
3- add the above to my AndroidManifest.xml in app/src/main/AndroidManifest.xml
<queries>
<!-- If your app opens https URLs -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<!-- If your app makes calls -->
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<!-- If your app emails -->
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
</queries>
and now everything work fine
Upvotes: 0
Reputation: 71
bro only put '!' before "if (!await canLaunch(url))" Use this -->
if (!await canLaunch(url)){
await launch(
url,
forceSafariVC: false,
forceWebView: false,
headers: <String, String>{'my_header_key': 'my_header_value'},
);
} else {
throw 'Could not launch $url';
}
Upvotes: 7
Reputation: 62429
Even after trying accepted answer, If its not working for you then Please try followed code.
PRE STEPS: Do as accepted answer suggested.
Add following tags in AndroidManifest.xml before <application/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
</queries>
NOW WHAT I HAVE DONE
Create one method:
Future<void> _makeSocialMediaRequest(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
and Called it by following way:
//FOR EMAIL
final Uri _emailLaunchUri = Uri(
scheme: 'mailto',
path: '[email protected]',
queryParameters: {'subject': 'Pratik Butani'});
_makeSocialMediaRequest(_emailLaunchUri.toString());
//FOR PHONE NUMBER:
final Uri _phoneLaunchUri =
Uri(scheme: 'tel', path: postOffice.mobileNo);
_makeSocialMediaRequest(_phoneLaunchUri.toString());
//FOR ANY URL.. YOU CAN PASS DIRECT URL..
_makeSocialMediaRequest("http://pratikbutani.com");
Its working for me. Hopefully it will work for you too. Thank you.
Upvotes: 10
Reputation: 1123
Personally, I don't like the uncertainty that seems to come with using the QUERY_ALL_PACKAGES permission (because Google could stop letting people use it in the future). For that reason, I did some investigation and found that adding the following to my AndroidManifest.xml allows my app to open the browser, phone app and email app on API 30:
<manifest>
<!-- Nest within the manifest element, not the application element-->
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
</queries>
<application>
....
</application>
</manifest>
To get the same functionality working on iOS, it may be necessary to add the following to your info.plist file:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>http</string>
<string>tel</string>
<string>mailto</string>
</array>
Just wanted to share in case it helps someone else out.
Upvotes: 75
Reputation: 449
This worked for me
if (!url.contains('http')) url = 'https://$url';
Complete Method:
launchURL(String url) async {
if (!url.contains('http')) url = 'https://$url';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
Upvotes: -4
Reputation: 1064
Starting from API30 (Android 11), your Android app has to list all apps it interacts with.
You can add:
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
in your android manifest to bypass it or specifically list them.
For more info: https://developer.android.com/about/versions/11/privacy/package-visibility
Upvotes: 80