Help us understand the problem. What is going on with this article?

targetSdkVersion 28 + Android 9.0からはWebView内にRGBAのカラーコードが書けるようになった話

More than 1 year has passed since last update.

2019年8月になったので、Google Playに新規アプリをリリースする際のtargetSdkVersionを28以上にしないといけないやつが始まりました。既存アプリのアップデートも、11月から同様の措置が入るので、そろそろ対策しておきたいですね。

そんなわけで、API Level 28って新しく何が入ったんだっけ、と確認してみました。

フォアグラウンドサービスにパーミッションが必要になったり、Apache HTTPクライアントのサポートが本格的に終了したりと、既存の実装次第ではアレしそうなものもいくつか見当たります。

WebViewでカラーコードの判定が変わる

読んでいく中で、ふと目についたのが「CSS RGBA 16 進値の処理」という項目です。

Android 9 以降をターゲットとするアプリでは、4 桁および 8 桁の 16 進数 CSS 色を扱うために、ドラフトの CSS Color Module Level 4 で策定された動作を有効にする必要があります。
CSS Color Module Level 4 は、Chrome 52 からサポートされていますが、現在は WebView で無効になっています。これは、既存の Android アプリが Android のバイト順(ARGB)で 32 ビットの 16 進数色を含み、レンダリング エラーを引き起こす可能性があると判明したためです。
たとえば現在、API レベル 27 以前をターゲットとするアプリにおいては、WebView#80ff8080 という色が不透明のライトレッド(#ff8080)にレンダリングされます。 先頭のコンポーネント(Android ではアルファ コンポーネントとして認識される)は現在、無視されます。 一方、API レベル 28 以降をターゲットとするアプリの場合、#80ff8080 は、透明度が 50% のライトグリーン(#80ff80)として認識されます。

CSS Color Module Level 3までは、カラーコードを4桁ないし8桁で表現して、アルファ値を指定する方法がありませんでした。Level 4では #80ff8080 のようなRGBA表記もサポートされるということですね。

Android 9 以降をターゲットとするアプリでは、4 桁および 8 桁の 16 進数 CSS 色を扱うために、ドラフトの CSS Color Module Level 4 で策定された動作を有効にする必要があります。

上記の通り、Android 9.0のWebViewでは、CSS Color Module Level 4の挙動でカラーコードが表現できるようになったようです。

さて、それだけなら話はシンプルなのですが、その後ろにごちゃごちゃと書いてある内容が気になります。

Androidのカラーコード判定はARGB

Androidはカラーコードを色指定に利用することができますが、アルファ値を含める場合の表記がARGB(#aarrggbb)になっています。もし textView.setTextColor(Color.parseColor("#80ff8080")) のようなコードでテキストに色を付けた場合、透明度50%の #ff8080 で彩色されます。

この辺の挙動が嫌な感じでAndroid ChromeのLevel 4対応とぶつかったのか、API Level 27以前はRGBA対応が無効化されていたそうです。

CSS Color Module Level 4 は、Chrome 52 からサポートされていますが、現在は WebView で無効になっています。これは、既存の Android アプリが Android のバイト順(ARGB)で 32 ビットの 16 進数色を含み、レンダリング エラーを引き起こす可能性があると判明したためです。
たとえば現在、API レベル 27 以前をターゲットとするアプリにおいては、WebView#80ff8080 という色が不透明のライトレッド(#ff8080)にレンダリングされます。 先頭のコンポーネント(Android ではアルファ コンポーネントとして認識される)は現在、無視されます。

先頭のアルファ値が無視されるという話はちょっと怪しい(後述)のですが、ひとまずアルファ値が付いているカラーコードは意図しない挙動をもたらすということで、無視する方針になったようです。

Web準拠のカラーコードが使えるようになる

API Level 28では、Chromeの間での折衝が済んだのか、WebViewでLevel 4準拠のカラーコードが使えるようになったそうです。

一方、API レベル 28 以降をターゲットとするアプリの場合、#80ff8080 は、透明度が 50% のライトグリーン(#80ff80)として認識されます。

喜ばしいことですね。

検証する

たとえば現在、API レベル 27 以前をターゲットとするアプリにおいては、WebView#80ff8080 という色が不透明のライトレッド(#ff8080)にレンダリングされます。 先頭のコンポーネント(Android ではアルファ コンポーネントとして認識される)は現在、無視されます。

上記の挙動が本当に発生するのか疑わしかったので、実際に動かしてみました。

targetSdkVersionが27と28のappモジュールをそれぞれ作成し、TextViewの挙動とWebViewの挙動が比較できる、次のような画面をそれぞれに配置しました。

MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val webView = findViewById<WebView>(R.id.webview)
        val html = """
            <html>
                <body>
                    <span style="color: #80ff8080;"><b>#80ff8080</b></span>
                </body>
            </html>
        """.trimIndent()
        webView.loadData(html, "text/html", "utf-8")
    }
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="16dp"
        tools:context=".MainActivity">

    <TextView
            android:text="API28 or 27"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" android:id="@+id/textView"
            android:textAppearance="@style/TextAppearance.AppCompat.Display1"/>

    <TextView
            android:text="TextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" android:id="@+id/textView1"
            android:textAppearance="@style/TextAppearance.AppCompat.Headline"/>

    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="#80ff8080"
            android:textColor="#80ff8080"
            android:textStyle="bold"/>

    <Space android:layout_width="match_parent" android:layout_height="16dp"/>

    <TextView
            android:text="WebView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" android:id="@+id/textView2"
            android:textAppearance="@style/TextAppearance.AppCompat.Headline"/>

    <WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="64dp"/>

</LinearLayout>

これらをAndroid 8.1(API Level 27)とAndroid 9.0(API Level 28)のエミュレータで、それぞれ動かします。

※あまり影響しなさそうですが、minSdkVersionは27で共通です。

Android 8.1エミュレータ

まずは、Android 8.1での挙動です。ドキュメントに沿うならば、targetSdkVersion 27のほうが「不透明のライトレッド(#ff8080)にレンダリングされ」るはず?です。

targetSdkVersion 27 targetSdkVersion 28
スクリーンショット 2019-08-02 12.30.29.png スクリーンショット 2019-08-02 12.30.12.png

TextViewに関しては、意図したとおり透明度50%の #ff8080 が表示されています。

WebViewに表示したほうは、気持ちいいくらいに無視です。

現在は WebView で無効になっています。

という記述とは矛盾しませんが、

たとえば現在、API レベル 27 以前をターゲットとするアプリにおいては、WebView#80ff8080 という色が不透明のライトレッド(#ff8080)にレンダリングされます。 先頭のコンポーネント(Android ではアルファ コンポーネントとして認識される)は現在、無視されます。

こちらの記述とは矛盾しているような気がします。

Android 9.0エミュレータ

次に、Android 9.0での挙動です。こちらはtargetSdkVersion 28のWebViewで色が付いてくれることを期待します。

targetSdkVersion 27 targetSdkVersion 28
スクリーンショット 2019-08-02 12.40.36.png スクリーンショット 2019-08-02 12.38.53.png

問題なく、期待通りの挙動をしました。

気をつけるべきこと

API Level 27以下のデバイスでは、8桁表記のカラーコードがそもそも無視されているような挙動になりました。ドキュメントとは矛盾気がしますが、まあもともと使えなかったと考えれば、保守性の観点では問題がなさそうです。

どちらかというと、今後「RGBAカラーコードが使えるようになったWebView」を使ってハイブリッドアプリを開発していく場合が心配です。WebView向けにはWeb標準に沿ってRGBA表記のカラーコードをデザイナーさんが指定する機会が増えるはずですが、これをAndroidにそのまま指定すると意図しない色になってしまいます。

「Androidはカラーコードの解釈が特殊である」ということをチーム内で共有し、アプリ内に意図しない差異が生まれないよう、気をつけましょう。

余談

3桁と6桁だけとはいえ、カラーコードを``で囲むと色が付くの、Qiitaさんすごいですね。と思いながら社内のGitLabにも貼ってみたら、あちらはRGBAの8桁にも対応してて、こちらはもっとすごかったです。

スクリーンショット 2019-08-02 14.32.58.png

すごく読みやすい。

Nkzn
新潟で農業アプリとか作ってる怪しいAndroidの人
https://blog.nkzn.info
water-cell
地球人口100億の時代への農業革命をWebテクノロジで支える
https://water-cell.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away