🍁

Swift: 異なる二つのmacOSアプリ間でデータをやりとりする

2021/05/15に公開

背景

アプリをAppStoreで配信する場合SandBoxを守らないといけない。するとそのストアアプリではできない処理が稀にある。その処理を野良配布の別アプリに行わせて、結果をストアアプリに返すという策が必要になった。

方法

両方のアプリでNotification.Nameを作っておく
extension Notification.Name {
    static let messageFromStoreApp = Notification.Name("MessageFromStoreApp")
    static let messageFromNonStoreApp = Notification.Name("MessageFromNonStoreApp")
}

Notification.Nameはmacの環境内で一意である必要があるので、実際にはアプリ名やUUIDなどを含めると良いかもしれない。

ストアアプリ側(AppDelegate)
import Cocoa

@main
class AppDelegate: NSObject, NSApplicationDelegate {

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        let dnc = DistributedNotificationCenter.default()
        dnc.addObserver(self, selector: #selector(AppDelegate.handleRequest(_:)),
                        name: .messageFromNonStoreApp, object: nil)
    }

    @objc func handleRequest(_ notification: NSNotification) {
        if let message = notification.object as? String {
            print(message) // 野良アプリからのメッセージ
        }
    }

}
ストアアプリ側(ViewControllerとか)
@IBAction func pushButton(_ sender: NSButton) {
    let message = "晩御飯はなんですか?"
    let dnc = DistributedNotificationCenter.default()
    dnc.post(name: .messageFromStoreApp, object: message)
}
野良アプリ側(AppDelegate)
import Cocoa

@main
class AppDelegate: NSObject, NSApplicationDelegate {

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        let dnc = DistributedNotificationCenter.default()
        dnc.addObserver(self, selector: #selector(AppDelegate.handleRequest(_:)),
                        name: .messageFromStoreApp, object: nil)
    }

    @objc func handleRequest(_ notification: NSNotification) {
        if let message = notification.object as? String {
            print(message) // ストアアプリからのメッセージ
            let dnc = DistributedNotificationCenter.default()
            dnc.post(name: .sendTemperature, object: "カレーです。")
        }
    }

}

今回は、野良アプリ側はバックグラウンドで動くエージェントアプリにしたかったので、Info.plistに<key>LSUIElement</key><true/>を追加した。

これで両方のアプリが起動していれば、二つのアプリ間でやりとりができるはず。

参考

URL Schemeを使った方法だとopen(url:)を使う関係で必ずアプリを起動しようとするのでバックグラウンドでデータの処理をしたい場合には向いていない。

Discussion