如何在Media3 ExoPlayer的MediaController场景下为媒体请求携带特定Cookie?
问题描述
我需要实现携带特定Cookie的媒体请求,且必须支持后台播放。我参考了Media3后台播放的官方文档,通过以下代码获取MediaController(其中PlaybackService是继承自MediaSessionService的类):
SessionToken sessionToken = new SessionToken(this.themedReactContext, new ComponentName(this.themedReactContext, PlaybackService.class)); ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(this.themedReactContext, sessionToken).buildAsync(); controllerFuture.addListener(() -> { try { player = controllerFuture.get(); } catch (Exception error) { Log.e(TAG, error.getMessage()); } MediaItem mediaItem = ALibrary.getMediaItem(); player.setMediaItem(mediaItem); player.prepare(); // ... play with the 'player' });
为了在媒体请求中嵌入Cookie,我用OkHttp创建了带Cookie的MediaSource,代码如下:
private final OkHttpClient httpClient = new OkHttpClient.Builder().build(); // CookieUtil is what I made List<Cookie> cookies = CookieUtil.convertListToCookies(listOfCookieMap); OkHttpClient client = httpClient .newBuilder() .cookieJar(new CookieJar() { @Override public void saveFromResponse(@NonNull HttpUrl httpUrl, @NonNull List<Cookie> list) { // } @NonNull @Override public List<Cookie> loadForRequest(@NonNull HttpUrl httpUrl) { return cookies; } }) .build(); OkHttpDataSource.Factory dataSourceFactory = new OkHttpDataSource.Factory(client); MediaItem mediaItem = ALibrary.getMediaItem(); // The code shown above MediaSource mediaSource = new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItem);
但MediaController只支持通过setMediaItem设置MediaItem,没有setMediaSource方法,而且我必须从外部库ALibrary获取MediaItem。请问怎么实现为媒体请求携带特定Cookie?
解决方案
核心思路是把带Cookie的OkHttp数据源配置放到MediaSessionService内部的Player实例中,因为MediaController本质是和后台Service的Player做通信,无法直接操作Service内的数据源配置,所有资源加载逻辑都应该在Service侧处理。
1. 在PlaybackService中配置带Cookie的全局数据源
修改你的PlaybackService,在初始化Player时绑定带Cookie的数据源工厂,让Player所有的媒体请求都自动携带Cookie:
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession; private ExoPlayer player; private UpdatableCookieJar cookieJar; @Override public void onCreate() { super.onCreate(); // 初始化可更新的CookieJar(方便后续动态修改Cookie) List<Cookie> initialCookies = CookieUtil.convertListToCookies(listOfCookieMap); cookieJar = new UpdatableCookieJar(initialCookies); // 构建带Cookie的OkHttpClient OkHttpClient cookieClient = new OkHttpClient.Builder() .cookieJar(cookieJar) .build(); // 配置数据源工厂和媒体源工厂 OkHttpDataSource.Factory dataSourceFactory = new OkHttpDataSource.Factory(cookieClient); ProgressiveMediaSource.Factory mediaSourceFactory = new ProgressiveMediaSource.Factory(dataSourceFactory); // 初始化Player并绑定媒体源工厂 player = new ExoPlayer.Builder(this) .setMediaSourceFactory(mediaSourceFactory) .build(); // 创建MediaSession并关联Player mediaSession = new MediaSession.Builder(this, player) .setSessionActivity(PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), PendingIntent.FLAG_IMMUTABLE)) .build(); } @Nullable @Override public MediaSession onGetSession(@NonNull MediaSession.ControllerInfo controllerInfo) { return mediaSession; } @Override public void onDestroy() { player.release(); mediaSession.release(); super.onDestroy(); } // 自定义可更新的CookieJar实现 private static class UpdatableCookieJar implements CookieJar { private List<Cookie> cookies; public UpdatableCookieJar(List<Cookie> initialCookies) { this.cookies = initialCookies; } public void updateCookies(List<Cookie> newCookies) { this.cookies = newCookies; } @Override public void saveFromResponse(@NonNull HttpUrl httpUrl, @NonNull List<Cookie> list) {} @NonNull @Override public List<Cookie> loadForRequest(@NonNull HttpUrl httpUrl) { return cookies; } } }
2. Controller端保持原有逻辑
你原来在Controller端获取MediaController、设置MediaItem的代码不需要任何改动,因为Service内部的Player已经会自动用带Cookie的数据源加载MediaItem对应的资源。
3. 动态更新Cookie(可选)
如果需要在运行时修改Cookie,可以通过MediaSession的自定义命令实现:
- Controller端发送更新命令:
// 准备更新后的Cookie列表 List<Cookie> updatedCookies = CookieUtil.convertListToCookies(newCookieMapList); Bundle args = new Bundle(); args.putParcelableArrayList("UPDATED_COOKIES", new ArrayList<>(updatedCookies)); // 发送自定义命令到Service player.sendCustomCommand("UPDATE_COOKIES", args, null);
- Service端接收并更新Cookie:
在PlaybackService的MediaSession中添加回调:
mediaSession.setCallback(new MediaSession.Callback() { @Override public void onCustomCommand(@NonNull SessionCommand command, @NonNull Bundle args, @NonNull ResultCallback resultCallback) { if ("UPDATE_COOKIES".equals(command.customAction)) { List<Cookie> updatedCookies = args.getParcelableArrayList("UPDATED_COOKIES"); if (updatedCookies != null) { cookieJar.updateCookies(updatedCookies); } resultCallback.sendResult(null); } } });
内容的提问来源于stack exchange,提问作者junep
相关产品推荐
相关产品推荐

