Looking for a Jetpack Compose YouTube Video Player wrapper dependency
Asked Answered
M

3

7

Intro

I'm new to Jetpack Compose and it is not that easy for me to understand or get everything correct on my first try.

That's why I love to have a look at other's open-source work to understand the topic a little bit better.

Problem

My current problem is that I must embed YouTube videos into my app. At first, I thought I use an embedded web view, but hey, I'm a native app dev, let's do it native!

But I stumbled a lot

  1. Is it true, that we as devs must use a local *.jar file from Google to embed the video player?
  2. Is it true, that there is no official Jetpack Compose component for that?
  3. Is it true, that there is no dependency our there which provides such functionality?
  4. Yes, I searched SO before I asked

That's why it would be awesome if someone of you could point me into the correct direction to make any progress with my tiny self-learning app.

Mirtamirth answered 15/8, 2022 at 14:48 Comment(0)
S
15

the simplest way is first just add this line in gradle file

"implementation" ("com.pierfrancescosoffritti.androidyoutubeplayer:core:11.1.0")
@Composable
fun YoutubeScreen(
    videoId: String,
    modifier: Modifier
) {
    val ctx = LocalContext.current
    AndroidView(factory = {
        var view = YouTubePlayerView(it)
        val fragment = view.addYouTubePlayerListener(
            object : AbstractYouTubePlayerListener() {
                override fun onReady(youTubePlayer: YouTubePlayer) {
                    super.onReady(youTubePlayer)
                    youTubePlayer.loadVideo(videoId, 0f)
                }
            }
        )
        view
    })
}
Silverside answered 3/2, 2023 at 0:40 Comment(2)
If anyone troubles with black and white screen while using this composable. Try it on a real device!Dellinger
is is support video youtube embed?Lidda
S
8

Here are the answers:

  1. As the official page says, yes you have to download a JAR.

  2. Yes and it's not necessary. You can use AndroidView composable function to wrap a YouTubePlayerFragment and play a video.

    But here you need to do a small-hack because the YouTubePlayerFragment does not extends from androidx.fragment.app.Fragment. Therefore, you'll need the following:

    2.1 Create an implementation of YoutubePlayerFragment which uses androidx. You can copy from this gist.

    2.2 Then, you can use it in your composable...

@Composable
fun YoutubeScreen() {
    val ctx = LocalContext.current
    AndroidView(factory = {
        val fm = (ctx as AppCompatActivity).supportFragmentManager
        val view = FragmentContainerView(it).apply {
            id = R.id.fragment_container_view_tag
        }
        val fragment = YouTubePlayerSupportFragmentXKt().apply {
            initialize("YoutubeApiKey",
                object : YouTubePlayer.OnInitializedListener {
                    override fun onInitializationFailure(
                        provider: YouTubePlayer.Provider,
                        result: YouTubeInitializationResult
                    ) {
                        Toast.makeText(
                            context,
                            "Error playing video",
                            Toast.LENGTH_SHORT
                        ).show()
                    }

                    override fun onInitializationSuccess(
                        provider: YouTubePlayer.Provider,
                        player: YouTubePlayer,
                        wasRestored: Boolean
                    ) {
                        if (!wasRestored) {
                            player.cueVideo("YoutubeVideoId")
                        }
                    }
                })
        }
        fm.commit {
            setReorderingAllowed(true)
            add(R.id.fragment_container_view_tag, fragment)
        }
        view
    })
}

For the commit function above, you will need this dependency:

implementation "androidx.fragment:fragment-ktx:$fragment_ktx_version"

Then add this in your AndroidManifest.xml

<queries>
    <intent>
        <action android:name="com.google.android.youtube.api.service.START" />
    </intent>
</queries>

I tested the code above and it worked, but maybe you need some more working to handle orientation changes.

  1. AFAIK and I mentioned in #1, no, there is not.

  2. It's not a question :)

Swarey answered 19/8, 2022 at 23:56 Comment(10)
Thanks for your help. I nearly got it working. I just have a problem that the fm aka there fragment manager does not know .commit and .add - I guess I have the wrong import statement.Mirtamirth
I forgot to add the fragment-ktx dependency. I edited the answer to include it.Swarey
Again thanks, now I have to check how to work with a ComponentActivity instead of a AppCombatActivity but it compiles! <3Mirtamirth
I think If I used replace the MainActivity's super class, I need another theming - app crashesMirtamirth
I pushed my sample in this repo. Please, take a look... github.com/nglauber/JetpackComposePlayground/blob/master/app/…Swarey
Awesome, if I will ever visit brasil, I will spend you one or two coffees. Nevertheless I cannot build your project due to "Android Studio not compatible". But that's not important. I guess I cannot use only a MD3 Theme file but also I have to set the values in the xml to get my styles back :)Mirtamirth
Never mind! A clean & rebuild fixed it! Sorry for your time!Mirtamirth
where do you define R.id.fragment_container_view_tag?Miscue
it is declared in the fragment library androidx.fragment:fragment-ktxSwarey
The official page says "This SDK is no longer supported or maintained by YouTube. It will be fully deprecated on or after May 1, 2023" there is an alternative for mobile Apps?Extracellular
T
2

You might use this library - https://github.com/IlyaPavlovskii/YouTubePlayer/

repositories {
    mavenCentral()
}

kotlin {
    sourceSets {
        commonMain {
            dependencies {
                implementation("io.github.ilyapavlovskii:youtubeplayer-compose:${latest_version}")
            }
        }
    }
}
val execCommand = mutableStateOf<YouTubeExecCommand?>(null)
YouTubePlayer(
    modifier = Modifier
        .fillMaxWidth()
        .height(300.dp),
    options = SimpleYouTubePlayerOptionsBuilder.builder {
        autoplay(true) // autoplay = true 
        controls(false).rel(false) // controls = false, rel = false
        ivLoadPolicy(false)
        ccLoadPolicy(false)
        fullscreen = true
    },
    execCommandState = execCommand,
    actionListener = { action ->
        when (action) {
            YouTubeEvent.Ready -> {
                execCommand.value = YouTubeExecCommand.LoadVideo(
                    videoId = YouTubeVideoId("ufKj1sBrC4Q"),
                )
            }

            is YouTubeEvent.VideoDuration -> {
                videoDuration = formatTime(action.duration)
            }

            is YouTubeEvent.TimeChanged -> {
                currentTime = formatTime(action.time)
            }

            is YouTubeEvent.OnVideoIdHandled,
            is YouTubeEvent.Error,
            is YouTubeEvent.PlaybackQualityChange,
            is YouTubeEvent.RateChange,
            is YouTubeEvent.StateChanged,
            -> println("webViewState. onAction HANDlED: $action")
        }
    },
)
Therm answered 19/11, 2023 at 16:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.