Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Files shared for "open in place" editing with third-party apps do not work correctly in iOS17 #19352

Closed
gavinschultz opened this issue Oct 26, 2023 · 8 comments
Labels
question The issue is a question
Milestone

Comments

@gavinschultz
Copy link

Steps to Reproduce

Our app has PDFs which we allow third-party PDF apps to "open in place" for editing. The mechanism works basically like this:

  1. Info.plist has all the necessary flags for opening a document, namely UIFileSharingEnabled and LSSupportsOpeningDocumentsInPlace, both set to true/YES.
  2. Store PDFs in our app in a subfolder of the Documents folder (Environment.SpecialFolder.MyDocuments); resolving ultimately to, for example: /var/mobile/Containers/Data/Application/788C7161-32EB-4AF0-964D-2A473257A791/Documents/7cafe7e7-9da9-40cd-b233-a85b0174fe00/624cbc1e-a7c5-4c0d-8937-b0a00013b2a9.pdf.
  3. Via UIDocumentInteractionController.PresentOpenInMenu, allow the user to open the PDF for editing in a third-party app:
private static UIDocumentInteractionController documentController;

public void OpenPdfFormFile(string filePath)
{
    PresentOpenInMenu(NSUrl.FromFilename(filePath));
}

public void PresentOpenInMenu(NSUrl url)
{
    documentController = UIDocumentInteractionController.FromUrl(url);
    var lastView = UIApplication.SharedApplication.KeyWindow.RootViewController.View;

    // Specify a frame for the Open In menu. Required for iPad (but can be run for all).
    var frame = new CGRect(lastView.Frame.Width / 2, lastView.Frame.Bottom, 0, 0);
    
    var menuPresented = documentController.PresentOpenInMenu(frame, lastView, true);
    if (!menuPresented)
    {
        Toast(NSBundle.MainBundle.GetLocalizedString("FileHelper_OpenPdfFailed"), Helpers.ToastLength.Long);
    }
}

The absolute URL generated at this point is a simple variation of the original e.g. file:///var/mobile/Containers/Data/Application/788C7161-32EB-4AF0-964D-2A473257A791/Documents/7cafe7e7-9da9-40cd-b233-a85b0174fe00/624cbc1e-a7c5-4c0d-8937-b0a00013b2a9.pdf

Expected Behavior

The original PDF files in our app's Documents directory can be opened in third-party PDF applications, and saved without any additional work from the user.

Actual Behavior

On iOS 16 and lower, it works as expected; the third-party app is able to read and automatically save changes to the PDF directly in our app's folder path. For example, the Xodo logs indicate that it's opening directly from our app's path:

Xodo initialized document instance: <PTCoordinatedDocument: 0x282453a00> fileURL: file:///private/var/mobile/Containers/Data/Application/788C7161-32EB-4AF0-964D-2A473257A791/Documents/7cafe7e7-9da9-40cd-b233-a85b0174fe00/624cbc1e-a7c5-4c0d-8937-b0a00013b2a9.pdf
Xodo opening document: <PTCoordinatedDocument: 0x282453a00> fileURL: file:///private/var/mobile/Containers/Data/Application/788C7161-32EB-4AF0-964D-2A473257A791/Documents/7cafe7e7-9da9-40cd-b233-a85b0174fe00/624cbc1e-a7c5-4c0d-8937-b0a00013b2a9.pdf

On iOS 17, this no longer works correctly, and although the third-party PDF editor can read our PDF, it's quite clear that it's actually using a copy. If not quite identical to what happens when LSSupportsOpeningDocumentsInPlace is false/NO, the end result is very similar:

Xodo initialized document instance: <PTCoordinatedDocument: 0x2828aae00> fileURL: file:///var/mobile/Containers/Data/Application/6830EDC5-F776-4BEF-8C30-046BCA1F2DF0/Documents/Processed%20Files/624cbc1e-a7c5-4c0d-8937-b0a00013b2a9.pdf
Xodo opening document: <PTCoordinatedDocument: 0x2828aae00> fileURL: file:///var/mobile/Containers/Data/Application/6830EDC5-F776-4BEF-8C30-046BCA1F2DF0/Documents/Processed%20Files/624cbc1e-a7c5-4c0d-8937-b0a00013b2a9.pdf

The third-party app will immediately prompt the user to save the file, but regardless, the copy is now beyond the purview of our app so we can no longer see any changes made to it.

The only workaround is to have the user explicitly share the file from the third-party app back to our app (we have the code in place to handle this), but much preferred the seamless "open in place" integration which did not require this.

There have been vague allusions to changes in the file system in iOS 17, but I have not been able to find primary sources or much specific detail. For example:

I have not been able to figure out if this is a flaw in our code, or iOS 17, or Xamarin's implementation of the API. Note that we are fairly sure this is not due to specific flaws in the third-party apps, as all of the ones we have tried (PDF Viewer, Xodo etc) exhibit basically the same behavior.

Environment

Version information
Visual Studio Community 2022 for Mac
Version 17.6.5 (build 417)
Installation UUID: 2f2234ec-5313-440b-8113-4742c87050d4

Runtime
.NET 7.0.3 (64-bit)
Architecture: Arm64
Microsoft.macOS.Sdk 13.1.1007; git-rev-head:8afca776a0a96613dfb7200e0917bb57f9ed5583; git-branch:release/7.0.1xx-xcode14.2

Roslyn (Language Service)
4.6.0-3.23180.6+99e956e42697a6dd886d1e12478ea2b27cceacfa

NuGet
Version: 6.4.0.117

.NET SDK (Arm64)
SDK: /usr/local/share/dotnet/sdk/7.0.309/Sdks
SDK Versions:
7.0.309
7.0.308
6.0.415
6.0.414
6.0.302
MSBuild SDKs: /Applications/Visual Studio.app/Contents/MonoBundle/MSBuild/Current/bin/Sdks

.NET SDK (x64)
SDK Versions:
3.1.426
3.1.421

.NET Runtime (Arm64)
Runtime: /usr/local/share/dotnet/dotnet
Runtime Versions:
7.0.12
7.0.11
6.0.23
6.0.22
6.0.7

.NET Runtime (x64)
Runtime: /usr/local/share/dotnet/x64/dotnet
Runtime Versions:
3.1.32
3.1.27

Xamarin.Profiler
Version: 1.8.0.49
Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

Updater
Version: 11

Apple Developer Tools
Xcode: 15.0 22265
Build: 15A240d

Xamarin.Mac
Not Installed

Xamarin.iOS
Version: 16.4.0.18 Visual Studio Community
Hash: 9d266025e
Branch: xcode14.3
Build date: 2023-09-06 19:52:27-0400

Xamarin Designer
Version: 17.6.3.9
Hash: 2648399ae8
Branch: remotes/origin/d17-6
Build date: 2023-10-04 18:09:13 UTC

Xamarin.Android
Not Installed

Microsoft Build of OpenJDK
Java SDK: Not Found

Eclipse Temurin JDK
Java SDK: Not Found

Android SDK Manager
Version: 17.6.0.50
Hash: a715dca
Branch: HEAD
Build date: 2023-10-04 18:09:18 UTC

Android Device Manager
Version: 0.0.0.1309
Hash: 06e3e77
Branch: HEAD
Build date: 2023-10-04 18:09:18 UTC

Build Information
Release ID: 1706050417
Git revision: 6d6585a706becbd4a5be3b0e99ace260dfdf5748
Build date: 2023-10-04 18:07:26+00
Build branch: release-17.6
Build lane: release-17.6

Operating System
Mac OS X 14.0.0
Darwin 23.0.0 Darwin Kernel Version 23.0.0
    Fri Sep 15 14:41:34 PDT 2023
    root:xnu-10002.1.13~1/RELEASE_ARM64_T8103 arm64

Build Logs

N/A, build works fine

Example Project (If Possible)

None

@Eagle104
Copy link

I have been experiencing the same issue on Word with .docx documents they seem to only open in Read-Only mode. with ios17. I have been looking for a solution for some time now and cant seem to find what could be causing this.

@rolfbjarne
Copy link
Member

My guess would be that this is an intentional change by Apple, but only they can confirm. Apple's documentation also isn't 100% clear that your code is supposed to work (the documentation for LSSupportsOpeningDocumentsInPlace seems to imply it's only for file provider (extension?)s, the fact that it worked for apps might not have been Apple's intention).

I would start diagnosing this by trying to replicate the problem in an Xcode project (which would rule out any problems in our bindings).

If the Xcode project works, please attach both the Xcode project and the Xamarin/.NET project here, reopen the issue, and we'll investigate to try to figure out what we're doing wrong.

If the Xcode project doesn't work, then I'd post a question on Apple's Developer Forums.

I'm closing this for now since it does not look like a bug on our side (as I said, feel free to reopen if you determine otherwise).

@rolfbjarne rolfbjarne closed this as not planned Won't fix, can't repro, duplicate, stale Oct 26, 2023
@rolfbjarne rolfbjarne added the question The issue is a question label Oct 26, 2023
@rolfbjarne rolfbjarne added this to the Future milestone Oct 26, 2023
@gavinschultz
Copy link
Author

Just a quick follow-up.

We posted a corresponding question in the Apple Developer Forum as suggested. No answers at time of writing, but one more "that's happening to me too" response.

We also submitted a formal TSI (Technical Support Incident) to Apple Developer Technical Support, but the response was, in short:

We’ve determined that your question should be addressed by the support channel for Xamarin - the third-party resource you are using. DTS supports developers using Apple-authored tools and frameworks only. We are unable to provide support for third-party tools, development environments, tutorials or other resources.

We agree with Rolf's advice that the next best step is to recreate this natively in an XCode project. Unfortunately we don't have the resourcing available to do this at the moment, so for now we'll keep our ear to the ground to see if a solution naturally emerges; perhaps eventually someone very important will have the same problem and Apple will jump on it.

Thank you for your responses to date.

@gavinschultz
Copy link
Author

Also, just in regards to this:

Apple's documentation also isn't 100% clear that your code is supposed to work (the documentation for LSSupportsOpeningDocumentsInPlace seems to imply it's only for file provider (extension?)s

I may be wrong, but my reading of the File Provider documentation is that with the flags we set and to simply provide access to our files, we wouldn't need to implement a File Provider extension:

You don’t need a File Provider extension to allow access to documents that your app stores locally. In iOS, to give other apps access to the files in your Documents directory, set the following keys in your app’s Info tab or its Info.plist file. For document browser-based apps, set the UISupportsDocumentBrowser key. For all other apps, set both the UIFileSharingEnabled and LSSupportsOpeningDocumentsInPlace keys.

@MartinWegner
Copy link

I came across the same problem. @Eagle104 and @gavinschultz. Did you make any progress on this problem? I'm stuck.

@gavinschultz
Copy link
Author

gavinschultz commented Dec 15, 2023

@MartinWegner No further progress yet - sorry.

We are using the workaround of making the users share the file back from the third-party application to our application and re-saving it. It's not ideal to have the users perform that extra step, but the best we have for now.

As a starting point, we do this by overriding OpenUrl in the iOS AppDelegate (disclaimer: this is relatively old code and still Xamarin rather than MAUI - there could well be a more modern way of doing this in 2023):

[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
        //This function will be triggered when a document is shared from third-party application via "Open in" or "Copy to"
        public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
        {
           // re-save file from url
        }
}

@MartinWegner
Copy link

@gavinschultz Thank you for sharing the workaround. We have the same function in place and it works for now. But we struggle with the fact, that our initial opening of the file is read only. This isn't the case in iOS 16.
Some apps like Microsoft Office offer a function to create a copy of the file to there own storage. Others like Collabora Office don't. So the user is stuck with a read only file he cant edit or save. Did you find any workaround for that? Seems like a Collabora Office problem, but I would like it to work like in iOS 16.

@gavinschultz
Copy link
Author

@MartinWegner I feel your pain but, like you, I too would guess that Collabora is probably not doing enough in this case. It makes some intuitive sense that, without open-in-place working properly, the file being shared wouldn't be initially writeable to other apps unless they make the local copy themselves. We've been fortunate in our own case that we haven't had to deal with that problem, as the third-party PDF apps we typically suggest (PDF Viewer and Xodo) do behave more like what you describe for Microsoft Office. Sorry I can't be of more help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question The issue is a question
Projects
None yet
Development

No branches or pull requests

4 participants