見出し画像

Now in REALITY Tech #77 AndroidのTextでHTMLタグは使える?

こんにちは、Androidエンジニアのtkcです。
最近はFF16をプレイ中です。バトルがたのしい。

今回はAndroidにおけるHTMLタグの使用方法についてご紹介します。HTMLタグを使ってテキストを装飾する方法や、Composeでの対応状況について検証してみました。


先日、施策でこういう利用規約の部分だけリンクにしたいという話がありました。

よくみるこういうやつ

ComposeのTextでこれを再現しようとすると、AnnotatedStringを利用して

  • 文章を三分割して、利用規約に当たる部分をLink化

  • 利用規約に当たる部分だけを抽出してLink化

で再現できそうだなと考えました。
しかし、前者はこの一文のために文言リソースを三分割する必要があるのが面倒であり、
後者は「利用規約」に当たる部分を対応する言語分調べておく必要があるのでもっと大変です。(REALITYは12ヵ国語対応!)

どっちもあんまりやりたくない…

もっと良い方法ないかなーと考えていたところ、iOSはmarkdownをテキストに反映できるらしいという話を聞きました。

Androidにも同様のものはあるのかな?と思って調べてみたところAndroidはHTMLのタグを使ったテキストの装飾ができるようです。

ですが、読んでいくとこれはxmlのTextView前提の話であり、
ComposeのTextは標準では対応していないようです。

なので、どうしてもHTMLタグを使いたい場合は、
ComposeのAndroidViewでTextViewを使うことで再現できます。

<resources>
    <string name="tagged_text"><a href="https://reality.app">REALITY</a>へようこそ!!!!!</string>
</resources>
AndroidView(
    factory = {
        TextView(it).apply {
            setText(R.string.tagged_text)
            // LinkMovementMethodを指定しないと<a href="https://~~~"> を指定してもクリックに反応しない
            movementMethod = LinkMovementMethod.getInstance()
        }
    },
)
クリックで外部ブラウザでリンクが開く!

調査する上でハマった点として、
TextViewに直接setTextしない場合(Context.getText()を使う場合など)はタグが削除されます。
その上でHtml.toHtml()を使いたい場合などは、リソース側でタグをHTMLエスケープする必要があります。
具体的には下記のようにする必要があります。

<resources>
    <string name="tagged_text">&lt;a href="https://reality.app">REALITY&lt;/a>へようこそ!!!!!</string>
</resources>
val text: String = getString(R.string.tagged_text)
val styledText: Spanned = Html.fromHtml(text, FROM_HTML_MODE_LEGACY)

AndroidView(
    factory = {
        TextView(it).apply {
            setText(styledText)
            // LinkMovementMethodを指定しないと<a href="https://~~~"> を指定してもクリックに反応しない
            movementMethod = LinkMovementMethod.getInstance()
        }
    },
)

ここまでで紹介したように、
技術的にはTextViewを使うことで文言リソースにHTMLタグを記述してテキストを装飾することが可能です。

一方で、

  • ComposeのTextはHTMLタグに対応しておらず、後方互換のAndroidViewを使う必要がある

    • REALITYのAndroidチームでは現在推進しているUIのCompose化に逆行してしまう。

  • Androidの実装によってはHTMLエスケープをする必要がある

    • REALITYではstring.xmlを管理しているのはエンジニアではないため、HTMLのエスケープを使う必要があったりすることで運用の難易度が高まる。

  • 多言語対応している場合は、各リソースごとにタグを設定する必要がある

    • 各言語に正しくタグを設定するのも、想定通りに装飾できているかの確認も大変。

などの問題点があることがわかってきました。

運用の難しさをクリアできるのであれば導入しても良いのかもしれないですが、ComposeのTextでまだ対応されていないことを考えると、無理して導入するにはデメリットが大きいかもしれないなという結論になり、一旦は文中をリンクしないデザインを作ってもらうことになりました。

このようなレイアウトを作ってもらった

まとめ

  • TextViewはHTMLタグを使ってテキストの装飾ができる。

  • Composeで画面を作っている場合はAndroidViewを使うことで利用可能。

  • HTMLタグを使ったリンク化は文言リソースを三分割したりと面倒なことをせずとも文中の特定の単語のリンクが作れる。

  • 一方で、運用が難しくなるなどのデメリットも少なくはない。

私はこれまでHTMLタグをAndroidクライアントで使うという発想をしたことがなかったため、TextViewでは簡単にHTMLタグが使えることを知りませんでした。
もともと知っている人からすると、単純にTextViewはHTMLタグに対応しているというだけの話だったのですが、最近はもっぱらComposeで画面をつくっており、現在のAndroid開発環境ではどう扱うべきかを考えるよい機会となりました。