Flutter WebView插件无法播放某些YouTube视频

时间:2019-05-28 19:00:28

标签: webview flutter youtube youtube-iframe-api

webview_flutter插件无法播放某些YouTube嵌入的视频,这些视频如果从网络应用程序中播放则可以正常工作。视频显示“视频不可用”。在Flutter应用中内嵌播放YouTube视频至少一年来一直是个问题。

https://github.com/flutter/flutter/issues/13756

我尝试了各种Flutter插件来内联播放YouTube视频,但它们要么仅支持Android,要么不支持YouTube。

我曾尝试直接在WebView插件中使用HTML字符串(YouTube iframe),但该视频不可用。从网络服务器加载HTML允许播放一些视频,否则这些视频将无法直接在flutter应用程序中播放,例如某些音乐视频显示“视频不可用。该视频包含Vevo的内容,已阻止其在网站或应用程序上显示”。

但是,如果我从网络应用程序中使用YouTube iframe API(请参见代码)启动同一视频,则该视频可以正常运行,即未禁用嵌入功能,但这些视频无法在Flutter应用中播放。我还读过在Android上播放YouTube视频时遇到的类似问题,建议使用WebChromeClient,这在Flutter中不可用。

Flutter应用程序,可在WebView插件中显示YouTube视频。

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

// Use IP instead of localhost to access local webserver
const _youTubeUrl = 'http://localhost:8080';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'YouTube Video',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'YouTube Video'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String title;

  MyHomePage({Key key, this.title}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  WebViewController _controller;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            child: WebView(
              initialUrl: '$_youTubeUrl/videos/IyFZznAk69U',
              javascriptMode: JavascriptMode.unrestricted,
              onWebViewCreated: (WebViewController controller) =>
                  _controller = controller,
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.play_arrow),
        onPressed: () async {
          await _controller.evaluateJavascript('player.loadVideoById("d_m5csmrf7I")');
        },
      ),
    );
  }
}

通过快速路由返回index.html的Node.js服务器端代码

const path = require("path");
const express = require("express");

const server = express();

// Define route
api.get("/", (req, res) =>
  res.sendFile(path.join(__dirname + "/index.html"))
);

const port = process.env.PORT || 8080;

server.listen(port, () => console.log(`Server listening on ${port}`));

process.on("exit", () => console.log("Server exited"));

使用YouTube iframe API的index.html文件投放到Flutter应用

<!DOCTYPE html>
<html>

<head>
    <style>
        #player {
            position: relative;
            padding-top: 56.25%;
            min-width: 240px;
            height: 0;
        }

        iframe {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
        }
    </style>
    <script>
        var player;

        function onYouTubeIframeAPIReady() {
            player = new YT.Player("yt", {
                videoId: "IyFZznAk69U",
                playerVars: {
                    autoplay: 1
                }
            });
        }
    </script>
    <script src="https://www.youtube.com/iframe_api" async></script>
</head>

<body>
    <div id="player">
        <div id="yt"></div>
    </div>
</body>

</html>

2 个答案:

答案 0 :(得分:0)

更新:此插件似乎更好(在jira问题url上提到),但不是Flutter团队的官方

https://github.com/hoanglm4/flutter_youtube_view

答案 1 :(得分:0)

您可以使用我的插件flutter_inappwebview在网络视图中播放youtube视频。

带有您的youtube视频ID的完整示例:

import 'dart:async';

import 'package:flutter/material.dart';

import 'package:flutter_inappwebview/flutter_inappwebview.dart';

Future main() async {
  runApp(new MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: InAppWebViewPage()
    );
  }
}

class InAppWebViewPage extends StatefulWidget {
  @override
  _InAppWebViewPageState createState() => new _InAppWebViewPageState();
}

class _InAppWebViewPageState extends State<InAppWebViewPage> {
  InAppWebViewController webView;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: Text("InAppWebView")
        ),
        body: Container(
            child: Column(children: <Widget>[
              Expanded(
                child: Container(
                  child: InAppWebView(
                    initialUrl: "https://www.youtube.com/embed/IyFZznAk69U",
                    initialHeaders: {},
                    initialOptions: InAppWebViewWidgetOptions(
                      inAppWebViewOptions: InAppWebViewOptions(
                        debuggingEnabled: true,
                      ),
                    ),
                    onWebViewCreated: (InAppWebViewController controller) {
                      webView = controller;
                    },
                    onLoadStart: (InAppWebViewController controller, String url) {

                    },
                    onLoadStop: (InAppWebViewController controller, String url) {

                    },
                  ),
                ),
              ),
            ]))
    );
  }
}