0

I have an iOS share extension that needs the URL of the opened web page. Everything works good, especially in a simulator. But on a real device I have around 20-30% cases where the extension does not receive any data i.e.:

NSExtensionItem *inputItem = self.extensionContext.inputItems.firstObject;
NSItemProvider *item = inputItem.attachments.firstObject;

[item loadItemForTypeIdentifier:(NSString *)kUTTypePropertyList options:nil completionHandler:^(NSDictionary *item, NSError *error) {
    // here the error is sometimes not nil and thus the _baseURI ends up nil
    _baseURI = [item[NSExtensionJavaScriptPreprocessingResultsKey] objectForKey:@"baseURI"];
}];

The error code is -100 with description "No item available for requested type identifier.". This happens mainly when I open the extension several times in a row without changing/refreshing the web page in the Safari.

In those situations I see a device log saying "iPhone kernel[0] : Sandbox: MobileSafari(7033) deny(1) file-read-data /private/var/containers/Bundle/Application/.../bundle.js" where the bundle.js is the javascript with the ExtensionPreprocessingJS object. The bundle.js declares the ExtensionPreprocessingJS object like this (extracted the relevant part):

ExtensionPreprocessingJS = {
  run: function(arguments){
      arguments.completionFunction({
        "baseURI": document.baseURI
      })
  },

  finalize: function(arguments){
  }
}

In this situation, it could some time happen that when the extension is closed the next time opening the share dialog in Safari shows my extension with no icon. This happens on my testing iPhone 5s and iPhone 6 with iOS 9.3.

I think that the missing data is because of the system could not read the extension's JavaScript file, but why could this happen?

shelll
  • 3,234
  • 3
  • 33
  • 67

1 Answers1

0

If you read the documentation for:

loadItemForTypeIdentifier(_:options:completionHandler:)

You'll see that:

The type information for the first parameter of your completionHandler block should be set to the class of the expected type. For example, when requesting text data, you might set the type of the first parameter to NSString or NSAttributedString. An item provider can perform simple type conversions of the data to the class you specify, such as from NSURL to NSData or NSFileWrapper, or from NSData to UIImage (in iOS) or NSImage (in OS X). If the data could not be retrieved or coerced to the specified class, an error is passed to the completion block’s.

Try this code to see what you recieve:

[item loadItemForTypeIdentifier:(NSString *)kUTTypePropertyList options:nil completionHandler:^(id item, NSError *error) {
// here the error is sometimes not nil and thus the _baseURI ends up nil
_baseURI = [item[NSExtensionJavaScriptPreprocessingResultsKey] objectForKey:@"baseURI"];
}];

Note that item is not set to NSDictionary.

Vamos
  • 2,701
  • 2
  • 24
  • 37
  • I just tried this and it behaves exactly the same, the *item* is nil. – shelll May 04 '16 at 12:16
  • When you open and close the extension many times, a new instance of the extension is not being instantiated each time. In fact the extension remains alive and is re-used, this could be the root of your issues. – Vamos May 04 '16 at 13:50
  • Why would Safari/iOS not send data to extension even if the extension is alive? This does not make any sense and it breaks apps. I confirmed that I can save the last *item* in a static variable which is there after the next extension start. This is a good fallback for quick returns to the extension. If needed I will later save it into the user defaults. Thank you. If you extend your answer with this "hack" I will accept it. – shelll May 05 '16 at 08:09