🖍️

iOSカスタムキーボードにMarkedTextを導入した

2022/11/11に公開約3,000字

これまで度々、iOSカスタムキーボードにMarkedTextを導入しないほうがいい、と書いてきました。
https://qiita.com/ensan_hcl/items/1f1a327ce3050aad47b5
https://zenn.dev/en3_hcl/articles/896fb7b52bf13b

が、自前のキーボードアプリで最近導入しました。

https://twitter.com/azooKey_dev/status/1587293355645538306

使わないほうがいいと書いたにもかかわらず自分は導入した、というのも筋が通らないので、導入に至った経緯を書いていきます。

背景

MarkedTextはiOSの日本語の標準キーボードに用いられている「背景に色がつく文字列」です。この機能はサードパーティー製のカスタムキーボードにも導入されており、setMarkedTextというAPIを介して操作が可能になっています。

不具合

しかし、setMarkedTextは挙動が非常に、非常に不安定です。例えば、この関数を介して作成したMarkedTextは、「テキストをタップすると表示されなくなる」という不具合があります。この不具合は導入当初からずっと治っていません[1]

こうした不安定な挙動をそのままユーザに提供する、というのは、一般的には正当化できません。たかだか色がつくだけの機能のためにここまでの不具合を許容するのはナンセンスです。そのため、これまでの記事でsetMarkedTextに触れる際には不具合の詳細を伝えつつ「導入しないほうがいい」と書いていました。

転機

しかし、しばらく開発を続けるうちに「MarkedTextがあったほうが良い場面」があることが明らかになってきました。その1つが、改造の施されたテキストフィールドにおける入力です。

そもそも、カスタムキーボードアプリにおいて、入力の管理は難所の1つです。基本的にはアプリケーションの内部状態をテキストフィールドに反映させれば良いのですが、主にAPIが貧弱なためにさまざまな困難があります。標準的なテキストフィールドに対応するだけでもかなり大変です。

一方、テキストフィールドはさまざまな目的で改造されます。例えばSlackのカスタム絵文字やLINEのLINE絵文字は対応のため何かしら複雑なことをしているはずです。
そのなかでも「マジかよ」となったのがWeb版のScrapboxのテキストフィールドです。詳しい実装まではわかりませんが、絵文字対応どころではなく、おそらくカーソルやテキスト選択までもが独自実装になっています。謎技術。

そういう入力欄だと、「カーソル前後の文字列を見て操作する」というようなカスタムキーボード側のロジックが崩壊し、しっかりバグります。そこでMarkedTextです。

MarkedTextの利点は、単に色をつけることにとどまりません。その内部は外部からある意味で「保護」されていて、MarkedTextに入っている文字列はプログラムで指定した値と確実に一致する、という保証があります。このことにより、改造されているテキストフィールドであっても、MarkedTextで包んでいる間は適切な処理が可能になります。

また、iOSの標準キーボードが使う方式なので、改造テキストフィールド側も当然対応している、という期待が出来ます。実際、MarkedTextベースの入力ロジックを作ってみると、完璧ではありませんが[2]、ずっとマシな動作をします。

こういう怪しい挙動の発生するテキストフィールドが世の中に結構ある、というのが最近の発見でした。存外にそのようなテキストフィールドが多く、MarkedTextによってそれらにも対応できるのであれば、MarkedTextの不具合は許容できるトレードオフ、ということになります。そこでMarkedTextをオプションでオンにする機能を導入することにしました[3]

機能の説明は非常に悩みました。「入力中のテキストを強調」とか「入力中の背景に色をつける」とすると、単に色をつけたい目的での利用が発生する可能性があります。もちろん色がつくのですが、不具合が避けられないことを考えるとあまりそれだけのためには使ってほしくありませんでした。今回は機能のそもそもの目的から「入力中のテキストを保護」と名付けました。
また、「試験版」と書くことでこちらからはどうしようもない不具合をある程度許容してもらうことを狙っています。

導入してみて

しばらく使ってみると、許容できないと思っていた不具合が案外問題でないことに気づきました。例えば入力中にテキストをタップしたら消えるとしても、実際の使用時にテキストをタップすることはあまりありません。MarkedTextが消えない、といった不具合も、見た目が少し悪くなるだけと考えれば耐えられないものではありません。

一方、MarkedTextと相性が悪いテキストフィールドというものもあることにも気づきました。例えばSlackのテキストフィールドは標準キーボードで日本語を打っているとしばしば不具合が起こります。これは海外製アプリで顕著で、Instagramで濁点が打てなくなった問題と本質的には同根のものではないかと思います。
https://zenn.dev/yuki0n0/articles/6b4370edda4735

とはいえ、総合的に見て、ほとんどの場面においてMarkedTextが使われていても不便さを感じることはありませんでした。また、色がついて見やすい、という利便性も案外無視できないと感じました。

もう1つ、このMarkedTextのAPIをカスタムキーボード経由で使うユーザが増えれば、Apple側もいよいよ真面目に不具合を修正してくれる可能性があります。そういう意味で搭載しておいてもいいかもしれません。

結論

MarkedText、案外悪くなかったです

もちろん不具合は色々あるので、MarkedText一本での実装は引き続きオススメできません。しかしMarkedTextなしでの入力に加えてのオプションとしては、アリな機能だと考えられると思うようになりました。

脚注
  1. (正確には、iOS14のどこかのバージョンと、iPadOSの一部のバージョンで治っているのですが、治ったり壊れたりしています) ↩︎

  2. 実は標準キーボードでも、カーソル移動は完全に壊れています。例えば、「」を打った際に中央にカーソルが移動するのが標準的な挙動ですが、Web版のScrapboxでは動作しません。 ↩︎

  3. 実装上の難関として、MarkedTextベースの入力マネージメントと、生テキストベースの入力マネージメントはかなり勝手が違います。この2つを統合して処理するプログラムを書くのは非常に骨が折れました。 ↩︎

Discussion

ログインするとコメントできます