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

When executing Amplify.Storage.uploadFile() on an iOS share extension, the error Error Domain=NSURLErrorDomain Code=-995 "(null)" occurs. #3340

Closed
Aoi-Takahashi opened this issue Nov 2, 2023 · 7 comments
Labels
feature-request Request a new feature storage Issues related to the Storage category

Comments

@Aoi-Takahashi
Copy link

Describe the bug

Hi!,Firstly, I would like to express my gratitude for this wonderful framework and all the advice from everyone.

Currently, we are developing a mobile app for both iOS and Android using React Native. To share PDFs with our app in development from external sources, we are considering using the iOS Share Extension to directly upload shared PDFs to our amplify S3 setup for mobile app use. However, when we execute Amplify.Storage.uploadFile() inside the ShareViewController UI's didSelectPost() provided by the Share Extension, the error Error Domain=NSURLErrorDomain Code=-995 "(null)" occurs. Below is the minimum code snippet that I can provide.

import UIKit
import Social
import Amplify
import AWSAPIPlugin
import AWSCognitoAuthPlugin
import AWSS3StoragePlugin

class ShareViewController: SLComposeServiceViewController {
  var typeIdentifier = "com.adobe.pdf"
  override func viewDidLoad() {
    super.viewDidLoad()
    do {
      Amplify.Logging.logLevel = .verbose
      try Amplify.add(plugin: AWSCognitoAuthPlugin())
      try Amplify.add(plugin: AWSAPIPlugin())
      try Amplify.add(plugin: AWSS3StoragePlugin())
      try Amplify.configure()
      print("Amplify configured with auth plugin")
    } catch {
      assertionFailure("Error initializing Amplify: \(error)")
    }
  }
  
  override func isContentValid() -> Bool {
    // Do validation of contentText and/or NSExtensionContext attachments here
    return true
  }
  
  override func didSelectPost() {
    // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
    // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
    if let item = extensionContext?.inputItems.first as? NSExtensionItem {
      if let itemProvider = item.attachments?.first {
        if itemProvider.hasItemConformingToTypeIdentifier(typeIdentifier) {
          itemProvider.loadItem(forTypeIdentifier:typeIdentifier, options: nil) { [weak self] (data, error) in
            guard let self = self else { return }
            
            if let fileURL = data as? URL {
              Task {
                do {
                  let isSignedIn = try await Amplify.Auth.fetchAuthSession().isSignedIn
                  if !isSignedIn {
                    print("User is not signed in!")
                    self.extensionContext?.cancelRequest(withError: NSError(domain: "Error", code: 401, userInfo: ["message": "User not authenticated"]))
                  }
                  let fileNameKey = "myDocument.pdf"
                  let options = StorageUploadFileRequest.Options(accessLevel: .private)
                  let uploadTask = Amplify.Storage.uploadFile(
                    key: fileNameKey,
                    local: fileURL,
                    options: options
                  )
                  let data = try await uploadTask.value
                  print("Completed: \(data)")
                  self.extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
                } catch {
                  print("Error: \(error)")
                  self.extensionContext?.cancelRequest(withError: NSError(domain: "Error", code: 400, userInfo: ["message": "Failed to upload PDF"]))
                }
              }
            }
          }
        }
      }
    }
  }
  override func configurationItems() -> [Any]! {
    // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
    return []
  }
  
}

Steps To Reproduce

1. Select `amplify-swift` in Swift PM, and add the following:
   - AWSAPIPlugin
   - AWSCognitoAuthPlugin
   - AWSPluginsCore
   - AWSS3StoragePlugin
   - Amplify
2. Execute `Amplify.add()` with the above plugins in `ShareExtension.swift`.
3. Execute `Amplify.configure()`.
4. Retrieve the PDF to be shared within `didSelectPost()` of the ShareViewController UI.
5. Execute `Amplify.Storage.uploadFile()` within `didSelectPost()` of the ShareViewController UI.
6. Confirm that the error `Error Domain=NSURLErrorDomain Code=-995 "(null)"` occurs and the PDF is not successfully uploaded to S3.

Expected behavior

The PDF selected in ShareExtension is successfully uploaded to S3.

Amplify Framework Version

2.21.3

Amplify Categories

Storage

Dependency manager

Swift PM

Swift version

5.0

CLI version

No Responce

Xcode version

Version 15.0

Relevant log output

<details>
<summary>Log Messages</summary>


ResumableUploadState: cannot initWithOriginalRequest with nil request
Started upload [1]
Resuming storage transfer task: 1
API MISUSE: Resuming an NSURLSessionTask with nil URL.
Task <C078E9F6-AC28-45F2-9D1B-96E8C6570F17>.<1> finished with error [18,446,744,073,709,550,621] Error Domain=NSURLErrorDomain Code=-995 "(null)" UserInfo={_NSURLErrorRelatedURLSessionTaskErrorKey=(
    "BackgroundUploadTask <C078E9F6-AC28-45F2-9D1B-96E8C6570F17>.<1>"
), _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundUploadTask <C078E9F6-AC28-45F2-9D1B-96E8C6570F17>.<1>}
[URLSession] Session task did complete with error: 1 [Error Domain=NSURLErrorDomain Code=-995 "(null)" UserInfo={_NSURLErrorRelatedURLSessionTaskErrorKey=(
    "BackgroundUploadTask <C078E9F6-AC28-45F2-9D1B-96E8C6570F17>.<1>"
), _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundUploadTask <C078E9F6-AC28-45F2-9D1B-96E8C6570F17>.<1>}]```
</details>

Is this a regression?

Yes

Regression additional context

No Responce

Platforms

iOS

OS Version

Main App iOS12.4 / ShareExtention iOS17.0

Device

iPhone15 Pro

Specific to simulators

No Responce

Additional context

I have conducted my own investigation regarding this issue and confirmed that the following operations work as expected:

  • The PDF selected in ShareExtension is correctly retrieved.
  • Amplify.Auth.SignIn()is executed within didSelectPost()of the ShareViewController UI, and authentication passes.
  • Amplify.Storage.List() is executed within didSelectPost() of the ShareViewController UI, and the expected information is retrieved with access levels of public/private.
    Furthermore, while investigating the origin of the error using breakpoints in Xcode, I observed that the error appears to be thrown at the following location:

Amplify/Core/Support/AmplifyTask+OperationTaskAdapters.swift

public var value: Success {
        get async throws {
            try await childTask.value
        }
    }
@thisisabhash thisisabhash added storage Issues related to the Storage category question General question feature-request Request a new feature labels Nov 2, 2023
Copy link
Contributor

github-actions bot commented Nov 2, 2023

This has been identified as a feature request. If this feature is important to you, we strongly encourage you to give a 👍 reaction on the request. This helps us prioritize new features most important to you. Thank you!

@thisisabhash
Copy link
Member

Hello @Aoi-Takahashi , App Extensions are currently not supported with Amplify. The error you're seeing is this one:
https://developer.apple.com/documentation/foundation/1508628-url_loading_system_error_codes/nsurlerrorbackgroundsessionrequiressharedcontainer

We are marking this as a feature request and update this thread we have an update.

@thisisabhash thisisabhash removed the question General question label Nov 2, 2023
@Aoi-Takahashi
Copy link
Author

Aoi-Takahashi commented Nov 3, 2023

Hello @Aoi-Takahashi , App Extensions are currently not supported with Amplify. The error you're seeing is this one: https://developer.apple.com/documentation/foundation/1508628-url_loading_system_error_codes/nsurlerrorbackgroundsessionrequiressharedcontainer

We are marking this as a feature request and update this thread we have an update.

@thisisabhash Oh...I see. Actually, I had a inkling of this result (that Amplify does not support File Up/Down on the Share extension)....
I understand that you are considering this as a feature request, but could you please tell us about the following?

  • I don't intuitively understand what is happening in this case with the NSURLErorBackgroundSessionRequiresSharedContainer URL you provided. What on earth is going on?
  •  I am sure there are others who have thought about this use case as well, but is there any current workaround or alternative to a requirement like this one?
  • I know this depends on the above question, but is it possible to approach the S3 endpoint directly using the URLSessiton API (https://developer.apple.com/documentation/foundation/urlsession) as a backdoor approach? Is this possible?

@harsh62
Copy link
Member

harsh62 commented Nov 3, 2023

Related: #2508

@thisisabhash
Copy link
Member

thisisabhash commented Nov 3, 2023

Hello @Aoi-Takahashi You may want to look at this thread here -
https://stackoverflow.com/questions/25438709/afnetworking-background-session-configuration-for-ios-8-extension

NSURLSession expects the App Extension to share the same container identifier as the host app. Currently, it is not configurable while using Amplify Storage APIs.
However, you may work around this by using Escape Hatch.
https://docs.amplify.aws/lib/storage/escapehatch/q/platform/ios/

This will give you access to the S3Client where you can use your custom URLSession object with shared container identifier and call methods on the S3Client directly.

@Aoi-Takahashi
Copy link
Author

Aoi-Takahashi commented Nov 10, 2023

Hello @Aoi-Takahashi You may want to look at this thread here - https://stackoverflow.com/questions/25438709/afnetworking-background-session-configuration-for-ios-8-extension

NSURLSession expects the App Extension to share the same container identifier as the host app. Currently, it is not configurable while using Amplify Storage APIs. However, you may work around this by using Escape Hatch. https://docs.amplify.aws/lib/storage/escapehatch/q/platform/ios/

This will give you access to the S3Client where you can use your custom URLSession object with shared container identifier and call methods on the S3Client directly.

@thisisabhash @harsh62  I am currently working on a solution to this problem based on your response, but I can't think of a specific technique based on the URL you provided, I would like to know if there are any other specific tips or approaches to solving this problem: ....

Copy link
Contributor

github-actions bot commented Oct 1, 2024

This issue is now closed. Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request Request a new feature storage Issues related to the Storage category
Projects
None yet
Development

No branches or pull requests

3 participants