Hướng dẫn di chuyển AndroidX Media3

Ứng dụng hiện đang sử dụng com.google.android.exoplayer2 độc lập thư viện và androidx.media cần di chuyển sang androidx.media3. Sử dụng tập lệnh di chuyển để di chuyển các tệp bản dựng gradle, Java và Các tệp nguồn Kotlin và tệp bố cục XML từ ExoPlayer 2.19.1 thành AndroidX Media3 1.1.1.

Tổng quan

Trước khi di chuyển, hãy xem những phần sau để tìm hiểu thêm về lợi ích của các API mới, API cần di chuyển và điều kiện tiên quyết mà dự án ứng dụng của bạn sẽ đáp ứng.

Lý do bạn nên chuyển sang Jetpack Media3

  • Đó là ngôi nhà mới của ExoPlayer, trong khi com.google.android.exoplayer2 là đã ngừng hoạt động.
  • Truy cập Player API trên các thành phần/quy trình bằng MediaBrowser/MediaController.
  • Sử dụng các tính năng mở rộng của MediaSession và API MediaController.
  • Quảng cáo khả năng phát bằng chế độ kiểm soát quyền truy cập chi tiết.
  • Đơn giản hoá ứng dụng của bạn bằng cách xoá MediaSessionConnectorPlayerNotificationManager.
  • Tương thích ngược với API ứng dụng có khả năng tương thích ngược (MediaBrowserCompat/MediaControllerCompat/MediaMetadataCompat)

Media API để di chuyển sang AndroidX Media3

  • ExoPlayer và các tiện ích
    Điều này bao gồm tất cả các mô-đun của dự án ExoPlayer cũ, ngoại trừ Mô-đun mediasession đã ngừng hoạt động. Ứng dụng hoặc mô-đun phụ thuộc vào bạn có thể di chuyển các gói trong com.google.android.exoplayer2 bằng tập lệnh di chuyển.
  • MediaSessionRenderer (tùy thuộc vào androidx.media.* gói androidx.media:media:1.4.3+)
    Xoá MediaSessionConnector và sử dụng androidx.media3.session.MediaSession.
  • MediaBrowserServiceCompat (tuỳ thuộc vào androidx.media.* gói androidx.media:media:1.4.3+)
    Di chuyển các lớp con của androidx.media.MediaBrowserServiceCompat sang androidx.media3.session.MediaLibraryService và mã sử dụng MediaBrowserCompat.MediaItem đến androidx.media3.common.MediaItem.
  • MediaBrowserCompat (tuỳ thuộc vào android.support.v4.media.* gói androidx.media:media:1.4.3+)
    Di chuyển mã ứng dụng bằng MediaBrowserCompat hoặc MediaControllerCompat để sử dụng androidx.media3.session.MediaBrowser cùng với androidx.media3.common.MediaItem.

Điều kiện tiên quyết

  1. Đảm bảo dự án của bạn nằm trong chế độ kiểm soát nguồn

    Đảm bảo bạn có thể dễ dàng huỷ bỏ các thay đổi mà các công cụ di chuyển theo tập lệnh đã áp dụng. Nếu bạn chưa có dự án ở chế độ kiểm soát nguồn, thì bây giờ là thời điểm thích hợp để bắt đầu. Nếu vì lý do nào đó mà bạn không muốn làm điều đó, hãy bản sao lưu dự án của bạn trước khi bắt đầu quá trình di chuyển.

  2. Cập nhật ứng dụng

    • Bạn nên cập nhật dự án để sử dụng phiên bản thư viện ExoPlayer mới nhất và xoá mọi lệnh gọi đến các phương thức không dùng nữa. Nếu bạn định sử dụng tập lệnh để di chuyển, bạn cần phải khớp với phiên bản mà bạn đang cập nhật lên bằng phiên bản do tập lệnh xử lý.

    • Tăng compileSdkVersion của ứng dụng lên ít nhất là 32.

    • Nâng cấp Gradle và trình bổ trợ Android Studio cho Gradle lên một phiên bản phiên bản hoạt động với các phần phụ thuộc đã cập nhật ở trên. Cho thực thể:

      • Phiên bản trình bổ trợ Android cho Gradle: 7.1.0
      • Phiên bản Gradle: 7.4
    • Thay thế tất cả câu lệnh nhập ký tự đại diện đang dùng ký tự đại diện (*) và sử dụng câu lệnh nhập đủ điều kiện: Xoá ký tự đại diện nhập câu lệnh và sử dụng Android Studio để nhập các câu lệnh đủ điều kiện (F2 – Alt/Enter, F2 – Alt/Enter, ...).

    • Di chuyển từ com.google.android.exoplayer2.PlayerView sang com.google.android.exoplayer2.StyledPlayerView. Điều này là cần thiết vì không có công thức nào tương đương với com.google.android.exoplayer2.PlayerView trong AndroidX Media3.

Di chuyển ExoPlayer có hỗ trợ tập lệnh

Tập lệnh hỗ trợ việc di chuyển từ com.google.android.exoplayer2 sang tập lệnh mới cấu trúc gói và mô-đun trong androidx.media3. Tập lệnh áp dụng một số bước kiểm tra xác thực dự án và in cảnh báo nếu không xác thực được. Nếu không, thao tác này sẽ áp dụng mối liên kết của các lớp và gói đã đổi tên trong các tài nguyên của một dự án Android gradle viết bằng Java hoặc Kotlin.

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

Sử dụng tập lệnh di chuyển

  1. Tải tập lệnh di chuyển từ thẻ của dự án ExoPlayer xuống GitHub tương ứng với phiên bản mà bạn đã cập nhật ứng dụng lên:

    curl -o media3-migration.sh \
      "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
    
  2. Làm cho tập lệnh có thể thực thi:

    chmod 744 media3-migration.sh
    
  3. Chạy tập lệnh bằng --help để tìm hiểu về các tuỳ chọn.

  4. Chạy tập lệnh bằng -l để liệt kê tập hợp các tệp được chọn di chuyển (sử dụng -f để buộc hiển thị trang thông tin mà không có cảnh báo):

    ./media3-migration.sh -l -f /path/to/gradle/project/root
    
  5. Chạy tập lệnh bằng -m để ánh xạ các gói, lớp và mô-đun với Media3. Việc chạy tập lệnh có tuỳ chọn -m sẽ áp dụng các thay đổi cho tuỳ chọn đã chọn tệp.

    • Dừng khi gặp lỗi xác thực mà không thay đổi gì
    ./media3-migration.sh -m /path/to/gradle/project/root
    
    • Thực thi bắt buộc

    Nếu tập lệnh phát hiện thấy lỗi vi phạm các điều kiện tiên quyết, thì quá trình di chuyển có thể buộc bằng cờ -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

Hãy hoàn tất các bước thủ công sau khi chạy tập lệnh với tuỳ chọn -m:

  1. Kiểm tra cách tập lệnh đã thay đổi mã của bạn: Sử dụng công cụ so sánh và khắc phục các vấn đề tiềm ẩn (hãy cân nhắc báo lỗi nếu bạn cho rằng tập lệnh có sự cố chung được giới thiệu mà không truyền tuỳ chọn -f).
  2. Xây dựng dự án: Sử dụng ./gradlew clean build hoặc trong Android Studio chọn Tệp > Đồng bộ hoá dự án với tệp Gradle, sau đó chọn Build > (Bản dựng >) Xoá dự án, sau đó chọn Tạo > Tạo lại dự án (theo dõi bản dựng trong "Build - Build Output" (Bản dựng – Kết quả của bản dựng) trong Android Studio.

Các bước tiếp theo bạn nên thực hiện:

  1. Xử lý trạng thái chọn nhận lỗi liên quan đến việc sử dụng API không ổn định.
  2. Thay thế các lệnh gọi API không dùng nữa: Sử dụng API thay thế được đề xuất. Giữ con trỏ trên cảnh báo trong Android Studio rồi tham khảo JavaDoc của biểu tượng không dùng nữa để tìm hiểu xem nên sử dụng gì thay vì một lệnh gọi nhất định.
  3. Sắp xếp câu lệnh nhập: Mở dự án trong Android Studio, sau đó nhấp chuột phải vào nút thư mục gói trong trình xem dự án và chọn Tối ưu hoá lệnh nhập trên các gói chứa tệp nguồn đã thay đổi.

Thay thế MediaSessionConnector bằng androidx.media3.session.MediaSession.

Trong thế giới MediaSessionCompat cũ, MediaSessionConnector là chịu trách nhiệm đồng bộ hóa trạng thái của trình phát với trạng thái của phiên và nhận lệnh từ những đơn vị kiểm soát cần uỷ quyền để trình phát. Với AndroidX Media3, việc này được MediaSession trực tiếp thực hiện mà không cần trình kết nối.

  1. Xóa tất cả tham chiếu và cách sử dụng MediaSessionRenderer: Nếu bạn đã sử dụng tập lệnh tự động để di chuyển các lớp và gói ExoPlayer, sau đó tập lệnh có thể đã để lại mã của bạn ở trạng thái không thể biên dịch liên quan đến việc MediaSessionConnector không thể giải quyết được. Android Studio sẽ cho bạn biết mã bị hỏng khi bạn cố gắng tạo hoặc khởi động ứng dụng.

  2. Trong tệp build.gradle là nơi bạn duy trì các phần phụ thuộc, hãy thêm một phần phụ thuộc triển khai vào mô-đun phiên AndroidX Media3 và xoá phần phụ thuộc cũ:

    implementation "androidx.media3:media3-session:1.4.0"
    
  3. Thay thế MediaSessionCompat bằng androidx.media3.session.MediaSession.

  4. Tại trang web mã mà bạn đã tạo MediaSessionCompat cũ, hãy sử dụng androidx.media3.session.MediaSession.Builder để tạo MediaSession. Truyền trình phát để tạo trình tạo phiên.

    val player = ExoPlayer.Builder(context).build()
    mediaSession = MediaSession.Builder(context, player)
        .setSessionCallback(MySessionCallback())
        .build()
    
  5. Triển khai MySessionCallback theo yêu cầu của ứng dụng. Bạn không bắt buộc phải làm việc này. Nếu bạn muốn cho phép bộ điều khiển thêm các mục nội dung đa phương tiện vào trình phát, hãy triển khai MediaSession.Callback.onAddMediaItems(). Nền tảng này hiện có nhiều để thêm các mục nội dung đa phương tiện vào trình phát để phát trong một tương thích ngược. Điều này bao gồm Các phương thức MediaController.set/addMediaItems() của bộ điều khiển Media3, như cũng như TransportControls.prepareFrom*/playFrom* của API cũ. Một ví dụ về cách triển khai onAddMediaItems có thể trong PlaybackService của ứng dụng minh hoạ phiên.

  6. Phát hành phiên phát nội dung đa phương tiện tại trang web mã mà bạn đã huỷ phiên trước khi di chuyển:

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

Chức năng MediaSessionConnector trong Media3

Bảng sau đây cho thấy các API Media3 xử lý chức năng được triển khai trước đó trong MediaSessionConnector.

MediaSessionTrình kết nốiAndroidX Media3
CustomActionProvider MediaSession.Callback.onCustomCommand()/ MediaSession.setCustomLayout()
PlaybackPreparer MediaSession.Callback.onAddMediaItems() (prepare() được gọi nội bộ)
QueueNavigator ForwardingPlayer
QueueEditor MediaSession.Callback.onAddMediaItems()
RatingCallback MediaSession.Callback.onSetRating()
PlayerNotificationManager DefaultMediaNotificationProvider/ MediaNotification.Provider

Di chuyển MediaBrowserService sang MediaLibraryService

AndroidX Media3 ra mắt MediaLibraryService thay thế cho MediaBrowserServiceCompat JavaDoc về MediaLibraryService và siêu dữ liệu của nó lớp MediaSessionService cung cấp phần giới thiệu tốt về API và mô hình lập trình không đồng bộ của dịch vụ.

MediaLibraryService tương thích ngược với MediaBrowserService Một ứng dụng khách đang sử dụng MediaBrowserCompat hoặc MediaControllerCompat, tiếp tục hoạt động mà không cần thay đổi mã khi kết nối thành MediaLibraryService. Đối với khách hàng, hãy cho biết rõ liệu ứng dụng của bạn có bằng cách sử dụng MediaLibraryService hoặc MediaBrowserServiceCompat cũ.

Sơ đồ thành phần ứng dụng với dịch vụ, hoạt động và ứng dụng bên ngoài.
Hình 1: Tổng quan về thành phần ứng dụng đa phương tiện
  1. Để khả năng tương thích ngược hoạt động, bạn cần đăng ký cả hai dịch vụ giao diện với dịch vụ của bạn trong AndroidManifest.xml. Bằng cách này, ứng dụng khách sẽ tìm thấy dịch vụ của bạn bằng giao diện dịch vụ bắt buộc:

    <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. Trong tệp build.gradle là nơi bạn duy trì các phần phụ thuộc, hãy thêm một phần phụ thuộc triển khai vào mô-đun phiên AndroidX Media3 và xoá phần phụ thuộc cũ:

    implementation "androidx.media3:media3-session:1.4.0"
    
  3. Thay đổi dịch vụ để kế thừa từ MediaLibraryService thay vì MediaBrowserService Như đã đề cập trước đó, MediaLibraryService tương thích với phiên bản cũ MediaBrowserService. Theo đó, API rộng hơn của dịch vụ việc cung cấp cho khách hàng vẫn không thay đổi. Có khả năng ứng dụng có thể duy trì hầu hết logic cần thiết để triển khai MediaBrowserService và điều chỉnh cho phù hợp với MediaLibraryService mới.

    Những điểm khác biệt chính so với phiên bản cũ MediaBrowserServiceCompat như sau:

    • Triển khai các phương thức vòng đời dịch vụ: Các phương thức cần bị ghi đè trên chính dịch vụ là onCreate/onDestroy, trong đó một ứng dụng phân bổ/giải phóng phiên thư viện, trình phát và các phiên bản khác của chúng tôi. Ngoài các phương thức vòng đời dịch vụ tiêu chuẩn, một ứng dụng cần ghi đè onGetSession(MediaSession.ControllerInfo) để trả về MediaLibrarySession được tạo trong onCreate.

    • Triển khai MediaLibraryService.MediaLibrarySessionCallback: Xây dựng một phiên hoạt động cần có một MediaLibraryService.MediaLibrarySessionCallback triển khai các phương thức API miền thực tế. Vì vậy, thay vì ghi đè các phương thức API của dịch vụ cũ, bạn sẽ ghi đè các phương thức của Hãy MediaLibrarySession.Callback.

      Sau đó, lệnh gọi lại được dùng để tạo MediaLibrarySession:

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

      Tìm API đầy đủ của MediaLibrarySessionCallback trong API tài liệu.

    • Triển khai MediaSession.Callback.onAddMediaItems(): Lệnh gọi lại onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) phục vụ nhiều phương thức API hiện tại và cũ giúp thêm mục nội dung đa phương tiện vào trình phát để phát theo cách có khả năng tương thích ngược. Điều này bao gồm MediaController.set/addMediaItems() phương thức của bộ điều khiển Media3, cũng như TransportControls.prepareFrom*/playFrom* của API cũ. Việc triển khai lệnh gọi lại mẫu có thể trong PlaybackService của ứng dụng minh hoạ phiên.

    • AndroidX Media3 đang sử dụng androidx.media3.common.MediaItem để thay thế của MediaBrowserCompat.MediaItemMediaMetadataCompat. Phần mã gắn với các lớp cũ cần được thay đổi tương ứng hoặc ánh xạ đến Media3 MediaItem.

    • Mô hình lập trình không đồng bộ chung đã thay đổi thành Futures trong trái ngược với phương thức Result có thể tách rời của phương thức MediaBrowserServiceCompat. Việc triển khai dịch vụ của bạn có thể trả về một ListenableFuture không đồng bộ thay vì tách kết quả hoặc trả về một hàm Future ngay lập tức để trực tiếp trả về một giá trị.

Xoá PlayerNotificationManager

MediaLibraryService tự động hỗ trợ thông báo về nội dung nghe nhìn và Bạn có thể xoá PlayerNotificationManager khi sử dụng MediaLibraryService hoặc MediaSessionService.

Một ứng dụng có thể tuỳ chỉnh thông báo bằng cách đặt MediaNotification.Provider trong onCreate() sẽ thay thế phương thức DefaultMediaNotificationProvider. Sau đó, MediaLibraryService sẽ xử lý khởi động dịch vụ trên nền trước theo yêu cầu.

Khi ghi đè MediaLibraryService.updateNotification(), ứng dụng có thể mất nhiều quyền truy cập hơn toàn quyền sở hữu việc đăng thông báo và bắt đầu/dừng dịch vụ trong nền trước theo yêu cầu.

Di chuyển mã ứng dụng bằng MediaBrowser

Với AndroidX Media3, MediaBrowser sẽ triển khai MediaController/Player và có thể dùng để điều khiển việc phát nội dung nghe nhìn bên cạnh việc duyệt qua thư viện của bạn. Nếu bạn phải tạo MediaBrowserCompatMediaControllerCompat trong thế giới cũ, bạn có thể làm tương tự bằng cách chỉ sử dụng MediaBrowser trong Media3.

Bạn có thể tạo MediaBrowser và chờ kết nối với dịch vụ đang được thiết lập:

scope.launch {
    val sessionToken =
        SessionToken(context, ComponentName(context, MusicService::class.java)
    browser =
        MediaBrowser.Builder(context, sessionToken))
            .setListener(BrowserListener())
            .buildAsync()
            .await()
    // Get the library root to start browsing the library.
    root = browser.getLibraryRoot(/* params= */ null).await();
    // Add a MediaController.Listener to listen to player state events.
    browser.addListener(playerListener)
    playerView.setPlayer(browser)
}

Tìm hiểu Điều khiển chế độ phát trong phiên phát nội dung nghe nhìn để tìm hiểu cách tạo MediaController để điều khiển quá trình phát trong nền.

Các bước tiếp theo và dọn dẹp

Lỗi API không ổn định

Sau khi chuyển sang Media3, bạn có thể thấy lỗi tìm lỗi mã nguồn về cách sử dụng API không ổn định. Các API này an toàn khi sử dụng và lỗi tìm lỗi mã nguồn là sản phẩm phụ trong đảm bảo khả năng tương thích nhị phân. Nếu bạn không yêu cầu tệp nhị phân nghiêm ngặt khả năng tương thích, bạn có thể chặn những lỗi này một cách an toàn bằng @OptIn của bạn.

Thông tin khái quát

Cả ExoPlayer v1 hoặc v2 đều không cung cấp đảm bảo nghiêm ngặt về khả năng tương thích nhị phân của thư viện giữa các phiên bản tiếp theo. Giao diện API ExoPlayer rất lớn theo thiết kế, để cho phép các ứng dụng tuỳ chỉnh hầu hết mọi khía cạnh của video. Các phiên bản tiếp theo của ExoPlayer đôi khi giới thiệu biểu tượng đổi tên hoặc các thay đổi có thể gây lỗi khác (ví dụ: phương thức bắt buộc mới trên giao diện). Trong hầu hết các trường hợp, những sự cố này đã được giảm thiểu bằng cách sử dụng biểu tượng mới cùng với việc ngừng sử dụng biểu tượng cũ cho một số phiên bản, để cho phép nhà phát triển di chuyển mức sử dụng của mình, nhưng điều này không phải lúc nào cũng có thể thực hiện được.

Những thay đổi có thể gây lỗi này dẫn đến hai vấn đề cho người dùng ExoPlayer v1 và thư viện v2:

  1. Việc nâng cấp từ phiên bản ExoPlayer có thể khiến mã ngừng biên dịch.
  2. Một ứng dụng phụ thuộc vào ExoPlayer cả trực tiếp và qua trung gian thư viện phải đảm bảo rằng cả hai phần phụ thuộc đều là cùng một phiên bản, nếu không, việc không tương thích tệp nhị phân có thể dẫn đến sự cố trong thời gian chạy.

Những cải tiến trong Media3

Media3 đảm bảo khả năng tương thích nhị phân cho một nhóm nhỏ nền tảng API. Chiến lược phát hành đĩa đơn những phần không đảm bảo khả năng tương thích nhị phân sẽ được đánh dấu bằng @UnstableApi. Để làm rõ sự khác biệt này, việc sử dụng nguồn không ổn định Các biểu tượng API sẽ báo lỗi tìm lỗi mã nguồn, trừ phi các biểu tượng đó được chú thích bằng @OptIn.

Sau khi chuyển từ ExoPlayer v2 sang Media3, bạn có thể thấy rất nhiều API không ổn định tìm lỗi mã nguồn. Điều này có vẻ như Media3 "kém ổn định" so với ExoPlayer phiên bản 2. Tuy nhiên, trường hợp này không đúng. "unstable" (không ổn định) các phần của API Media3 có cùng mức độ ổn định là tổng thể của giao diện API ExoPlayer v2 cũng như không đảm bảo giao diện API Media3 ổn định trong ExoPlayer v2 tại tất cả. Sự khác biệt đơn giản là giờ đây lỗi tìm lỗi mã nguồn sẽ cảnh báo bạn về ổn định.

Xử lý các lỗi tìm lỗi mã nguồn API không ổn định

Hãy xem phần khắc phục sự cố về các lỗi tìm lỗi mã nguồn này để biết thông tin chi tiết về cách chú thích cách sử dụng Java và Kotlin đối với các API không ổn định bằng @OptIn.

API không dùng nữa

Bạn có thể nhận thấy rằng các lệnh gọi đến các API không dùng nữa bị gạch ngang trong Android Studio. Bạn nên thay thế các lệnh gọi đó bằng phương thức thay thế phù hợp. Hãy di chuột qua biểu tượng này để xem JavaDoc cho biết cần sử dụng API nào.

Ảnh chụp màn hình: Cách hiển thị JavaDoc với phương thức thay thế cho phương thức không dùng nữa
Hình 3: Chú giải công cụ JavaDoc trong Android Studio đề xuất một phương án thay thế cho mọi biểu tượng không dùng nữa.

Mã mẫu và ứng dụng minh hoạ

  • Ứng dụng minh hoạ phiên AndroidX Media3 (thiết bị di động và WearOS)
    • Thao tác tuỳ chỉnh
    • Thông báo trên giao diện người dùng hệ thống, MediaButton/BT
    • Điều khiển chế độ phát của Trợ lý Google
  • UAMP: Android Media Player (branch media3) (thiết bị di động, AutomotiveOS)
    • Thông báo giao diện người dùng hệ thống, MediaButton/BT, Tiếp tục phát
    • Điều khiển chế độ phát cho Trợ lý Google/WearOS
    • AutomotiveOS: lệnh tuỳ chỉnh và thông tin đăng nhập