Bitmap.getWidth() on a null object reference at webview.getDefaultVideoPoster

分析

遇到这样一个 bug:

java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
       at com.android.webview.chromium.WebViewContentsClientAdapter.getDefaultVideoPoster(WebViewContentsClientAdapter.java:657)
       at org.chromium.android_webview.DefaultVideoPosterRequestHandler$$Lambda$0.run(Unknown Source:2)
       at android.os.Handler.handleCallback(Handler.java:808)
       at android.os.Handler.dispatchMessage(Handler.java:101)
       at android.os.Looper.loop(Looper.java:166)
       at android.app.ActivityThread.main(ActivityThread.java:7425)
       at java.lang.reflect.Method.invoke(Native Method)
       at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)

分析:

从 log 看出和 getDefaultVideoPoster 方法有关,查看
WebChromeClient.getDefaultVideoPoster:

/**
 * When not playing, video elements are represented by a 'poster' image. The
 * image to use can be specified by the poster attribute of the video tag in
 * HTML. If the attribute is absent, then a default poster will be used. This
 * method allows the ChromeClient to provide that default image.
 *
 * @return Bitmap The image to use as a default poster, or null if no such image is
 * available.
 */
public Bitmap getDefaultVideoPoster() {
    return null;
}

按注释所述,当 WebView 显示视频时,如果 <video> tag 中没有 poster 属性,该方法就会调用,显示一个默认占位图。该方法默认返回 null,如果没有重写,调用时获取到的就是 null,再直接调用 bitmap.getWidth(),就会产生空指针。

解决方案:
重写 WebChromeClient:

// 视频未播放时的默认图
public Bitmap getDefaultVideoPoster() {
   if (mClient.getDefaultVideoPoster() == null) {
       return BitmapFactory.decodeResource(ODApplication.getODApp().getResources(), R.drawable.ic_shortcut);
   } else {
       return mClient.getDefaultVideoPoster();
   }
}

参考链接
https://bugs.chromium.org/p/chromium/issues/detail?id=521753#c8
https://blog.****.net/SCHOLAR_II/article/details/81330403

验证:

使用(小米mix2,8.0)、(华为mate20,9.0)、(vivo X7 plus,5.1.1) 验证,效果相同。

查看有 poster 属性的 html 显示

<html>
   <body>
       <video  src="https://qiniu-video9.vmoviercdn.com/5c91f3027033b.mp4" controls="controls"
           poster="http://img.zcool.cn/community/[email protected]_1l_2o_100sh.jpg">
       </video>
   </body>
</html>

这样一个 html,在 chrome 上可以看到 poster:Bitmap.getWidth() on a null object reference at webview.getDefaultVideoPoster
在手机 WebView 上也能看到:
Bitmap.getWidth() on a null object reference at webview.getDefaultVideoPoster
当不设 poster,即

<html>
   <body>
       <video  src="https://qiniu-video9.vmoviercdn.com/5c91f3027033b.mp4" controls="controls">
       </video>
   </body>
</html>

这样一个 html,在 chrome 上可以看到显示视频的第一帧:
Bitmap.getWidth() on a null object reference at webview.getDefaultVideoPoster
在手机 WebView 上看到的一个播放按钮:
Bitmap.getWidth() on a null object reference at webview.getDefaultVideoPoster
两种情况下 getDefaultVideoPoster 都没有调到。所以,无法验证问题是否解决。????