Funny Solution to play YouTubePlayerView on Customized Fragment

Bram Yeh
3 min readAug 10, 2018

--

Here is what we tried to add YouTubePlayerView programmatically into out customized fragment. However, we discard this solution because we dislike to use private APIs and … we afraid to violate Google and YouTube’s developer policy. I will suggest not to use this solution, but just read how to trace code inside 3rd party’s obscured source codes.

Why we need

An app has a fragment that wants to play YouTube videos, but it just wants the player view to be part of the fragment layout (maybe it needs displaying another messages on other spaces of the fragment.)

Generally, if we want to play YouTube video, you will download YouTube Android Player API and then use the YouTubePlayerView to play these streams. However, when using YouTubePlayerView, you have to make your activity extend YouTubeBaseActivity, or choose to use YouTubePlayerFragment.

That’s a problem because the app already based on FragmentActivity but cannot use YouTubePlayerFragment. So.. let’s try to find a tricky solution to work around.

Conclusion and Utils Sample

It’s a long story to trace codes, so the conclusion we’re going to share how to create YouTubePlayerView programmatically is given in the beginning.

Here it is the YouTubePlayerViewUtils, which is a compact tool to create YoutTubePlayerView:

The sample shows how we use the YouTubePlayerViewUtils to create YouTubePlayerView in the customized fragment:

Code Tracing

Here, let me introduce why this solution works. First, let’s go through the obfuscated codes of YouTube library (I just pick a part of the source codes so all the following codes are not completed.)

Inside YouTubePlayerView.class, there are 3 public constructors, however, all of them will verify the context is YouTubeBaseActivity or throw IllegalStateException. However, luckily, YouTubePlayerView has one package-privacy constructor which didn’t verify the type of activity.

YouTubePlayerView(Context var1, AttributeSet var2, int var3, YouTubePlayerView.b var4) { 
super((Context)ab.a(var1, “context cannot be null”), var2, var3);
this.c = (YouTubePlayerView.b)ab.a(var4, “listener cannot be null”);
....
}

We can create a class under package com.google.android.youtube.player in our project, and it can create the YouTubePlayerView with any kind of context (activity).

Let’s trace the codes deeper, try to get more details about why original context must be YouTubeBaseActivity and what’s the interaction between YouTubeBaseActivity, YouTubePlayerFragment and YouTubePlayerView.

We saw many similarities in both YouTubeBaseActivity and YouTubePlayerFragment: the lifecycle delegates into YouTubePlayerView.

public class YouTubeBaseActivity extends Activity {                               
private YouTubeBaseActivity.a a;

protected void onStart() {
super.onStart();
if (this.b != null) { this.b.a(); }
}
protected void onResume() {
super.onResume();
if (this.b != null) { this.b.b(); }
}
....
}

When we create YouTubePlayerView and add it into our customized fragment, we should handle the lifecycle delegates into YouTubePlayer which state, pause, stop the video streaming correctly.

Finally, we go to learn how YouTube sample project creates YouTubePlayerView and initializes it. If we use original YouTubePlayerFragment, these steps are

YouTubePlayerFragment youTubePlayerFragment = getFragmentManager().findFragmentById(R.id.youtube_fragment);youTubePlayerFragment.initialize(DeveloperKey.DEVELOPER_KEY, this);

And YouTubePlayerFragment’s initialize() will do

if (this.c != null && this.e != null) {
this.c.a(this.getActivity(), this, this.d, this.e, this.b);
}

Because this.c is YouTubePlayerView, and YouTubePlayerView’s instance method a() has 5 parameters, which are

final void a(final Activity var1, Provider var2, String var3, OnInitializedListener var4, Bundle var5) { ... }
  1. Activity
  2. Provider: Good luck again, YouTubePlayerView implements Provider
  3. String: this is YouTube Developer Key
  4. OnInitializedListener
  5. Bundle: the YoutubePlayerView’s player view state.

So the only problem now is how to offer Bundle to create YouTubePlayerView. Inside YouTubePlayerFragment, here is what it does in onSaveInstanceState(Bundle var1):

public void onSaveInstanceState(Bundle var1) {
super.onSaveInstanceState(var1);
Bundle var2 = this.c != null ? this.c.e() : this.b;
...
}

Again, this.c is YouTubePlayerView, and what it does is

final Bundle e() {
return this.e == null ? this.i : this.e.h();
}

this.e is library’s internal class which implements YouTubePlayer. And if there is no YouTubePlayer, try to use saved Bundle from previous state.

To create YouTubePlayerView, we will implement the listener, YouTubePlayer.OnInitializedListener, and it will offer the internal class instance which implements YouTubePlayer.

--

--

Bram Yeh
Bram Yeh

Written by Bram Yeh

Lead Android & iOS Mobile Engineer at Yahoo (Verizon Media) Taiwan https://www.linkedin.com/in/hanruyeh/

Responses (2)

Write a response