7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SwiftUIでShare Extensionを実装する

Last updated at Posted at 2022-04-28

はじめに

いきなりタイトルと矛盾するようですが、残念ながら現時点(2022年4月)ではShare Extensionを純SwiftUIで実装することはできません。多少UIKitが必要になります。

Share Extensionについて詳しく知る
App Extension Programming Guide: Creating an App Extension

(手順1)Share ExtensionをTargetに追加

File > New > Target... からShare Extensionを選択。
スクリーンショット 2022-04-28 23.51.00.png
すると以下のファイルが生成されます。

MainInterface.storyboard

テキストやURLなどが共有されるとまずこれが開かれます。エントリーポイントとしてShareViewControllerが指定されています。

ShareViewController.swift

エントリーポイントのビューコントローラーには、extensionContextというプロパティにNSExtensionContextのオブジェクトが当てられます。これが共有の中心人物で、共有されたデータを取り出したり、共有が完了して画面を閉じたりするのはこのオブジェクトを通して行います。
この段階ではSLComposeServiceViewControllerというビューコントローラーが継承されていますが、これを使う必要は全然ありません。extensionContextを扱えるビューコントローラーでさえあればいいので、通常はカスタムのビューコントローラーを使います。

Info.plist

受け入れるデータの形式(URLだけ受け入れる、など)を指定したりします。詳細はこちらの記事でわかりやすく解説されています。

(手順2)以下のコードをコピペ

ShareView.swift
import SwiftUI

struct ShareView: View {
    @ObservedObject var model = ShareModel()
    
    var body: some View {
        NavigationView {
            Form {
                TextField("Shared Text", text: self.$model.sharedText)
            }
            .onSubmit {
                self.model.submit()
            }
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button {
                        self.model.cancel()
                    } label: {
                        Text("Cancel")
                    }
                }
            }
        }
    }
}
ShareModel.swift
import SwiftUI
import UniformTypeIdentifiers

class ShareModel: ObservableObject {
    @Published var sharedText: String = ""
    var extensionContext: NSExtensionContext?
    
    init() {
        // 初期化処理
    }
    
    func configure(context: NSExtensionContext?) {
        self.extensionContext = context
        
        guard let item = context?.inputItems.first as? NSExtensionItem else { return }
        guard let itemProvider = item.attachments?.first else { return }
        
        // テキストが共有された場合
        if itemProvider.hasItemConformingToTypeIdentifier(UTType.text.identifier) {
            // テキストを取り出して代入
            itemProvider.loadItem(forTypeIdentifier: UTType.text.identifier, options: nil) { data, error in
                guard let sharedText = data as? String else { return }
                DispatchQueue.main.async {
                    self.sharedText = sharedText
                }
            }
        }
    }
    
    func cancel() {
        self.extensionContext?.cancelRequest(withError: ShareError.cancel) // 共有をキャンセル
    }
    
    func submit() {
        // ここに共有処理を記述する
        
        self.extensionContext?.completeRequest(returningItems: nil) // 共有完了
    }
    
    enum ShareError: Error {
        case cancel
    }
}

バックエンドとの通信などの共有処理は省略しています。バックエンドを用いないアプリの場合はAppGroupを使ったりして上手くやります。

(手順3)ShareViewControllerを変更

SwiftUIのビューをUIKitで利用するためにUIHostingControllerというクラスを使います。

ShareViewController.swift
import SwiftUI

class ShareViewController: UIHostingController<ShareView> {
    
    required init?(coder: NSCoder) {
        super.init(coder: coder, rootView: ShareView())
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.rootView.model.configure(context: self.extensionContext)
    }
}

ShareViewContoroller.extensionContextをShareModelに渡し、ShareModelで共有の処理を行えるようにします。

ここまでの手順をたどれば、このようにテキストを共有することができるはずです。
スクリーンショット 2022-04-29 2.47.22.png

単語帳アプリを作りました!

自分で単語を追加する系の単語帳アプリです。

Safariなどの外部のアプリから単語を追加するために本アプリでもShare Extensionを実装しています。Vocabula

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?