Skip to content

Add metadatabase URL override for CloudKit sync#426

Open
byMohamedali wants to merge 1 commit intopointfreeco:mainfrom
byMohamedali:codex/metadatabase-url-override
Open

Add metadatabase URL override for CloudKit sync#426
byMohamedali wants to merge 1 commit intopointfreeco:mainfrom
byMohamedali:codex/metadatabase-url-override

Conversation

@byMohamedali
Copy link

Summary

Adds an optional metadatabaseURL override to SQLiteData's CloudKit APIs so callers can choose where the CloudKit metadata database lives.

Changes

  • Add metadatabaseURL: URL? = nil to:
    • SyncEngine.init(for:tables:privateTables:containerIdentifier:metadatabaseURL:defaultZone:startImmediately:delegate:logger:)
    • Database.attachMetadatabase(containerIdentifier:metadatabaseURL:)
  • Preserve existing behavior when no override is provided.
  • Create the parent directory of the resolved metadata URL instead of always creating Application Support.

Motivation

Some platforms, notably tvOS, may not allow the current hardcoded Application Support behavior for this metadata database. The main user database may already be configured to live somewhere else, but CloudKit setup still fails because the metadata store is not configurable.

This change keeps the default behavior intact for existing apps while allowing callers to explicitly provide a writable location when needed.

Example

let metadataURL = FileManager.default
  .urls(for: .cachesDirectory, in: .userDomainMask)
  .first?
  .appendingPathComponent(".SQLiteData.metadata.sqlite")

var configuration = Configuration()
configuration.prepareDatabase { db in
  try db.attachMetadatabase(metadatabaseURL: metadataURL)
}

let database = try SQLiteData.defaultDatabase(
  path: databaseURL.path,
  configuration: configuration
)

let syncEngine = try SyncEngine(
  for: database,
  privateTables: MyTable.self,
  metadatabaseURL: metadataURL
)

@mbrandonw
Copy link
Member

Hi @byMohamedali, it's intended that the metadatabase is created right alongside wherever the user's database is. You can see that's done right here:

return
databaseURL.deletingLastPathComponent().appending(
component: ".\(databaseURL.deletingPathExtension().lastPathComponent)"
)
.appendingPathExtension("metadata\(containerIdentifier.map { "-\($0)" } ?? "").sqlite")

So I'm not sure why this would be needed. Are you positive that the metadatabase is always created in application support?

@mbrandonw
Copy link
Member

Hi @byMohamedali, can you confirm my comments above? If we don't hear back we will go ahead and close this.

@byMohamedali
Copy link
Author

Yes sorry for late answer, on tvOS we can use only this
FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first path and the app crash when trying to create the SyncEngine sql file, have you tried on tvOS ?

@Armenm
Copy link

Armenm commented Mar 25, 2026

I was having the same issue on tvOS.

Metadatabase connection:
open "/var/mobile/Containers/Data/Application/EA2A5822-43D4-4D8D-A18A-B51577A8284C/Library/Caches/AppName/.playlist-credentials.metadata-iCloud.***.sqlite"
[CloudKit] sync unavailable

  • Container: iCloud.***
  • Domain: NSCocoaErrorDomain
  • Code: 513
  • Description: You don’t have permission to save the file “Application Support” in the folder “Library”.
  • UserInfo: ["NSUnderlyingError": Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted", "NSURL": file:///var/mobile/Containers/Data/Application/EA2A5822-43D4-4D8D-A18A-B51577A8284C/Library/Application%20Support, "NSFilePath": /var/mobile/Containers/Data/Application/EA2A5822-43D4-4D8D-A18A-B51577A8284C/Library/Application Support]

@mbrandonw
Copy link
Member

Yes, so then it seems to me this is the problem:

try FileManager.default.createDirectory(
at: .applicationSupportDirectory,
withIntermediateDirectories: true
)

We are actively creating the application support directory when establishing the metadatabase. I don't think that really needs to be there and may have just been left over from some other change. It seems we could just remove that to fix this.

But either way, I would ask you to please investigate a better fix than what this PR does right now, because as far as I can tell it should not be necessary to customize where the metadatabase is saved. It is saved in the same directory as the user's database, and so as long as the user is saving their database is the correct place, the metadatbase should be fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants