Hi everyone,
I’m trying to register fonts system-wide using CTFontManagerRegisterFontURLs with the .persistent scope. The fonts are delivered through Apple-Hosted Background Assets (since On-Demand Resources are deprecated).
Process-level registration works perfectly, but persistent registration triggers a system “Install Fonts” prompt, and tapping Install causes the app to crash immediately.
I’m wondering if anyone has successfully used Apple-Hosted Background Assets to provide persistent, system-wide installable fonts, or if this is a current OS limitation/bug.
What I Expect
- Fonts delivered through Apple-Hosted Background Assets should be eligible for system-wide installation
- Tap “Install” should install fonts into Settings → Fonts just like app-bundled or ODR fonts
- App should not crash
Why This Matters
According to:
WWDC 2019: Font Management and Text Scaling
- Developers can build font provider apps that install fonts system-wide, using bundled or On-Demand Resources.
WWDC 2025: Discover Apple-Hosted Background Assets
- On-Demand Resources are deprecated, and AHBAs are the modern replacement.
Therefore, persistent font installation via Apple-Hosted Background Assets appears to be the intended path moving forward.
Question
Is this a known limitation or bug in iOS?
Should .persistent font installation work with Apple-Hosted Background Assets?
Do we need additional entitlement, manifest configuration, or packaging rules?
Any guidance or confirmation from Apple engineers would be greatly appreciated.
Additional Info
I submitted a Feedback including a minimal reproducible sample project:
FB21109320
I submitted a Feedback including a minimal reproducible sample project:
I got your crash report from that. In that I see this:
Exception Type: EXC_BREAKPOINT (SIGTRAP)
which strongly suggests that your app is crashing due to a trap, that is, some code has detected an inconsistency and deliberately crashed the process. The crashing thread looks like this:
Thread 3 name: Dispatch queue: com.apple.NSXPCConnection.user.com.apple.FontServices.FontProviderLoader
Thread 3 Crashed:
0 libdispatch.dylib … _dispatch_assert_queue_fail + 120
1 libdispatch.dylib … dispatch_assert_queue$V2.cold.1 + 115
2 libdispatch.dylib … dispatch_assert_queue + 107
3 libswift_Concurrency.dylib … _swift_task_checkIsolatedSwift + 47
4 libswift_Concurrency.dylib … swift_task_isCurrentExecutorWithFlagsImpl(swift::SerialExecutorRef, swift::swift_task_is_current_executor_flag) + 355
5 InstallFonts.debug.dylib … closure #5 in ContentView.register(scope:) + 96
6 InstallFonts.debug.dylib … thunk for @escaping @callee_guaranteed (@guaranteed CFArrayRef, @unowned Bool) -> (@unowned Bool) + 80
7 CoreText … invocation function for block in _CTFontManagerRegisterActionFontURLs(__CFArray const*, CTFontManagerScope, bool, Action, URLTrust, __CFArray const*, bool (__CFArray const*, bool) block_pointer) + 263
8 FontServices … __FSFontProviderRegisterFonts_block_invoke + 67
9 FontServices … __64-[FontProviderManager _registerFonts:enabled:completionHandler:]_block_invoke_2 + 99
Frame 7 is CTFont calling your callback, frames 6 and 5 are your code, and frames 4 through 0 are a Swift concurrency runtime check that your code is running on the expected actor. That check has failed, and hence the trap.
AFAICT this relates to this line of your code:
CTFontManagerRegisterFontURLs(cfArray, scope, true) { _, _ in true }
You have trailing closure that acts as a completion handler. Due to a lack of appropriate annotations in CoreText, Swift assumes that this closure will be called on the main actor. It is not, and hence the trap.
I’m not able to test this right now, but I suspect that the following will fix the crash:
CTFontManagerRegisterFontURLs(cfArray, scope, true) { @Sendable _, _ in true }
This tells Swift to form a sendable closure, which thus won’t include a main actor check.
Lemme know how this pans out because, if this does resolve the problem, we should repurpose FB21109320 to request a fix to the annotations on CTFontManagerRegisterFontURLs.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"