Google絵文字フォントポリシーのサポート
GoogleはAndroidを導入しました:Android絵文字ポリシーは、アプリ開発者にUnicode絵文字の最新バージョンをサポートすることを強制します。このポリシーでは、次のように述べています:
サードパーティのライブラリによって提供されるものを含め、カスタム絵文字実装を持つアプリは、新しいUnicode絵文字がリリースされてから4ヶ月以内にAndroid 12+上で実行する場合、最新のUnicodeバージョンを完全にサポートする必要があります。
このガイドでは、絵文字フォントをバンドルするか、Androidを使用することによって、このポリシーをサポートする方法を示します:Googleダウンロード可能フォント。
絵文字フォントのバンドル VS Googleダウンロード可能フォント
最新の絵文字をサポートするために、両方の方法にはいくつかの利点と欠点があります。ここでは、2つの方法のメリットとデメリットをご紹介します:
バンドルフォントの利点
- フォントの読み込みが速い
- インターネットがない環境でも利用可能
- すべてのオペレーティングシステムで動作
- 独立(Qt以外の依存関係がない)
- よりシンプルなソリューション
フォントをバンドルするデメリット
- アプリケーションのサイズが大きくなる(NotoColorEmojiは10MB程度)
- 新しいリリースでフォントを更新する必要がある。
- 古いアプリでは絵文字が自動的に更新されない
Googleダウンロードフォントの利点
- アプリケーションのサイズを変更しない
- 自動更新
- 関係のない複数のアプリが同じフォントを共有する
Googleダウンロードフォントのデメリット
- Googleモバイルサービスに依存
- アンドロイドのみ
- キャッシュされていないフォントはダウンロードされる
- 事前にキャッシュされていない場合、インターネットなしでは動作しない
- フォントをバンドルするよりも複雑
フォントをバンドルする方法
フォントを入手してバンドルし、後でQMLまたはC++を使って読み込む必要があります。
フォントの入手
このガイドでは、GoogleNotoColorEmojiフォントを使用します。NotoColorEmojiはSIL OPEN FONT LICENSEによってライセンスされたフォントです。
注意: リポジトリからダウンロードする場合は、NotoColorEmoji.ttfの代わりにNotoColorEmoji_WindowsCompatible.ttfフォントをダウンロードしてください。NotoColorEmoji.ttf は異なるフォーマットで内部的にビルドされており、Android/Chrome/Chromium OS でのみサポートされています。Qtは他のプラットフォームでも動作するため、Qtのフォントローダーは標準的な形式のTrueType/OpenTypeフォントを必要とします。
フォントの追加
フォントをバンドルする適切な方法は、Qt Resource Systemファイルに追加することです。例えば、NotoColorEmoji_WindowsCompatible.ttfを含むフォント用のリソースファイル "font.qrc "を作成します。新しいリソースファイルを埋め込むには、CMakeLists.txt に以下のコードを記述します:
qt_add_big_resources(PROJECT_SOURCES font.qrc)
バンドルされているフォントを C++ で読み込む
C++ を使っ て フ ォ ン ト を読み込むには、QFontDatabase を使います。
// Loading NotoColorEmoji bundled using C++ QFontDatabase QFontDatabase::addApplicationFont(QStringLiteral(":/NotoColorEmoji_WindowsCompatible.ttf"));
注: 上記のコードは、QQmlApplicationEngine が QML をロードする前に使用する必要があります。そうすれば、QML がロードされたときにフォントはすでに存在し、使用する準備ができています。
バンドルされているフォントを QML で読み込む
QML でフォントを読み込むには、FontLoader を使います:
// Loading NotoColorEmoji using QML FontLoader FontLoader { source:"NotoColorEmoji_WindowsCompatible.ttf" }
Googleダウンロードフォントを使う
絵文字フォントにGoogleダウンロードフォントを使用することで、アプリケーションのサイズを大きくすることなく、自動的に絵文字フォントを更新することができます。ダウンロード可能なフォント機能を使ってフォントをダウンロードする手順は、Androidで詳しく見ることができます:ダウンロード可能なフォントのプロセス
このガイドでは、以下のプロセスを説明します:
- C++コードの開始
- C++がJava関数を呼び出す
- JavaがGDFを呼び出してフォントを取得
- JavaがフォントURIを開く
- Javaがファイル記述子をC++に返す
- C++がQFontDatabase
設定
Google Downloadable FontsはAPIレベル26(Android 8.0)で利用可能です。しかし、アプリがAndroidXを使用している場合、API 14以前のAPIに対応することも可能です。
注: Androidのドキュメントでは、AndroidX.Support Libraryではなく、Android.SupportLibraryを参照しています:注:Androidのドキュメントでは、AndroidXではなくAndroid:Support Libraryを参照しています。しかし、サポート・ライブラリのメンテナンスは終了しており、AndroidXに取って代わられているため、Googleの推奨に従ってAndroidXを使用することにしました。
Androidパッケージ・テンプレートのカスタマイズ
まず、Androidパッケージのテンプレートをカスタマイズする必要があります。Qt CreatorのProjectsタブで、Build Settingsの "Build Android APK "を検索してください。Build Steps "の中にあるはずなので、詳細を展開すると "Create Templates "というボタンが表示されます。
Create templates "をクリックし、ウィザードに従うと、Android用の設定ファイルがいくつか入ったフォルダが作成される。デフォルトでは、プロジェクト・ディレクトリ内のandroid
というフォルダになります。
qmakeを使ってandroidテンプレートをカスタマイズする方法については、Android Package Templatesを参照してください。
このガイドのようにCMakeとQt 6を使用している場合は、QT_ANDROID_PACKAGE_SOURCE_DIRプロパティを設定する必要があります。例
set_property(TARGET emojiremotefont PROPERTY
QT_ANDROID_PACKAGE_SOURCE_DIR
${CMAKE_CURRENT_SOURCE_DIR}/android)
AndroidXの追加
AndroidXを追加するには、上で追加したQT_ANDROID_PACKAGE_SOURCE_DIRフォルダ内のbuild.gradle
ファイルを開き、そこに依存関係を追加します:
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) implementation 'androidx.appcompat:appcompat:1.4.1' }
AndroidXを使用するには、フラグを設定する必要があります。そのために、QT_ANDROID_PACKAGE_SOURCE_DIR内にgradle.properties
という名前のファイルを作成し、次の行を追加します:
android.useAndroidX=true
フォント・プロバイダ証明書の追加
AndroidXを使うので、もう1つ必要な設定があります:フォント・プロバイダ証明書を追加します。GMSフォント・プロバイダを使用するには、Android.GMSフォント・プロバイダ証明書をダウンロードしてください:GMSフォント・プロバイダ証明書をダウンロードしてください。他のフォントプロバイダーを使用する場合は、プロバイダー自身から証明書を取得する必要があります。
ファイルをダウンロードしたら、android templatesフォルダ内のvalues
フォルダにコピーして、Android Resources(Qtリソース・システムではない)に追加します。以下の画像は(1)の正しいフォルダを示しています:
Javaコード
さて、コードを掘り下げましょう!
Java/KotlinコードをAndroidテンプレートに追加する必要があります。アンドロイド・テンプレート・フォルダーのsrc
フォルダーの下に置いてください。src
フォルダーと java ファイル用のフォルダー構造を作成する必要があるかもしれません。このフォルダ構造は、前節の(2)のAndroid Templates Folderの画像で確認できます。
C++でフォントを取得するには、Javaのコードで以下のことを行う必要があります:
- フォント要求を作成する
- フ ォ ン ト 要求を使っ て FontsContractCompat か ら フ ォ ン ト を取得。
- フ ォ ン ト 情報 と フ ォ ン ト URI (内容ス キーマ フ ァ イ ル) を取得。
- URI を開いてファイル記述子を取得する。
- ファイル記述子をC++コードに返す
フ ォ ン ト 要求を作成す る には、 フ ォ ン ト プ ロ バ イ ダー情報 (権限、 パ ッ ケージ、 証明書) と フ ォ ン ト の検索 ク エ リ が必要です。証明書については、前に Android リソースに追加した GMS Font Provider Certificates ファイルfonts_cert.xml
を使います。
// GMS fonts provider data private static final String PROVIDER_AUTHORITY = "com.google.android.gms.fonts"; private static final String PROVIDER_PACKAGE = "com.google.android.gms"; // Emoji font search query (copied from EmojiCompat source) private static final String EMOJI_QUERY = "emojicompat-emoji-font"; // Font Certificates resources strings (from fonts_certs.xml) private static final String FONT_CERTIFICATE_ID = "com_google_android_gms_fonts_certs"; private static final String FONT_CERTIFICATE_TYPE = "array"; (...) // obtain id for the font_certs.xml int certificateId = context.getResources().getIdentifier( FONT_CERTIFICATE_ID, FONT_CERTIFICATE_TYPE, context.getPackageName()); // creating the request FontRequest request = new FontRequest( PROVIDER_AUTHORITY, PROVIDER_PACKAGE, EMOJI_QUERY, certificateId);
さて、先ほど作成したリクエストを使ってフォントを取得します:
// fetch the font FontsContractCompat.FontFamilyResult result = FontsContractCompat.fetchFonts(context, null, request);
FontInfo と URI を取得:
final FontsContractCompat.FontInfo[] fontInfos = result.getFonts(); final Uri emojiFontUri = fontInfos[0].getUri();
FontInfo と URI を取得 : URI か ら 新規ネ イ テ ィ ブ フ ァ イ ル記述子を開 く :
final ContentResolver resolver = context.getContentResolver(); // in this case the Font URI is always a content scheme file, made // so the app requesting it has permissions to open final ParcelFileDescriptor fileDescriptor = resolver.openFileDescriptor(fontInfos[0].getUri(), "r"); // the detachFd will return a native file descriptor that we must close // later in C++ code int fd = fileDescriptor.detachFd(); // return fd to C++
注: Javaでコーディングされたものはすべて、JNIを使ってC++で行うことができます。このガイドで紹介するコードは簡略化されています。本番用のコードでは、例外のキャッチなどをチェックする必要があります。
C++コード
OK、Java側ではすべて終わりました。C++側に行きましょう。
C++はJavaコードを呼び出し、ファイル記述子を使用してフォントをQtにロードする役割を担います。
Qt 6におけるC++とJava間の通信がどのように行われるかをより深く理解するには、Qt Android Notifierのサンプルをご覧ください。
Java コードからファイル記述子を取得した後、ファイル記述子をQFile クラスにラップし、QFontDatabase を使ってフォントファイルを読み込みます:
QFile file; file.open(fd, QFile::OpenModeFlag::ReadOnly, QFile::FileHandleFlag::AutoCloseHandle); QFontDatabase::addApplicationFontFromData(file->readAll());
2024The Qt Company Ltd. 本書に含まれるドキュメントの著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。