AndroidX Media3 移行ガイド

現在スタンドアロンの com.google.android.exoplayer2 ライブラリと androidx.media を使用しているアプリは、androidx.media3 に移行する必要があります。移行スクリプトを使用して、Gradle ビルドファイル、Java ソースファイル、Kotlin ソースファイル、XML レイアウト ファイルを ExoPlayer 2.19.1 から AndroidX Media3 1.1.1 に移行します。

概要

移行する前に、以下のセクションで新しい API のメリット、移行する API、アプリのプロジェクトが満たす必要のある前提条件について確認してください。

Jetpack Media3 に移行する理由

  • com.google.android.exoplayer2 が 廃止されたため、ExoPlayer の新しいホーム になります。
  • MediaBrowser/MediaController を使用して、コンポーネント/プロセス間で Player API にアクセス します。
  • MediaSession および MediaController API の拡張機能
  • きめ細かいアクセス制御 で再生機能を宣伝します。
  • MediaSessionConnectorPlayerNotificationManager を削除してアプリを簡素化 します。
  • メディア互換クライアント API(MediaBrowserCompat/MediaControllerCompat/MediaMetadataCompat)と下位互換性 があります。

AndroidX Media3 に移行するメディア API

  • ExoPlayer とその拡張機能
    これには、廃止された mediasession モジュールを除く、以前の ExoPlayer プロジェクトのすべてのモジュールが含まれます。com.google.android.exoplayer2 のパッケージに依存するアプリまたはモジュールは、移行スクリプトを使用して移行できます。
  • MediaSessionConnectorandroidx.media.* パッケージに依存)
    MediaSessionConnector を削除し、代わりに androidx.media3.session.MediaSession を使用します。androidx.media:media:1.4.3+
  • MediaBrowserServiceCompatandroidx.media.*androidx.media:media:1.4.3+ パッケージに依存)
    androidx.media.MediaBrowserServiceCompat のサブクラスを androidx.media3.session.MediaLibraryService に移行し、 MediaBrowserCompat.MediaItem を使用するコードを androidx.media3.common.MediaItem に移行します。
  • MediaBrowserCompatandroidx.media:media:1.4.3+android.support.v4.media.* パッケージに依存)
    MediaBrowserCompat または MediaControllerCompat を使用するクライアント コードを移行して、androidx.media3.common.MediaItemandroidx.media3.session.MediaBrowser を使用します。

前提条件

  1. プロジェクトがソース管理下にあることを確認する

    スクリプトによる移行ツールで適用された変更を簡単に元に戻せるようにします。 プロジェクトがまだソース管理下にない場合は、今すぐ開始することをおすすめします。何らかの理由でソース管理を使用しない場合は、移行を開始する前にプロジェクトのバックアップ コピーを作成してください。

  2. アプリを更新する

    • プロジェクトを更新して 最新バージョンの ExoPlayer ライブラリを使用し、 非推奨のメソッドの呼び出しを削除することをおすすめします。移行に スクリプトを使用する場合は、更新する バージョンをスクリプトで処理されるバージョンと一致させる必要があります。

    • アプリの compileSdkVersion を 32 以上 にします。

    • Gradle と Android Studio Gradle プラグインをアップグレード して、上記の更新された依存関係で動作する最新バージョンにします。例:

      • Android Gradle プラグインのバージョン: 7.1.0
      • Gradle のバージョン: 7.4
    • アスタリスク(*)を使用しているすべてのワイルドカード import ステートメントを置き換え 、完全修飾された import ステートメントを使用します。ワイルドカード import ステートメントを削除し、Android Studio を使用して完全修飾されたステートメントをインポートします(F2 - Alt/Enter、F2 - Alt/Enter など)。

    • から com.google.android.exoplayer2.PlayerView に移行 com.google.android.exoplayer2.StyledPlayerView します。AndroidX Media3 には com.google.android.exoplayer2.PlayerView に相当するものがないため、これが必要です。

スクリプト サポートを使用して ExoPlayer を移行する

このスクリプトを使用すると、com.google.android.exoplayer2 から新しい パッケージとモジュール構造(androidx.media3)に簡単に移行できます。このスクリプトは、プロジェクトに対していくつかの検証チェックを行い、検証に失敗した場合は警告を出力します。 それ以外の場合は、Java または Kotlin で記述された Android Gradle プロジェクトの リソースで、名前が変更されたクラスとパッケージのマッピングを適用します。

usage: ./media3-migration.sh [-p|-c|-d|-v]|[-m|-l [-x <path>] [-f] PROJECT_ROOT]
 PROJECT_ROOT: path to your project root (location of 'gradlew')
 -p: list package mappings and then exit
 -c: list class mappings (precedence over package mappings) and then exit
 -d: list dependency mappings and then exit
 -l: list files that will be considered for rewrite and then exit
 -x: exclude the path from the list of file to be changed: 'app/src/test'
 -m: migrate packages, classes and dependencies to AndroidX Media3
 -f: force the action even when validation fails
 -v: print the exoplayer2/media3 version strings of this script
 -h, --help: show this help text

移行スクリプトを使用する

  1. アプリを更新したバージョンに対応する GitHub の ExoPlayer プロジェクトのタグから移行スクリプトをダウンロードします。

    curl -o media3-migration.sh \
      "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
    
  2. スクリプトを実行可能にします。

    chmod 744 media3-migration.sh
    
  3. --help を指定してスクリプトを実行し、オプションについて確認します。

  4. -l を指定してスクリプトを実行し、移行用に選択されたファイルのセットを一覧表示します(-f を使用すると、警告なしで強制的に一覧表示されます)。

    ./media3-migration.sh -l -f /path/to/gradle/project/root
    
  5. -m を指定してスクリプトを実行し、パッケージ、クラス、モジュールを Media3 にマッピングします。-m オプションを指定してスクリプトを実行すると、選択したファイルに変更が適用されます。

    • 変更を加えずに検証エラーで停止する
    ./media3-migration.sh -m /path/to/gradle/project/root
    
    • 強制実行

    スクリプトで前提条件の違反が見つかった場合は、-f フラグを使用して移行を強制できます。

    ./media3-migration.sh -m -f /path/to/gradle/project/root
    
 # list files selected for migration when excluding paths
 ./media3-migration.sh -l -x "app/src/test/" -x "service/" /path/to/project/root
 # migrate the selected files
 ./media3-migration.sh -m -x "app/src/test/" -x "service/" /path/to/project/root

-m オプションを指定してスクリプトを実行したら、次の手動の手順を完了します。

  1. スクリプトによってコードがどのように変更されたかを確認する: 差分ツールを使用して、 潜在的な問題を修正します(スクリプトに 一般的な問題があると思われる場合は、バグを報告してください。-f オプションを渡さずに導入されました)。
  2. プロジェクトをビルドする: ./gradlew clean build を使用するか、Android Studio で [File > Sync Project with Gradle Files]、次に [Build > Clean project]、次に [Build > Rebuild project] を選択します(Android Studio の [Build - Build Output] タブでビルドをモニタリングします)。

推奨されるフォローアップ手順:

  1. 不安定な API の使用に関するエラーのオプトイン を解決します。
  2. 非推奨の API 呼び出しを置き換える: 推奨される代替 API を使用します。 Android Studio で警告にポインタを合わせ、非推奨のシンボルの JavaDoc を参照して、特定の呼び出しの代わりに何を使用するかを確認します。
  3. import ステートメントを並べ替える: Android Studio でプロジェクトを開き、 プロジェクト ビューアでパッケージ フォルダのノードを右クリックして、変更されたソースファイルを含むパッケージで [Optimize imports] を選択します。

MediaSessionConnectorandroidx.media3.session.MediaSession に置き換える

以前の MediaSessionCompat では、MediaSessionConnector はプレーヤーの状態とセッションの状態を同期し、適切なプレーヤー メソッドに委任する必要があるコントローラからコマンドを受信していました。AndroidX Media3 では、コネクタを必要とせずに MediaSession によって直接行われます。

  1. MediaSessionConnector のすべての参照と使用を削除する: 自動スクリプトを使用して ExoPlayer のクラスとパッケージを移行した場合、スクリプトによって MediaSessionConnector に関して解決できないコンパイルできない状態のコードが残っている可能性があります。アプリをビルドまたは起動しようとすると、Android Studio に破損したコードが表示されます。

  2. 依存関係を維持する build.gradle ファイルで、AndroidX Media3 セッション モジュールへの実装依存関係を追加 し、以前の依存関係を削除します。

    implementation "androidx.media3:media3-session:1.10.0"
    
  3. MediaSessionCompatandroidx.media3.session.MediaSession に置き換えます。

  4. 以前の MediaSessionCompat を作成したコードサイトで、 androidx.media3.session.MediaSession.Builder を使用して build a MediaSession します。プレーヤーを渡して セッション ビルダーを構築します。

    Kotlin

    val player = ExoPlayer.Builder(context).build()
    mediaSession = MediaSession.Builder(context, player).setCallback(MySessionCallback()).build()

    Java

    ExoPlayer player = new ExoPlayer.Builder(context).build();
    mediaSession =
        new MediaSession.Builder(context, player).setCallback(new MySessionCallback()).build();

  5. アプリに必要な MySessionCallback を実装します。これは省略可能です。コントローラがメディア アイテムをプレーヤーに追加できるようにする場合は、 を実装します MediaSession.Callback.onAddMediaItems()。これは、メディア アイテムをプレーヤーに追加して下位互換性のある方法で再生する、現在と以前のさまざまな API メソッドに対応しています。これには、Media3 コントローラの MediaController.set/addMediaItems() メソッドと、以前の API の TransportControls.prepareFrom*/playFrom* メソッドが含まれます。onAddMediaItems の実装例は、セッション デモアプリの PlaybackService にあります

  6. 移行前にセッションを破棄したコードサイトで、メディア セッションを解放します。

    Kotlin

    mediaSession?.run {
      player.release()
      release()
      mediaSession = null
    }

    Java

    if (mediaSession != null) {
      mediaSession.getPlayer().release();
      mediaSession.release();
      mediaSession = null;
    }

Media3 の MediaSessionConnector 機能

次の表に、以前に MediaSessionConnector で実装されていた機能を処理する Media3 API を示します。

MediaSessionConnectorAndroidX Media3
CustomActionProvider MediaSession.Callback.onCustomCommand()/ MediaSession.setMediaButtonPreferences()
PlaybackPreparer MediaSession.Callback.onAddMediaItems()prepare() は内部で呼び出されます)
QueueNavigator ForwardingSimpleBasePlayer
QueueEditor MediaSession.Callback.onAddMediaItems()
RatingCallback MediaSession.Callback.onSetRating()
PlayerNotificationManager DefaultMediaNotificationProvider/ MediaNotification.Provider

MediaBrowserServiceMediaLibraryService に移行する

AndroidX Media3 では、MediaBrowserServiceCompat を置き換える MediaLibraryService が導入されています。MediaLibraryService とそのスーパークラス MediaSessionService の JavaDoc には、API とサービスの非同期プログラミング モデルの概要が記載されています。

MediaLibraryServiceMediaBrowserService と下位互換性があります。MediaBrowserCompat または MediaControllerCompat を使用しているクライアント アプリは、MediaLibraryService に接続してもコードを変更せずに動作します。クライアントの場合、アプリが MediaLibraryService を使用しているか、以前の MediaBrowserServiceCompat を使用しているかは透過的です。

サービス、Activity、外部アプリを含むアプリ コンポーネントの図。
図 1: メディアアプリ コンポーネントの概要
  1. 下位互換性を機能させるには、AndroidManifest.xml でサービスに両方のサービス インターフェースを登録 する必要があります。これにより、クライアントは必要なサービス インターフェースでサービスを見つけることができます。

    <service android:name=".MusicService" android:exported="true">
        <intent-filter>
            <action android:name="androidx.media3.session.MediaLibraryService"/>
            <action android:name="android.media.browse.MediaBrowserService" />
        </intent-filter>
    </service>
    
  2. 依存関係を維持する build.gradle ファイルで、an 実装依存関係を AndroidX Media3 セッション モジュール に追加し、 以前の依存関係を削除します。

    implementation "androidx.media3:media3-session:1.10.0"
    
  3. サービスを MediaBrowserService ではなく MediaLibraryService から継承するように変更 します。前述のように、MediaLibraryService は以前の MediaBrowserService と互換性があります。したがって、サービスがクライアントに提供する広範な API は変わりません。そのため、アプリは MediaBrowserService の実装に必要なロジックのほとんどを維持し、新しい MediaLibraryService に適応させることができます。

    以前の MediaBrowserServiceCompat との主な違いは次のとおりです。

    • サービス ライフサイクル メソッドを実装する: サービス自体でオーバーライドする必要があるメソッドは onCreate/onDestroy です。アプリはここでライブラリ セッション、プレーヤー、その他のリソースを割り当て/解放します。標準のサービス ライフサイクル メソッドに加えて、アプリは onGetSession(MediaSession.ControllerInfo) をオーバーライドして、onCreate でビルドされた MediaLibrarySession を返す必要があります。

    • MediaLibraryService.MediaLibrarySessionCallback を実装する: セッションをビルドするには、実際のドメイン API メソッドを実装する MediaLibraryService.MediaLibrarySessionCallback が必要です。そのため、以前のサービスの API メソッドをオーバーライドするのではなく、MediaLibrarySession.Callback のメソッドをオーバーライドします。

      コールバックは、MediaLibrarySession のビルドに使用されます。

      Kotlin

      mediaLibrarySession = MediaLibrarySession.Builder(context, player, MySessionCallback()).build()

      Java

      mediaLibrarySession =
          new MediaLibrarySession.Builder(context, player, new MySessionCallback()).build();

      MediaLibrarySessionCallback の完全な API については、API ドキュメントをご覧ください。

    • を実装する MediaSession.Callback.onAddMediaItems(): コールバック onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) は メディア アイテムをプレーヤーに追加して下位互換性のある方法で再生する、現在と以前のさまざまな API メソッドに対応しています。これには、Media3 コントローラの MediaController.set/addMediaItems() メソッドと、以前の API の TransportControls.prepareFrom*/playFrom* メソッドが含まれます。コールバックの実装例は、セッション デモアプリの PlaybackService にあります

    • AndroidX Media3 では、androidx.media3.common.MediaItem の代わりに MediaBrowserCompat.MediaItemMediaMetadataCompat を使用しています。以前のクラスに関連付けられているコードの一部は、必要に応じて変更するか、Media3 MediaItem にマッピングする必要があります。

    • 一般的な 非同期プログラミング モデルは、Futures と は対照的に、分離可能な Result アプローチの MediaBrowserServiceCompat に変更 されました。サービス実装では、結果を分離する代わりに 非同期の ListenableFuture を返すか、 即時の Future を返して値を直接返すことができます

PlayerNotificationManager を削除する

MediaLibraryService はメディア通知を自動的にサポート します。MediaLibraryService または MediaSessionService を使用する場合は、PlayerNotificationManager を削除できます。

アプリは、onCreate() でカスタムの MediaNotification.Provider を設定して、DefaultMediaNotificationProvider を置き換えることで通知をカスタマイズ できます。その後、MediaLibraryService は必要に応じてサービスをフォアグラウンドで起動します。

アプリは MediaLibraryService.updateNotification() をオーバーライドすることで、通知の投稿と、必要に応じてフォアグラウンドでのサービスの開始/停止を完全に制御できます。

MediaBrowser を使用してクライアント コードを移行する

AndroidX Media3 では、MediaBrowserMediaController/Player インターフェースを実装し、メディア ライブラリの閲覧に加えてメディア再生の制御にも使用できます。以前の環境で MediaBrowserCompatMediaControllerCompat を作成する必要があった場合は、Media3 で MediaBrowser のみを使用して同じことができます。

MediaBrowser をビルドして、サービスへの接続が確立されるまで待機できます。

Kotlin

scope.launch {
  val sessionToken = SessionToken(context, ComponentName(context, "MusicService"))
  browser =
    MediaBrowser.Builder(context, sessionToken)
      .setListener(BrowserListener())
      .buildAsync()
      .await()
}

Java

SessionToken sessionToken =
    new SessionToken(context, new ComponentName(context, "MusicService"));
ListenableFuture<MediaBrowser> browserFuture =
    new MediaBrowser.Builder(context, sessionToken)
        .setListener(new BrowserListener())
        .buildAsync();

バックグラウンドで再生を制御するMediaControllerを作成する方法については、 メディア セッションで再生を制御する をご覧ください。

次のステップとクリーンアップ

不安定な API エラー

Media3 に移行すると、不安定な API の使用に関する lint エラーが表示されることがあります。 これらの API は安全に使用でき、lint エラーは新しいバイナリ互換性の保証の副産物です。厳密なバイナリ互換性が不要な場合は、@OptIn アノテーションを使用してこれらのエラーを安全に抑制できます。

背景

ExoPlayer v1 と v2 のどちらも、後続バージョン間のライブラリのバイナリ互換性について厳密な保証を提供していませんでした。ExoPlayer API サーフェスは、アプリが再生のほぼすべての側面をカスタマイズできるように、設計上非常に大きくなっています。ExoPlayer の後続バージョンでは、シンボルの名前変更やその他の互換性を破る変更(インターフェースに必要な新しいメソッドなど)が導入されることがありました。ほとんどの場合、これらの破損は、古いシンボルを非推奨にするとともに、新しいシンボルを数バージョンにわたって導入することで軽減され、デベロッパーが使用状況を移行する時間を確保できましたが、常に可能とは限りませんでした。

これらの互換性を破る変更により、ExoPlayer v1 と v2 のライブラリのユーザーに次の 2 つの問題が発生しました。

  1. から ExoPlayer バージョンにアップグレードすると、コードのコンパイルが停止する可能性があります。
  2. ExoPlayer に直接依存し、中間ライブラリを介して依存するアプリでは、両方の依存関係が同じバージョンであることを確認する必要がありました。そうしないと、バイナリの非互換性によりランタイム クラッシュが発生する可能性があります。

Media3 の改善点

Media3 は、API サーフェスのサブセットのバイナリ互換性を保証します。 バイナリ互換性を保証しない 部分は、 @UnstableApiでマークされています。この区別を明確にするため、不安定な API シンボルの使用は、@OptIn でアノテーションが付けられていない限り、lint エラーを生成します。

ExoPlayer v2 から Media3 に移行すると、不安定な API lint エラーが多数表示されることがあります。これにより、Media3 が ExoPlayer v2 よりも「不安定」に見えることがあります。これは明細書、請求書ではありません。Media3 API の「不安定」な部分は、ExoPlayer v2 API サーフェス全体 と同じレベルの安定性を備えており、安定した Media3 API サーフェスの保証は ExoPlayer v2 では利用できません。違いは、lint エラーによって安定性のレベルが異なることが通知されるようになったことです。

不安定な API lint エラーを処理する

不安定な API の Java と Kotlin の使用に @OptIn でアノテーションを付ける方法について詳しくは、これらの lint エラーに関するトラブルシューティング セクションをご覧ください。

非推奨 API

非推奨の API の呼び出しが Android Studio で取り消し線で表示されることがあります。このような呼び出しは、適切な代替手段に置き換えることをおすすめします。 シンボルにカーソルを合わせると、代わりに使用する API を示す JavaDoc が表示されます。

スクリーンショット: 非推奨メソッドの代替手段を含む JavaDoc を表示する方法
図 3: Android Studio の JavaDoc ツールチップは、非推奨のシンボルの代替手段を示しています。

コードサンプルとデモアプリ