Access realm in iOS 14 Widget via shared AppGroup while also still reliably running schema migrations? RealmSwift

Hey folks, I’ve got an iOS app using RealmSwift. I’m trying to set things up to access the default realm from both the main app, as well as a new Widget I’m trying to make for iOS 14. I’ve successfully got the realm migrated to a shared AppGroup container, and can successfully get the read access I need from the Widget. The problem I can’t seem to work around is Schema migrations…

The only way I can get the Widget process to successfully retrieve realm data, is by initially running an identical launch configuration from both the Widget, and from the parent app’s didFinishLaunching (which requires setting the most current schema version):

public static func startRealm() {
    guard let fileUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: UserDefaults.mySharedAppGroupID)?.appendingPathComponent("default.realm") else { return }
    let config = Realm.Configuration(
        fileURL: fileUrl,
        schemaVersion: 46,
        migrationBlock: { migration, oldSchemaVersion in
           /* all the various migration logic */
        },
        deleteRealmIfMigrationNeeded: false
    )
    Realm.Configuration.defaultConfiguration = config

    do {
        let _ = try Realm()
    } catch let error {
        print("error: \(error)")
    }
}

The above func gets called from both the Widget and the parent app’s didFinishLaunching. The problem is that if a migration is necessary, it is very inconsistent whether it actually runs or not. When the app is launched, it seems as though the Widget process is making this call for realm access before the parent app’s didFinishLaunching. Therefore, the schema version is being bumped to the current version via the Widget process, which is only sometimes (and randomly) running the migration (8 out of 10 times, it’s not running the migration and just bumping the schemaversion up anyways), and by the time the parent app calls this from didFinishLaunching, the current schema version has already been bumped by the Widget, so the parent app’s didFinishLaunching also never triggers the migrationBlock.

I’ve tried attempting to initialize the realm inside the Widget, using just the fileURL:

do {
      let realm = try Realm(fileURL: fileURL)
} catch let error {
      print(error)
}

But it just complains that the schemaVersion (0) is less than the current version. Which brings me back to the root problem where the Widget is forcing the update to the latest schema version, but usually just skipping the migration block.

Is there a trick I’m not doing correctly, or best practices to both access a shared realm from an AppGroup, while also being able to run schema migrations?

Also important to point out that I am not using a synced realm or encrypted realm. I’ve read that multi-process realm access is not supported with sycned or encrypted, but I am not using either.

Totally stumped on this, would appreciate any insight or guidance!

1 Like

Hello. Have you found a solution? Could you answer, please.

Yes, I have really the same problem. Did you find the solution there?

Ok, as @DiscoPixel mentioned, the realm is starting in Widget first. And the migration block is called there. Because the schema is the same I’m making migration changes in Widget code.

Or if you comment realm initialization in Widget you will get migration block in main app and you can debug it there.

We are also finding the same issue. Posted bug report in github. Have found a probable solution also. Could check that if works.