BrickDeLait
BrickDeLait

Reputation: 126

Widget not loading on iOS 17 beta, "Missing backing store for Intent" error

I work on an iOS app supporting iOS 15 and above, with a widget supporting iOS 16 and above.

The widget currently does not load on iOS 17 beta, for users it's just an empty box, both during snapshot preview while choosing the widget size, and after placing it on the home screen.

When building it from Xcode, I get the following error:

-[INIntent _initWithIdentifier:backingStore:schema:error:] Missing backing store for Intent: {xxx-xxx-xxx some ID} (N/A - N/A)

The app uses a custom Intent to allow some settings on the widget. The widget and app share data through an App Group to avoid duplication of network requests.

I could not find any information on this error on SO, nor on Apple beta release notes. Is anybody experiencing this as well?

Upvotes: 8

Views: 2623

Answers (2)

optz
optz

Reputation: 521

I could resolve this by making sure the intent is running on the main thread. With iOS 17 it seems the intent code can now run directly in the app and on the widget extension.

For me the extension seems to have crashed because it was running the code in the app instead of the extension. Some parts of my code are a bit old and need to run on the main thread. The EntityQuery is running on a background thread though so I changed this and it's working again in my case.

struct DataAppEntityQuery: EntityQuery {
        func entities(for identifiers: [DataAppEntity.ID]) async throws -> [DataAppEntity] {
            let data = await retrieveData().filter { identifiers.contains($0.id) }
            return data
        }

        func suggestedEntities() async throws -> [DataAppEntity] {
            return await retrieveData()
        }
        
        func defaultResult() async -> DataAppEntity? {
            try? await suggestedEntities().first
        }
        
        
        func retrieveData() async -> [DataAppEntity] {
            //code that needs to run on the main thread in my case            

            await MainActor.run {
                //....
                return data
            }
        }
    }

Upvotes: 1

Sophy Swicz
Sophy Swicz

Reputation: 1367

Have you tried to add

let configuration: ConfigurationAppIntent in the TimeLine Entry?

Example:

struct SimpleEntry: TimelineEntry {
     let date: Date
     let configuration: ConfigurationAppIntent
     let character: CharacterDetail
 }


func placeholder(in context: Context) -> SimpleEntry {
    SimpleEntry(date: Date(), configuration: ConfigurationAppIntent(), character: .panda)
}

func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry {
    SimpleEntry(date: Date(), configuration: ConfigurationAppIntent(), character: .panda)
}

This code is generated automatically, and basically it's the view that you see when the widget turns or spins to the other side

import WidgetKit
import AppIntents

struct ConfigurationAppIntent: WidgetConfigurationIntent {
    static var title: LocalizedStringResource = "Configuration"
    static var description = IntentDescription("This is an example widget.")

    // An example configurable parameter.
    @Parameter(title: "Favorite Emoji", default: "😃")
    var favoriteEmoji: String
}

This worked for me using the example EmojiRangers

Upvotes: 3

Related Questions