2012年8月27日月曜日

Android WebView で https のサイトにアクセスして白画面になるのを避ける方法

追記:
指摘が多かったので書いておきます。勝手にSSLの証明書検証をスキップするアプリはセキュリティホールのあるアプリとして扱われるので注意してください。
標準のブラウザのようにダイアログを出したり、アプリでアクセスを許可しているドメインかどうかチェックしたりするべきでしょう。
あと、この方法を格別オススメしているわけではありません。あくまで対処法です。あしからず。



WebView で https で提供されている URL のサイトにアクセスしようとしたとき、証明書がオレオレ証明書だったり、Android にデフォルトで入っている信頼済証明書機関(trusted certificate authorities)に入っていない場合 SSL のエラーが発生し、処理がキャンセルされ white screen / empty screen (つまり真っ白画面)になります。

例えば、いくつかの CA root certificates は Gingerbread 以前には入っていません。
Issue 10807: Root Certificates missing from Android root store

Android 2.2 以降の標準ブラウザでこの URL にアクセスしようとすると、次のような確認ダイアログがでます。



ここで Continue ボタンをクリックすると、エラーを無視してそのまま読み込みます。

デフォルトで WebView にセットされている WebViewClient では、 onReceivedSslError() の中で処理をキャンセルしているため、white screen になります。
つまり、先のダイアログでキャンセルを押した場合の動作がデフォルトになっているということです。

http://tools.oesf.biz/android-2.3_r1.0/xref/frameworks/base/core/java/android/webkit/WebViewClient.java#180
  1. 180     public void onReceivedSslError(WebView view, SslErrorHandler handler,  
  2. 181             SslError error) {  
  3. 182         handler.cancel();  
  4. 183     }  


常に Continue を押したときの動作にしたい場合は、この onReceivedSslError() をオーバーライドして handler.proceed() を呼ぶようにします。こうすれば、エラーを無視してそのままページを読み込むようになります。

  1. class CustomWebViewClient extends WebViewClient {  
  2.     public CustomWebViewClient() {  
  3.         super();  
  4.     }  
  5.   
  6.     @Override  
  7.     public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {  
  8.         handler.proceed();  
  9.     }  
  10. }  
  11.   
  12. @Override  
  13. public void onCreate(Bundle savedInstanceState) {  
  14.     super.onCreate(savedInstanceState);  
  15.   
  16.     mWebview = new WebView(this);  
  17.     mWebview.setWebViewClient(new CustomWebViewClient());  
  18.     mWebview.setWebChromeClient(new CustomWebChromeClient());  
  19.   
  20.     setContentView(mWebview);  
  21.   
  22.     String url = "https://www.library.city.kawasaki.jp/idcheck.html"  
  23.     mWebview.loadUrl(url);  
  24. }  


上記の対応は 2.2 以降に対してだけです。

2.2 より前のデバイスでは、標準のブラウザで読み込もうとしても次のようにエラー画面になって読み込めません。



残念ながら onReceivedSslError() は API Level 2.2 からなので 2.1 より以前では Override できません。
代わりに onReceivedError() が呼ばれますが、ここでは読み込みをそのまま進ませるということができません。
対処方法として http://damianflannery.wordpress.com/2010/09/28/android-webview-with-https-loadurl-shows-blankempty-page/ とかあるんですけど、4.0.1 のコードでやってもうまくいきませんでした。コメントみても解決してる人とだめな人がいて、あまりいい方法ではないようです。
どうしたものか。。。



0 件のコメント:

コメントを投稿