GenmojiとNSAdaptiveImageGlyph:アプリでユーザー生成インライン絵文字を表示する方法
Genmojiは、Apple Intelligenceのカスタム絵文字機能のユーザー向け名称です。ユーザーが説明を入力すると、システムがインラインの絵文字風画像を生成し、結果がUnicode絵文字とともにテキスト中に表示されます。開発者向けの実装面はNSAdaptiveImageGlyphであり、属性付きテキスト内の適応型インライン画像を表すiOS 18+のクラスです1。GenmojiはNSAdaptiveImageGlyphインスタンスのソースの1つであり、属性付きテキストを扱うアプリはGenmoji(およびAppleが今後導入する適応型画像グリフコンテンツ)を表示するためにこのクラスをサポートする必要があります。
この記事では、Appleのドキュメントに沿ってAPIを解説していきます。フレームは「既存のテキスト処理アプリがGenmojiを正しく表示するために何をすべきか」です。なぜなら、UITextViewでユーザー入力テキストを受け付けるほとんどのアプリは、ユーザーのGenmojiをそもそも描画するために適応型画像グリフをオプトインする必要があり、永続化側では見落とされがちなシリアライゼーションの影響があるからです。
TL;DR
NSAdaptiveImageGlyph(iOS 18+)は、適応型画像と識別用メタデータをラップするデータ型です。システムキーボードからのGenmoji入力は、属性付きテキストに埋め込まれたNSAdaptiveImageGlyphインスタンスとして到着します2。supportsAdaptiveImageGlyphはUITextInputプロトコルで宣言されており、UITextViewが準拠しているため、textView.supportsAdaptiveImageGlyph = trueとして設定可能です。デフォルトはfalseで、オプトインしないとユーザーが入力したGenmojiは描画されません。- 適応型画像グリフにはTextKit 2が必要です。TextKit 1のままのアプリは
NSAdaptiveImageGlyphを正しく描画できません。iOS 18+を対象とする新規アプリはTextKit 2をデフォルトにすべきです。 NSAttributedStringはNSAttributedString.Key.adaptiveImageGlyph属性を介して適応型画像グリフを保持します。イニシャライザNSAttributedString(adaptiveImageGlyph:attributes:)は単一のグリフを含む属性付き文字列を構築します3。- 永続化とラウンドトリップには注意が必要です。プレーンテキストストレージはGenmojiを完全に削除しますが、リッチテキスト形式(RTFD、拡張Markdown、画像データを埋め込んだHTML)は保持します。
NSAdaptiveImageGlyphが保持するもの
NSAdaptiveImageGlyphは、4つの識別プロパティを持つデータラッパーです2。
imageContent: Data—contentTypeで宣言された形式の画像データそのものです。contentIdentifier: String— グリフインスタンスの一意な識別子です。重複排除とシステムの内部キャッシュに使用されます。contentDescription: String— グリフを説明する代替テキストです。アクセシビリティラベルを表示するアプリや、グリフ非対応の受信者にグリフを送るアプリがこれを使います。contentType: UTType— Appleが適応型グリフに使用する画像形式(HEICのバリアント)を公開するクラスレベルの型プロパティです。シリアライズするアプリは、形式を意識した処理を行うためにこれをチェックします。
データは標準的なGenmojiで通常数十キロバイトです。HEICの適応型画像機能を使って同じ画像ファイル内に複数のサイズがエンコードされており、システムは描画コンテキストに基づいて適切なサイズを選択します。
UITextViewで適応型画像グリフを有効にする
オプトインは単一のプロパティで行います1。
import UIKit
let textView = UITextView()
textView.supportsAdaptiveImageGlyph = true
// Also requires TextKit 2 (default on UITextView for iOS 16+
// when constructed via Interface Builder or modern initializer)
supportsAdaptiveImageGlyph = trueがないと、ユーザーが入力したGenmojiはプレースホルダー文字として表示されます(システムがグリフを描画できないためです)。このプロパティを設定すると、描画とシステムキーボードの「Genmoji」タブの両方が有効になり、ユーザーはテキストビュー内でカスタムGenmojiを作成できるようになります。
SwiftUIのネイティブなTextFieldとTextEditorは、現時点ではsupportsAdaptiveImageGlyphモディファイアを公開していません。適応型画像グリフの描画が必要なSwiftUIアプリは、UITextViewをUIViewRepresentableでラップし、基となるビューにsupportsAdaptiveImageGlyph = trueを設定します。GlyphMeThatのようなコミュニティ製ラッパーは、このブリッジをすぐに使える形で提供しています。
TextKit 2は不可欠
NSAdaptiveImageGlyphにはTextKit 2のレイアウトアーキテクチャが必要です4。TextKit 1(オリジナルのNSTextStorage/NSLayoutManager/NSTextContainerモデルとともに登場したレガシーなテキストエンジン)は適応型画像グリフを正しく描画できません。グリフは汎用プレースホルダーとして表示されるか、レイアウト自体に失敗します。
アプリは以下の3つの状態に分かれます。
iOS 18+の新規アプリ。 TextKit 2がデフォルトとなります。Interface Builderまたはinit(frame:textContainer:)で初期化されたUITextViewは、iOS 16+ではデフォルトでTextKit 2を使用します。新しいコードは追加の作業なしでこれを得られます。
TextKit 1を使い続けているレガシーアプリ。 移行が必要です。NSLayoutManagerをサブクラス化したり、レイアウト関連のデリゲートメソッドをオーバーライドしたり、古いNSTextStorageを直接使用しているアプリにとって、TextKit 2への移行は容易ではありません。AppleのTextKit移行ガイドが道筋を示しています。シンプルなUITextView使用のアプリでは、移行はほぼ自動です。
ハイブリッドアプリ。 一部のアプリはHTML編集用にWKWebViewを、プレーン編集用にUITextViewを併用しています。WKWebViewは独自の描画パス(TextKit経由ではない)で適応型画像グリフを処理するため、ハイブリッドアプリではGenmojiをサポートする面と削除する面が混在することがあります。この挙動はドキュメント化しましょう。一方のエディタがカスタム絵文字をサポートし、もう一方が削除すると、ユーザーは気づきます。
NSAttributedStringとの統合
適応型画像グリフは、NSAttributedString.Key.adaptiveImageGlyph属性を介して属性付き文字列を流れます3。
import UIKit
// Construct an attributed string containing a single adaptive image glyph
let glyph: NSAdaptiveImageGlyph = ...
let attrString = NSAttributedString(
adaptiveImageGlyph: glyph,
attributes: [
.font: UIFont.systemFont(ofSize: 17)
]
)
// Concatenate with surrounding text
let composed = NSMutableAttributedString(string: "Look at this ")
composed.append(attrString)
composed.append(NSAttributedString(string: " I just made!"))
このパターンは合成可能です。テキストの中にグリフ、さらにそれを別のテキストの中に。レイアウト(周囲のテキストのフォントに対するグリフの適応的サイジングを含む)はシステムが自動的に処理します。
読み取りに関しては、NSAttributedStringの.adaptiveImageGlyph属性をイテレートすると、グリフが現れる位置でNSAdaptiveImageGlyphインスタンスが返されます。
attributedString.enumerateAttribute(
.adaptiveImageGlyph,
in: NSRange(location: 0, length: attributedString.length)
) { value, range, _ in
if let glyph = value as? NSAdaptiveImageGlyph {
// process glyph + range
}
}
テキストをフィルタリング・変換・永続化するアプリは、この列挙を使ってグリフを見つけ、どう処理するかを決定します。
永続化とシリアライゼーション
プレーンテキストストレージ(String、UTF-8ファイル)は適応型画像グリフを保持しません。属性付きテキストでグリフを表すUnicodeプレースホルダー文字はU+FFFC(オブジェクト置換文字)または何も書き出されず、実際のグリフデータは失われます。
ラウンドトリップ可能な永続化のためには、リッチテキスト形式が必要です5。
RTFD。 Appleのリッチテキスト+添付形式です。適応型画像グリフをラウンドトリップできます。Notes、Mail(リッチコンテンツ送信時)、TextEditで使用されています。形式は冗長(添付ファイル付きのディレクトリバンドル)ですがロスレスです。
画像を埋め込んだHTML。 Web向きです。グリフは<img>タグとbase64エンコードのデータURIとしてシリアライズされます。ペイロードは大きくなりますが、ほとんどのリッチテキスト対応の受信者で動作します。
拡張Markdown。 標準のMarkdownには適応型画像グリフ構文がありませんが、拡張方言(添付ファイル対応のCommonMark、Apple独自の拡張Markdown)はそれらを保持できます。Markdownベースの永続化を行う場合は、方言要件をドキュメント化しましょう。
ネットワーク経由でテキストを送信するアプリ(チャット、メール、SNS)は、グリフをエンドツーエンドで保持する(送信側と受信側の両方がiOS 18+でトランスポートがリッチテキストをサポートする場合のみ機能する)、グリフを削除してフォールバックテキスト(contentDescription)に置き換える、グリフをシステム画像として描画して画像を埋め込む、のいずれかを決める必要があります。正しい選択は、対象者とプラットフォームによって異なります。
よくある失敗
Genmoji統合ログから3つのパターンを紹介します。
supportsAdaptiveImageGlyph = trueを忘れる。 最も一般的なバグです。テキストビューはUnicode絵文字は問題なく描画しますが、Genmojiはプレースホルダー文字として表示されます。修正:ユーザー入力テキストを受け付けるすべてのUITextView/NSTextViewでこのプロパティをtrueに設定します。SwiftUIでは.supportsAdaptiveImageGlyph(true)モディファイアを使います。
プレーンテキストでの永続化がグリフを削除する。 テキストビューの内容をtext(プレーンなString)として保存するとGenmojiは破棄されます。ユーザーがカスタム絵文字を入力し、テキストビューで確認し、ドキュメントを保存して再度開くと、絵文字は消えています。修正:適応型画像グリフをサポートするリッチテキスト形式(RTFD、HTML、添付サイドチャネル付きのカスタム形式)でattributedTextとして永続化します。
ネットワーク送信時にグリフが静かに消失する。 送信メッセージをプレーンテキストとしてシリアライズするメッセージングアプリは、送信時にGenmojiを削除します。受信者にはプレースホルダー文字や空白が表示されます。修正:リッチコンテンツを送信する(受信者がそれをサポートしていることを確認)か、プレーンテキスト受信者のためにcontentDescriptionに置き換えて画像データを別添付として含めます。
このパターンがiOS 18+アプリにとって意味するもの
3つの要点があります。
-
すべてのテキスト入力に
supportsAdaptiveImageGlyph = trueを設定する。 ユーザー入力テキストを受け付けるアプリは、適応型画像グリフをデフォルトでオプトインすべきです。この単一プロパティが、Genmojiが描画されるか壊れるかの分かれ目となります。 -
TextKit 1を使っているならTextKit 2に移行する。 TextKit 1はメンテナンスモードに入っています。新しいiOS 26時代の機能(適応型画像グリフ、Writing Toolsのインラインリライト、Liquid Glassテキスト描画)はすべてTextKit 2を前提としています。移行コストは現実的なものですが、代替策は非推奨のテキストエンジンで出荷することです。
-
適応型画像グリフを念頭に永続化形式を選ぶ。 ネイティブiOSストレージにはRTFD、Web互換ストレージには画像を埋め込んだHTML、高性能アプリには添付サイドチャネル付きカスタムバイナリ形式。ユーザーがGenmojiを入力するアプリにとって、プレーンテキストは間違ったデフォルトとなります。
Apple Ecosystemクラスター全文:型付きのApp Intents、MCPサーバー、ルーティングの問題、Foundation Models、ランタイム vs ツーリングのLLM区別、3つのサーフェス、単一情報源パターン、2つのMCPサーバー、Apple開発のためのhooks、Live Activities、watchOSランタイム、SwiftUI内部、RealityKitの空間メンタルモデル、SwiftDataスキーマ規律、Liquid Glassパターン、マルチプラットフォーム出荷、プラットフォームマトリクス、Visionフレームワーク、Symbol Effects、Core ML推論、Writing Tools API、Swift Testing、Privacy Manifest、プラットフォームとしてのアクセシビリティ、SF Proタイポグラフィ、visionOS空間パターン、Speechフレームワーク、SwiftDataマイグレーション、tvOSフォーカスエンジン、@Observable内部、SwiftUI Layoutプロトコル、カスタムSF Symbols、AVFoundation HDR、watchOSワークアウトライフサイクル、iOS 26のApp Intents 2.0、Image Playground API、私が書くことを拒むもの。ハブはApple Ecosystem Seriesにあります。AIエージェントを伴うiOSのより広範な文脈については、iOS Agent Development guideをご覧ください。
FAQ
UITextViewを使うだけでGenmojiが「無料で」手に入りますか?
そうとは限りません。UITextView.supportsAdaptiveImageGlyphのデフォルトはfalseです。アプリはこのプロパティをtrueに設定してオプトインする必要があります。有効にすると、ユーザー向けにシステムキーボードのGenmojiタブが表示され、ペーストされたGenmojiも正しく描画されます。オプトインしない場合、他の場所で入力されてテキストビューにペーストされたGenmojiはプレースホルダー文字として表示されます。
Genmojiをテストするのに、Apple Intelligenceの有効化は必要ですか?
完全なGenmoji作成には必要です。ユーザー向けのGenmoji作成フローには、Apple Intelligence対応ハードウェア(iPhone 15 Pro以降、Mシリーズ Mac)でiOS 18+とApple Intelligenceが有効になっていることが必要です。NSAdaptiveImageGlyph描画の開発テストでは、サンプル画像データを使ってテストグリフインスタンスをプログラムで構築し、iOS 18+のデバイスやシミュレータでテキストビューの描画を検証できます。
iOS 17のユーザーにGenmojiを送るとどうなりますか?
グリフを保持するリッチテキストトランスポートがない場合、受信者にはcontentDescription(代替テキスト)またはプレースホルダー文字が表示されます。最新のメッセージングフレームワーク(AppleのMessagesアプリ、最近のメールクライアント)はフォールバックを自動処理しますが、カスタムプロトコルでは明示的な処理が必要です。
NSAdaptiveImageGlyphインスタンスをプログラムで作成できますか?
はい。公開イニシャライザはinit(imageContent: Data)で、事前にエンコードされたHEIC適応型画像データを受け取ります。contentDescription、contentIdentifier、contentTypeは別の引数として渡すのではなく、エンコードされたデータから読み取られます。カスタム適応型画像グリフを作成するアプリは、メタデータを埋め込んだHEICペイロードを準備し、そのデータからグリフを構築します。WWDC 2024セッション10220「Bring expression to your app with Genmoji」が完全な作成フローを解説しています。
Writing Toolsとの相互作用は?
Writing Tools(Writing Tools APIで取り上げています)は、リライト出力で適応型画像グリフを保持します。Genmojiを含むテキストを選択してWriting Toolsでリライトを依頼したユーザーは、Genmojiが意味的に適切な位置に保持されたリライトを得られます。UIWritingToolsCoordinatorを介してWriting Toolsに参加するアプリは、カスタムテキストストレージを通じてNSAdaptiveImageGlyphインスタンスを正しくラウンドトリップする必要があります。
NSAdaptiveImageGlyphとNSTextAttachmentの違いは?
NSTextAttachmentは、属性付きテキスト内のインライン非テキストコンテンツ(画像、ファイル、カスタム描画)のための古く、より広範な添付システムです。NSAdaptiveImageGlyphは、周囲のフォント特性に適応する絵文字風インライン画像のためのiOS 18特化型です。両者は属性付き文字列の属性を介して添付されますが、異なるキー(.attachment vs .adaptiveImageGlyph)を使い、異なる描画パス(TextKit 1+TextKit 2 vs TextKit 2のみ)を持ちます。Genmoji風コンテンツを対象とする新しいコードはNSAdaptiveImageGlyphを使います。
参考文献
-
Apple Developer Documentation:
supportsAdaptiveImageGlyph。UITextInputプロトコルで宣言され、UITextViewが準拠するオプトインプロパティ。同じプロパティはtextView.supportsAdaptiveImageGlyphとしてアクセス可能。 ↩↩ -
Apple Developer Documentation:
NSAdaptiveImageGlyph。画像コンテンツ、識別子、説明、コンテンツタイプをラップするデータ型。 ↩↩ -
Apple Developer Documentation:
NSAttributedString.Key.adaptiveImageGlyphおよびNSAttributedString(adaptiveImageGlyph:attributes:)。適応型画像グリフのための属性付き文字列統合面。 ↩↩ -
Apple Developer Documentation: TextKit 2移行ガイド。レガシーのTextKit 1レイアウトエンジンからTextKit 2への移行パス。適応型画像グリフ描画には必須。 ↩
-
Apple Developer Documentation:
NSAttributedString.DocumentType。永続化を介して適応型画像グリフをラウンドトリップするためのサポート対象リッチテキスト形式(RTFD、HTMLなど)。 ↩