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的处理,强制允许跨域重定向。
- 我更倾向于前者吧。