Action Extensionはアプリから任意のデータを受け取り、処理を行い、結果を戻すことができる汎用的なエクステンションです。
URLをWebViewで開き、全体のスクリーンショットをカメラロールに保存するサンプルを作成しました。
https://github.com/imk2o/Try-AppExtensions
処理の流れ
- ビューコントローラがインスタンス化される
- アプリより渡されたアイテムを取得し、任意の処理を行う
- UIViewController#extensionContext
- NSExtensionContext#inputItems
- リクエストを完了する
- NSExtensionContext#completeRequestReturningItems(_:completionHandler:)
- NSExtensionContext#cancelRequestWithError(_:)
Info.plistの設定
Info.plist
のNSExtensionActivationRule
に、受入可能なデータタイプの設定を行います。
デフォルトでは全てを受け入れる
TRUEPREDICATE
が設定されているが、リジェクトされる可能性があるため適宜設定すること。
- NSExtensionActivationSupportsAttachmentsWithMaxCount:
- NSExtensionActivationSupportsAttachmentsWithMinCount
- NSExtensionActivationSupportsFileWithMaxCount: 受入可能なファイル数
- NSExtensionActivationSupportsImageWithMaxCount: 受入可能な画像数
- NSExtensionActivationSupportsMovieWithMaxCount: 受入可能な動画数
- NSExtensionActivationSupportsText: テキストは受入可能か?(Boolean)
- NSExtensionActivationSupportsWebURLWithMaxCount: 受入可能なURL数
- NSExtensionActivationSupportsWebPageWithMaxCount: 受入可能なWebページ数
アプリより渡されたアイテムの取得
アプリより渡されたアイテムはextensionContext.inputItems
に格納されています。受入可能な型として値を取り出します。
override func viewDidLoad() {
super.viewDidLoad()
// 1つのアイテムを抽出(Info.plistの設定により制限されている)
guard
let item = self.extensionContext?.inputItems.first as? NSExtensionItem,
let itemProvider = item.attachments?.first as? NSItemProvider
else {
return
}
// アイテムからURLを抽出
if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
itemProvider.loadItemForTypeIdentifier(kUTTypeURL as String, options: nil) { [weak self] (item, error) in
if let error = error {
self?.extensionContext?.cancelRequestWithError(error)
} else if let URL = item as? NSURL {
dispatch_async(dispatch_get_main_queue()) {
self?.loadURL(URL)
}
}
}
}
}
リクエストの完了
処理が成功した場合はNSExtensionContext#completeRequestReturningItems(_:completionHandler:)
を呼び出します。このとき、アプリ側に処理したNSExtensionItemを返すこともできます。処理に失敗した場合はNSExtensionContext#cancelRequestWithError(_:)
を呼び出します。
サンプルコードではWebページのキャプチャを行い、その画像の保存完了時に各ハンドラを呼び出しています。
func image(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeMutablePointer<Void>) {
if let error = error {
self.extensionContext?.cancelRequestWithError(error)
} else {
self.extensionContext?.completeRequestReturningItems(nil, completionHandler: nil)
}
}
参考
http://dev.classmethod.jp/references/ios-8-action-extension/
http://hack.sonix.asia/archives/936