🫘

iOS向け日本語キーボードアプリ「azooKey」をOSSにした

2023/02/05に公開

2年半近く趣味として個人開発してきたiOS・iPadOS向けの日本語キーボードアプリ「azooKey」をオープンソース化しました。ライセンスはMIT Licenseです。

https://github.com/ensan-hcl/azooKey

azooKeyは2年前からApp Storeで無料で公開し、開発を続けてきました。日本語対応のiOS向けキーボードアプリには、Simeji、Flickなど多くの先輩がいますが、標準キーボード志向で高機能なOSSとしては初めてのものではないかと思います。

技術的な特徴

azooKeyの技術的特徴としては、変換エンジンの独自実装、ライブ変換のサポート、独自に調整した辞書、強力なカスタマイズ機能などがあります。

IME開発の特色は幅広い技術的課題を扱えることにあります。競プロ的なアルゴリズムとデータ構造の問題もあればNLP的な話やGUIのデザインの問題もあり、めっちゃ楽しいです。

なお、azooKeyは全てSwiftで実装されています。Appleのプラットフォーム以外ではマイナーな言語ですが、Windowsでも、一部のLinux系のOSでも動くはずです。iOSネイティブの開発者にとっては触りやすいプロジェクトになっていると思います。

変換エンジンとして

かな漢字変換の方法としてはMozcを参考にした「統計的かな漢字変換」と呼ばれる手法を用いています。さまざまな言語データからコストを推定し、変換に用いています。azooKeyでは入力に対して「ラティス」と呼ばれる構造を作り、Viterbiアルゴリズムによって単語ユニグラム(頻度)と品詞バイグラム(連接コスト)を合わせたコストを最小化するような候補を選択する手法を使っています。

下の図は「まにあいそうです」に対するラティスです。頻度が高いほどノードの色が濃く、連接コストが小さいほどノード同士を結ぶ辺が太くなります。Viterbiアルゴリズムを使うと、ラティスの上で最適な候補を効率よく選択することができます。


しかし、実際の入力時にいきなり「まにあいそうです」が入ってくることはなく、大体の場合「ま」「まに」「まにあ」「まにあい」「まにあいそ」「まにあいそう」「まにあいそうで」「まにあいそうです」と順に入力します。そこで前回の差分をうまく活用することで、さらに処理を最適化することが可能です。azooKeyでは以下のケースで差分を活用した計算を行います。

  • 入力末尾に1文字追加
  • 入力末尾にn≥2文字追加
  • 入力末尾からn≥1文字削除
  • 入力末尾からn≥1文字削除してm≥1文字追加 (ローマ字入力などで発生)
  • 入力先頭のn≥1文字を削除 (部分的に確定した場合などで発生)

アルゴリズムもパフォーマンスチューニングなどはまだまだ途上で、発展の余地がかなりあります。

変換エンジンというとかな漢字変換部分が派手で楽しいのですが、地味なのに辛い問題が入力管理です。あまりにも地味なので詳しくはドキュメントを見ていただければと思いますが、ローマ字→かなの変換は表面的な仕様以上に複雑で、英日入力の切り替えやカーソル移動などを含めて考えていくと目も当てられない難しさになってきます。この辺りは2、3回書き直してようやく多少まともになってきたところです。一方で、初めからスマートフォンでの利用を想定して開発したため、文節区切りの変更などデスクトップ環境で必要な機能はまだ実装していません。このおかげで多少入力管理が容易になっていると思っています。

入力管理の関連では、ライブ変換の実装があります。ライブ変換はmacOSで主に用いられていますが、モバイル環境への移植としてはおそらく唯一の実装ではないかと思います。ライブ変換には好みがありますが、個人的にはとても気に入っている機能です。
見た目にインパクトのある機能なのですが、実装上は実は入力管理の問題です。もちろんライブ変換に変換エンジンを最適化していくとまた変わってくるのだと思いますが、現在azooKeyのライブ変換は「一番いい完全一致の候補を入力中に表示する」というシンプルな構成になっています。

辞書データとして

辞書のライセンスはApache License Version 2.0です。NEologdとSudachiDictをベースとし、独自にエントリを追加し、コストを調整して用いています。独自のエントリには、新語、人名、絵文字、顔文字、単漢字、一般的だが漏れている語などが含まれます。追加エントリについてもApache License Version 2.0にしました。

プログラム上の取り扱いとしては、事前にトライをLOUDSとしてコンパイルした辞書ファイルを実行時に動的に読み込む形式をとっています。トライは「接頭辞木(prefix tree)」とも呼ばれ、辞書データの保存に適した木構造です。

LOUDSは「簡潔データ構造」と呼ばれるもので、ノードがn個あるトライの構造を2n+1ビット(ほとんど最低限の情報量に近い)で表現できる上に、検索が効率的に行えるという良いデータ構造です。そこでトライを構造を示すLOUDSのビット列とラベルの列に分解して保存することで、効率よく辞書データを圧縮することができます。

iOSのキーボードアプリではメモリの使用量を30MB程度に抑えないと動作が重たくなります。そこでLOUDSを用いることで、この厳しいメモリの制約を満たすレベルまでランタイムのメモリ使用量を減らすことができました。azooKeyではさらなる節約のため、事前に頭文字ごとに分割した辞書を必要に応じて少しずつ読み込んでいく方法をとっています。

ただし、辞書生成モジュールは完全にはOSS化しておらず、現状はコンパイル済みの辞書ファイルのみ配布している状態です。コンパイル用のソースコードなどについても将来的にはOSS化を目指したいです。

ソフトウェアキーボードアプリとして

標準キーボードをベースに利便性・拡張性を高める機能の追加を目指しています。ソフトウェアのキーボードであることを活かした拡張性の向上を重視しています。

大きな特徴としては「カスタムキー」というキーボード上の一部のキーをカスタマイズする機能を導入しています。また、「カスタムタブ」という異種レイアウトキーボードを動的に読み込む機能を備えており、さまざまな配列に対応することができるようになっています。

例えば、これは私がiPadで使っているカスタムタブです。フリックで利用する3つのキーボードを横に並べることで、1つのキーボード上で日本語・英語・数字・記号の入力が可能になっています。azooKeyではこうしたオリジナルの配列をアプリ内で自由に作成できるようになっています。

iPad向けのカスタムタブの画像

カスタムタブのAPIはCustardKitとして公開していて、プログラムを利用してカスタムタブを作成することも可能です。

また、一般的に見られる着せ替え機能やユーザ辞書といったカスタマイズ機能も実装済みです。

Keyboard Extensionとして

技術的には、iOS上のキーボードアプリはKeyboard Extensionという拡張機能の一種として実装されています。Keyboard Extensionにはさまざまな技術上の制約があるため、少し複雑な構成をとる必要があります。

例えば、Keyboard Extensionはそれ単体では配布できず、必ず本体となるコンテナアプリとセットで配布されなければなりません。扱いとしては別のプロジェクトになるため、ソースコードの共有なども工夫する必要があります。

UIについては、Keyboard Extensionの中でもかなり高度な処理を実装しています。Keyboard Extensionが利用可能なAPIは非常に限られているため、ここを頑張っているプロダクトはあまり多くありません。しかしazooKeyはそれらを適切に組み合わせることでデフォルトキーボードの代替となりうる操作感を実現しています。

また、前述のメモリの制限も厳しいものです。端末やOSによっても変わるようですが、Keyboard Extensionが使えるメモリは多くても70MB程度で、パフォーマンスに影響なく使えるメモリに制限するとたかだか30~40MB程度になります。これはUIの表示などで必要なメモリも含むので、アルゴリズムの実行には大体20~30MB使える、というような感覚です。

この辺りは本当にニッチな話が無限にあるので、そのうち記事にしたいと思います。

OSS化の背景

開発者は言語学と自然言語処理を学ぶ大学生です。大学一年生の夏から2年半にわたって、趣味と勉強(古典的な自然言語処理や日本語学など)を兼ねて個人で開発してきました。「個人で日本語入力を作っている大学生」という珍しさもあってか、色々な方に声をかけていただき、私生活にも良い影響がありました。インターンとして、TURINGという会社で自動車や自動運転に関わるエンジニアリングに取り組んだり、GoogleのGboardチームで「多様な文字を入力しやすくする」というプロジェクトに取り組んだりしました。azooKeyの開発で勉強を多少犠牲にした面があったのですが、やってきてよかったと思います。

Gboardチームでのプロジェクト成果の1つ

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

azooKeyの開発はこれまで完全にクローズドで実施してきていて、オープンソース化はほとんど意識してきませんでした。OSS化そのものに抵抗はなかったのですが、ソースコードの整理などが必要となるため、面倒でやってこなかったのです。「開発をやめる時はOSS化しようかな?」と漠然と思っていましたが、本当に開発をやめたくなったときにはOSS化の準備をすることも多分ないので、実現しなかったでしょう。

そんな中でazooKeyの公開から2年が経過し、最近は好意的なレビューや評価をもらうことが増えてきました。開発を止めることは全く考えていませんが、いろいろなレビューを読んだり機能リクエストをもらったりする中で、このまま完全にクローズドな状態で開発を続けるべきではないと思い、OSS化を決意しました。

開発の持続性

個人開発の持続可能性は大きな問題です。もしazooKeyの開発(不具合の修正等も含む)が停止すれば、それはユーザにとって大きな不利益になってしまいます。しかし私は大学生なので、そういう事態が起こる可能性はそれなりにあると考えています。

  • 忙しくなるリスク
    • 卒論
    • 院進
    • 就職
  • 金銭的リスク
    • Apple Developer Accountの契約のため毎年赤字が出ている(年1万円強)
  • モチベーションのリスク
    • 他に面白いことを見つけてしまう可能性
  • その他のリスク
    • 事故・事件・病気等

azooKeyのユーザは日々少しずつ増えています。大袈裟にいうと、ユーザの数はそのまま私一人がサポートするユーザの数ということです。「ユーザがほとんど知り合いのみ」という時期もあったのですが、今は見知らぬ誰かがazooKeyを使っています。突然メンテできなくなるのはやはり心が痛みます。

そこで、最低限「誰かが勝手に引き継げる」状況を整えておく必要があると考えました。

そのような状況を実現するには、単にソースを公開するだけではなく、それを再配布できる必要があります。これはOSSライセンスでしか実現できないと判断し、MIT Licenseを選択しました。これにより、もし今後何かあってメンテナンスが止まっても、(奇特な方がいれば)ユーザの方が勝手に再配布することができます。

日本語入力開発コミュニティへの貢献

日本語話者圏では、iOS・iPadOSに限らず、あらゆるプラットフォームで日本語入力が重要な問題になります。しかし、iOSのキーボードアプリはかなりの割合でMozcをベースにしています。Mozcは非常に優れた実装ですが、有名なSwiftラッパーが7、8年前のバージョンをフォークしていることもあり、古いバージョンのMozcが今でも利用されています。

日本語入力のソフトウェアとしてazooKeyがMozcよりも優れているとはもちろん言えませんが、iOS向けで変換エンジン・UI・辞書の3機能揃った実装としては唯一無二であり、新規に参入する際のベースとしても十分利用可能なクオリティだと考えています。Swiftで比較的小さく実装されているため、改造もしやすいはずです。azooKeyを公開し自由に利用可能にすることで、日本語入力の発展に何らかの形で貢献できれば、とても嬉しいことです。

個人の方でも企業の方でも、azooKeyを採用して何かの製品を作りたい場合はぜひご相談ください。

リファクタリングの動機付け

もともとOSS化にあたってやらないといけないと思っていたのが大規模なリファクタリングやテストの追加でした。azooKeyは私が「テスト」という概念を持っていなかった頃から開発を続けています。さまざまな事情でテストを導入しづらいコードになっていたことも災いし、テストの存在を知ってからも何だかんだprintデバッグで済ませてきたため、テストケースもほぼ存在しないプロジェクトになっていました。

しかし、放っておいてコードが綺麗になるわけもなく、デバッグもしづらい状態でダラダラと開発が続いてきました。

そこで、逆に「OSS化する」と決断することで、そこに向けて最低限コードを整える動機とすることにしました。OSS化を決意したのは公開2周年のタイミングでしたが、そこから2ヶ月強でシングルトンや依存性の削減をおこなってユニットテストを導入したり、プロジェクトの構成を見直し命名を揃えたりした結果、当社比で非常に見通しが良くなりました。具体的なメリットもあり、テストを導入したことでかな漢字変換の品質管理が容易になり、パフォーマンスのプロファイリングもしやすくなりました。まだ手のつけられていない部分もありますが、出してしまったからにはどんどん綺麗にしていきたいと思います。

信頼の向上

キーボードアプリに要求されるものの1つが、信頼です。キーボードでは様々なセンシティブな情報を入力するので、信頼出来ないキーボードアプリを利用するのは避けたいことです。
一方で、過去にはいくつものキーボードアプリがキーロガーじみた機能を実装し、発覚し、信頼を失っています。信頼を失ったキーボードはググると「〇〇キーボード 危険」とサジェストされるので、利用者の獲得が難しくなります。

azooKeyは安全なアプリケーションで、全ての情報は端末内でのみ処理します。しかし「個人開発である」という特徴は、決して信頼を高めるものではありません。ちゃんとした企業がちゃんと作っているアプリの方が、信頼自体はあります。
中には「日本製」であるという点で信頼してくれる方もいるのですが、それはそれで良くない信頼の仕方だと感じています。日本製なのは事実ですし、歴史的経緯から海外勢のキーボードアプリに不信感を覚えるのもわかるのですが、だからといって日本製ならば信頼できるとは限りません。

そこで、OSS化によって実装の透明性を高めることで、「悪意のないアプリケーションである」ということを明確にし、適切な信頼を得ることができるのではないかと考えています。

ただしOSS実装とApp Storeで配布するアプリケーションのソースコードが異なる可能性は当然残ってしまうので、これ以外の方法でも信頼を確保していく必要があります。

これから

azooKeyの開発は引き続き少しずつ進めていきます。GitHubでスターをいただければ嬉しいです!

また、万が一azooKeyに興味があるデベロッパの方がいらっしゃれば、ぜひ手伝ってください。面白いアイデアがあれば教えてください!

https://github.com/ensan-hcl/azooKey

Twitter(誰でもDM可能です)
https://twitter.com/azooKey_dev

メール:azooKey.dev😁gmail.com

azooKey blogs

Discussion