はじめに
もうタイトル通りそのまんまのトラブルなんですが、意外と原因特定に手間取りました
概要
アプリのWebviewで表示しているWebページが、Android 9だけ表示されないという状況です。何も表示されず画面が真っ白になります。Android 10以降は何の問題もありません。
いったんWebページが表示されたあとに真っ白になるならJavaScriptとかの問題かなという気がしますが、今回は最初から何も表示されません。状況的にWebサイトのSSL証明書あたりでトラブってるんじゃないか? というのが社内での最初の見立てでした
実際にそのWebサイトのSSL証明書を調べてみたら最近更新されていて、発行元のサイトに載っている対応情報を見るとAndroid 10以上対応となっていました。これはSSL証明書の問題ってことで終了…と思ったのですが
Android 9の標準ブラウザ(Chrome) では表示される
ところが、Webviewで表示されなくなっているWebサイトを標準ブラウザのChromeで開いてみると、Android 9には非対応のSSL証明書を使ったサイトのはずなのに何の問題も無く表示されるのです。
はて、非対応と書かれてたのは何だったのか。標準ブラウザで表示されるなら、証明書の問題ではないってことなんだろうか…
正直、ちょっとなに言ってるかわからない状況でしたが、よくよく調べていくとChromeでも開ける場合とWebview同様に真っ白になる場合があるパターン、どっちも起きていることがわかりました。ますますわからん…
Chromeのアップデートでルート証明書も追加・更新される
実はさらに詳しく調べていくと、Chromeで開けない場合であっても、どうやらChrome自体をGooglePlayでアップデートすれば開けるようになることがわかりました。
これがわかったとき、やっぱり証明書が原因っぽいなと思いました。
今回の件で怪しいと睨んでいたこの手のSSL証明書は、それが信頼していいものか確認するために「中間証明書」とか「サーバ証明書」といったものを使うのですが、そもそもの信頼性を担保する一番起点となるものとして「ルート証明書」というものがあります。
このルート証明書は一般的にOSに組み込まれる形で内部に保存されていて、簡単には追加できないようになっています。まあ、信頼の起点ですから。
これがOSのアップデート時とかに追加・更新されたりするんですが、実はブラウザ自体にも追加でルート証明書を持っている場合があります。
ここからはちょっと推測入ってきますが、Chromeをアップデートすることで表示されなかったサイトが表示されるようになったのは、アップデート時にブラウザが持っているルート証明書が更新されたおかげである可能性が高いように思います。
証明書自体はAndroid 10以降対応とされていましたが、これはルート証明書がOSに組み込まれているかどうかを指しているのだと思います。このルート証明書がChromeのアップデートによってブラウザに追加されればOSのバージョンとは関係なくWebサイトは問題なく表示されるようになるはずなので、アップデートによってそれが起こったと考えるのが一番自然です。
僕がやはり証明書が原因っぽいと思ったのはこれが理由です。
WebviewはOSのルート証明書しかみていない
Chrome自体がアップデートされることでルート証明書が追加されるようだ、ということはわかりましたが、同時にAndroid 9のWebviewはその恩恵を受けることができないようだということもわかりました。
あくまでブラウザにルート証明書が追加されただけで、OSが持っているルート証明書には変化がないからなのでしょう。
実際、Android 9でChromeをアップデートして表示されなかったWebサイトが表示されるようになっても、アプリのWebviewでの表示は真っ白なままで何の変化もありませんでした。
開発チームにお願いして確認してもらったところ
SslError.SSL_UNTRUSTED
といった感じで「SSLの証明書が信頼できない」というエラーが出ていたようで、さらに端末にインストールされているルート証明書を確認したところAndroid 10以降には入っているルート証明書がAndroid 9には入っていないことも確認できたので、見立てに間違いはなさそうです。
こうなると対処法はWebサイトのSSL証明書をAndroid 9に対応したものに戻してもらうしかありません。
Android 10以降では起きない(かもしれない)
ここまでの結果を踏まえると、この先も同じような問題は定期的に発生しそうな感じがしますが、実はこれAndroid 10以降では起きないかもしれません。しらんけど。
AndroidのWebviewは「AndroidシステムのWebview」という名前で、個別のアプリとして登録されています。GooglePlayにも出てきますし、アップデートがかかっていることもあるので見たことある方もいるんじゃないでしょうか。
実はこのようにWebviewが独立したアプリになっているのはAndroid 5〜6とAndroid 10以降で、Android 7〜9の頃だけWebviewの機能自体がChrome for Androidに統合されていました。
Chromeと統合されているならルート証明書もChromeと共有してて欲しいところですが、そこはそうはなっていなかったようです。
正直なんでやねんと思いましたが、この頃のWebviewはChromeと統合されていながらもシステム的にはChrome自体を無効にすることもでき、その場合は内部的に持っている「AndroidシステムのWebview」が自動で有効になったようです。
というより、そもそもAndroidは標準ブラウザを切り替えられる仕様です(iOSが切り替えられるようになったのはわりと最近)。この時期に発売されていたGalaxy S10(Android 9)の標準ブラウザはChromeではなくSamsungのブラウザですし、超小型で話題になったRakuten Mini(Android 9)も発売後にRakuten Browserが提供され、デフォルトのブラウザに切り替える方法がアナウンスされています。
このように標準ブラウザ自体が簡単に変更できるOS事情を考えると、Webview機能がChromeに統合されても証明書周りはOS依存させておかないとダメな感じがします。その結果、Android 7〜9はOS自体がルート証明書を追加してくれないとダメということになってしまったんじゃないかと。
しかし最新版がAndroid 14というこのご時世にそんな更新がされることは期待できないので、ここで完全に手詰まりです。さっきも書いたとおり、Android 9に対応する証明書に戻すしか手がありません。
ですが、Android 10以降はアプリとしてWebviewが独立しているので、もしかしたらChrome同様にアップデートすることでルート証明書を追加することができるかもしれません。しらんけど。(調べてないので)
さいごに
アプリの対応OSについてはAndroid SDKの更新やらでみなさん普段から気を遣ってると思いますが、Webサイト側の担当者にもアプリ対応バージョンに合わせた運用を心がけてもらわないと、こういう事態が起きることもあるという話でした。
Android 9もそろそろ足切りされるタイミングになってきてるので、この記事がお役に立てるのも、あと1年あるかないかってところかもしれませんが、お役に立てば幸いです