LoginSignup
11
2

More than 3 years have passed since last update.

Android Target29に設定するとWebViewで#以降が表示されない

Posted at

こんばんは

タイトル通りなのですが、AndroidのtargetSdkVersionを29(Android10において後方互換モードでない設定)を設定すると、#文字以降が表示されなくなる問題があります。

再現するコード

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

        WebView.setWebContentsDebuggingEnabled(true)

        val html = """
            <html>
                <body>
                    <style>
                     #red { color:red; }
                    </style> 
                    <div id="red">ああああ</div>
                </body>
            </html>
        """.trimIndent()

        webview.loadData(html, null, null)
    }
}

わざわざ掲載するほどではありませんが、レイアウトxmlです

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <WebView
        android:id="@+id/webview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

実行結果

失敗例

本来であればcssのstyleにてidセレクタのredに指定されているので、
赤い「ああああ」が表示されるはずなのですが、表示されません。

Inspectionで中身を見た結果

Screen Shot 2020-06-21 at 15.45.05.png
空のstyleタグのみが残っています。。。
Chromeの検査ツールは不完全なHTMLがあると、勝手に終了タグを補完するので、
#redの#が解釈できずにそれ以降が存在しないものとして扱われるのだろうと推測しています。

なぜなのか

https://issuetracker.google.com/issues/141625552
Googleのissuetrackerでの発言にヒントがありました。

"For all other values of encoding (including null) it is assumed that the data uses ASCII encoding for octets inside the range of safe URL characters and use the standard %xx hex encoding of URLs for octets outside that range. See RFC 3986 for more information. Applications targeting Build.VERSION_CODES.Q or later must either use base64 or encode any # characters in the content as %23, otherwise they will be treated as the end of the content and the remaining text used as a document fragment identifier."

話題のDeepL翻訳

"エンコーディングの他のすべての値(nullを含む)については、データは安全なURL文字の範囲内のオクテットにASCIIエンコーディングを使用し、その範囲外のオクテットにはURLの標準的な%xxの16進数エンコーディングを使用すると仮定されています。詳細はRFC 3986を参照してください。Build.VERSION_CODES.Q 以降をターゲットにしたアプリケーションは、base64 を使用するか、コンテンツ内の # 文字を %23 としてエンコードしなければなりません。

要するに「安全なURL文字の範囲内のオクテットにASCIIエンコーディングを使用し、」の安全なURL文字の範囲に#が引っかかるということでしょうか。

対応方法

発言で述べられている通り、base64化するか、#を%23に置き換えましょう。

Base64化の例

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

        WebView.setWebContentsDebuggingEnabled(true)

        val html = """
            <html>
                <body>
                    <style>
                     #red { color:red; }
                    </style> 
                    <div id="red">ああああ</div>
                </body>
            </html>
        """.trimIndent()

        val base64version: String = Base64.encodeToString(html.toByteArray(), Base64.DEFAULT)
        webview.loadData(base64version, null, "base64")
    }
}

※importはandroid.util.Base64のものを使用しています。

#を直接%23に置き換える例

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

        WebView.setWebContentsDebuggingEnabled(true)

        val html = """
            <html>
                <body>
                    <style>
                     #red { color:red; }
                    </style> 
                    <div id="red">ああああ</div>
                </body>
            </html>
        """.trimIndent()

        val replace = html.replace("#", "%23")
        webview.loadData(replace, null, null)
    }
}

無事、表示されました。:ok_hand:
成功例

11
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
2