[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7341":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":19,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":24,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":38,"readmeContent":39,"aiSummary":40,"trendingCount":16,"starSnapshotCount":16,"syncStatus":41,"lastSyncTime":42,"discoverSource":43},7341,"android-youtube-player","PierfrancescoSoffritti\u002Fandroid-youtube-player","PierfrancescoSoffritti","YouTube Player library for Android and Chromecast, stable and customizable.","https:\u002F\u002Fpierfrancescosoffritti.github.io\u002Fandroid-youtube-player\u002F",null,"Kotlin",3698,795,85,248,0,4,11,1,30.7,"MIT License",false,"dev",true,[26,5,27,28,29,30,31,32,33,34,35,36,37],"android","chromecast-receiver","chromecast-sender","chromecast-support","custom-view","webview","youtube","youtube-player","youtube-player-api","youtube-player-library","youtube-video","youtubeplayerview","2026-06-12 02:01:38","#### \\\u003CAdvertisement\\>\n\n#### [:mega: Reply to Google Play Reviews using AI :arrow_right:](https:\u002F\u002Fplaystorereply.com) \nIncrease your apps ratings. Engage with all users, no more unanswered reviews.\nSave time and increase customer satisfaction.\n\n#### \\\u003C\u002FAdvertisement\\>\n\n# android-youtube-player\n\n[![Android YouTube Player](https:\u002F\u002Fwww.appbrain.com\u002Fstats\u002Flibraries\u002Fshield\u002Fandroid_youtube_player.svg)](https:\u002F\u002Fwww.appbrain.com\u002Fstats\u002Flibraries\u002Fdetails\u002Fandroid_youtube_player\u002Fandroid-youtube-player) \n[![website](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F-website-brightgreen.svg)](https:\u002F\u002Fpierfrancescosoffritti.github.io\u002Fandroid-youtube-player\u002F)\n\n[![share on twitter](https:\u002F\u002Fimg.shields.io\u002Ftwitter\u002Furl\u002Fhttp\u002Fshields.io.svg?style=social)](https:\u002F\u002Ftwitter.com\u002Fintent\u002Ftweet?text=A%20new%20YouTube%20Player%20library%20for%20Android%20and%20Chromecast,%20stable%20and%20customizable&url=https:\u002F\u002Fgithub.com\u002FPierfrancescoSoffritti\u002Fandroid-youtube-player&via=psoffritti&hashtags=opensource,youtubeplayer,androiddev)\n\n\u003Cimg align=\"right\" width=\"180px\" src=\".\u002Fimages\u002Fandroid-youtube-player_512x512.png\" title=\"android-youtube-player logo\" \u002F>\n\nandroid-youtube-player is a stable and customizable open source YouTube player for Android. It provides a simple View that can be easily integrated in every Activity\u002FFragment.\n\nThe library is a wrapper around the [IFrame Player API](https:\u002F\u002Fdevelopers.google.com\u002Fyoutube\u002Fiframe_api_reference), which runs inside of a WebView. Therefore there are [no issues with YouTube Terms of Service](#does-this-library-breaks-youtube-terms-of-service).\n\nThis library also provides a [Chromecast YouTube player](#chromecast-extension-library), that you can use to cast YouTube videos from your app to a Chromecast device.\n\n## Why does this library exist?\nThe library provided by Google is the [YouTube Android Player API](https:\u002F\u002Fdevelopers.google.com\u002Fyoutube\u002Fandroid\u002Fplayer\u002F).\nThis library has been [historically not reliable]((https:\u002F\u002Fcode.google.com\u002Fp\u002Fgdata-issues\u002Fissues\u002Fdetail?id=4395)) and is now deprecated by Google.\n\nGoogle now recommends using the IFrame Player API inside a WebView, which is exactly what this library does, while also providing a native Java\u002FKotlin interface to interact with the web player.\n\nA lengthier explanation of why this library was created can be found in [this Medium post](https:\u002F\u002Fmedium.com\u002F@soffritti.pierfrancesco\u002Fhow-to-play-youtube-videos-in-your-android-app-c40427215230).\n\n## Who is using this library\nNow that **the official API from Google is deprecated**, `android-youtube-player` is the main YouTube player library for Android.\n\n**Used by over 5 thousands apps**, with some big names like [Tumblr](https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=com.tumblr), [Flipkart](https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=com.flipkart.android), [McDonald's](https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=com.mcdo.mcdonalds), [InShot Video Editor](https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=com.camerasideas.instashot), [Genius](https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=com.genius.android) and [reddit is fun](https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=com.andrewshu.android.reddit).\n\nYou can [see more stats here](https:\u002F\u002Fwww.appbrain.com\u002Fstats\u002Flibraries\u002Fdetails\u002Fandroid_youtube_player\u002Fandroid-youtube-player).\n\n**If you choose to use this library and profit from it**, consider informing me and [become a sponsor on GitHub](https:\u002F\u002Fgithub.com\u002Fsponsors\u002FPierfrancescoSoffritti). This will enable me to continue developing the library, so you don't have to.\n\n![showcase](.\u002Fimages\u002Fshowcase.jpg)\n\n## Does this library break YouTube terms of service?\n**TL;DR** No. \n\nThe library uses YouTube's own web player to play videos. Therefore it is 100% compliant with  terms of service.\nPlaying YouTube videos in a WebView is the recommended approach by Google, both on [Android](https:\u002F\u002Fdevelopers.google.com\u002Fyoutube\u002Fandroid\u002Fplayer\u002F) and [iOS](https:\u002F\u002Fdevelopers.google.com\u002Fyoutube\u002Fv3\u002Fguides\u002Fios_youtube_helper).\n\nThat said how you use the library matters, be sure to play videos only when the player is visible. If you follow the instructions in the documentation, the library will automatically handle this for you.\n\nAlso remember when publishing your app on the PlayStore to write title and description in a way that makes it obvious that your app doesn't have any affiliation with YouTube (the company). **This issue has nothing to do with the library itself**, but I figured it may be useful knowledge for many of you considering to use it.\n\n# Table of Contents (Core)\n1. [Sample app](#sample-app)\n2. [Download](#download)\n    1. [Core](#core)\n    2. [Chromecast](#chromecast)\n3. [Quick start](#quick-start)\n4. [API documentation](#api-documentation)\n    1. [YouTubePlayerView](#youtubeplayerview)\n        1. [XML attributes](#xml-attributes)\n        2. [Initialization](#initialization)\n        3. [IFramePlayerOptions](#iframeplayeroptions)\n        4. [Full screen](#full-screen)\n        5. [Release the YouTubePlayerView](#release-the-youtubeplayerview)\n        6. [LifecycleObserver](#lifecycleobserver)\n    2. [YouTubePlayer](#youtubeplayer)\n        1. [Get a reference to YouTubePlayer](#get-a-reference-to-youtubeplayer)\n        2. [Load videos](#load-videos)\n            1. [Utility for loading videos](#utility-for-loading-videos)\n        3. [Events](#events)\n        4. [Get state from the player](#get-state-from-the-player)\n        5. [YouTubePlayerTracker](#youtubeplayertracker)\n    3. [YouTubePlayerListener](#youtubeplayerlistener)\n        1. [onReady callback](#onready-callback)\n        2. [onStateChanged callback](#onstatechanged-callback)\n    4. [Create your own custom UI](#create-your-own-custom-ui)\n        1. [DefaultPlayerUiController](#defaultplayeruicontroller)\n        2. [Reusable UI components](#reusable-ui-components)\n            1. [YouTubePlayerSeekBar](#youtubeplayerseekbar)\n            2. [FadeViewHelper](#fadeviewhelper)\n            3. [TimeUtilities](#timeutilities)\n    5. [Network events](#network-events)\n    6. [Chromecast support](#chromecast-support)\n    7. [Useful info](#useful-info)\n        1. [Hardware acceleration](#hardware-acceleration)\n        2. [Play YouTube videos in the background](#play-youtube-videos-in-the-background)\n        3. [minSdk](#minsdk)\n\n# Table of Contents (Chromecast)\n1. [Chromecast extension library](#chromecast-extension-library)\n2. [Quick start and API documentation](#quick-start---chromecast)\n    1. [Download extra dependencies](#download-extra-dependencies)\n    2. [Sender](#sender)\n    3. [Receiver](#receiver)\n    4. [Registration](#registration)\n    5. [Hosting the Chromecast receiver](#hosting-the-chromecast-receiver)\n    \n# FAQ\n1. [Workarounds](#workarounds)\n    1. [Change video quality](#change-video-quality)\n    2. [Login to YouTube account](#login-to-youtube-account)\n    3. [Block Ads (Auto Ad Skip)](#block-ads)\n    4. [Remove views that cannot be removed by the controls parameter](#remove-annoying-views)\n    5. [Force to hide subtitles](#hide-captions)\n    6. [Play Next Recomended Video](#play-next-recomended-video)\n\n# Sample app\n:memo: Both the **core module** and the **chromecast module** have a sample app, to provide examples of usage of the libraries.\n\n* [Go to source code of **core** sample app](.\u002Fcore-sample-app\u002F).\n* [Go to source code of **chromecast-sender** sample app](.\u002Fchromecast-sender-sample-app).\n\n:calling: You can also download and install the apks of both sample apps.\n\n* [Download apk of **core** sample app](.\u002Fcore-sample-app\u002Fapk).\n* [Download apk of **chromecast-sender** sample app](.\u002Fchromecast-sender-sample-app\u002Fapk).\n\n:eyes: If you want to know when a new release of the library is published: [watch this repository on GitHub](https:\u002F\u002Fgithub.com\u002FPierfrancescoSoffritti\u002Fandroid-youtube-player\u002Fwatchers).\n\n# Download\nThe Gradle dependency is available via [MavenCentral](https:\u002F\u002Frepo1.maven.org\u002Fmaven2\u002Fcom\u002Fpierfrancescosoffritti\u002Fandroidyoutubeplayer\u002F).\n\nThe minimum API level supported by this library is API 21.\n\n### Core\nThe *core* module contains the YouTube Player. It's all you need to play YouTube videos in your app.\n\nAdd this to your module level `build.gradle` file.\n\n```gradle\ndependencies {\n  implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:core:13.0.0'\n}\n```\n\n### Chromecast\nThe *chromecast-sender* module contains the Chromecast YouTube Player. Use it if you need to cast YouTube videos from your app to a Chromecast device.\n\nAdd this to your module level `build.gradle` file.\n\n```gradle\ndependencies {\n  implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:chromecast-sender:0.32'\n}\n```\n\n# Quick start\nIn order to start using the player you need to add a [YouTubePlayerView](#youtubeplayerview) to your layout.\n\n```xml\n\u003CLinearLayout\n    xmlns:android=\"http:\u002F\u002Fschemas.android.com\u002Fapk\u002Fres\u002Fandroid\"\n    xmlns:app=\"http:\u002F\u002Fschemas.android.com\u002Fapk\u002Fres-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\" >\n\n    \u003Ccom.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView\n        android:id=\"@+id\u002Fyoutube_player_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        \n        app:videoId=\"S0Q4gqBUs7c\"\n        app:autoPlay=\"true\" \u002F>\n\u003C\u002FLinearLayout>\n```\n\nIt is recommended that you add `YouTubePlayerView` as a lifecycle observer of its parent Activity\u002FFragment. You can [read why in the documentation](#lifecycleobserver).\n\n```java\nYouTubePlayerView youTubePlayerView = findViewById(R.id.youtube_player_view);\ngetLifecycle().addObserver(youTubePlayerView);\n```\n*(If you have problems adding `YouTubePlayerView` as a `LifecycleObserver`, you probably aren't using androidx, [I suggest you migrate your dependencies](https:\u002F\u002Fdeveloper.android.com\u002Fjetpack\u002Fandroidx\u002Fmigrate))*\n\nThis is all you need, a YouTube video is now playing in your app.\n\nIf you want more control, everything can be done programmatically by getting a reference to your `YouTubePlayerView` and adding a `YouTubePlayerListener` to it.\n\n```java\nYouTubePlayerView youTubePlayerView = findViewById(R.id.youtube_player_view);\ngetLifecycle().addObserver(youTubePlayerView);\n\nyouTubePlayerView.addYouTubePlayerListener(new AbstractYouTubePlayerListener() {\n  @Override\n  public void onReady(@NonNull YouTubePlayer youTubePlayer) {\n    String videoId = \"S0Q4gqBUs7c\";\n    youTubePlayer.loadVideo(videoId, 0);\n  }\n});\n```\n\nIf you decide to initialize the player programmatically, remember to remove the `autoPlay` and `videoId` attributes from the `YouTubePlayerView` in your XML file.\n\n----\n\n# API documentation\nThe following sections provides detailed documentation for every component in the library.\n\nIf you see any problem or mistake in the documentation, feel free to contribute by opening an issue an\u002For sending a pull request.\n\n## YouTubePlayerView\n`YouTubePlayerView` is the access point to the `YouTubePlayer`.\n\nYou can add the View to your layout.\n\n```xml\n\u003CLinearLayout\n    xmlns:android=\"http:\u002F\u002Fschemas.android.com\u002Fapk\u002Fres\u002Fandroid\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" >\n\n    \u003Ccom.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView\n        android:id=\"@+id\u002Fyoutube_player_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\u002F>\n\u003C\u002FLinearLayout>\n```\n\nOr you can create it programmatically and manually add it to a ViewGroup.\n\n```java\nYouTubePlayerView youTubePlayerView = new YouTubePlayerView(this);\nlayout.addView(youTubePlayerView);\n```\n\nIf the height of the View is set to `wrap_content`, the View will automatically have an aspect ratio of 16:9, to match the aspect ratio of most YouTube videos.\n\n### XML attributes\nIf you add the view to your XML layout you have the possibility to set a few custom attributes, to customize the view's look and behavior. Everything can also be done programmatically.\n\n- [videoId](#videoId)\n- [autoPlay](#autoPlay)\n- [enableAutomaticInitialization](#enableAutomaticInitialization)\n- [handleNetworkEvents](#handleNetworkEvents)\n\n#### videoId\nThis attribute expects a `String`, which is the id of a YouTube video.\n\n**If set**, the player will automatically start playing the video.\n\n**If not set**, the player won't automatically play.\n\nIn general you should use this attribute if you want your player to play only one video. This is not a rule, just best practice. In fact, even if you set the attribute it is still possible to play other videos programmatically.\n\n#### autoPlay\nThis attribute expects a `boolean`. Its default value is `false`.\n\n**If `true`**, the player start playing the video provided with `videoId` without waiting for user input.\n\n**If `false`**, the player will wait for user input before playing the video provided with `videoId`.\n\nIf `videoId` is not set, this attribute is useless, therefore if it is set to `true` `YouTubePlayerView` will throw an exception.\n\n`autoPlay` won't work if `YouTubePlayerView` is not [added as a `LifecycleObserver` of its parent Activity\u002FFragment](#lifecycleobserver).\n\n#### enableAutomaticInitialization\nThis attribute expects a `boolean`. Its default value is `true`.\n\n**If `true`**, `YouTubePlayerView` will take care of its initialization.\n\n**If `false`**, you will have to initialize `YouTubePlayerView` programmatically.\n\nIn general it makes sense to leave this attribute to `true`. You may want to set it to `false` only if you need to initialize the view using [`IFramePlayerOptions`](#iframeplayeroptions).\n\n#### handleNetworkEvents\nThis attribute expects a `boolean`. Its default value is `true`.\n\n**If `true`**, `YouTubePlayerView` handle network events by registering a `NetworkReceiver`.\n\n**If `false`**, you will be responsible for handling network events.\n\nIt is useful to have this attribute set to `true` so that if the connection drops while the player is initializing `YouTubePlayerView` will be able to resume the initialization automatically once the network is back.\n\nIf you decide to set it to `false` you should also disable `enableAutomaticInitialization` and manage network events on your own.\n\nRead more about network events [here](#network-events).\n\n### Initialization\nIf you need to initialize `YouTubePlayerView` programmatically, you can set its xml attribute `enableAutomaticInitialization` to false.\nYou can do the same programmatically by calling `youTubePlayerView.setEnableAutomaticInitialization(false)`.\n\nAfter automatic initialization has been disabled, you need to take care of the initialization of `YouTubePlayerView`.\n\nYou can use these methods:\n```java\nYouTubePlayerView.initialize(YouTubePlayerListener listener)\n```\n```java\nYouTubePlayerView.initialize(YouTubePlayerListener listener, IFramePlayerOptions iframePlayerOptions)\n```\n```java\nYouTubePlayerView.initialize(YouTubePlayerListener listener, boolean handleNetworkEvents)\n```\n```java\nYouTubePlayerView.initialize(YouTubePlayerListener listener, boolean handleNetworkEvents, IFramePlayerOptions iframePlayerOptions)\n```\n```java\nYouTubePlayerView.initialize(YouTubePlayerListener listener, boolean handleNetworkEvents, IFramePlayerOptions iframePlayerOptions, String videoId)\n```\n#### `initialize(YouTubePlayerListener)`\nInitialize the `YouTubePlayer`. Network events are automatically handled by the player.\n\nThe argument is a `YouTubePlayerListener`, you can read more about it [here](#youtubeplayerlistener).\n\n#### `initialize(YouTubePlayerListener, boolean)`\nInitialize the `YouTubePlayer`. By using the `boolean` is possible to decide if the player should handle network events or not, read more about network events [here](#network-events).\n\n#### `initialize(YouTubePlayerListener, boolean, IFramePlayerOptions)`\nBy passing an `IFramePlayerOptions` to the initialize method it is possible to set some of the parameters of the IFrame YouTubePlayer. Read more about `IFramePlayerOptions` [here](#iframeplayeroptions).\n\nAll the possible parameters and values are listed [here](https:\u002F\u002Fdevelopers.google.com\u002Fyoutube\u002Fplayer_parameters#Parameters). Not all of them are supported in this library because some don't make sense in this context. [Open an issue](https:\u002F\u002Fgithub.com\u002FPierfrancescoSoffritti\u002Fandroid-youtube-player\u002Fissues) if you need a parameter that is not currently supported.\n\n#### `initialize(YouTubePlayerListener, boolean, IFramePlayerOptions, String)`\nBy passing the `videoId` the video will be loaded as soon as possible after initialization.\n\n### IFramePlayerOptions\nThe `IFramePlayerOptions` is an optional argument that can be passed to `YouTubePlayerView.initialize(YouTubePlayerListener, boolean, IFramePlayerOptions)`, it can be used to set some of the parameters of the IFrame YouTubePlayer.\n\nA simple example of how to use `IFramePlayerOptions` can be found in the sample app [here](.\u002Fcore-sample-app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fpierfrancescosoffritti\u002Fandroidyoutubeplayer\u002Fcore\u002Fsampleapp\u002Fexamples\u002FiFramePlayerOptionsExample\u002FIFramePlayerOptionsExampleActivity.java).\n\nUse the Builder to get a `IFramePlayerOptions` object.\n\n```java\nIFramePlayerOptions iFramePlayerOptions = new IFramePlayerOptions.Builder(context)\n  .controls(1)\n  .build();\n```\n\nAll the possible parameters and values are listed [here](https:\u002F\u002Fdevelopers.google.com\u002Fyoutube\u002Fplayer_parameters#Parameters). Not all of them are supported in this library because some don't make sense in this context. [Open an issue](https:\u002F\u002Fgithub.com\u002FPierfrancescoSoffritti\u002Fandroid-youtube-player\u002Fissues) if you need a parameter that is not currently supported.\n\n#### Supported options\n\n##### `controls`\nThis option indicates whether the web-based UI of the IFrame player should be hidden or visible.\n\nIf set to 0: web UI is not visible.\n\nIf set to 1: web UI is visible.\n\n##### `rel`\nThis option controls the related videos shown at the end of a video.\n\nIf set to 0: related videos will come from the same channel as the video that was just played.\n\nIf set to 1: related videos will come from multiple channels.\n\n##### `ivLoadPolicy`\nThis option controls video annotations.\n\nIf set to 1: the player will show annotations.\n\nIf set to 3: the player won't show annotations.\n\n##### `ccLoadPolicy`\nThis option controls video captions. It doesn't work with automatically generated captions.\n\nIf set to 0: the player will show captions.\n\nIf set to 1: the player won't show captions.\n\n##### `start`\nThis parameter causes the player to begin playing the video at the given number of seconds from the start of the video. The parameter value is a positive integer.\n\nIt works similarly to the `seekTo` method, and the `startSeconds` argument of `loadVideo` and `cueVideo`.\n\n##### `end`\nThis parameter specifies the time, measured in seconds from the beginning of the video, when the player should stop playing the video. The parameter value is a positive integer.\n\n### Full screen\nThe full screen button can be added to the player by using `IFramePlayerOptions`\n\n```java\nIFramePlayerOptions iFramePlayerOptions = new IFramePlayerOptions.Builder(context)\n  .controls(1)\n  \u002F\u002F enable full screen button\n  .fullscreen(1)\n  .build();\n```\n\nYou can listen to full screen events by adding a `FullscreenListener` to `YouTubePlayerView`\n\n```java\nyouTubePlayerView.addFullscreenListener(new FullscreenListener() {\n  @Override\n  public void onEnterFullscreen(@NonNull View fullscreenView, @NonNull Function0\u003CUnit> exitFullscreen) {\n  }\n\n  @Override\n  public void onExitFullscreen() {\n  }\n});\n```\n\nSee [the sample app for an example](.\u002Fcore-sample-app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fpierfrancescosoffritti\u002Fandroidyoutubeplayer\u002Fcore\u002Fsampleapp\u002Fexamples\u002FfullscreenExample\u002FFullscreenExampleActivity.kt).\n\nWhen `FullscreenListener#onEnterFullscreen` is called, the player will be rendered inside `fullscreenView` instead of `YouTubePlayerView`, until `FullscreenListener#onExitFullscreen` is called.\nTherefore you are required to add `fullscreenView` to your app's view hierarchy when fullscreen is started, and remove it when fullscreen is ended.\n\nYou can also use the `YouTubePlayerView#matchParent` and `YouTubePlayerView#wrapContent` to expand the view to fill its parent.\nIt is responsibility of the developer to hide other Views in the Activity, change the orientation of the Activity etc. The sample app contains an [helper class](.\u002Fcore-sample-app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fpierfrancescosoffritti\u002Fandroidyoutubeplayer\u002Fcore\u002Fsampleapp\u002Futils\u002FFullscreenHelper.java) that can help you to update your app state, but this is not part of the library.\n\nIf you need to change the orientation of your Activity\u002FFragment, remember that by default Android recreates Activities and Fragments when the orientation changes. Make sure that you manually handle orientation changes by adding the attribute `android:configChanges` to your Activity definition in the manifest.\n\n```xml\n\u003Capplication >\n  \u003Cactivity\n    android:configChanges=\"orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout\" \u002F>\n\u003C\u002Fapplication>\n```\n\n### Playlist\nYou can initialize the player to play playlists instead of videos. This can be done by setting `listType` to `playlist` and then providing the id of the playlist to `list`.\n\n```kotlin\nval iFramePlayerOptions = IFramePlayerOptions.Builder(context)\n  .controls(1)\n  .listType(\"playlist\")\n  .list(PLAYLIST_ID)\n  .build()\n```\n\n### Release the YouTubePlayerView\nRemember to release the `YouTubePlayerView` when you're done using it, by calling `YouTubePlayerView.release()`.\n\n```java\n@Override\npublic void onDestroy() {\n    super.onDestroy();\n    youTubePlayerView.release();\n}\n```\n\n**You don't need to manually release the player if you registered it as an observer of your Activity\u002FFragment's lifecycle.**\n\n### LifecycleObserver\n`YouTubePlayerView` implements the `LifecycleObserver` interface, this means that it is a lifecycle aware component.\n\nIf added as an observer of your Activity\u002FFragment's lifecycle, `YouTubePlayerView` will be smarter. **It is highly recommended that you register `YouTubePlayerView` as a `LifecycleObserver`.**\n\n```java\nlifecycleOwner.getLifecycle().addObserver(youTubePlayerView);\n```\nAdding `YouTubePlayerView` as an observer to a lifecycle will allow `YouTubePlayerView` to automatically pause the playback when the Activity\u002FFragment stops (not when it pauses, in order to support multi-window applications).\n\n\nIf you want your app to keep [playing when the Activity\u002FFragment is not visible](#play-youtube-videos-in-the-background) (remember that this behavior is not allowed, if you want to publish your app on the PlayStore), don't register the `YouTubePlayerView` as a lifecycle observer. But remember to manually call `release()` when the Activity\u002FFragment is being destroyed.\n\n## YouTubePlayer\n`YouTubePlayer` is the component responsible for controlling the playback of YouTube videos. You can see its contract [here](.\u002Fcore\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fpierfrancescosoffritti\u002Fandroidyoutubeplayer\u002Fcore\u002Fplayer\u002FYouTubePlayer.kt).\n\nEvery [`YouTubePlayerView`](#youtubeplayerview) contains a `YouTubePlayer`.\n\n### Get a reference to YouTubePlayer\nThere are two ways to get a reference to the `YouTubePlayer`, through the `YouTubePlayerView`.\n\n#### 1. YouTubePlayerView.getYouTubePlayerWhenReady\n`YouTubePlayerView.getYouTubePlayerWhenReady` can be used to get a reference to the `YouTubePlayer`. As the name of the method says, you'll only get the player when it is ready.\n\nTherefore this function takes a callback as argument, the callback will be called when the `YouTubePlayer` is ready.\n\n```java\nyouTubePlayerView.getYouTubePlayerWhenReady(youTubePlayer -> { \n  \u002F\u002F do stuff with it\n})\n```\n\n#### 2. YouTubePlayerListener\nEvery method of a [`YouTubePlayerListener`](#youtubeplayerlistener) has the `YouTubePlayer` as argument.\n\n### Load videos\nTo load a video you can use two methods.\n\n```java\nYouTubePlayer.loadVideo(String videoId, float startTime)\n```\nor\n```java\nYouTubePlayer.cueVideo(String videoId, float startTime)\n```\nThe difference between the two is that `loadVideo` loads and automatically plays the video, while `cueVideo` just loads video and thumbnail but doesn't autoplay.\n\n#### Utility for loading videos\nIf the Activity\u002FFragment is in the background, but you created a `YouTubePlayerListener` that calls `loadVideo` when `onReady` is called, the video will start playing even if the Activity is in the background.\n\nTo solve this problem you should use the `loadOrCueVideo` function.\n\nProvided as an utility function in Java.\n\n```java\nYouTubePlayerUtils.loadOrCueVideo(\n  youTubePlayer,\n  getLifecycle(),\n  videoId,\n  startTime\n);\n```\n\nAnd as an extension function in Kotlin.\n\n```kotlin\nyouTubePlayer.loadOrCueVideo(lifeCycle, videoId, startTime)\n```\n\nThis function will call `loadVideo` only if the Activity is resumed, otherwise it will call `cueVideo`, so that the video starts loading but not playing.\n\n### Events\nDuring its existence the player will constantly emit events, you can easily listen to all of them by adding a [`YouTubePlayerListener`](#youtubeplayerlistener) to it.\n\n### Get state from the player\nThe IFrame API exposes methods like `isMute` that can be used to read the current state of the player.\n\nThese are exposed in the `YouTubePlayer` interface as async calls. They are async becasue in order to get them, the JVM player needs to send a requesto to the IFrame player inside the Webview.\n\nThese methods are exposed with the `async` suffix in the `YouTubePlayer`. Suspending extension functions are available to simplify usage from Kotlin.\n\n```kotlin\nfun isMutedAsync(callback: BooleanProvider)\nsuspend fun isMuted(): Boolean\n```\n\n### YouTubePlayerTracker\n`YouTubePlayerTracker` is an utility provided by the library to easily keep track of a `YouTubePlayer`'s state and other information.\n\n`YouTubePlayerTracker` is a [`YouTubePlayerListener`](#youtubeplayerlistener), therefore in order to use it you need to add it as a listener to the `YouTubePlayer`.\n\nYou can then use the tracker to get the player's state and various information about the video that is being played.\n\n```java\nYouTubePlayerTracker tracker = new YouTubePlayerTracker();\nyouTubePlayer.addListener(tracker);\n\ntracker.getState();\ntracker.getCurrentSecond();\ntracker.getVideoDuration();\ntracker.getVideoId();\n```\n\n## YouTubePlayerListener\nA `YouTubePlayerListener` is used to intercept events emitted by a [`YouTubePlayer`](#youtubeplayer).\n\nDuring its existence a `YouTubePlayer` will constantly emit events, you can listen to them by adding a `YouTubePlayerListener` to it.\n\n```java\nyouTubePlayer.addListener(YouTubePlayerListener listener);\nyouTubePlayer.removeListener(YouTubePlayerListener listener);\n```\nThese are the method that a `YouTubePlayerListener` must implement, every method takes a reference to the `YouTubePlayer` and some other arguments.\n\n```java\n\u002F\u002F Called when the player is ready to play videos.\n\u002F\u002F You should start using the player only after this method is called.\nvoid onReady(@NonNull YouTubePlayer youTubePlayer)\n\n\u002F\u002F Called every time the state of the player changes.\nvoid onStateChange(@NonNull YouTubePlayer youTubePlayer, @NonNull PlayerConstants.PlayerState state)\n\n\u002F\u002F Called every time the quality of the playback changes.\nvoid onPlaybackQualityChange(@NonNull YouTubePlayer youTubePlayer, @NonNull PlayerConstants.PlaybackQuality playbackQuality)\n\n\u002F\u002F Called every time the speed of the playback changes.\nvoid onPlaybackRateChange(@NonNull YouTubePlayer youTubePlayer, @NonNull PlayerConstants.PlaybackRate playbackRate)\n\n\u002F\u002F Called when an error occurs in the player.\nvoid onError(@NonNull YouTubePlayer youTubePlayer, @NonNull PlayerConstants.PlayerError error)\n\n\u002F\u002F Called periodically by the player, the argument is the number of seconds that have been played.\nvoid onCurrentSecond(@NonNull YouTubePlayer youTubePlayer, float second)\n\n\u002F\u002F Called when the total duration of the video is loaded.\n\u002F\u002F Note that getDuration() will return 0 until the video's metadata is loaded, which normally happens just after the video starts playing.\nvoid onVideoDuration(@NonNull YouTubePlayer youTubePlayer, float duration)\n\n\u002F\u002F Called periodically by the player, the argument is the percentage of the video that has been buffered.\nvoid onVideoLoadedFraction(@NonNull YouTubePlayer youTubePlayer, float loadedFraction)\n\n\u002F\u002F Called when the id of the current video is loaded\nvoid onVideoId(@NonNull YouTubePlayer youTubePlayer, String videoId)\n\nvoid onApiChange(@NonNull YouTubePlayer youTubePlayer)\n```\n\nIf you don't want to implement all the methods of this interface, you can extend `AbstractYouTubePlayerListener` instead of implementing `YouTubePlayerListener` and override only the methods you are interested in.\n\nFor more information on the methods defined in the `YouTubePlayerListener` interface, please refer to the documentation defined above each method [in the codebase](.\u002Fcore\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fpierfrancescosoffritti\u002Fandroidyoutubeplayer\u002Fcore\u002Fplayer\u002Flisteners\u002FYouTubePlayerListener.kt).\n\n### onReady callback\nThe onReady callback of a `YouTubePlayerListener` is called once, when the `YouTubePlayer` is ready to be used for the first time. **You can't use a `YouTubePlayer` before it is ready**.\n\n### onStateChanged callback\nThe `YouTubePlayer` has a state, that changes accordingly to the playback changes. The [list of possible states](.\u002Fcore\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fpierfrancescosoffritti\u002Fandroidyoutubeplayer\u002Fcore\u002Fplayer\u002FPlayerConstants.kt) is the same of the YouTube [IFrame Player API](https:\u002F\u002Fdevelopers.google.com\u002Fyoutube\u002Fiframe_api_reference#Playback_status).\n\n```\nUNKNOWN\nUNSTARTED\nENDED\nPLAYING\nPAUSED\nBUFFERING\nVIDEO_CUED\n```\n\n## Create your own custom UI\nCustomization is an important aspect of this library. If need to, you can completely replace the default UI of the player.\n\n`YouTubePlayerView` has methods for that. \n\n```java\nView inflateCustomPlayerUi(@LayoutRes int customUiLayoutID)\nvoid setCustomPlayerUi(View view)\n```\n\nThis method takes in the `id` of a layout resource, which is a regular XML file containing the definition of a layout, or a `View`. \n\nThe new UI will be overlayed over the player.\nFor this reason it is recommended to disable the UI of the IFrame player, by initializing the `YouTubePlayerView` with `IFramePlayerOptions`.\n\n```java\n\u002F\u002F disable web ui\nIFramePlayerOptions options = new IFramePlayerOptions.Builder(context).controls(0).build();\nyouTubePlayerView.initialize(listener, options);\n```\n\nYou are responsible for managing your custom UI with your own code. Meaning: you should write your own class to manage the UI. A simple but complete example can be seen [here, in the sample app](.\u002Fcore-sample-app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fpierfrancescosoffritti\u002Fandroidyoutubeplayer\u002Fcore\u002Fsampleapp\u002Fexamples\u002FcustomUiExample), I recommend taking a few minutes to read it, it should be trivial to understand.\n\nExample (taken from sample app):\n\n```java\nView customPlayerUi = youTubePlayerView.inflateCustomPlayerUi(R.layout.custom_player_ui);\n\nYouTubePlayerListener listener = new AbstractYouTubePlayerListener() {\n\n  @Override\n  public void onReady(@NonNull YouTubePlayer youTubePlayer) {\n    CustomPlayerUiController customPlayerUiController = new CustomPlayerUiController(CustomUiActivity.this, customPlayerUi, youTubePlayer, youTubePlayerView);\n    youTubePlayer.addListener(customPlayerUiController);\n\n    YouTubePlayerUtils.loadOrCueVideo(\n      youTubePlayer, getLifecycle(),\n      VideoIdsProvider.getNextVideoId(),0f\n    );\n  }\n};\n\n\u002F\u002F disable iframe ui\nIFramePlayerOptions options = new IFramePlayerOptions.Builder(context).controls(0).build();\nyouTubePlayerView.initialize(listener, options);\n```\nA blog post going deeper on this is available [at this link](https:\u002F\u002Fmedium.com\u002F@soffritti.pierfrancesco\u002Fcustomize-android-youtube-players-ui-9f32da9e8505).\n\n*Example of a custom UI: (this is just a ugly example, but here your design skills are the limit :))*\n\n![custom ui example](.\u002Fimages\u002Fcustom_ui_screenshot.jpg)\n\nWarning: when replacing the IFrame UI, be carfeul not to break YouTube's terms of service. Altering the player look and feel might be an issue if you intend to publish your app on the PlayStore.\n\n### DefaultPlayerUiController\n`DefaultPlayerUiController` is a pre-made ready-to-use custom UI. \n\nStarting from version 12.0.0 of the library, this UI is available as a separate module that needs to be used in conjunction with the `core` module. To import the library add this to the dependencies in your `gradle.build` file:\n\n```gradle\ndependencies {\n  implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:core:{latest-version}'\n  implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:custom-ui:{latest-version}'\n}\n```\n\nAfter importing the dependency, you can use it like this:\n\n```java\nYouTubePlayerListener listener = new AbstractYouTubePlayerListener() {\n  @Override\n  public void onReady(@NonNull YouTubePlayer youTubePlayer) {\n    \u002F\u002F using pre-made custom ui\n    DefaultPlayerUiController defaultPlayerUiController = new DefaultPlayerUiController(youTubePlayerView, youTubePlayer);\n    youTubePlayerView.setCustomPlayerUi(defaultPlayerUiController.getRootView());\n  }\n};\n\n\u002F\u002F disable iframe ui\nIFramePlayerOptions options = new IFramePlayerOptions.Builder(context).controls(0).build();\nyouTubePlayerView.initialize(listener, options);\n```\n\nThe UI will look something like this.\n\n![YouTubePlayerSeekBar](.\u002Fimages\u002Fchromecast_screenshot.jpg)\n\nYou can use the `DefaultPlayerUiController` to hide views, add new view etc.\n\n#### Menu\n`DefaultPlayerUiController` has an optional menu. You can use these methods to control the menu's behavior:\n\n``` java\nPlayerUiController.showMenuButton(boolean show);\nPlayerUiController.setMenuButtonClickListener(@NonNull View.OnClickListener customMenuButtonClickListener);\n```\n\nBy default the menu icon is not visible. \n\nThe default `OnClickListener` opens the menu when the menu icon is clicked. You can change this behavior, for example to open a menu with a different UX, like a bottom sheet panel. Obviously if you want a UX different from the one provided by the library, you are responsible for creating your own components.\n\n*Menu screenshot:*\n\n![menu screenshot](.\u002Fimages\u002Fmenu_screenshot.jpg)\n\n##### YouTubePlayerMenu\nYou can get a reference of the `YouTubePlayerMenu` from the `PlayerUiController`.\n```java\nYouTubePlayerMenu PlayerUiController.getMenu()\n```\nOnce you get a `YouTubePlayerMenu` object you can add and remove items to it, show it and dismiss it.\n\n```java\nYouTubePlayerMenu addItem(MenuItem menuItem)\nYouTubePlayerMenu removeItem(MenuItem menuItem)\nYouTubePlayerMenu removeItem(int itemIndex)\n\nvoid show(View anchorView)\nvoid dismiss()\n```\n\nInitially the `YouTubePlayerMenu` doesn't contain any item. You need to add them.\n\n##### MenuItem\n`MenuItem`s are the items of the `YouTubePlayerMenu`. They have a title, an optional icon and a `OnClickListener` that is called when the item is clicked.\n\n### Reusable UI components\nThe library provides some pre-built UI components, these components are useful to reduce the time needed to build your own UI and controllers.\n\nStarting from version 12.0.0, these components exist in the `custom-ui` module. So you need to add it to your app's dependencies in order to use them.\n\n#### YouTubePlayerSeekBar\nThis component is useful to display and control the time of the playback. It shows the current time, the total duration of the video and a seek bar.\n\n![YouTubePlayerSeekBar](.\u002Fimages\u002FYouTubePlayerSeekBar.jpg)\n\nYou can add it to your layout programmatically or in your xml.\n\n```xml\n\u003Ccom.pierfrancescosoffritti.androidyoutubeplayer.core.customui.views.YouTubePlayerSeekBar\n  android:id=\"@+id\u002Fyoutube_player_seekbar\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"wrap_content\"\n\n  app:fontSize=\"12sp\"\n  app:color=\"@color\u002Fred\" \u002F>\n```\nIt is possible to change font size and color by using the `fontSize` and `color` attributes.\n\n`YouTubePlayerSeekBar` implements `YouTubePlayerListener`. In order for it to work you need to add it as a listener to your `YouTubePlayer` object.\n\n```java\nyouTubePlayer.addListener(youTubePlayerSeekBar);\n```\n\nYou may want to listen to events from `YouTubePlayerSeekBar`, in order to update the current time of your `YouTubePlayer` when the user moves the touch bar. To do that pass a `YouTubePlayerSeekBarListener` to `YouTubePlayerSeekBar`.\n\n```java\nyouTubePlayerSeekBar.setYoutubePlayerSeekBarListener(new YouTubePlayerSeekBarListener() {\n  @Override\n  public void seekTo(float time) {\n    youTubePlayer.seekTo(time);\n  }\n});\n```\n\n#### FadeViewHelper\nAn helper class that automatically fades out a view when not used. It can be used to automate the fade in and out of a container for the player controls, so that they automatically fade when appropriate.\n\nThe `FadingFrameLayout` is a `YouTubePlayerListener` therefore it can change it's behavior based on the state of the player. For example: if the video is paused it won't automatically fade out.\n\nYou can initialize it by passing to the constructor the view you want to be fading.\n\n```java\nFadeViewHelper fadeViewHelper = new FadeViewHelper(controlsContainer);\n```\n\nIt is possible to change the animation duration and fade out delay by using the setter methods.\n\n```java\nfadeViewHelper.setAnimationDuration(FadeViewHelper.DEFAULT_ANIMATION_DURATION);\nfadeViewHelper.setFadeOutDelay(FadeViewHelper.DEFAULT_FADE_OUT_DELAY);\n```\nThey both take the time in milliseconds.\n\nIn order for `FadeViewHelper` to work properly you need to add it as a listener to your `YouTubePlayer` object.\n\n```java\nyouTubePlayer.addListener(fadeViewHelper);\n```\nUse the method `FadeViewHelper.setDisabled(boolean)` to disable the automatic fading.\n\nUse the method `FadeViewHelper.toggleVisibility()` to toggle the visibility of the target view, with a fade animation.\n\n#### TimeUtilities\nA set of utilities than can be used to format time Strings (like duration and current time of videos).\n\n```java\nString TimeUtilities.formatTime(float timeInSeconds)\n```\nTakes in the time in seconds and returns a String with the time formatted as \"M:SS\". (M = minutes, S = seconds).\n\n## Network events\n[`YouTubePlayerView`](#youtubeplayerview) automatically handles network events, using an internal BroadcastReceiver. You can choose to enable or disable this feature [when initializing the player](#initialization), or by setting the xml attribute `app:handleNetworkEvents=\"false\"`.\n\nUsing the internal BroadcastReceiver is the easiest and recommended way to handle network events. The library is capable of handling cases in which the connection goes off and the playback can't continue, or cases in which the connection goes off while the player is in the process of initialization.\n\nIf you want to use your own BroadcastReceiver make sure to cover all the possible scenarios, in order to provide a good user experience.\n\n## Chromecast support\nIf you need to cast YouTube videos to a Chromecast device you can use the *chromecast-sender* extension library. Read its documentation [here](#chromecast-extension-library).\n\n## Useful info\n### Hardware acceleration\nIs important that the Activity containing the [YouTubePlayerView](#youtubeplayerview) is hardware accelerated. This option is enabled by default, you don't have to change anything in your app. Unless you manually disabled hardware acceleration.\n\nIf you need to disable hardware acceleration in your application, you can enable it at the Activity level, only for the Activity containing the `YouTubePlayerView`, as explained [here](https:\u002F\u002Fdeveloper.android.com\u002Fguide\u002Ftopics\u002Fgraphics\u002Fhardware-accel.html).\n\nDisabling hardware acceleration on the Activity containing `YouTubePlayerView` may result in some weird behavior. The one I have observed so far shows a black image in the player, while the audio is playing normally.\n\n### Play YouTube videos in the background\nWith this library it's easy to play YouTube videos when the app is not visible. In order to do that you simply have to not call `youTubePlayer.pause()` when the Activity is being paused or stopped and enable background playback by calling `YouTubePlayerView.enableBackgroundPlayback(true)`.\n\nAdding `YouTubePlayerView` as an [observer to a lifecycle](#lifecycleobserver) will automatically cause the player to pause the playback when the Activity\u002FFragment stops.\n\nTherefore if you want your app to keep playing even when the Activity\u002FFragment is paused\u002Fstopped, don't register it as a lifecycle observer and enable background playback for the view. But remember to manually call `YouTubePlayerView.release()` when the Activity\u002FFragment is destroyed.\n\nRemember that this behavior is against [YouTube terms of service](https:\u002F\u002Fdevelopers.google.com\u002Fyoutube\u002Fterms\u002Fapi-services-terms-of-service), therefore if you decide to allow background playback you won't be able to publish your app on the Play Store.\n\nUse this functionality only if you plan to build the app for personal use or if you plan to distribute it through different channels.\n\n### minSdk\nThe minSdk of the library is 21. [At this point in time](https:\u002F\u002Fdeveloper.android.com\u002Fabout\u002Fdashboards\u002Findex.html) it doesn't make much sense for new apps to support older versions of Android.\n\n---\n\n# Chromecast extension library\n\n\u003Cimg align=\"right\" width=\"180px\" src=\".\u002Fimages\u002Fchromecast-youtube-player-icon_512x512.png\" title=\"chromecast-youtube-player logo\" \u002F>\n\nThe *chromecast-sender* extension library extends the *core* library with chromecast functionalities. It shares some interfaces with the *core* library, therefore they can be used together.\n\nThe scope of this library is to provide the basic framework and utilities needed to cast YouTube videos to a Chromecast device.\n\n**The api of this library is not 100% finalized yet, but is stable. You can use it in your apps.**\n\n# Quick start - Chromecast\nA Google Cast application is made of two components: a Sender and a Receiver.\n\n* [Sender](#sender): is responsible for initiating the cast sessions. In our case the sender is an Android app.\n* [Receiver](#receiver): a web app that gets downloaded on the Chromecast when a sender initiates a cast sessions.\n\n### Download extra dependencies\nTo use Google Cast functionalities add the *chromecast-sender* module to your dependencies:\n\n[last-version](#download).\n\n```\nimplementation 'com.pierfrancescosoffritti.androidyoutubeplayer:chromecast-sender:last-version'\n\n\u002F\u002F this is not needed to use the library, but it provides the quite useful cast button.\nimplementation 'androidx.mediarouter:mediarouter:last-version'\n```\n\n### Sender\nIn order to use the Google Cast framework an app has to declare a `OptionsProvider`, as described in the [Google Cast documentation](https:\u002F\u002Fdevelopers.google.com\u002Fcast\u002Fdocs\u002Fandroid_sender_integrate#initialize_the_cast_context).\n\nAdd this class to your project:\n```java\npublic final class CastOptionsProvider implements com.google.android.gms.cast.framework.OptionsProvider {\n  public com.google.android.gms.cast.framework.CastOptions getCastOptions(Context appContext) {\n\n  \u002F\u002F Register you custom receiver on the Google Cast SDK Developer Console to get this ID.\n  String receiverId = \"\";\n\n  return new com.google.android.gms.cast.framework.CastOptions.Builder()\n    .setReceiverApplicationId(receiverId)\n    .build();\n  }\n\n  public List\u003CSessionProvider> getAdditionalSessionProviders(Context context) {\n    return null;\n  }\n}\n```\nYou can read how to get a `receiverId` [here](#registration).\n\nAdd the `OptionsProvider` to your `manifest.xml` file.\n\n*(`OPTIONS_PROVIDER_CLASS_NAME` is meant to be like that, change only the `android:value` attribute)*\n```xml\n\u003Cmeta-data\n  android:name=\"com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME\"\n  android:value=\"yourpackagename.CastOptionsProvider\" \u002F>\n```\n\nAdd a MediaRouterButton to your layout, in your xml file or programmatically.\n```xml\n\u003CLinearLayout\n  xmlns:android=\"http:\u002F\u002Fschemas.android.com\u002Fapk\u002Fres\u002Fandroid\"\n  android:id=\"@+id\u002Froot\"\n  android:layout_width=\"match_parent\"\n  android:layout_height=\"match_parent\"\n  android:orientation=\"vertical\" >\n\n  \u003Candroidx.mediarouter.app.MediaRouteButton\n    android:id=\"@+id\u002Fmedia_route_button\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\" \u002F>\n\u003C\u002FLinearLayout>\n```\n\nThen in your Activity\u002FFragment get a reference to the `MediaRouteButton` and check the status of the GooglePlayServices on the user's phone.\n```java\nprivate int googlePlayServicesAvailabilityRequestCode = 1;\n\n@Override\nprotected void onCreate(Bundle savedInstanceState) {\n  super.onCreate(savedInstanceState);\n  setContentView(R.layout.activity_main);\n\n  androidx.mediarouter.app.MediaRouteButton mediaRouteButton = findViewById(R.id.media_route_button);\n  CastButtonFactory.setUpMediaRouteButton(this, mediaRouteButton);\n\n  \u002F\u002F can't use CastContext until I'm sure the user has GooglePlayServices\n  PlayServicesUtils.checkGooglePlayServicesAvailability(this, googlePlayServicesAvailabilityRequestCode, this::initChromecast);\n}\n\n@Override\npublic void onActivityResult(int requestCode, int resultCode, Intent data) {\n  super.onActivityResult(requestCode, resultCode, data);\n\n  \u002F\u002F can't use CastContext until I'm sure the user has GooglePlayServices\n  if(requestCode == googlePlayServicesAvailabilityRequestCode)\n    PlayServicesUtils.checkGooglePlayServicesAvailability(this, googlePlayServicesAvailabilityRequestCode, this::initChromecast);\n}\n\nprivate void initChromecast() {\n  new ChromecastYouTubePlayerContext(\n    CastContext.getSharedInstance(this).getSessionManager(),\n    new SimpleChromecastConnectionListener()\n  );\n}\n\n```\nYou can easily check the GooglePlayServices status by using `PlayServicesUtils.checkGooglePlayServicesAvailability`, a utility function provided by the *chromecast-sender* library.\n\n`PlayServicesUtils.checkGooglePlayServicesAvailability` does what is described [here, in the official doc](https:\u002F\u002Fdevelopers.google.com\u002Fandroid\u002Fguides\u002Fsetup#ensure_devices_have_the_google_play_services_apk). It will check the status of GooglePlayServices and will show a dialog to the user if some action is needed in order to fix the problem. It won't display anything if everything is ok (which it is, 99% of the cases), in this case it will simply call the function passed as third parameter.\nIf there are some problems, the result of the operation is delivered through the `onActivityResult` callback.\n\nOnce you're sure the user's GooglePlayServices is all right, you can create the `ChromecastYouTubePlayerContext`. The access point to the *chromecast-sender* library.\n\n`ChromecastYouTubePlayerContext` is the entry point to the *chromecast-sender* library. Once it is created, it automatically starts listening for Chromecast connection events. The `ChromecastConnectionListener` passed to the constructor will be used to do just that.\n\nWhen a user clicks the `MediaRouteButton` a series of events will be triggered in the framework, use `ChromecastConnectionListener`'s callbacks to be notified of these events.\n\n```java\nprivate class SimpleChromecastConnectionListener implements ChromecastConnectionListener {\n\n  @Override\n  public void onChromecastConnecting() {\n    Log.d(getClass().getSimpleName(), \"onChromecastConnecting\");\n  }\n\n  @Override\n  public void onChromecastConnected(@NonNull ChromecastYouTubePlayerContext chromecastYouTubePlayerContext) {\n    Log.d(getClass().getSimpleName(), \"onChromecastConnected\");\n    initializeCastPlayer(chromecastYouTubePlayerContext);\n  }\n\n  @Override\n  public void onChromecastDisconnected() {\n    Log.d(getClass().getSimpleName(), \"onChromecastDisconnected\");\n  }\n\n  private void initializeCastPlayer(ChromecastYouTubePlayerContext chromecastYouTubePlayerContext) {\n    chromecastYouTubePlayerContext.initialize(new AbstractYouTubePlayerListener() {\n      @Override\n      public void onReady(@NonNull YouTubePlayer youTubePlayer) {\n        youTubePlayer.loadVideo(\"S0Q4gqBUs7c\", 0f);\n      }\n    });\n  }\n}\n```\n\nOnly after a Chromecast connection has been established you can initialize the `ChromecastConnectionListener`.\n\nFrom now on it will be the same as using a local `YouTubePlayer`. As you can see in the example, you need to call `ChromecastYouTubePlayerContext.initialize`, providing a `YouTubePlayerListener`.\n\nThe `YouTubePlayerListener` will notify you of changes in the playback.\nYou can call `loadVideo`, `cueVideo`, `pause`, `play` etc.. on the `YouTubePlayer` object as you're used to, the library will take care of the communication with the Google Cast device.\n\nFor how to use the `YouTubePlayer` object and `YouTubePlayerListener`, you can refer to the documentation for the *core* library, [YouTubePlayer](#youtubeplayer).\n\nThis example can be found [in the chromecast-sender sample app](.\u002Fchromecast-sender-sample-app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fpierfrancescosoffritti\u002Fandroidyoutubeplayer\u002Fchromecast\u002Fsampleapp\u002Fexamples\u002FbasicExample\u002FBasicExampleActivity.kt), written in Kotlin and in the [core sample app](.\u002Fcore-sample-app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fpierfrancescosoffritti\u002Fandroidyoutubeplayer\u002Fcore\u002Fsampleapp\u002Fexamples\u002FchromecastExample\u002F), written in Java.\n\n*Screenshot of the CastButton added to the YouTubePlayerView:*\n\n![chromecast button screenshot](.\u002Fimages\u002Fchromecast_screenshot.jpg)\n\n### Receiver\nThis library requires a custom receiver, you can find the source code of the *chromecast-receiver* [here](.\u002Fchromecast-receiver).\n\nYou don't need to change anything here, it just works.\nTake this code and upload it (as it is) on your server. (Read the [hosting paragraph](#hosting-the-chromecast-receiver) to learn more about hosting).\n\n### Registration\nIn order to use your receiver you need a receiverId. This is the ID of your receiver app. To get a receiver ID you need to register your receiver on the Google Cast SDK developer console, you can learn how to do it by reading the [official documentation](https:\u002F\u002Fdevelopers.google.com\u002Fcast\u002Fdocs\u002Fregistration). Remember to register a **Custom Receiver**, this is the type of receiver you need for this library.\n\n### Hosting the chromecast-receiver\nYou will be required to host your receiver somewhere, host it where you prefer. Firebase free hosting may be a good option, for development.\n\n# Workarounds\nThe following sections provides unofficial workarounds that can't be implemented in the library because they might break at anytime. To use them you will need to create your own fork of the library. Use them at your own peril. Using any of these workarounds might break YouTube terms of service.\n\nThese workaround have been provided by the community of users of this library. Thanks to @Serkali-sudo for the help!\n\n## Change Video Quality\nThe IFrame Player API currently doesn't support changing the video quality on modile devices, but we can do it indirectly.\n\nThe IFrame player keeps the quality value in a window interface called [localStorage](https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FWindow\u002FlocalStorage). We can access it and change it from there.\n\nIn order to access the player's `localStorage`, you need to turn on the `domStorageEnabled` setting in the webview.\n\nGo to `WebViewYouTubePlayer#initWebView` and add this line to enable `domStorage`:\n\n```kt\n settings.domStorageEnabled = true\n```\n\nAdd these functions to `ayp_youtube_player.html`:\n\n\n```js\n\u002F\u002F Return the available quality options for the current video.\n\u002F\u002F Not all videos have the same quality options, so we need to check what's available first. \n\u002F\u002F this function will return an array like: [\"hd1080\",\"hd720\",\"large\",\"medium\",\"small\",\"tiny\",\"auto\"]\nfunction sendVideoQuality(player) {\n    YouTubePlayerBridge.sendVideoQuality(JSON.stringify(player.getAvailableQualityLevels()))\n}\n\nfunction setPlaybackQuality(playbackQuality) {\n  if (playbackQuality == \"auto\") {\n    localStorage.removeItem(\"yt-player-quality\");\n  } else {\n    var now = Date.now();\n    \u002F\u002F this will set `playbackQuality` as the selected video quality, untile it expires\n    localStorage.setItem(\"yt-player-quality\", JSON.stringify({\n      data: playbackQuality,\n      creation: now,\n      expiration: now + 2419200000\n    }));\n  }\n\n  \u002F\u002F after changing the quality you need to reload the video to see changes.\n  \u002F\u002F reload the video and start playing where it was.\n  if (player) {\n    var currentTime = player.getCurrentTime();\n    player.loadVideoById(player.getVideoData().video_id, currentTime);\n  }\n}\n```\n\nTo receive events from the webview, add this to `YouTubePlayerBridge.kt`:\n\n```kt\n@JavascriptInterface\nfun sendVideoQuality(quality: String) {\n  mainThreadHandler.post {\n    for(listener in youTubePlayerOwner.getListeners()) {\n      \u002F\u002F also add this new method to the listener interface\n      listener.onVideoQuality(youTubePlayerOwner.getInstance(), quality)\n    }\n  }\n}\n```\n\nAdd this to the `YoutubePlayer` interface:\n\n```kt\nfun setPlaybackQuality(quality: String)\n```\n\nAnd implement it in `WebViewYouTubePlayer.kt`\n\n```kt\noverride fun setPlaybackQuality(quality: String) {\n  mainThreadHandler.post { loadUrl(\"javascript:setPlaybackQuality('$quality')\") }\n}\n```\n\nNow you should be able to change the quality of your videos :)\n\nGet all the available qualities using `YouTubePlayerListener#onVideoQuality` and set the player's quality using `youtubePlayer#setPlaybackQuality`.\n\n## Login to YouTube account\n\nBy logging in you will be able to play private videos from the user.\n\nThe idea here is to create a `WebView` and use it to authentucate with YouTube. The results of the authentication will be shared with the `WebView` containing the YouTube player.\n\n```java\nprivate void log_in() {\n  WebView webView = new WebView(context);\n  webView.getSettings().setJavaScriptEnabled(true);\n  webView.getSettings().setDomStorageEnabled(true);\n  webView.getSettings().setSavePassword(true);\n  webView.getSettings().setSaveFormData(true);\n  webView.loadUrl(\"https:\u002F\u002Faccounts.google.com\u002FServiceLogin?service=youtube&uilel=3&passive=true&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Faction_handle_signin%3Dtrue%26app%3Dm%26hl%3Dtr%26next%3Dhttps%253A%252F%252Fm.youtube.com%252F\");\n  webView.setWebViewClient(new WebViewClient() {\n    @Override\n    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {\n      \u002F\u002Fif webview redirects to youtube.com it means we're logged in\n      if (\n        request.getUrl().toString().startsWith(\"https:\u002F\u002Fm.youtube.com\") ||\n        request.getUrl().toString().startsWith(\"https:\u002F\u002Fwww.youtube.com\")\n      ) {\n        Log.d(TAG, \"Logged in\");\n        Toast.makeText(MainActivity.this, \"Logged in\", Toast.LENGTH_SHORT).show();\n        return false;\n      }\n      return false;\n    }\n  });\n}\n```\n\nIn `WebViewYouTubePlayer#initWebView` add this code to enable dom storage, to avoid being logged out constantly:\n\n```kt\n settings.domStorageEnabled = true\n```\n\n## Block Ads\n\nThis workaround searches for the `video-ads` element in the webview by running a query selector every 100 milliseconds. When it finds a `video-ads` element, first mutes it, then subtracts the duration of the ad from the duration of the main video and unmutes it again.\n\nAdd this function to `ayp_youtube_player.html` and call it from `sendPlayerStateChange`:\n\n```js\nlet adblockIntervalId;\n\nfunction initializeAdBlock() {\n  if (adblockIntervalId) {\n    clearInterval(adblockIntervalId);\n  }\n\n  const playerIFrame = document.querySelector(\"iframe\");\n  if (playerIFrame) {\n    adblockIntervalId = setInterval(() => {\n      if (!playerIFrame) {\n        return;\n      }\n\n      const frameDoc = playerIFrame.contentDocument;\n      if (!frameDoc) {\n        return;\n      }\n\n\n      const adsContainer = frameDoc.querySelector('.video-ads');\n      if (!adsContainer || adsContainer.childElementCount == 0) {\n        return;\n      }\n\n      const adsVideo = adsContainer.querySelector(\"video\");\n\n      if (adsVideo) {\n        adsVideo.muted = true;\n        adsVideo.style.display = 'none';\n        adsVideo.currentTime = adsVideo.duration - 0.15;\n        adsVideo.muted = false;\n        adsVideo.style.display = '';\n        if (adblockIntervalId) {\n          clearInterval(adblockIntervalId);\n        }\n      }\n      else {\n        const isAdShowing = frameDoc.getElementsByClassName('ad-showing').length != 0;\n        if (!isAdShowing) {\n          return;\n        }\n\n        const mainVideo = frameDoc.querySelector('.html5-main-video');\n        if (!mainVideo) {\n          return;\n        }\n\n        mainVideo.muted = true;\n        mainVideo.currentTime = mainVideo.duration - 0.15;\n        mainVideo.muted = false;\n        if (adblockIntervalId) {\n          clearInterval(adblockIntervalId);\n        }\n      }\n    }, 100);\n  }\n}\n```\n\n## Remove Annoying Views\n\nThis workaround provides ways to remove annoying views from the player that can't be removed with official APIs.\n\n### Hide Title\n\nHide title and channel picture at once\n\nAdd this to `ayp_youtube_player.html`, and call it inside `onReady`.\n\n```js\nfunction hideVideoTitle() {\n  setInterval(() => {\n    const playerIFrame = document.querySelector(\"iframe\");\n    if (!playerIFrame) {\n      return;\n    }\n    \n    const frameDoc = playerIFrame.contentDocument;\n    if (!frameDoc) {\n      return;\n    }\n\n    const title = frameDoc.querySelector('.ytp-chrome-top');\n    if (title) {\n      title.style.display = 'none';\n    }\n  }, 100);\n}\n```\n\n### Hide 'More Videos' section that covers most of the video when paused (Only visible on tablets and bigger screens)\n\nAdd this to `ayp_youtube_player.html`, and call it inside `onReady`.\n\n```js\nfunction hideTabletPopup() {\n  setInterval(() => {\n    const playerIFrame = document.querySelector(\"iframe\");\n    if (!playerIFrame) {\n      return;\n    }\n\n    const frameDoc = playerIFrame.contentDocument;\n    if (!frameDoc) {\n      return;\n    }\n\n    const collection = frameDoc.getElementsByClassName(\"ytp-pause-overlay-container\")[0];\n    if (!collection) {\n      return;\n    }\n    collection.style.display = 'none';\n  }, 100);\n}\n```\n## Hide Captions\n\nAdd this to `ayp_youtube_player.html`, and call it inside `onReady`.\n\n```js\nfunction hideCaption() {\n  setInterval(() => {\n    if(!player) {\n      return;\n    }\n    player.unloadModule('captions');\n  }, 1000);\n}\n```\n\nTo enable captions\n\n```js\nfunction hideCaption() {\n  if(!player) {\n    return;\n  }\n  player.loadModule('captions');\n}\n```\n\n## Play Next Recomended Video\n\nThis workaround gets the id from 'more videos' and plays it as a next video, you can think of it like the \"recomended\" section on YouTube. You can use it like auto-play on YouTube.\n\nIf the `rel` paramter is set to 0: the next video will come from the same channel as the video that was just played.\n\nIf the `rel` paramater is set to 1: the next video will be from related videos that come from multiple channels.\n\nAdd this to `ayp_youtube_player.html`, and call it inside `onReady`.\n\n```js\nfunction playNextVideo() {\n  const playerIFrame = document.querySelector(\"iframe\");\n  if (!playerIFrame) {\n    return;\n  }\n\n  const frameDoc = playerIFrame.contentDocument;\n  if (!frameDoc) {\n    return;\n  }\n\n  const nextVideo = frameDoc.querySelectorAll('.ytp-suggestions a')\n  if(!nextVideo){\n    return;\n  }\n\n  let videoId = nextVideo[0].href.split('v=')[1];\n  let ampersandIndex = videoId.indexOf('&');\n  if (ampersandIndex != -1) {\n  videoId = videoId.substring(0, ampersandIndex);\n  }\n  player.loadVideoById(videoId, 0);\n}\n```\n\nThen add this method to the `YouTubePlayer` interface:\n\n```kt\nfun playNextVideo()\n```\n\nAnd implement it in `WebViewYouTubePlayer`\n\n```kt\noverride fun playNextVideo() {\n  mainThreadHandler.post { loadUrl(\"javascript:playNextVideo()\") }\n}\n```\n\n---\n\nFor any question feel free to [open an issue on the GitHub repository](https:\u002F\u002Fgithub.com\u002FPierfrancescoSoffritti\u002Fandroid-youtube-player\u002Fissues).\n","android-youtube-player 是一个为 Android 和 Chromecast 设计的稳定且可自定义的 YouTube 播放器库。它通过封装 IFrame Player API 在 WebView 中运行，从而避免了违反 YouTube 服务条款的问题，并提供了一个简单的视图组件，可以轻松集成到任何 Activity 或 Fragment 中。此外，该库还支持 Chromecast 功能，允许用户将视频从应用投射到 Chromecast 设备上播放。由于 Google 官方的 YouTube Android Player API 已被弃用，此项目成为了众多 Android 应用中实现 YouTube 视频播放功能的主要选择之一，适用于需要嵌入 YouTube 内容的各种移动应用开发场景。",2,"2026-06-11 03:11:51","top_language"]