【iOS】ShareExtension を導入してみたよ
どうも。Reo です。
個人アプリに ShareExtension を使うついでに、手順をメモしながら導入しようと思います。
環境
- Xcode11.3
- Swift 5.1.3
- iOS 13.3
今回はサンプルプロジェクトを用意しません。余裕があるときに追記するかもしれませんが。
ターゲットを追加する
まずはターゲットを追加します。
ShareExtension は別ターゲットで開発していくことになります。なのでライブラリ等を使う場合は注意が必要です。
File > New > Target より ShareExtension を追加します。
名前はそのまま ShareExtension にしました。
作成するとポップアップが出てきました。Activate を選択しましょう。
これで ShareExtension フォルダができていればおkです。
簡単!
とりあえずビルドをしてみましょう。
ビルドターゲットを ShareExtension に設定をして実行します。
すると、どのアプリで実行するかのポップアップが表示されます。とりあえず Safari で見てみましょう。
Safari が開かれるので 下部タブバーのシェアボタンを押してみます。
はい!プロジェクト名のアイコン(設定してないので白ペッペ)を見つけられたらオッケーです。
押してみると、デフォルトの画面が表示されます。
ここの画面をカスタマイズして、アプリに情報を送信することができます。今は Post に何もアクションを設定してないので、画面を閉じる処理のみが行われます。
また、Cancel, Post の部分はアプリをローカライズしている場合には反映がされるはずです。ちょっと試してないんですが、されるはず...
こんな風に画面をカスタマイズすることもできますよ。
全く手入れができていないんですが、AppApp のコードは GitHub に公開してあります。
AppGroups の設定をする
さて。ShareExtension とアプリを繋げるために AppGroups の設定をしていきます。
プロジェクトを選択して、TARGETS > ShareExtension の 上部タブの Sigining & Capabilities を開きます。+アイコンを押して Capability を追加します。(Capabilityは能力という意味。能力の追加...!カコイイ!)
AppGroups をダブルクリックで追加します。
そうすると以下のような項目が追加されます。
これね、すごいね。AppAppが出てきちゃった!!
App Groups を利用すると、FileManager や UserDefaults を使ってアプリ間でファイルの共有をすることができます。でも今回は使わないのでここには特にチェックを入れず、新規に Group を作ります。
+を押して、Group を追加します。group. プロジェクトのBundle ID にすると良いです。
間違えた名前で作ってしまった奴が消せない...消せないのかこいつ...ちょっとわかったら追記します。
Keychain Sharingを追加する
AppGroups を追加する手順と同様に Keychain Sharing を追加します。
こちらは+ボタンを押すだけで追加されます。
これでとりあえずおkのはず。
UserDefaults で保存してみる
最後に実際にデータを UserDefaults で保存して、アプリで受け取ることができるかを試してみます。
ShareViewController.swift の didSelectPost() 内で URL を取得します。Safari で検証する予定なので、URL が取得できる前提です。
didSelectPost() は投稿ボタンが押されたときの処理を書きます。
override func didSelectPost() {
guard let extensionItem: NSExtensionItem = extensionContext?.inputItems.first as? NSExtensionItem, let itemProviders = extensionItem.attachments else { return }
// URL を取得する
let identifier = "public.url"
let urlProvider = itemProviders.first(where: { $0.hasItemConformingToTypeIdentifier(identifier)})
urlProvider?.loadItem(forTypeIdentifier: identifier, options: nil, completionHandler: { [weak self] (item, error) in
// item に格納されている
guard let url = item as? URL else { return }
self?.save(url: url)
// 最後にこれを呼ばないとフリーズする
self?.extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
})
}
private func save(url: URL) {
// UserDefaults に保存
}
この辺の説明はちょっと割愛。いずれAppAppのリファクタリングブログを書くつもりなのでその時に余裕があれば...(書く書く詐欺なう...)
save(url:)の中で、UserDefaultsに保存します。
private func save(url: URL) {
// AppGroups に設定したもの
let suiteName = "group.hoge.hoge.hogehoge"
let key = "shareSampleURLKey"
let userDefaults = UserDefaults(suiteName: suiteName)
userDefaults?.set(url, forKey: key)
}
これで ShareExtension を実行して Post まで実行します。
アプリ側の適当な ViewController で取得してみます。
final class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// AppGroups に設定したもの
let suiteName = "group.hoge.hoge.hogehoge"
let key = "shareSampleURLKey"
let userDefaults = UserDefaults(suiteName: suiteName)
let value = userDefaults?.url(forKey: key)
print(value)
}
}
これで取得ができていればおkです。
...
nil だと ...
AppGroups の設定を Targets > メインアプリの方 でも同様に設定が必要でした!!!!
AppGroupsの項でも追記しておきました。
無事取得できたぞ...
extensionContext.completeRequest を呼ばなかったら...
以前、AppAppを作っていた時は extensionContext.completeRequest を呼び忘れるとフリーズしてしまいます。
フリーズというよりかは SLComposeViewController が閉じてくれません。
iOS13.3で確認すると、デフォルトでモーダル表示になるので、下にスワイプすると画面を閉じることができます。そうじゃない場合には呼び出すのを忘れると、閉じることができなくなります。
Info.plist で取得コンテンツを制限する
今のままだと以下のような Warning が表示されます。
Embedded binary's NSExtensionActivationRule is TRUEPREDICATE. Before you submit your containing app to the App Store, be sure to replace all uses of TRUEPREDICATE with specific predicate statements or NSExtensionActivationRule keys. If any extensions in your containing app include TRUEPREDICATE, the app will be rejected.
ShareExtension の Info.plist で修正します。
NSExtensionActivationRule の型を Dictionary に変更します。
その中に必要な情報のみを書きましょう。
今回はURLのみを使いたいので
NSExtensionActivationSupportsWebURLWithMaxCount | Number | 1
を設定します。
これでURLのみが取得できるようになります。
おわりに
少しぐだってしまった。メモがてら書くつもりが、記事を書く方がメインになってしまっていました。
そして、ほとんど「Share Extensionでデータを共有する - Qiita」の記事を見てやってたようなものなので、実質書く意味もなかった気がしますね...
Xcodeのバージョンが変わって、AppGroups の追加方法が若干変わっているので、その辺ぐらいですかねー。
とりあえず今回はこの辺で。画像ばっかりで重くなるのでブログを軽くすることも考えないと...
ではでは〜
コメントはありません。
現在コメントフォームは工事中です。