Bundle a Realm - Kotlin SDK
On this page
- Overview
- Asset Realm Locations by Platform
- Bundle a Non-Synced Realm
- Populate an Asset Realm with Seed Data
- Bundle and Open the Realm File in Your Production Application
- Bundle a Synced Realm
- Populate an Asset Realm with Seed Data
- Create a Copy of the Asset Realm
- Bundle and Open a Synced Realm File in your Production Application
Overview
New in version 1.9.0.
The Realm Kotlin SDK supports bundling realm files with your application. This enables you to pre-populate a database with seed data in your application download.
Tip
Consider Initial Data Callback or Initial Subscriptions
You can also add data to your realm the first time an application opens it using InitialDataCallback or InitialSubscriptions.
Asset Realm Locations by Platform
The Realm Kotlin SDK looks for the asset realm that contains your seed data based on the platform's conventional locations for bundled assets/resources:
Android: Through
android.content.res.AssetManager.open(assetFilename)
JVM:
Class<T>.javaClass.classLoader.getResource(assetFilename)
Darwin:
NSBundle.mainBundle.pathForResource(assetFilenameBase, assetFilenameExtension)
You must place the asset realm in the appropriate location after you create it.
If the asset realm cannot be located when opening the realm for the first time,
Realm.open()
fails with an IllegalArgumentException
.
Bundle a Non-Synced Realm
Populate an Asset Realm with Seed Data
Create a new temporary project to create and populate an asset realm with seed data. This project uses the same Realm object schema as your production app.
Open an existing realm with the data you wish to seed, or create a new realm. Set a specific name for your asset realm so you can refer to it by name as the initial data source for your app.
Populate the asset realm with the seed data you want to include in your production application.
You can get the path to the asset realm file using Realm.configuration.path.
// Open a local realm to use as the asset realm val config = RealmConfiguration.Builder(schema = setOf(Item::class)) .name("asset.realm") .build() val assetRealm = Realm.open(config) assetRealm.writeBlocking { // Add seed data to the asset realm copyToRealm(Item().apply { summary = "Write an awesome app" isComplete = false }) } // Verify the data in the existing realm // (this data should also be in the bundled realm we open later) val originalItems: RealmResults<Item> = assetRealm.query<Item>().find() for(item in originalItems) { Log.v("Item in the assetRealm: ${item.summary}") } // Get the path to the realm Log.v("Realm location: ${config.path}") assetRealm.close()
Now that you have an asset realm, you can move it into your production application and use it there.
Tip
Realms are compatible across SDKs
Realm files that use the same file format are compatible across SDKs. If you need to programmatically create asset realms to bundle with a production application, you can use the Node.js SDK for easy integration with CI pipelines.
You can find the file format supported by your SDK version in the changelog for your SDK. This may resemble something like "File format: Generates Realms with file format v23."
Bundle and Open the Realm File in Your Production Application
Save the copy of the asset realm file to your production application. You must place this asset file in the appropriate location for your app's platform. For details, refer to Asset Realm Locations by Platform.
Create a Configuration that your production app can use to open the asset realm. Set the
initialRealmFile
property in this configuration to the name of your asset realm.You can optionally provide a
sha256checkSum
for theinitialRealmFile
to verify the integrity of the realm file when opening it. If you provide a checksum that does not match the computed checksum of the asset file when you open the seed realm,Realm.open()
fails with anIllegalArgumentException
.With this configuration, you can open the bundled asset realm. It contains the data that was in the asset realm at the time you copied it.
// The config should list the bundled asset realm as the initialRealmFile val bundledRealmConfig = RealmConfiguration.Builder(schema = setOf(Item::class)) .initialRealmFile("asset.realm") .build() // After moving the bundled realm to the appropriate location for your app's platform, // open and use the bundled realm as usual. val bundledRealm = Realm.open(bundledRealmConfig) val bundledItems: RealmResults<Item> = bundledRealm.query<Item>().find() for(item in bundledItems) { Log.v("Item in the bundledRealm: ${item.summary}") } bundledRealm.close()
Bundle a Synced Realm
Bundling a synced realm reduces the size of the data that users must download on the initial open when using a synced realm, at the cost of increasing your app's download file size. When you bundle an asset realm with your application, the only data users must download when opening the realm is any changes that have occurred since preparing the asset realm.
Important
Bundling Synced Realms
If your backend application uses Flexible Sync, users could experience a client reset the first time they open the bundled realm file. This can occur when client maximum offline time is enabled (client maximum offline time is enabled by default). If the bundled realm file was generated more than the number of days specified by the client maximum offline time setting before the user syncs for the first time, the user experiences a client reset.
Applications that perform a client reset download the full state of the realm from the application backend. This negates the advantages of bundling a realm file. To prevent client resets and preserve the advantages of realm file bundling:
Avoid using a client maximum offline time in applications that bundle a synchronized realm.
If your application does use a client maximum offline time, ensure that your application download always includes a recently synced realm file. Generate a new file each application version, and ensure that no version ever stays current for more than client maximum offline time number of days.
If your application uses Flexible Sync, you can populate your application with data using initial sync subscriptions as an alternative to bundling a synced asset realm. With initial subscriptions, you do not need to be concerned with data being older than the client maximum offline time. To learn more about using sync subscriptions, refer to Subscriptions.
To bundle a synced realm, perform the following:
Populate an Asset Realm with Seed Data
Create a new temporary project to create and populate the asset realm. This project uses the same Realm object schema as your production app.
Open the synced realm that you want to use as an asset realm.
Populate the asset realm with the seed data you want to include in your production application. You must wait for all local changes to synchronize with the Device Sync server. Use uploadAllLocalChanges() and downloadAllServerChanges() to ensure all sync processes are completed.
val app = App.create(yourFlexAppId) // Login with user that has the server-side permissions to // read and write the data you want in the asset realm val user = app.login(credentials) // Create a SyncConfiguration to open a synced realm to use as the asset realm val assetRealmConfig = SyncConfiguration.Builder(user, setOf(Item::class)) .name("asset.realm") // Add a subscription that matches the data being added // and your app's backend permissions .initialSubscriptions{ realm -> add( realm.query<Item>("isComplete == $0", false), "Incomplete Items") } .build() val assetRealm = Realm.open(assetRealmConfig) assetRealm.subscriptions.waitForSynchronization(10.seconds) assertEquals(SubscriptionSetState.COMPLETE, assetRealm.subscriptions.state) assetRealm.writeBlocking { // Add seed data to the synced realm copyToRealm(Item().apply { summary = "Make sure the app has the data it needs" isComplete = false }) } // Verify the data in the existing realm // (this data should also be in the bundled realm we open later) val assetItems: RealmResults<Item> = assetRealm.query<Item>().find() for(item in assetItems) { Log.v("Item in the assetRealm: ${item.summary}") } // IMPORTANT: Sync all changes with server before copying the synced realm assetRealm.syncSession.uploadAllLocalChanges(30.seconds) assetRealm.syncSession.downloadAllServerChanges(30.seconds)
Create a Copy of the Asset Realm
You must create a copy of the asset realm from the temporary project that you can bundle with your production application.
Create a SyncConfiguration that your app can use to open a copy of the asset realm. Set the
initialRealmFile
property in this configuration to the name of your asset realm.You can optionally provide a
sha256checkSum
for theinitialRealmFile
to verify the integrity of the realm file when opening it. If you provide a checksum that does not match the computed checksum of the seed realm when you open it,Realm.open()
fails with anIllegalArgumentException
.// Create a SyncConfiguration for the bundled copy. // The initialRealmFile value is the `name` property of the asset realm you're bundling. val copyConfig = SyncConfiguration.Builder(user, setOf(Item::class)) .initialRealmFile("asset.realm") .build() Create a new version of the synced realm using writeCopyTo() . You must use
writeCopyTo()
to bundle a synced realm. This method removes metadata that associates the realm with the user, which allows other users to open the realm file as well.Get the path to the copied realm file using Realm.configuration.path.
// Copy the synced realm with writeCopyTo() assetRealm.writeCopyTo(copyConfig) // Get the path to the copy you just created. // You must move this file into the appropriate location for your app's platform. Log.v("Bundled realm location: ${copyConfig.path}") assetRealm.close()
Now that you have a copy of the asset realm, you can move it into your production application and use it there.
Bundle and Open a Synced Realm File in your Production Application
Save the copy of the asset realm file to your production application. You must place this asset file in the appropriate location for your app's platform. For details, refer to Asset Realm Locations by Platform.
Now that you have a copy of the asset realm bundled with your app, you can open it using the copied realm configuration you created. It contains the data that was in the asset realm at the time you copied it.
// After moving the bundled realm to the appropriate location for your app's platform, // open and use the bundled realm as usual. val copiedRealm = Realm.open(copyConfig) // This should contain the same Items as in the asset realm val copiedItems: RealmResults<Item> = copiedRealm.query<Item>().find() for(item in copiedItems) { Log.v("Item in the copiedRealm: ${item.summary}") } copiedRealm.close()