You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 14:55:19