我正在尝试使用url_launcher
插件通过链接打开youtube视频,但是canLaunch
函数不断抛出错误。我只能通过完全删除canLaunch
函数来绕过此错误,但无法找出问题所在。
代码不起作用:
_goToVideo(YoutubeVideoData video) async {
if (await canLaunch(video.url)) {
await launch(video.url);
} else {
throw 'Could not launch ${video.url}';
}
}
代码正常工作
_goToVideo(YoutubeVideoData video) async {
await launch(video.url);
}
我不太确定为什么我不能使用README Example
中写的canLaunch
方法
错误:
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)
使用以下功能的小部件:
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))),
),
),
);
}
}
答案 0 :(得分:7)
从API30(Android 11)开始,您的Android应用必须列出与之交互的所有应用。
您可以添加:
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
在您的Android清单中绕过它或专门列出它们。
有关更多信息: https://developer.android.com/about/versions/11/privacy/package-visibility
答案 1 :(得分:2)
即使在尝试接受的答案后,如果它不适合您,请尝试遵循代码。
准备步骤:按照建议的已接受答案进行操作。
在 AndroidManifest.xml 中的 <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>
现在我做了什么
创建一个方法:
Future<void> _makeSocialMediaRequest(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
并通过以下方式调用它:
//FOR EMAIL
final Uri _emailLaunchUri = Uri(
scheme: 'mailto',
path: 'pratik13butani@gmail.com',
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");
它对我有用。希望它也对你有用。谢谢。
答案 2 :(得分:1)
我个人不喜欢使用QUERY_ALL_PACKAGES权限似乎带来的不确定性(因为Google将来可能不再允许人们使用它)。因此,我进行了一些调查,发现将以下内容添加到我的AndroidManifest.xml中允许我的应用在API 30上打开浏览器,电话应用和电子邮件应用:
<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>
只是想分享一下,以防别人帮忙。
答案 3 :(得分:1)
兄弟只放'!'在“if (!await canLaunch(url))”之前 使用这个 -->
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';
}
答案 4 :(得分:0)
确保在 android manifest 中添加以下行
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
不要忘记 Info.plist 以及
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>http</string>
<string>tel</string>
<string>mailto</string>
</array>
答案 5 :(得分:-2)
这对我有用
if (!url.contains('http')) url = 'https://$url';
完整方法:
launchURL(String url) async {
if (!url.contains('http')) url = 'https://$url';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}