iOS Dynamically loaded custom fonts in WidgetKit not working on real device (simulator is fine). Sandbox chronod deny file-read-data for font file.

Project structure is:
App target + widget extension + widget intent extension
All share a common appgroup group.com.x.y and all file handling is done using
Code Block
FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.x.y")

so that only the shared container is used.

Using the Main app target, a font "Chewy-Regular.ttf" is downloaded and saved to the shared AppGroup container.

Font can now be loaded via
Code Block
CTFontManagerRegisterFontsForURL

and displayed in a Main App Text view
Code Block
Text("Testing...").font(Font.custom("Chewy-Regular", size: 20))


Now add a Widgetkit widget instance that uses this font.

In 'getTimeLine() and getSnapShot() of IntentTimelineProvider we load the font again via CTFontManagerRegisterFontsForURL (this needs to happen again probably because widget runs in a separate process from the main app?).

On simulator, the widget will show the correct font.
BUT
On iPhone7 real device, the widget will show the 'redacted placeholder view'. It seems that something is crashing.

I see in the device console :
Code Block
error 14:39:07.567120-0800 chronod No configuration found for configured widget identifier: D9BF75EE-4A04-441A-8C85-1507F7ECE379
fault 14:39:07.625600-0800 widgetxExtension -[EXSwiftUI_Subsystem beginUsing:withBundle:] unexpectedly called multiple times.
error 14:39:07.672733-0800 chronod Encountered an error reading the view archive for <private>; error: <private>
error 14:39:07.672799-0800 chronod [co.appevolve.onewidget.widgetx:widgetx:small:1536744920620481560@148.0/148.0/20.2] reload: could not decode view
error 14:39:07.674984-0800 kernel Sandbox: chronod(2128) deny(1) file-read-metadata /private/var/mobile/Containers/Shared/AppGroup/9B524570-1765-4C24-9E0C-15BC3982F0DC/downloadedFonts/Chewy/Chewy-Regular.ttf
error 14:39:07.675762-0800 kernel Sandbox: chronod(2128) deny(1) file-read-data /private/var/mobile/Containers/Shared/AppGroup/9B524570-1765-4C24-9E0C-15BC3982F0DC/downloadedFonts/Chewy/Chewy-Regular.ttf
error 14:39:07.708914-0800 chronod [u 8D2C83B3-A6CB-432E-A9D4-9BC8F7056B10:m (null)] [<private>(<private>)] Connection to plugin invalidated while in use.
fault 14:39:07.710284-0800 widgetxExtension -[EXSwiftUI_Subsystem beginUsing:withBundle:] unexpectedly called multiple times.
error 14:39:07.803468-0800 chronod Encountered an error reading the view archive for <private>; error: <private>


It seems that it's a permission issue, and the textview can't access the font file it needs when the widget is rendering.

Notes:

1) Font is definitely registered because I can see them in
Code Block
for fontFamily in UIFont.familyNames {
            for fontName in UIFont.fontNames(forFamilyName: fontFamily) {
                print(fontName)
...

in both the Main App target and the Widget Extension target

2) If I make make the font part of the app bundle and add to 'Fonts provided by application' , the are loaded absolutely fine in the Main App and the Widget on simulator and iPhone 7 real device.

3) I do see this error sometimes in the Widget extension target log, don't know if it's related.

Code Block
widgetxExtension[1385:254599] [User Defaults] Couldn't read values in CFPrefsPlistSource<0x28375b880> (Domain: group.co.appevolve.onewidget, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null), Contents Need Refresh: Yes): Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd


4) I suspected something to do with app groups, so I tried to copy the font into the Widget Extension container and load from there, but had the same result.


Please help! Thank you.

Replies

I've filed a feedback assistant bug report for this issue -  FB8978909 , waiting on ... feedback.

Hey,

I'm not sure whether you still have the issue, but I had a similar one.

The Error you have seen in the widgets extension log was a hint. When you use CTFontManagerRegisterFontsForURL you have to pass a CTFontManagerScope to define how long the dynamically loaded font should be available or alive.

However, the option .user that you probably had chosen is not available in your widget extension target. So the font's are not loaded and the RegisterFonts function does return true, which is something I had not expected in this case.

So you need to take a CTFontManagerScope value that is available within this context e.g. .process.

  • Hello @Vincentthe0ne ,

    Have you resolute this question?

    As your suggestion, CTFontManagerRegisterFontsForURL with parameter .process

    let success = CTFontManagerRegisterFontsForURL(containerCachePath as CFURL, .process, &error)

    In Application, success = true and font works well.

    But In Widget, success = false, and error = com.apple.CoreText.CTFontManagerErrorDomain Code=105

    Seems code in getTimeline(...) has no permission using the file in AppGroupContainer in that way.

    Any advice?

Add a Comment

Hi, any updates?