9

I basically want to open a specific youtube video from my app, when a button is pressed. If the youtube app is installed on the user's device, then the video should be opened in the youtube app (and not in the browser or a separate webview).

I used the url_launcher package for that, and it works fine on android. However on iOS the youtube app is not opened even if it is installed, instead a separate web window is opened, where the corresponding youtube url is shown as a webpage.

I thought, that I could override this behaviour like so:

_launchURL() async {
  if (Platform.isIOS) {
    if (await canLaunch('youtube://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw')) {
      await launch('youtube://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw');
    } else {
      if (await canLaunch('https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw')) {
        await launch('https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw');
      } else {
        throw 'Could not launch https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw';
      }
    }
  } else {
    const url = 'https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw';
    if (await canLaunch(url)) {
      await launch(url);
    } else {
      throw 'Could not launch $url';
    }
  }
}

but it didn’t work. In case you wonder, I use the following imports:

import 'dart:io' show Platform;
import 'package:url_launcher/url_launcher.dart';

I am pretty sure, the youtube:// URL-Scheme works (launches the YouTube app), because I tested it on third party apps (Launch Center Pro and Pythonista).

The last thing I was not able to test, is if the Platform.isIOS is really true on my IPhone.

Is there a working way, to open the YouTube App from flutter?

frankenapps
  • 3,514
  • 4
  • 22
  • 50

3 Answers3

12

I fixed it. I had to set forceSafariVC: false, because it is true on default, which causes the url to be opened inside a sort of webview inside the app.

_launchURL() async {
  if (Platform.isIOS) {
    if (await canLaunch('youtube://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw')) {
      await launch('youtube://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw', forceSafariVC: false);
    } else {
      if (await canLaunch('https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw')) {
        await launch('https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw');
      } else {
        throw 'Could not launch https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw';
      }
    }
  } else {
    const url = 'https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw';
    if (await canLaunch(url)) {
      await launch(url);
    } else {
      throw 'Could not launch $url';
    }
}

This is actually documented in the url_launcher docs, but somewhat hidden...

frankenapps
  • 3,514
  • 4
  • 22
  • 50
  • 1
    canLaunch('youtube://www.youtube…') gives a false but launch('youtube://www.youtube…') works forceSafariVC seems false on default? I’m using flutter 1.7.8 & url_launcher: ^5.0.2 on iOS – Suyon Won Aug 25 '19 at 11:23
  • LSApplicationQueriesSchemes              youtube      solved the problem – Suyon Won Aug 25 '19 at 12:05
  • 1
    As of iOS 9, you also need the LSApplicationQueriesSchemes set in the info.plist to an array containing youtube: https://stackoverflow.com/a/31086148/6024667 – punjabi4life Oct 05 '19 at 18:50
5

You don't have to have all that if/else clauses. The most important thing to take into consideration is that whether the device has the YouTube app or not, regardless of the O.S (and remember to define your function as Future because of the async):

Future<void> _launchYoutubeVideo(String _youtubeUrl) async {
if (_youtubeUrl != null && _youtubeUrl.isNotEmpty) {
  if (await canLaunch(_youtubeUrl)) {
    final bool _nativeAppLaunchSucceeded = await launch(
      _youtubeUrl,
      forceSafariVC: false,
      universalLinksOnly: true,
    );
    if (!_nativeAppLaunchSucceeded) {
      await launch(_youtubeUrl, forceSafariVC: true);
    }
  }
 }
}

The thing to highlight here to avoid several if/else si the attribute universalLinksOnly set to true.

Phillip Schulze
  • 118
  • 2
  • 8
Carlos Daniel
  • 2,082
  • 22
  • 25
0

I have solved the issue. You can try the below code:

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

    void main() => runApp(const HomePage());  

    class HomePage extends StatelessWidget {  
      const HomePage({Key? key}) : super(key: key);  
      @override  
      Widget build(BuildContext context) {  
        return const MaterialApp(  
          debugShowCheckedModeBanner: false,  
          home: MyApp(),  
        );  
      }  
    }  

    class MyApp extends StatefulWidget {  
      const MyApp({Key? key}) : super(key: key);  
      @override  
      _MyAppState createState() => _MyAppState();
    }  

    class _MyAppState extends State<MyApp> {  
      Future<void>? _launched;  
      @override  
      Widget build(BuildContext context) {  
        const String toLaunch = 'https://www.youtube.com/watch?v=WcZ8lTRTNM0';  
        return Scaffold(  
          appBar: AppBar(title: const Text('Flutter Demo')),  
          body: Center(  
            child: ElevatedButton(  
              onPressed: () => setState(() {  
                _launched = _launchInBrowser(toLaunch);  
              }),  
              child: const Text('Launch in browser'),  
            ),  
          ), );  
      }  
      Future<void> _launchInBrowser(String url) async {  
        if (!await launch(  
          url,  
          forceSafariVC: true,  
          forceWebView: false,  
          headers: <String, String>{'my_header_key': 'my_header_value'},  
        )) {  
          throw 'Could not launch $url';  
        }  
      }  
    }
Er1
  • 2,085
  • 1
  • 11
  • 21
Ke1212
  • 21
  • 6