今回は写真 App で選択した写真を、自分のアプリに共有できるまでをなぞります。
その際の画面は、自分で作成した画面を出すようにします ✧٩(ˊωˋ*)و✧
アプリにもよると思いますが、私の周りでは意外と需要があるようで、仕事でもそのような実装をお願いされたり、自分のアプリでも問い合わせがあります。
実装する機会が少なそうなので、方法を載せながらやっていきたいと思います!
開発環境(前提条件)
・Xcode12.5((21年05月16日再確認済み)
・Swift5
・Storyboard を使います(SwiftUI は使いません)
実装方法
ShareExtension を使うための設定
File → New → Target を選択すると、以下の画面になるので、Share Extension を選択。

プロジェクト名をテキトーに入力してください。(ここでは MyProject-ShareExtension とします)
ターゲットの作成が完了したら、写真 App と自分のアプリ間でファイル共有をするために App Gourps という仕組みを利用するので、以下の手順で設定してください。
TARGETS → MyProject → Signing & Capabilities → + Capability → App Groups
App Group に作成された group.bundleid にチェックを入れましょう!
そして同じ手順で MyProject の部分を MyProject-ShareExtension に変えて同じ操作をします。
TARGETS → MyProject-ShareExtension → Signing & Capabilities → + Capability → App Groups
これで共有できるようになったので、コードに戻ります。
画面を作成する
再執筆時では、ターゲット作成時に ShareViewController.swift と MainInterface.storyboard 、Info.plist というファイルが自動で生成されています。
ShareViewController.swift を開くと、以下のようになっています。
import UIKit
import Social
class ShareViewController: SLComposeServiceViewController {
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.
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
override func configurationItems() -> [Any]! {
// To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
return []
}
}
SLComposeServiceViewController を継承していますが、このクラスを画像検索してみてください。
ザ・投稿!みたいなアラートが表示された画像が出てくると思います。
冒頭でも述べたように、今回は自分で作成した画面を出したいので、override を全て削除し、継承するクラスを UIViewController に変更します。
import UIKit
class ShareViewController: UIViewController {
override func viewDidLoad() {}
}
UITableView を使ってもいいし UICollectionView を使ってもいいので、お好きな UI を作成してオリジナルの画面を作成しましょう!(画面作成は省略します)
選択された画像を取得する
とりあえず取得できるコードを載せます。
import UIKit
import MobileCoreServices
class ShareViewController: UIViewController {
override func viewDidLoad() {
guard let inputItem = self.extensionContext?.inputItems.first as? NSExtensionItem, let attachments = inputItem.attachments else {
return
}
let identifier = String(kUTTypeImage)
let imgAttachments = attachments.filter { $0.hasItemConformingToTypeIdentifier(identifier) }
for itemProvider in imgAttachments {
itemProvider.loadItem(forTypeIdentifier: identifier, options: nil) { item, error in
do {
if let error = error {
throw error
} else if let url = item as? URL {
let data = try Data(contentsOf: url)
let image = UIImage(data: data)
}
} catch {
}
}
}
}
}
このままじゃ使わねーよ感のあるコードですね!
まぁ僕もこのままは使ってないですけど。笑
表示するタイミングとかはよしなにしてください。
元のアプリに戻る設定をする
自作画面なので、元のアプリに戻るコードも自分で実装する必要があります。
昔は UIApplication の shared にアクセスして open(_:options:completionHandler:) が使えたんですけど、今は使えないので別の方法で実装するしかないです。
func backToApp() {
self.extensionContext?.completeRequest(returningItems: nil, completionHandler: { _ in
let selector = sel_registerName("openURL:")
var responder = self as UIResponder?
while let r = responder, !r.responds(to: selector) {
responder = r.next
}
_ = responder?.perform(selector, with: URL.schemeURL)
})
}
無理矢理感ありますけど、これ以外に戻る方法が浮かびませんでしたー!
何かいい方法があれば教えてください。
さいごに
なんかもっと実装が簡単になってほしい。笑
今あるメソッドが廃止になるのは仕方ないけど、ちゃんと代わりのやつ提供してほしい _(꒪ཀ꒪」∠)_
とりあえず共有はできたのでよしとします!!!



コメント