このページの内容

Googleの絵文字フォントポリシーの対応

Googleは「Android: Android 絵文字ポリシー」を導入し、アプリ開発者に対し、最新バージョンのUnicode絵文字をサポートすることを義務付けています。このポリシーでは次のように規定されています:

サードパーティ製ライブラリによって提供されるものを含め、カスタム絵文字を実装しているアプリは、新しいUnicode絵文字がリリースされてから4ヶ月以内に、Android 12以降で実行される際に、最新のUnicodeバージョンを完全にサポートする必要があります。

このガイドでは、絵文字フォントをバンドルするか、Android: Google ダウンロード可能フォントを使用することで、このポリシーに対応する方法について説明します。

絵文字フォントのバンドルと Google ダウンロード可能フォントの比較

最新の絵文字に対応するための両方の方法には、それぞれ長所と短所があります。最適な選択肢はアプリごとに異なります。以下に、2つの方法の長所と短所を挙げます:

フォントのバンドルによるメリット:

  • フォントの読み込みが速い
  • ユーザーがインターネットに接続していない場合でも動作する
  • すべてのオペレーティングシステムで動作する
  • 独立性が高い(Qt以外の依存関係がない)
  • シンプルなソリューション

フォントのバンドルによるデメリット:

  • アプリケーションのサイズが大きくなる(NotoColorEmojiは約10 MB)
  • 新しいリリースではフォントの更新が必要
  • 古いアプリでは絵文字が自動的に更新されない

Google Downloadable Fontsのメリット:

  • アプリケーションのサイズが変わらない
  • 自動的に更新される
  • 関連性のない複数のアプリ間で同じフォントを共有できる

Google ダウンロード可能フォントのデメリット:

  • Google Mobile Servicesに依存する
  • Androidのみ
  • 事前にキャッシュされていない場合はフォントをダウンロードする
  • 事前にキャッシュされていない場合、インターネット接続がないと動作しない
  • フォントをバンドルするよりも複雑

フォントのバンドル方法

フォントを取得してバンドルし、後でQMLまたはC++を使用して読み込む必要があります。

フォントの入手

このガイドでは、GoogleのNotoColorEmojiフォントを使用します。NotoColorEmojiは、SIL OPEN FONT LICENSEの下でライセンスされているフォントです。

注: リポジトリからダウンロードする場合は 、NotoColorEmoji.ttf ではなく、NotoColorEmoji_WindowsCompatible.ttf フォントをダウンロードしてください。NotoColorEmoji.ttf は内部で異なる形式でビルドされており、Android/Chrome/Chromium OS でのみ十分にサポートされています。 Qtは他のプラットフォームでも動作するため、Qtのフォントローダーには標準形式のTrueType/OpenTypeフォントが必要です。

フォントの追加

フォントをバンドルする適切な方法は、Qt リソースシステムファイルにフォントを追加することです。 たとえば、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: ダウンロード可能フォントの手順」を参照してください。

このガイドでは、以下の手順で進めます:

  1. C++コードの開始
  2. C++からJava関数を呼び出す
  3. JavaがGDFを呼び出してフォントを取得
  4. JavaがフォントURIを開く
  5. JavaがファイルディスクリプタをC++に返す
  6. C++が以下を使用してフォントを読み込むQFontDatabase

設定

Google Downloadable Fonts は API レベル 26 (Android 8.0) から利用可能です。ただし、アプリが AndroidX を使用している場合は、API レベル 14 までの以前の API にも対応可能です。

注:Androidのドキュメントでは、 AndroidXではなく「Android: Support Library」という名称が使用されています。しかし、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 パッケージテンプレート」を参照してください。

このガイドのように 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を使用しているため、Android: フォントプロバイダー証明書の追加という別の設定が必要です。GMSフォントプロバイダーを使用する場合は、Android: GMSフォントプロバイダー証明書をダウンロードしてください。他のフォントプロバイダーを使用する場合は、プロバイダー側から証明書を入手する必要があります。

ファイルをダウンロードしたら、androidテンプレートフォルダ内のvalues フォルダにコピーして、Androidリソース(Qtリソースシステムではありません)に追加してください。次の画像は、正しいフォルダの位置を示しています(1):

Androidテンプレートフォルダ

Javaコード

それでは、コードについて詳しく見ていきましょう!

AndroidテンプレートにJava/Kotlinコードを追加する必要があります。これを、androidテンプレートフォルダ内のsrc フォルダに配置してください。必要に応じて、src フォルダおよびJavaファイル用のフォルダ構造を作成する必要があります。このフォルダ構造は、前のセクションの「Androidテンプレートフォルダ」画像の(2)で確認できます。

C++でフォントを取得するには、Javaコードで以下の処理を行う必要があります:

  • フォントリクエストの作成
  • フォントリクエストを使用して、FontsContractCompatからフォントを取得する
  • フォント情報とフォント URI(コンテンツスキーマファイル)の取得
  • URIを開き、ファイルディスクリプタを取得する
  • ファイルディスクリプタを C++ コードに返す

フォントリクエストを作成するには、フォントプロバイダー情報(権限、パッケージ、証明書)と、フォントの検索クエリが必要です。証明書については、以前にAndroidリソースに追加したGMSフォントプロバイダー証明書ファイル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();

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++ コード

Java側の作業はこれで完了です。次にC++側に移りましょう。

C++側では、Javaコードを呼び出し、ファイルディスクリプタを使用してQtにフォントを読み込む役割を担います。

Qt 6におけるC++とJava間の通信の仕組みをより深く理解するには、「Qt for Android Notifier」のサンプルを参照してください。

Javaコードからファイルディスクリプタを取得したら、そのファイルディスクリプタをQFile クラスでラップし、QFontDatabase を使用してフォントファイルをロードします:

QFile file;
file.open(fd, QFile::OpenModeFlag::ReadOnly, QFile::FileHandleFlag::AutoCloseHandle);

QFontDatabase::addApplicationFontFromData(file->readAll());

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.