Chromium和百度网盘

起因:

  • 因为最近接触了一下大屏幕Android设备相关的浏览器的事情,所以碰到了在Android设备上,浏览器打开百度网盘,无法播放视频的问题。
  • 事实上这种场景应该确实也相对较少,毕竟Android基本上都会考虑安装客户端版本。
  • 但是大屏幕设备的客户端版本吧,UI适配的相对没这么好。
  • 有的大屏幕设备,甚至Web页面的效果可能会更合适一下。
  • 那就来看看为什么不能播放吧。

结论:

  • 试了一圈,把chrome的公版122的内核,在小米、华为的手机上,都安装了一份,切到PC版本的百度网盘上。发现就是播放不了。
  • 看样子,这应该不是个例问题,应该是chromium在Android设备上,就是无法在Web端PC版直接播放视频。
  • 源码跟一下吧。

MediaPlayer和Chromium

  • 从系统log看了一下,百度网盘播放(PC Web)尝试播放视频的时候,在Android上,遵循的是MediaPlayer桥。

MediaPlayerBridge

  • 路径:

    • media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
    • 这个是Android平台,处理内核的播放业务和Android系统的MediaPlayer的桥接层。基本的用法就是把播放转换给了系统的MediaPlayer。了解MediaPlayer的同学,看一眼这个Java文件就知道内核调用原生的播放能力是怎么实现的了。
    • 按理说这是一个非常完善的路径了才对。
  • 问题:

    • 跨域重定向
@CalledByNative
    protected boolean setDataSource(
            String url, String cookies, String userAgent, boolean hideUrlLog, HashMap headers) {
        Uri uri = Uri.parse(url);
        HashMap<String, String> headersMap = new HashMap<String, String>();
        if (hideUrlLog) headersMap.put("x-hide-urls-from-log", "true");
        if (!TextUtils.isEmpty(cookies)) headersMap.put("Cookie", cookies);
        if (!TextUtils.isEmpty(userAgent)) headersMap.put("User-Agent", userAgent);

        headersMap.put("android-allow-cross-domain-redirect", "0");//这里,在交给MediaPlayer之前,增加了一个header
    	//字面意思应该是仅用了跨域名重定向。
    	//我去分析过百度网盘的一些播放链接,看样子是涉及到跨域重定向了,所以MediaPlayer会产生播放错误。

        headers.forEach(
                (key, value) -> {
                    if (!TextUtils.isEmpty(value.toString())) {
                        headersMap.put(key.toString(), value.toString());
                    }
                });

        try {
            getLocalPlayer().setDataSource(ContextUtils.getApplicationContext(), uri, headersMap);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

Android侧

  • Android侧针对这个“android-allow-cross-domain-redirect”的处理,在如下路径:
  • frameworks/base/media/java/android/media/MediaHTTPConnection.java
  • 其实就是一个非常简单的boolean控制:
if (!mAllowCrossDomainRedirect && !sameHost) {
    throw new NoRouteToHostException("Cross-domain redirects are disallowed");
}

// handle redirects ourselves if we do not allow cross-domain redirect
mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect);

解决方案

  • 所以综上,如果想要实现跨域播放,那最根本的方式,可能得改动一下Chromium的内核代码,把flag换成1。
  • 或者修改Android系统的MediaHTTPConnection的处理,强制允许跨域重定向。
  • 我更倾向于前者吧。

 评论