I'm developing an app extension as an Action
.
The host app will use my extension in the normal way: by presenting the UIActivityViewController
to include an array of activityItems
which are then passed to my extension.
iOS will decide whether to present my Action based on whether the items match the NSExtensionActivationRule
setting that I have defined in info.plist
of the extension.
This feature seems to be meant for content and pointers to content (images, videos, text, files, URLs).
Instead I need to pass structured data and receive back structured data.
I could define my itemType
as text using activation rule NSExtensionActivationSupportsText
, and then just pass serialized JSON. However, then my action would be offered for simple plain text. Not good.
There is apparently some cryptic query language that can be used to define an NSPredicate
in my NSExtensionActivationRule
setting, which allows some kind of customization.
But I cannot figure it out. All the examples are based on content, not data. How I can define my custom actionItem
as structured data and let iOS know when my action is truly appropriate?
Can I accomplish what I want? How? Any tips are appreciated.
UPDATE: I suspect the key to this question is custom Uniform Type Identifiers. However, I'm still stuck because all the examples of UTI definitions are still content (files and media), not structured data.
Uniform Type Identifiers are indeed the correct way to do this.
I have not finished developing this, but I managed to get it minimally working. Basically you define a custom type like com.company.app.myThing
and you can pass your custom object as a hash with whatever data structure you want. Obviously the consumer needs to know and follow this schema.
Here is the relevant portion of info.plist
in the extension:
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<string>SUBQUERY(extensionItems, $extensionItem, SUBQUERY($extensionItem.attachments, $attachment, ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "com.company.app.myThing").@count == 1).@count == 1</string>
<key>NSExtensionPointName</key>
<string>com.apple.ui-services</string>
<key>NSExtensionPointVersion</key>
<string>1.0</string>
</dict>
In the ActionViewController.viewDidLoad
in the extension:
let item = self.extensionContext.inputItems[0] as NSExtensionItem
let provider = (item.attachments as Array<NSItemProvider>)[0] as NSItemProvider
provider.loadItemForTypeIdentifier("com.company.app.myThing", options: nil, completionHandler: { msg, error in
let my_thing = (msg as? NSDictionary) as Dictionary<String, AnyObject>
// do stuff with my_thing
})
Then in the host app:
let my_thing = [
"foo": "bar",
"baz": 123
]
let item = NSExtensionItem()
let attachment = NSItemProvider(item: my_thing, typeIdentifier: "com.company.app.myThing")
item.attachments = [attachment]
let activityViewController = UIActivityViewController(activityItems: [item], applicationActivities: nil)
self.presentViewController(activityViewController, animated: true, completion: actionComplete)
DISCLAIMER: Please do not consider this an authoritative how-to, but I hope it can point you in the right direction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With