iOS - Google Drive Provider doesn’t update when overwritten later, but works after opening the file

I’m seeing odd behavior with the Google Drive File Provider on iOS/iPadOS when using only the system file APIs.

For this feature, I cannot use the Google Drive REST API or SDK. The app must treat Google Drive just like any other location in the Files app and rely strictly on:

  • UIDocumentPickerViewController

  • security-scoped URLs

  • NSFileCoordinator

The goal is to let a user save a plain text file into Google Drive on an iPad, then continue overwriting that same file (for Save / autosave).Minimal test app
To isolate the issue, I built a small test app:

  • SwiftUI front end with a TextEditor and three buttons: Open, Save As, Save.

  • A FileSystem service that uses UIKit’s UIDocumentPickerViewController underneath.

The operations are:

Open

UIDocumentPickerViewController(

forOpeningContentTypes: [.plainText],

asCopy: false

)

The user chooses an existing .txt file from the Files UI (including Google Drive). I then:

  • Call startAccessingSecurityScopedResource() on the URL.

  • Use NSFileCoordinator.coordinate(readingItemAt:) to read the data.

  • Store that URL as the “current file” for later Save.

Save As
To “Save As”, I first write the current text to a temporary file in the app’s sandbox. Then I present:

UIDocumentPickerViewController(

forExporting: [tempURL],

asCopy:true

)

The user chooses a destination (e.g., a folder in Google Drive), and the system copies the temp file there. I capture the URL returned by the picker for debugging and, originally, as the “current file”.

Save (overwrite)

func saveCurrentFile(text: String, completion: @escaping (Result<Void, Error>) -> Void) {

guard let url = currentFileURL else {

completion(.failure(MyError.noCurrentFile))

return

}

guard url.startAccessingSecurityScopedResource() else {

completion(.failure(MyError.securityScopeFailed))

return

}

defer { url.stopAccessingSecurityScopedResource() }

let data = text.data(using: .utf8) ?? Data()

let coordinator = NSFileCoordinator(filePresenter: nil)

var coordError: NSError?

var writeError: Error?

coordinator.coordinate(

writingItemAt: url,

options: .forReplacing,

error: &coordError

) { coordinatedURL in

do {

try data.write(to: coordinatedURL, options: .atomic)

} catch {

writeError = error

}

}

if let error = writeError ?? coordError {

completion(.failure(error))

} else {

completion(.success(()))

}

}

Reads for Open use the same pattern with coordinate(readingItemAt:).

Behavior with local storage and iCloud Drive
With this setup:

  • Saving to On My iPad works exactly as expected.

  • “Save As → Save” creates the file and then overwrites it correctly.

  • Saving to iCloud Drive also works.

  • Both “Save As → Save” and “Open → Save” reliably update the same file.

So the pattern (document picker + security-scoped URL + NSFileCoordinator) is behaving correctly for local and iCloud.

Behavior with Google Drive

Things change when the target is Google Drive (Google Drive iOS app installed and exposed as a File Provider in the Files app).

Case 1: Open → Save
If I:

  1. Use Open to select an existing text file from Google Drive,

  2. Edit the text, and

  3. Press Save (calling the code above),

then the file in Google Drive updates correctly. The contents change as expected, and there are no errors from NSFileCoordinator.

So files obtained through UIDocumentPickerViewController(forOpeningContentTypes:asCopy:) behave as “live” editable documents.

Case 2: Save As → Save
If I:

  1. Enter some text,

  2. Use Save As to create a new file in Google Drive via UIDocumentPickerViewController(forExporting:asCopy:),

  3. Confirm that the file appears in Google Drive with the correct initial content,

  4. Change the text in the app, and

  5. Press Save,

then the coordinated write reports success, but the visible contents of the file in Google Drive do not change. It looks like the overwrite never happened, even though from the app’s perspective everything succeeded.

The exact same Save logic does update the file immediately when that file was originally chosen via Open.Example URLs from Google Drive
Here’s a concrete example of the URLs involved. These are for what is logically the same document, but obtained in two different ways:

Save As - URL:

file:///private/var/mobile/Containers/Shared/AppGroup/3D1452DB-C494-4E2E-AFBA-B3EFA9127134/File%20Provider%20Storage/52759511/1764183970.661987/Example.txt

Open - URL:

file:///private/var/mobile/Containers/Shared/AppGroup/3D1452DB-C494-4E2E-AFBA-B3EFA9127134/File%20Provider%20Storage/52759511/1yrsv8rN37GHl4AT3iLKry9FyIBemuqTX/Example.txt

Important constraint
In this feature, I cannot use the Google Drive REST API or SDK to, for example, resolve the real file ID and update it over HTTP.
I have to treat Google Drive like any other Files location and use only:

  • UIDocumentPickerViewController

  • security-scoped URLs returned by the picker

  • NSFileCoordinator for reading and writing

So the only information I have is the file URLs that the File Provider gives me.

Questions

Given all of the above, I’m trying to understand how this is supposed to work from the Google Drive side.

  • Is it expected that the URL returned from UIDocumentPickerViewController(forExporting:asCopy:) is effectively a one-time import source rather than the canonical document URL?

  • Is there any supported way, using only iOS file APIs (no Drive REST/SDK), to obtain a URL that is guaranteed to be the “real” Google Drive document after Save As, so that later overwrites are reflected in the Drive UI?

  • If the current behavior is “by design”, is the recommended pattern simply to treat Save As as export-only, and require the user to use Open (via forOpeningContentTypes) on that file before we rely on overwriting it?

Any clarification or guidance from the Drive / File Provider team, or from developers who have solved this with only iOS file system APIs, would be very appreciated.

Hey,

Hope you’re keeping well.

On iOS, the Google Drive File Provider treats forExporting:asCopy: operations as a content hand‑off, not a persistent reference to the canonical file in Drive. The URL you get in that case often points to a transient location in the provider’s container, which won’t track changes back to the cloud unless the file is explicitly re‑opened via forOpeningContentTypes. In contrast, opening a file directly gives you a live reference bound to the Drive document ID, so coordinated writes are synced back.

Thanks and regards,
Taz

Hey,

Hope you’re keeping well.

On iOS, the Google Drive File Provider treats forExporting as a copy operation rather than a live reference to the canonical file in Drive. The URL you get in that flow often points to a transient location in the provider’s cache, so subsequent writes may succeed locally but won’t sync back to the cloud unless the file was opened via forOpeningContentTypes. From the Drive side this is expected behavior, since only “open” operations establish the correct backed document handle for overwrite sync.

If you must rely solely on iOS file APIs, the safe pattern is to treat Save As to Google Drive as export-only and then require the user to re-open the file from Drive before overwriting it. This ensures you get a persistent, sync-backed URL from the File Provider that Drive will update correctly. There’s no iOS API to resolve a transient export URL to the canonical Drive file without using the REST API or SDK.

Thanks and regards,
Taz

1 Like

Hello Taz!

Thank you for your insight and response as it was very helpful in narrowing down to the core problem. Your response about treating the operation as Save As then requiring the user to re-open the file to overwrite the contents of the file is what seems to be the solution for now.

Thank you for your time,
Jason

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.