Genmoji i NSAdaptiveImageGlyph: jak aplikacje wyświetlają wbudowane emoji generowane przez użytkownika
Genmoji to skierowana do użytkownika nazwa funkcji niestandardowych emoji w Apple Intelligence: użytkownik wpisuje opis, system generuje wbudowany obraz przypominający emoji, a wynik pojawia się w tekście obok emoji Unicode. Powierzchnią dla deweloperów jest NSAdaptiveImageGlyph — klasa dostępna od iOS 18+, reprezentująca adaptacyjne obrazy wbudowane w tekście atrybutowanym1. Genmoji to jedno ze źródeł instancji NSAdaptiveImageGlyph; aplikacje obsługujące tekst atrybutowany muszą wspierać tę klasę, aby wyświetlać Genmoji (oraz wszelkie przyszłe treści typu adaptive-image-glyph, które wprowadzi Apple).
Niniejszy wpis omawia API w odniesieniu do dokumentacji Apple. Punktem odniesienia jest pytanie „co istniejąca aplikacja obsługująca tekst musi zrobić, aby poprawnie wyświetlać Genmoji”, ponieważ większość aplikacji przyjmujących tekst wprowadzony przez użytkownika w UITextView musi włączyć obsługę adaptacyjnych glifów obrazkowych, aby w ogóle wyrenderować Genmoji użytkownika. Strona persystencji niesie ze sobą implikacje serializacyjne, które bywają przeoczane.
TL;DR
NSAdaptiveImageGlyph(iOS 18+) to typ danych opakowujący adaptacyjny obraz wraz z identyfikującymi metadanymi. Wprowadzane Genmoji z systemowej klawiatury trafia jako instancjeNSAdaptiveImageGlyphosadzone w tekście atrybutowanym2.supportsAdaptiveImageGlyphjest zadeklarowane w protokoleUITextInput;UITextViewjest jego zgodną implementacją, więc właściwość można ustawić jakotextView.supportsAdaptiveImageGlyph = true. Domyślną wartością jestfalse; bez tego włączenia Genmoji wpisane przez użytkownika nie zostanie wyrenderowane.- Adaptacyjne glify obrazkowe wymagają TextKit 2. Aplikacje wciąż korzystające z TextKit 1 nie renderują
NSAdaptiveImageGlyphpoprawnie. Nowe aplikacje kierowane na iOS 18+ powinny domyślnie używać TextKit 2. NSAttributedStringprzenosi adaptacyjne glify obrazkowe poprzez atrybutNSAttributedString.Key.adaptiveImageGlyph. InicjalizatorNSAttributedString(adaptiveImageGlyph:attributes:)konstruuje ciąg atrybutowany zawierający pojedynczy glif3.- Persystencja i pełen cykl odczyt-zapis wymagają uwagi. Przechowywanie w czystym tekście całkowicie usuwa Genmoji; formaty tekstu wzbogaconego (RTFD, Markdown z rozszerzeniami, HTML z osadzonymi danymi obrazu) zachowują je.
Co przenosi NSAdaptiveImageGlyph
NSAdaptiveImageGlyph to opakowanie danych z czterema właściwościami identyfikującymi2:
imageContent: Data. Same dane obrazu w formacie zadeklarowanym przezcontentType.contentIdentifier: String. Unikalny identyfikator instancji glifu. Używany do deduplikacji oraz wewnętrznego buforowania w systemie.contentDescription: String. Tekst alternatywny opisujący glif. Używają go aplikacje udostępniające etykiety dostępności lub przekazujące glify do odbiorców nieobsługujących glifów.contentType: UTType. Właściwość typu na poziomie klasy, ujawniająca format obrazu, którego Apple używa dla glifów adaptacyjnych (wariant HEIC). Aplikacje serializujące sprawdzają tę wartość, aby sterować obsługą zależną od formatu.
Dla standardowego Genmoji dane mają zwykle wielkość rzędu kilkudziesięciu kilobajtów. Wiele rozmiarów jest zakodowanych w jednym pliku obrazu z wykorzystaniem funkcji adaptacyjnych HEIC; system wybiera odpowiedni rozmiar w zależności od kontekstu renderowania.
Włączanie adaptacyjnych glifów obrazkowych w UITextView
Włączenie sprowadza się do jednej właściwości1:
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)
Bez supportsAdaptiveImageGlyph = true Genmoji wpisane przez użytkownika pojawia się jako znak zastępczy (system nie potrafi wyrenderować glifu). Ustawienie tej właściwości włącza zarówno renderowanie, jak i zakładkę „Genmoji” w klawiaturze systemowej, dzięki czemu użytkownik może tworzyć niestandardowe Genmoji bezpośrednio w polu tekstowym.
Natywne TextField i TextEditor w SwiftUI obecnie nie udostępniają modyfikatora supportsAdaptiveImageGlyph. Aplikacje SwiftUI, które potrzebują renderowania adaptacyjnych glifów obrazkowych, opakowują UITextView w UIViewRepresentable i ustawiają supportsAdaptiveImageGlyph = true na opakowanym widoku. Społecznościowe wrappery, takie jak GlyphMeThat, zapewniają gotowy taki most.
TextKit 2 jest elementem nośnym
NSAdaptiveImageGlyph wymaga architektury układu TextKit 24. TextKit 1 (starszy silnik tekstu dostarczany z oryginalnym modelem NSTextStorage/NSLayoutManager/NSTextContainer) nie renderuje poprawnie adaptacyjnych glifów obrazkowych; glif pojawia się jako ogólny znak zastępczy lub w ogóle nie zostaje rozłożony.
Aplikacje znajdują się w jednym z trzech stanów:
Nowe aplikacje na iOS 18+. Domyślnie korzystają z TextKit 2. UITextView zainicjalizowany przez Interface Builder lub init(frame:textContainer:) używa TextKit 2 jako domyślnego rozwiązania na iOS 16+. Nowy kod otrzymuje to za darmo.
Starsze aplikacje wciąż używające TextKit 1. Wymagana jest migracja. Migracja do TextKit 2 nie jest trywialna dla aplikacji, które dziedziczą po NSLayoutManager, nadpisują metody delegata związane z układem lub korzystają bezpośrednio ze starszego NSTextStorage. Przewodnik migracji TextKit firmy Apple opisuje tę ścieżkę; dla aplikacji z prostym użyciem UITextView migracja jest w większości automatyczna.
Aplikacje hybrydowe. Niektóre aplikacje osadzają WKWebView do edycji w formacie HTML obok UITextView do prostej edycji. WKWebView obsługuje adaptacyjne glify obrazkowe poprzez własną ścieżkę renderowania (nie TextKit), więc aplikacja hybrydowa może mieć jedną powierzchnię, która wspiera Genmoji, i drugą, która tego nie robi. Należy udokumentować to zachowanie; użytkownicy zauważają, kiedy jeden edytor obsługuje niestandardowe emoji, a drugi je usuwa.
Integracja z NSAttributedString
Adaptacyjne glify obrazkowe przepływają przez ciągi atrybutowane za pośrednictwem atrybutu NSAttributedString.Key.adaptiveImageGlyph3:
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!"))
Wzorzec się komponuje: glif wewnątrz tekstu wewnątrz większego tekstu. System obsługuje układ automatycznie (w tym adaptacyjne dopasowanie rozmiaru glifu do czcionki otaczającego tekstu).
W przypadku odczytu iterowanie atrybutu .adaptiveImageGlyph w NSAttributedString zwraca instancje NSAdaptiveImageGlyph w pozycjach, w których występują:
attributedString.enumerateAttribute(
.adaptiveImageGlyph,
in: NSRange(location: 0, length: attributedString.length)
) { value, range, _ in
if let glyph = value as? NSAdaptiveImageGlyph {
// process glyph + range
}
}
Aplikacje, które filtrują, transformują lub utrwalają tekst, używają tej enumeracji, aby znaleźć glify i zdecydować, co z nimi zrobić.
Persystencja i serializacja
Przechowywanie w czystym tekście (String, plik UTF-8) nie zachowuje adaptacyjnych glifów obrazkowych. Znak zastępczy Unicode reprezentujący glif w tekście atrybutowanym zostaje zserializowany jako U+FFFC (object replacement) lub nic, a właściwe dane glifu są tracone.
Aby zapewnić pełen cykl odczyt-zapis, aplikacje potrzebują formatu tekstu wzbogaconego5:
RTFD. Format Apple łączący tekst wzbogacony z załącznikami. Zachowuje adaptacyjne glify obrazkowe w obie strony. Używany przez Notatki, Mail (przy wysyłaniu treści wzbogaconej) oraz TextEdit. Format jest rozwlekły (pakiet katalogu z załącznikami), lecz bezstratny.
HTML z osadzonymi obrazami. Przyjazny dla sieci. Glify są serializowane jako tagi <img> z URI danych zakodowanymi w base64. Większy ładunek, ale działa w większości odbiorców obsługujących tekst wzbogacony.
Markdown z rozszerzeniami. Standardowy Markdown nie ma składni dla adaptacyjnych glifów obrazkowych, ale rozszerzone dialekty (CommonMark z obsługą załączników, własny rozszerzony Markdown firmy Apple) mogą je przenosić. Należy udokumentować wymagania dialektu dla każdej persystencji opartej na markdown.
Aplikacje wysyłające tekst przez sieć (czat, e-mail, media społecznościowe) muszą zdecydować: zachować glify od końca do końca (działa tylko, jeśli zarówno nadawca, jak i odbiorca korzystają z iOS 18+, a transport obsługuje tekst wzbogacony), usunąć glify i podstawić tekst zastępczy (contentDescription) lub wyrenderować glif jako obraz systemowy i osadzić go. Właściwy wybór zależy od odbiorców i platformy.
Częste błędy
Trzy wzorce z dzienników integracji Genmoji:
Pominięcie supportsAdaptiveImageGlyph = true. Najczęstszy błąd. Pole tekstowe poprawnie renderuje emoji Unicode, lecz Genmoji pojawia się jako znaki zastępcze. Rozwiązanie: ustawić właściwość na true w każdym UITextView/NSTextView, który przyjmuje tekst wprowadzony przez użytkownika. W SwiftUI należy użyć modyfikatora .supportsAdaptiveImageGlyph(true).
Persystencja w czystym tekście usuwająca glify. Zapisanie zawartości pola tekstowego jako text (czysty String) odrzuca Genmoji. Użytkownik wpisuje niestandardowe emoji, widzi je w polu tekstowym, zapisuje dokument, otwiera ponownie — emoji znika. Rozwiązanie: utrwalić jako attributedText w formacie tekstu wzbogaconego, który obsługuje adaptacyjne glify obrazkowe (RTFD, HTML, własny format z bocznym kanałem na załączniki).
Ciche usuwanie glifów przy transmisji sieciowej. Aplikacja do komunikacji, która serializuje wiadomości wychodzące jako czysty tekst, usuwa Genmoji przy wysyłce. Odbiorca widzi znak zastępczy lub puste miejsce. Rozwiązanie: albo wysyłać treść wzbogaconą (i upewnić się, że odbiorca ją obsługuje), albo podstawić contentDescription dla odbiorców czystego tekstu i dołączyć dane obrazu jako oddzielny załącznik.
Co ten wzorzec oznacza dla aplikacji na iOS 18+
Trzy wnioski.
-
Należy ustawić
supportsAdaptiveImageGlyph = truew każdym polu tekstowym. Aplikacje przyjmujące tekst wprowadzony przez użytkownika domyślnie pomijają adaptacyjne glify obrazkowe. Pojedyncza właściwość decyduje, czy Genmoji się wyrenderuje, czy się złamie. -
Należy migrować do TextKit 2, jeśli aplikacja wciąż używa TextKit 1. TextKit 1 jest w trybie utrzymaniowym. Wszystkie nowe funkcje z ery iOS 26 (adaptacyjne glify obrazkowe, wbudowane przepisywanie Writing Tools, renderowanie tekstu w Liquid Glass) zakładają TextKit 2. Koszt migracji jest realny, ale alternatywą jest dostarczanie produktu na deprecjonowanym silniku tekstu.
-
Należy wybrać format persystencji z myślą o adaptacyjnych glifach obrazkowych. RTFD dla natywnego przechowywania w iOS; HTML z osadzonymi obrazami dla magazynu kompatybilnego z siecią; własny format binarny z bocznym kanałem na załączniki dla aplikacji wymagających wysokiej wydajności. Czysty tekst to niewłaściwy domyślny wybór dla aplikacji, w których użytkownicy będą wpisywać Genmoji.
Pełny klaster Apple Ecosystem: typowane App Intents; serwery MCP; pytanie o routing; Foundation Models; rozróżnienie LLM runtime kontra tooling; trzy powierzchnie; wzorzec pojedynczego źródła prawdy; Dwa serwery MCP; hooki dla rozwoju Apple; Live Activities; runtime watchOS; wewnętrzna budowa SwiftUI; model przestrzenny RealityKit; dyscyplina schematu SwiftData; wzorce Liquid Glass; wieloplatformowe dostarczanie; matryca platform; framework Vision; Symbol Effects; inferencja Core ML; API Writing Tools; Swift Testing; Privacy Manifest; dostępność jako platforma; typografia SF Pro; wzorce przestrzenne visionOS; framework Speech; migracje SwiftData; silnik fokusu tvOS; wewnętrzna budowa @Observable; protokół Layout w SwiftUI; niestandardowe SF Symbols; AVFoundation HDR; cykl życia treningu watchOS; App Intents 2.0 w iOS 26; API Image Playground; o czym odmawiam pisać. Hub znajduje się w serii Apple Ecosystem. Szerszy kontekst dotyczący iOS z agentami AI można znaleźć w przewodniku iOS Agent Development.
FAQ
Czy moja aplikacja otrzyma Genmoji „za darmo”, jeśli po prostu używam UITextView?
Niezupełnie. Domyślną wartością UITextView.supportsAdaptiveImageGlyph jest false. Aplikacje muszą się włączyć, ustawiając tę właściwość na true. Po włączeniu zakładka Genmoji w klawiaturze systemowej pojawia się dla użytkownika, a wklejone Genmoji renderuje się poprawnie. Bez tego włączenia Genmoji wpisane gdzie indziej i wklejone do pola tekstowego pojawia się jako znaki zastępcze.
Czy do testowania Genmoji potrzebuję włączonego Apple Intelligence?
Aby w pełni tworzyć Genmoji — tak. Skierowany do użytkownika proces tworzenia Genmoji wymaga sprzętu obsługującego Apple Intelligence (iPhone 15 Pro i nowsze, komputery Mac z procesorami serii M) z iOS 18+ oraz włączonym Apple Intelligence. Do deweloperskich testów renderowania NSAdaptiveImageGlyph można programowo skonstruować testowe instancje glifów z przykładowymi danymi obrazu i zweryfikować renderowanie pola tekstowego na dowolnym urządzeniu lub symulatorze z iOS 18+.
Co dzieje się z Genmoji, gdy wysyłam je komuś korzystającemu z iOS 17?
Bez transportu tekstu wzbogaconego, który zachowuje glif, odbiorca widzi contentDescription (tekst alternatywny) lub znak zastępczy. Nowoczesne frameworki komunikacyjne (aplikacja Wiadomości firmy Apple, najnowsze wersje klientów pocztowych) automatycznie obsługują takie awaryjne podstawienie; niestandardowe protokoły wymagają jawnej obsługi.
Czy mogę programowo tworzyć instancje NSAdaptiveImageGlyph?
Tak. Publicznym inicjalizatorem jest init(imageContent: Data), przyjmujący wstępnie zakodowane adaptacyjne dane obrazu HEIC. Wartości contentDescription, contentIdentifier i contentType są odczytywane z zakodowanych danych, nie przekazywane jako oddzielne argumenty; aplikacje tworzące niestandardowe adaptacyjne glify obrazkowe przygotowują ładunek HEIC z osadzonymi metadanymi, a następnie konstruują glif z tych danych. Sesja WWDC 2024 nr 10220 („Bring expression to your app with Genmoji”) opisuje pełny przepływ tworzenia.
Jak to współgra z Writing Tools?
Writing Tools (omówione w API Writing Tools) zachowuje adaptacyjne glify obrazkowe w wynikach przepisywania. Użytkownik, który zaznaczy tekst zawierający Genmoji i poprosi Writing Tools o przepisanie, otrzyma tekst zachowujący Genmoji w semantycznie odpowiednich miejscach. Aplikacje uczestniczące w Writing Tools przez UIWritingToolsCoordinator muszą poprawnie przeprowadzać instancje NSAdaptiveImageGlyph w obie strony przez własne magazyny tekstu.
Jaka jest różnica między NSAdaptiveImageGlyph a NSTextAttachment?
NSTextAttachment to starszy, szerszy system załączników dla treści nietekstowej osadzonej w wierszu (obrazów, plików, niestandardowych rysunków) w tekście atrybutowanym. NSAdaptiveImageGlyph to specjalizacja iOS 18 dla wbudowanych obrazów przypominających emoji, które dostosowują się do charakterystyki otaczającej czcionki. Oba są dołączane przez atrybuty ciągu atrybutowanego, lecz używają różnych kluczy (.attachment kontra .adaptiveImageGlyph) i różnych ścieżek renderowania (TextKit 1 + TextKit 2 kontra wyłącznie TextKit 2). Nowy kod adresujący treści w stylu Genmoji używa NSAdaptiveImageGlyph.
Bibliografia
-
Dokumentacja Apple Developer:
supportsAdaptiveImageGlyph. Włączająca właściwość zadeklarowana w protokoleUITextInput, do którego stosuje sięUITextView; ta sama właściwość jest zatem dostępna jakotextView.supportsAdaptiveImageGlyph. ↩↩ -
Dokumentacja Apple Developer:
NSAdaptiveImageGlyph. Typ danych opakowujący zawartość obrazu, identyfikator, opis oraz typ treści. ↩↩ -
Dokumentacja Apple Developer:
NSAttributedString.Key.adaptiveImageGlyphorazNSAttributedString(adaptiveImageGlyph:attributes:). Powierzchnia integracji adaptacyjnych glifów obrazkowych z ciągami atrybutowanymi. ↩↩ -
Dokumentacja Apple Developer: Przewodnik migracji do TextKit 2. Ścieżka migracji ze starszego silnika układu TextKit 1 do TextKit 2, wymagana do renderowania adaptacyjnych glifów obrazkowych. ↩
-
Dokumentacja Apple Developer:
NSAttributedString.DocumentType. Obsługiwane formaty tekstu wzbogaconego (RTFD, HTML itp.) dla pełnego cyklu odczyt-zapis adaptacyjnych glifów obrazkowych przez persystencję. ↩