Flutter url_launcher 未处理的异常:无法启动 youtube url(由 canLaunch 引起)

Nik*_*cio 14 flutter

我正在尝试使用该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}';
  }
}
Run Code Online (Sandbox Code Playgroud)

代码工作:

_goToVideo(YoutubeVideoData video) async {
  await launch(video.url);
}
Run Code Online (Sandbox Code Playgroud)

我不太确定为什么我不能使用自述文件示例中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)
Run Code Online (Sandbox Code Playgroud)

使用函数的小部件:

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))),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*y B 41

从 API30 (Android 11) 开始,您的 Android 应用程序必须列出它与之交互的所有应用程序。

你可以加:

<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
Run Code Online (Sandbox Code Playgroud)

在您的 android 清单中绕过它或专门列出它们。

更多信息:https : //developer.android.com/about/versions/11/privacy/package-visibility

  • 请务必小心权限“QUERY_ALL_PACKAGES”。Google Play 将于 2021 年 5 月 5 日开始限制,您的应用可能会从商店中删除:https://support.google.com/googleplay/android-developer/answer/10158779 (4认同)

Wes*_*324 30

就我个人而言,我不喜欢使用 QUERY_ALL_PACKAGES 权限似乎带来的不确定性(因为 Google 可能会在未来停止让人们使用它)。出于这个原因,我做了一些调查,发现将以下内容添加到我的 AndroidManifest.xml 允许我的应用程序在 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>
Run Code Online (Sandbox Code Playgroud)

要在 iOS 上使用相同的功能,可能需要将以下内容添加到您的 info.plist 文件中:

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>https</string>
    <string>http</string>
    <string>tel</string>
    <string>mailto</string>
</array> 
Run Code Online (Sandbox Code Playgroud)

只是想分享,以防它帮助别人。


Pra*_*ani 9

即使在尝试接受的答案之后,如果它不适合您,请尝试以下代码。

前期步骤:按照建议的已接受答案进行操作。

之前在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>
Run Code Online (Sandbox Code Playgroud)

现在我已经做了什么

创建一个方法:

Future<void> _makeSocialMediaRequest(String url) async {
    if (await canLaunch(url)) {
      await launch(url);
    } else {
      throw 'Could not launch $url';
    }
  }
Run Code Online (Sandbox Code Playgroud)

并通过以下方式调用它:

  //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");
Run Code Online (Sandbox Code Playgroud)

它对我有用。希望它也对你有用。谢谢。


小智 7

兄弟只放了'!' 在“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';
}
Run Code Online (Sandbox Code Playgroud)