この記事の終わりには、いろいろあってAndroidアプリを公開しました、というオチになるわけだけど、そこまで長いので、いったんアプリをお知らせします。
システムフォントを一覧するアプリです。無料。どうぞご利用ください。
前日譚
2024年11月10日、Google Play Supportからメールが届いた。件名はこうだ。
[ご対応のお願い] デベロッパー アカウント(cockscomb)に問題があります
筆者のGoogle Play Consoleデベロッパーアカウントが使用されていないため、利用者の安全性を維持するため、閉鎖の警告を受けた。
筆者がGoogle Play Consoleのデベロッパーアカウントを開設したのは、このメールからおよそ1年前、2023年11月10日のことだ。というのも、2023年11月13日以降に個人としてデベロッパーアカウントを登録すると、一定の基準をクリアしない限りアプリを公開できなくなる。それより前に登録しておけばこの制約を逃れられるというので、25ドル払ってデベロッパーアカウントを開設しておいたのだった。
ところがその後放置状態にあったため、「休眠アカウント」という扱いになり、閉鎖の危機を迎えた。一度閉鎖されるとそのデベロッパーアカウントは削除されてしまい、新たに登録すると、やはり前述の制約下に置かれることになる。
最初のメールの時点で解決の期限は59日後。1ヶ月後に2度目のメールがあり、そして元日に3度目のメールが届く。残り8日。
残り1週間を切ったところで、解決のために活動を始める。解決するには、まだ何もないデベロッパーアカウントなので、何かアプリを作成して公開するしかない。慌ててAndroid Studioを起動する。
開発動機
そもそも普段使っているのはiPhoneだから、Androidで作りたいアプリとかないのだけど、ないなりにしばらく考えたところ、以前欲しかったアプリのことを思い出した。
Android OSをアップデートした時か何かに、ブラウザで日本語フォントのウェイトの感じが変わったような気がした。もともと端末に搭載されている日本語フォントはウェイトが少なかったのだけど、見知らぬウェイトが表示された、とかだったように思う。それで端末に搭載されているフォントの様子を知りたい。ところが標準アプリにそういった機能はなく、Google Playでもいいアプリを見つけられなかった。
ということで端末に搭載されているフォントを一覧するだけのアプリが欲しい。ちょっとAPIを調べたところ、SystemFonts.getAvailableFonts()
というのを見つけた。
これじゃんということで、Android Studioでプロジェクトを作る。さすがにAndroidの最近の開発事情をうっすらとは把握しているので、Jetpack Composeのテンプレートを選ぶ。
フォント名
UIとかは置いておいて、SystemFonts.getAvailableFonts()
を呼び出して、エミュレータで様子を見てみる。Font
の集合がちゃんと返ってくる。それじゃあフォントの名前のリストでも表示するかと思ったが、まったくこれがどうにもならない。
このFont
というクラスには、フォントの名前にあたる情報を取得するメソッドが生えていない。フォントファイルそのものにはアクセスできる。なるほど……。
ということで、フォントファイルをちゃんと読んで、フォントのファミリー名などを取得していくことにする。
手元のAndroid端末では、OpenType、TrueType、TrueType Collectionの3つの形式のフォントが使われているようであった。現実的にもこれくらいに対応しておれば十分だろうということで、これらをパースするコードを書いていく。3つというと多く感じられるが、メタデータだけ読むくらいなら3つはほとんど共通している。
フォントファイルはいろいろなテーブルが並んでいるような構造で、冒頭にそれぞれのテーブルへのオフセットが記録されている。TrueType Collectionの場合は、ひとつのファイルの中にそれが複数並んでいて、冒頭にそれぞれへのオフセットが記録されているような形だ。これを順にパースしていって、目的のテーブルを参照する。
フォント名はname
テーブルに入っているので、これを読み出す。
name
テーブルにはNameRecord
が並んでおり、フォントファミリーの名前だけでなく、いろいろな文字列メタデータが格納されている。NameID
が1
のレコードを探すと、フォントファミリーの名前がわかる。
ちまちまname
テーブルを読んでいくことで、フォントの一覧ができてくる。
SystemFonts.getAvailableFonts()
ここで改めてSystemFonts.getAvailableFonts()
の返り値Set<Font>
について見ていく。ここで返ってくるFont
はフォントファイルひとつひとつに対応するのかと思っていたが、実際には違った。
まずはTrueType Collectionで、フォントファイルひとつに複数のフォントが格納されている。これが個別のエントリとして返る。TrueType Collection内部のどれかということについては、Font.getTtcIndex()
で示される。
フォントファイル | ttcIndex |
axes |
備考 |
---|---|---|---|
/system/fonts/NotoSerifCJK-Regular.ttc |
0 | N/A | Noto Serif CJK JP |
/system/fonts/NotoSerifCJK-Regular.ttc |
1 | N/A | Noto Serif CJK KR |
/system/fonts/NotoSerifCJK-Regular.ttc |
2 | N/A | Noto Serif CJK SC |
/system/fonts/NotoSerifCJK-Regular.ttc |
3 | N/A | Noto Serif CJK TC |
もうひとつ、Variable Fontがある。フォントファイルは単一のVariable Fontで、その可変なパラメータ違いが個別のエントリとして返る。パラメータはFont.getAxes()
で取得できる。
フォントファイル | ttcIndex |
axes |
備考 |
---|---|---|---|
/system/fonts/NotoSansKhmer-VF.ttf |
0 | wdth : 100, wght : 26 |
Thin |
/system/fonts/NotoSansKhmer-VF.ttf |
0 | wdth : 100, wght : 39 |
ExtraLight |
/system/fonts/NotoSansKhmer-VF.ttf |
0 | wdth : 100, wght : 58 |
Light |
/system/fonts/NotoSansKhmer-VF.ttf |
0 | wdth : 100, wght : 90 |
Regular |
/system/fonts/NotoSansKhmer-VF.ttf |
0 | wdth : 100, wght : 108 |
Medium |
/system/fonts/NotoSansKhmer-VF.ttf |
0 | wdth : 100, wght : 128 |
SemiBold |
/system/fonts/NotoSansKhmer-VF.ttf |
0 | wdth : 100, wght : 151 |
Bold |
/system/fonts/NotoSansKhmer-VF.ttf |
0 | wdth : 100, wght : 169 |
ExtraBold |
/system/fonts/NotoSansKhmer-VF.ttf |
0 | wdth : 100, wght : 190 |
Black |
Variable Font
アプリではフォントファミリー名に加えて、フォントのウェイトなどを表示したい。「Regular」や「Bold」、あるいは「Italic」のようなラベルになる。これは通常、フォントのサブファミリーとしてname
テーブルから取得できる。しかしVariable Fontの場合はそうはいかない。
Variable Fontにとってのウェイトは、wght
というaxisの値で表現される。値はフォントにもよるが、100から900までの任意の整数で表せる。これをどうラベルにするといいのか。
ここでVariable Fontのfvar
テーブルを使う。fvar
テーブルには、Variable Fontのパラメータの軸(axis)の定義と、インスタンスと呼ばれる典型的な設定が格納されている。例えばwght
が100、200、300、400……、の各インスタンスとそれに対応する名前のIDが記録されている。名前はname
テーブルの該当のIDを取ってきて、それぞれ「Thin」「ExtraLight」「Light」「Regular」……、と表示できる。
これを逆引きして、axisの値からインスタンスを探すと、いい具合にウェイトの名前などを表示できた。
UI
データが取れたということでJetpack ComposeでUIを作る。単純にリストを作るだけなら簡単。特にこだわりもないので、シンプルに済ませた。
Material 3というやつがみんな好きなんだろうと思うので、なるべくそこからはみ出さないようにする。といってもTop App Barをそれらしくするくらい。同僚の記事を参考にした。
ナビゲーション時のトランジションがちょっと違う感じがするけど、いろいろ調べても容易にはMaterial 3のトランジションを再現できないので妥協した。
審査
2日間の開発でアプリがなんとなくできた。まだいくらでもやったらよさそうなことが思いつくが、そうしている間にデベロッパーアカウントが閉鎖されると本末転倒。ということで、Google Play Consoleでリリースを作成し、アプリをアップロードした。アプリ名もこだわりないので、フォントの一覧なら「Font List」だろうと決めた。アイコンもなんかそれらしく15分で作成。諸々のメタデータを埋めて、審査に提出。最近はGoogle Playもしっかり審査してくれる。
この時点で、Google Play Consoleのデベロッパーアカウントの閉鎖の危機は去った。
数営業日で審査が終わり、アプリを無事公開。
いかがでしたか
システムフォントが知りたい皆さまに大変おすすめの製品となっております。
もうちょっとよくできる気がするので、暇なときに改善するかもしれない。