アイリッジ開発者ブログ

アイリッジに所属するエンジニアが技術情報を発信していきます。

【Android/Kotlin】ExoPlayerをPicture in Pictureで再生してみた

こんにちは。開発部第一グループの岡田です。 今回は、動画をピクチャーインピクチャー(PiP)で再生できるAndroidアプリの実装方法についてご紹介します。

使用技術

  • Kotlin 2.0.21
  • ExoPlayerライブラリ

主な機能

  • 動画の再生
  • PiPモードへの切り替え(動画を小窓で再生しながら他の操作が可能)

実装ポイント

1. ExoPlayerのセットアップ

build.gradle.kts

    implementation("androidx.media3:media3-exoplayer:1.8.0")
    implementation("androidx.media3:media3-ui:1.8.0")

レイアウト

    <androidx.media3.ui.PlayerView
        android:id="@+id/movie"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toTopOf="@+id/vertical"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

Kotlinコード

import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer
・
・
override fun onCreate(savedInstanceState: Bundle?) {
    val playerView = findViewById<PlayerView>(R.id.playerView)
    val player = ExoPlayer.Builder(this).build()
    playerView.player = player

    val mediaItem = MediaItem.fromUri("https://www.example.com/sample.mp4")
    player.setMediaItem(mediaItem)
    player.prepare()
    player.play()
}
・
・

override fun onDestroy() {
    super.onDestroy()
    player.release()
}

注意点

  • 権利やライセンスに注意(特にネットワーク動画)
  • ExoPlayerはカスタマイズ性が高いが、VideoViewより実装がやや複雑
  • UIスレッドで重い処理をしない

2. PiPモードへの切り替え

minimize()メソッドを呼び出すボタンを配置し、押下することでPiPモードに移行するように設定しています。
アスペクト比や表示位置は、動画Viewのサイズや位置から動的に計算しています。

private fun updatePictureInPictureParams(): PictureInPictureParams {
    // PiPに入った時の比率を指定
    val aspectRatio = Rational(16, 9)
    
    val visibleRect = Rect()
    binding.movie.getGlobalVisibleRect(visibleRect)
    val params = PictureInPictureParams.Builder()
        .setAspectRatio(aspectRatio)
        .setSourceRectHint(visibleRect)

    // Androidのバージョンによって処理を分ける
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        // Android 12(API 31)以降では setAutoEnterEnabled(true) を設定することで、一度PiPに入った後はホームボタン操作でも自動的にPiPへ遷移します。
        params.setAutoEnterEnabled(true)
    }
    return params.build().also {
        setPictureInPictureParams(it)
    }
}

// PiPモードに入る
private fun minimize() {
    enterPictureInPictureMode(updatePictureInPictureParams())
}

3. 権限追加

AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />
<activity
    android:supportsPictureInPicture="true" />

ハマりどころ・注意点

  • PiPは端末やOSバージョンによって挙動が異なる場合があるので、十分なテストが必要です。Android12以降なら一度呼び出した後はホームボタンでもPiPモードに入るようになります。
  • 動画Viewのサイズが0の場合、アスペクト比計算で例外が発生することがあるので注意しましょう。
  • ライフサイクル管理を怠ると、クラッシュやメモリリークの原因になります。

まとめ

PiPとExoPlayerを組み合わせることで、マルチタスクに強い動画アプリを簡単に作成できます。
最新APIへの対応やライフサイクル管理を意識することで、より快適なユーザー体験を提供できます。