How to use YouTube APIs and Play YouTube videos in Flutter.

By | August 27, 2020

In this article we are gonna talk about how to use YouTube API’s and play YouTube videos in Flutter.

Watch Video Tutorial


Add Dependencies

Open pubspec.yaml file in your Flutter project and add below dependencies

http: ^0.12.0+2
youtube_player_flutter: ^7.0.0+7
cached_network_image: ^2.2.0+1

Now, Let’s create two screens

  • Home Screen
  • Video Player Screen

In the HomeScreen we will show the list of videos.


API Key

We need the API key to access the YouTube APIs.

For that we need to

  1. Go to https://console.developers.google.com/
  2. Create a new project, 
  3. Click Create Project
  4. Once done, click Dashboard, Enabled APIs, find YouTube API V3
  5. Click Enable
  6. Create Credentials, Choose Youtube API V3
  7. Select Platform
  8. Select ‘Public Data’
  9. Click “What credentials do I need?”
  10. Click Done
  11. Copy API Key.

Lets copy this api key into our Flutter project.

String API_KEY = 'AIzaSyBGj_Duj__ivCxJ2ya3ilkVfEzX1ZSRlpE';

Get the Channel Info

To Get the channel info, we can use the below youtube API

Let’s create a Services class to call these APIs.

Create a class named “Services.dart and call the above API.


Get the channel ID of one of the YouTube Channels.

Below is my Channel’s ID.
https://www.youtube.com/channel/UC5lbdURzjB0irr-FTbjWN1A

static const CHANNEL_ID = 'UC5lbdURzjB0irr-FTbjWN1A';
  static const _baseUrl = 'www.googleapis.com';
static Future<ChannelInfo> getChannelInfo() async {
    Map<String, String> parameters = {
      'part': 'snippet,contentDetails,statistics',
      'id': CHANNEL_ID,
      'key': Constants.API_KEY,
    };
    Map<String, String> headers = {
      HttpHeaders.contentTypeHeader: 'application/json',
    };
    Uri uri = Uri.https(
      _baseUrl,
      '/youtube/v3/channels',
      parameters,
    );
    Response response = await http.get(uri, headers: headers);
    // print(response.body);
    ChannelInfo channelInfo = channelInfoFromJson(response.body);
    return channelInfo;
}

ChannelInfo Model class for the above API.

Now let’s use this API in the home screen.

ChannelInfo _channelInfo;
_getChannelInfo() async {
    _channelInfo = await Services.getChannelInfo();
    _item = _channelInfo.items[0];
    _playListId = _item.contentDetails.relatedPlaylists.uploads;
    print('_playListId $_playListId');
    await _loadVideos();
    setState(() {
      _loading = false;
    });
 }
 

Let’s build the Channel Info View.

_item.snippet.title. - gets the channel title
_item.snippet.thumbnails.medium.url - gets the channel thumbnail image. in medium resolution.

_buildInfoView() {
    return _loading
        ? CircularProgressIndicator()
        : Container(
            padding: EdgeInsets.all(20.0),
            child: Card(
              child: Padding(
                padding: const EdgeInsets.all(10.0),
                child: Row(
                  children: [
                    CircleAvatar(
                      backgroundImage: CachedNetworkImageProvider(
                        _item.snippet.thumbnails.medium.url,
                      ),
                    ),
                    SizedBox(width: 20),
                    Expanded(
                      child: Text(
                        _item.snippet.title,
                        style: TextStyle(
                          fontSize: 20,
                          fontWeight: FontWeight.w400,
                        ),
                      ),
                    ),
                    Text(_item.statistics.videoCount),
                    SizedBox(width: 20),
                  ],
                ),
              ),
            ),
          );
  }

Get the Videos List

To get the videos list, we need to use the YouTube API below…

https://developers.google.com/youtube/v3/docs/playlistItems/list

Let’s write the service for getting the video list.

static Future<VideosList> getVideosList(
    {String playListId, String pageToken}) async {
  Map<String, String> parameters = {
    'part': 'snippet',
    'playlistId': playListId,
    'maxResults': '8',
    'pageToken': pageToken,
    'key': Constants.API_KEY,
  };
  Map<String, String> headers = {
    HttpHeaders.contentTypeHeader: 'application/json',
  };
  Uri uri = Uri.https(
    _baseUrl,
    '/youtube/v3/playlistItems',
    parameters,
  );
  Response response = await http.get(uri, headers: headers);
  // print(response.body);
  VideosList videosList = videosListFromJson(response.body);
  return videosList;
}

The VideosList model for the API above

import 'dart:convert';
VideosList videosListFromJson(String str) =>
    VideosList.fromJson(json.decode(str));
String videosListToJson(VideosList data) => json.encode(data.toJson());
class VideosList {
  VideosList({
    this.kind,
    this.etag,
    this.nextPageToken,
    this.videos,
    this.pageInfo,
  });
String kind;
  String etag;
  String nextPageToken;
  List<VideoItem> videos;
  PageInfo pageInfo;
factory VideosList.fromJson(Map<String, dynamic> json) => VideosList(
        kind: json["kind"],
        etag: json["etag"],
        nextPageToken: json["nextPageToken"],
        videos: List<VideoItem>.from(
            json["items"].map((x) => VideoItem.fromJson(x))),
        pageInfo: PageInfo.fromJson(json["pageInfo"]),
      );
Map<String, dynamic> toJson() => {
        "kind": kind,
        "etag": etag,
        "nextPageToken": nextPageToken,
        "items": List<dynamic>.from(videos.map((x) => x.toJson())),
        "pageInfo": pageInfo.toJson(),
      };
}
class VideoItem {
  VideoItem({
    this.kind,
    this.etag,
    this.id,
    this.video,
  });
String kind;
  String etag;
  String id;
  Video video;
factory VideoItem.fromJson(Map<String, dynamic> json) => VideoItem(
        kind: json["kind"],
        etag: json["etag"],
        id: json["id"],
        video: Video.fromJson(json["snippet"]),
      );
Map<String, dynamic> toJson() => {
        "kind": kind,
        "etag": etag,
        "id": id,
        "snippet": video.toJson(),
      };
}
class Video {
  Video({
    this.publishedAt,
    this.channelId,
    this.title,
    this.description,
    this.thumbnails,
    this.channelTitle,
    this.playlistId,
    this.position,
    this.resourceId,
  });
DateTime publishedAt;
  String channelId;
  String title;
  String description;
  Thumbnails thumbnails;
  String channelTitle;
  String playlistId;
  int position;
  ResourceId resourceId;
factory Video.fromJson(Map<String, dynamic> json) => Video(
        publishedAt: DateTime.parse(json["publishedAt"]),
        channelId: json["channelId"],
        title: json["title"],
        description: json["description"],
        thumbnails: Thumbnails.fromJson(json["thumbnails"]),
        channelTitle: json["channelTitle"],
        playlistId: json["playlistId"],
        position: json["position"],
        resourceId: ResourceId.fromJson(json["resourceId"]),
      );
Map<String, dynamic> toJson() => {
        "publishedAt": publishedAt.toIso8601String(),
        "channelId": channelId,
        "title": title,
        "description": description,
        "thumbnails": thumbnails.toJson(),
        "channelTitle": channelTitle,
        "playlistId": playlistId,
        "position": position,
        "resourceId": resourceId.toJson(),
      };
}
class ResourceId {
  ResourceId({
    this.kind,
    this.videoId,
  });
String kind;
  String videoId;
factory ResourceId.fromJson(Map<String, dynamic> json) => ResourceId(
        kind: json["kind"],
        videoId: json["videoId"],
      );
Map<String, dynamic> toJson() => {
        "kind": kind,
        "videoId": videoId,
      };
}
class Thumbnails {
  Thumbnails({
    this.thumbnailsDefault,
    this.medium,
    this.high,
    this.standard,
    this.maxres,
  });
Default thumbnailsDefault;
  Default medium;
  Default high;
  Default standard;
  Default maxres;
factory Thumbnails.fromJson(Map<String, dynamic> json) => Thumbnails(
        thumbnailsDefault: Default.fromJson(json["default"]),
        medium: Default.fromJson(json["medium"]),
        high: Default.fromJson(json["high"]),
        standard: null == json["standard"]
            ? null
            : Default.fromJson(json["standard"]),
        maxres:
            null == json["maxres"] ? null : Default.fromJson(json["maxres"]),
      );
Map<String, dynamic> toJson() => {
        "default": thumbnailsDefault.toJson(),
        "medium": medium.toJson(),
        "high": high.toJson(),
        "standard": standard.toJson(),
        "maxres": maxres.toJson(),
      };
}
class Default {
  Default({
    this.url,
    this.width,
    this.height,
  });
String url;
  int width;
  int height;
factory Default.fromJson(Map<String, dynamic> json) => Default(
        url: json["url"],
        width: json["width"],
        height: json["height"],
      );
Map<String, dynamic> toJson() => {
        "url": url,
        "width": width,
        "height": height,
      };
}
class PageInfo {
  PageInfo({
    this.totalResults,
    this.resultsPerPage,
  });
int totalResults;
  int resultsPerPage;
factory PageInfo.fromJson(Map<String, dynamic> json) => PageInfo(
        totalResults: json["totalResults"],
        resultsPerPage: json["resultsPerPage"],
      );
Map<String, dynamic> toJson() => {
        "totalResults": totalResults,
        "resultsPerPage": resultsPerPage,
      };
}

So let’s call this API

_loadVideos() async {
    VideosList tempVideosList = await Services.getVideosList(
      playListId: _playListId,
      pageToken: _nextPageToken,
    );
    _nextPageToken = tempVideosList.nextPageToken;
    _videosList.videos.addAll(tempVideosList.videos);
    print('videos: ${_videosList.videos.length}');
    print('_nextPageToken $_nextPageToken');
    setState(() {});
}

and in the build method, we will display it in a ListView

ListView.builder(
  controller: _scrollController,
  itemCount: _videosList.videos.length,
  itemBuilder: (context, index) {
    VideoItem videoItem = _videosList.videos[index];
    return InkWell(
      onTap: () async {
        Navigator.push(context,
            MaterialPageRoute(builder: (context) {
          return VideoPlayerScreen(
            videoItem: videoItem,
          );
        }));
      },
      child: Container(
        padding: EdgeInsets.all(20.0),
        child: Row(
          children: [
            CachedNetworkImage(
              imageUrl: videoItem
                  .video.thumbnails.thumbnailsDefault.url,
            ),
            SizedBox(width: 20),
            Flexible(child: Text(videoItem.video.title)),
          ],
        ),
      ),
    );
  },
),

Video Player Screen

So now we have each Video Item, each of them have a videoId which can be used to Load the Video.
The Video Player Screen will accept the VideoItem Model from above and play the video.

import 'package:flutter/material.dart';
import 'package:flutter_demos/models/viideos_list.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
class VideoPlayerScreen extends StatefulWidget {
  //
  VideoPlayerScreen({this.videoItem});
  final VideoItem videoItem;
@override
  _VideoPlayerScreenState createState() => _VideoPlayerScreenState();
}
class _VideoPlayerScreenState extends State<VideoPlayerScreen> {
  //
  YoutubePlayerController _controller;
  bool _isPlayerReady;
@override
  void initState() {
    super.initState();
    _isPlayerReady = false;
    _controller = YoutubePlayerController(
      initialVideoId: widget.videoItem.video.resourceId.videoId,
      flags: YoutubePlayerFlags(
        mute: false,
        autoPlay: true,
      ),
    )..addListener(_listener);
  }
void _listener() {
    if (_isPlayerReady && mounted && !_controller.value.isFullScreen) {
      //
    }
  }
@override
  void deactivate() {
    _controller.pause();
    super.deactivate();
  }
@override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.videoItem.video.title),
      ),
      body: Container(
        child: YoutubePlayer(
          controller: _controller,
          showVideoProgressIndicator: true,
          onReady: () {
            print('Player is ready.');
            _isPlayerReady = true;
          },
        ),
      ),
    );
  }
}

Source Code

https://bitbucket.org/vipinvijayan1987/tutorialprojects/src/YoutubePlayer/FlutterTutorialProjects/flutter_demos/

That’s it.

Watch my YouTube video tutorial for more detailed explanation.

Thanks for reading.


Leave a Reply

Your email address will not be published. Required fields are marked *