ShareSheet fails to open a local file

1.6k Views Asked by At

I have a file-exporter class that was working in previous iOS versions. Now it is throwing an error saying the file can't be opened.

The function that opens the ShareSheet looks like this:

func share(log: Log, fileType: String, excludedActivityTypes: [UIActivity.ActivityType]? = nil
    ) {
        guard let source = (UIApplication.shared.connectedScenes.first as? UIWindowScene)?.windows.first?.rootViewController else {
            return
        }
        
        DispatchQueue.main.async {
            self.isSharing = true
        }
    
        let filename = dateFormatterShort.string(from: log.date) + "_\(log.takeOff)"
        let exportURL = save(filename, fileContents: fileContents, fileExt: fileExt)

        DispatchQueue.main.async {
            let vc = UIActivityViewController(
                activityItems: [exportURL],
                applicationActivities: nil
            )
            vc.excludedActivityTypes = excludedActivityTypes
            vc.popoverPresentationController?.sourceView = source.view
            source.present(vc, animated: true)
            self.isSharing = false
        }
        return
    }

The log says:

"Writing CSV file with 11 entries."
"Saved file to: file:///var/mobile/Containers/Data/Application/2E8013C8-DACF-4F53-8A73-18067C9B1812/Documents/21.07.23_Munich.csv"
[ShareSheet] Failed to request default share mode for fileURL:file:///var/mobile/Containers/Data/Application/2E8013C8-DACF-4F53-8A73-18067C9B1812/Documents/21.07.23_Munich.csv error:Error Domain=NSOSStatusErrorDomain Code=-10814 "(null)" UserInfo={_LSLine=1569, _LSFunction=runEvaluator}
[ShareSheet] Only support loading options for CKShare and SWY types.
[ShareSheet] error fetching item for URL:file:///var/mobile/Containers/Data/Application/2E8013C8-DACF-4F53-8A73-18067C9B1812/Documents/21.07.23_Munich.csv : Error Domain=NSCocoaErrorDomain Code=256 "The file couldn’t be opened."
[default] LaunchServices: store (null) or url (null) was nil: Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=66, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler}
[default] Attempt to map database failed: permission was denied. This attempt will not be retried.
[db] Failed to initialize client context with error Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=66, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler}
[ShareSheet] error loading metadata for documentURL:file:///var/mobile/Containers/Data/Application/2E8013C8-DACF-4F53-8A73-18067C9B1812/Documents/21.07.23_Munich.csv error:Error Domain=NSFileProviderInternalErrorDomain Code=0 "No valid file provider found from URL file:///var/mobile/Containers/Data/Application/2E8013C8-DACF-4F53-8A73-18067C9B1812/Documents/21.07.23_Munich.csv." UserInfo={NSLocalizedDescription=No valid file provider found from URL file:///var/mobile/Containers/Data/Application/2E8013C8-DACF-4F53-8A73-18067C9B1812/Documents/21.07.23_Munich.csv.}
[Presentation] Attempt to present <UIActivityViewController: 0x10500ea00> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x105019e00> (from <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x105019e00>) which is already presenting <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x103810000>.
[default] LaunchServices: store (null) or url (null) was nil: Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=66, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler}
[default] Attempt to map database failed: permission was denied. This attempt will not be retried.
[db] Failed to initialize client context with error Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=66, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler}
[ShareSheet] connection invalidated

If I simply try String(contentsOf: exportURL) I can read the file content just fine!

I have tried to find a solution for days now and would like to ask you for help!

Thanks to some comments below, I have updated my Info.plist with these points, but it still doesn't work unfortunately:

    <key>CFBundleDocumentTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeName</key>
            <string>CSV File</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>com.lcairsports.csv</string>
            </array>
        </dict>
    </array>
    <key>UTExportedTypeDeclarations</key>
    <array>
        <dict>
            <key>UTTypeConformsTo</key>
            <array>
                <string>public.comma-separated-values-text</string>
            </array>
            <key>UTTypeIdentifier</key>
            <string>com.lcairsports.csv</string>
            <key>UTTypeDescription</key>
            <string>CSV File</string>
            <key>UTTypeTagSpecification</key>
            <dict>
                <key>public.filename-extension</key>
                <string>csv</string>
            </dict>
        </dict>
    </array>
    <key>UIFileSharingEnabled</key>
    <true/>
2

There are 2 best solutions below

1
Luke Crouch On BEST ANSWER

It works now by using the new "ShareLink" functionality presented in iOS 16:

ShareLink("Share File", item: fileURL)
0
Gavin On

[ShareSheet] Failed to request default share mode for fileURL:file:///var/mobile/Containers/Data/Application/2E8013C8-DACF-4F53-8A73-18067C9B1812/Documents/21.07.23_Munich.csv error:Error Domain=NSOSStatusErrorDomain Code=-10814 "(null)" UserInfo={_LSLine=1569, _LSFunction=runEvaluator} [ShareSheet] Only support loading options for CKShare and SWY types. [ShareSheet] error fetching item for URL:file:///var/mobile/Containers/Data/Application/2E8013C8-DACF-4F53-8A73-18067C9B1812/Documents/21.07.23_Munich.csv : Error Domain=NSCocoaErrorDomain Code=256 "The file couldn’t be opened."

and

[ShareSheet] error loading metadata for documentURL:file:///var/mobile/Containers/Data/Application/2E8013C8-DACF-4F53-8A73-18067C9B1812/Documents/21.07.23_Munich.csv error:Error Domain=NSFileProviderInternalErrorDomain Code=0 "No valid file provider found from URL file:///var/mobile/Containers/Data/Application/2E8013C8-DACF-4F53-8A73-18067C9B1812/Documents/21.07.23_Munich.csv." UserInfo={NSLocalizedDescription=No valid file provider found from URL file:///var/mobile/Containers/Data/Application/2E8013C8-DACF-4F53-8A73-18067C9B1812/Documents/21.07.23_Munich.csv.}

I believe the above quoted errors are to do with the introduction of iOS 13. For myself these errors do not prevent the ShareSheet from showing or saving the file to Files, it is just suboptimal and a bit ugly. Full disclosure I am using UIKit rather than SwiftUI and I am Exporting a custom type.
(Hacking with Swift has a write up on the ShareSheet and SwiftUI, the article seems to target iOS16+).

That said I think that with the introduction of iOS 13 Apple have tightened up on the correct use of Exported types.
In your example you should not define your application as exporting CSV files as you do not own CSV files they are a public type, instead you should be defining that your app can be a target for importing/open CSV files. From the Apple docs:

When defining a type, you need to define it as an exported or imported type; this declaration indicates whether your app is the source of the type or whether it supports using a type defined elsewhere, respectively. If your app uses a type that this framework provides, don’t redeclare it in your app’s bundle.

Define an exported type when your app is the canonical source of information for that type. For example, if your app uses its own proprietary document format, declare it as an exported type.

Define an imported type if your app uses a type that another app defines, or if it’s a proprietary file format the system doesn’t declare. When importing a type from another app, don’t declare your own identifier; instead, use the same type identifier as the original.

As such I would try replacing the UIExportedTypeDeclarations with a UIImportedTypeDeclarations.
If I am understanding the documentation correctly UITypeIdentifier should be public.comma-separated-values-text and its UITypeConformsTo should be public.delimited-values-text.
CSV UTType (Note that the CSV UTType was introduced in iOS14)

Also I extended UIActivityItemSource to wrap the URL and then overloaded (UIActivityItemSource) activityViewControllerLinkMetadata and passed this to the UIActivityViewController list of items. This seemed to eliminate the errors relating the file url. Alternatively passing a Data representation of the file rather than URL to the UIActivityViewController list of items also seemed too work. (Note LPLinkMetadata was introduced in iOS13)