macOS MojaveでSwift 4.2 + Scripting Bridge

スポンサーリンク

作るもの

私が作っているアプリ同様、iTunes の再生中の楽曲情報を取得できるようにします
Scripting Bridge で値を取得するフレームワークは GitHub に転がってるので利用します。今回は MichaelRow/PlayerBridge を利用します。フレームワークについては割愛します
MichaelRow/PlayerBridge
Swift version of scripting bridge framework for iTunes, Spotify and Vox. - MichaelRow/PlayerBridge

Info.plistに値を追加

まずは AppleScript、つまり Apple Events の機能を利用するということを Info.plist で示す。NSAppleEventsUsageDescription というキーに対して String で This script needs to control other applications to run. と入れる

EntitlementsにiTunesへのアクセス権を追加

Scripting Bridge で iTunes へアクセスするためにどの権限を利用するかをentitlementsへ記入します。今回は再生中の楽曲のタイトルを取得できればよしとするので、Dictionary 型で com.apple.security.scripting-targets というキーに Array の com.apple.iTunes を追加。com.apple.iTunes.playback を追加する

権限は次のコマンドでxmlを出力して利用する commandpropertyaccess-groupidentifier を参照してください

sdef /Applications/iTunes.app > itunes.sdef.xm

今回利用するのはcurrent trackなので以下の部分を参照します

<property name="current track" code="pTrk" type="track" access="r" description="the current targeted track">
    <access-group identifier="com.apple.iTunes.playback" access="r"/>
</property>

アプリ内で権限を確認

ここからMojaveで追加されて必要になったものです。後方互換性を維持するのであれば if #available(macOS 10.14, *) で要求するようにしてください
NSAppleEventDescriptor(bundleIdentifier: "com.apple.iTunes") で iTunes の Descriptor を初期化。AEDeterminePermissionToAutomateTarget で Automation のアクセス権を確認します
アクセス権を要求するには第四引数を true にしてください。しかし第四引数が true でも初回のみ要求するアラートが出るので、2回目以降に権限がないときは有効にする方法をユーザーへ提示する必要があります。戻り値は4種類ありますが権限を要求するのであれば知っておく必要があるのは以下の3つです

グローバルな定数ですが noErr のみ OSStatus 型で他は数値型なので以下のサンプルのように条件分岐させるときは OSStatus(procNotFound) とする必要があります

一つ注意が必要で、要求するアプリが起動していない時には Automation の権限を要求するアラートは出ません。ただ procNotFound が返ってくるだけなのでそれを考慮してください

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        let targetAEDescriptor: NSAppleEventDescriptor = NSAppleEventDescriptor(bundleIdentifier: "com.apple.iTunes")
        let status: OSStatus = AEDeterminePermissionToAutomateTarget(targetAEDescriptor.aeDesc, typeWildCard, typeWildCard, true)

        var isRunning: Bool = false
        var hasPermission: Bool = false

        switch status {
          case noErr:
            isRunning = true
            hasPermission = true
          case OSStatus(errAEEventNotPermitted):
            isRunning = true
          case OSStatus(procNotFound), _:
            break
        }

        if !isRunning {
            let alert = NSAlert(message: "iTunesが起動していません。アプリを終了します",
                                style: .warning)
            alert.runModal()
            NSApplication.shared().terminate(self)
            retur! iTu
        }

        if !hasPermission {
            let alert = NSAlert(message: "iTunesへのアクセスが拒否されています。環境設定のセキュリティとプライバシー>プライバシー>オートメーションからこのアプリにiTunesへのアクセスを許可してください。アプリを終了します",
                                style: .warning)
            alert.runModal()
            NSApplication.shared().terminate(self)
            return
        }
    }

}

楽曲情報を取得する

以上が済めばあとは今までと変わりません。今回は PlayerBridge を利用しているので iTunesBridge を import して再生中の楽曲情報を iTunesApplication クラスから取得します

import ScriptingBridge

// PlayerBridgeのiTunes用のフレームワーク
import iTunesBridge

/* ... */

guard let itunes: iTunesApplication = SBApplication(bundleIdentifier: "com.apple.iTunes") as? iTunesApplication, let currentTrack: iTunesTrack = itunes.currentTrack else {
    let alert = NSAlert(message: "再生中の楽曲はありません",
                                style: .informational)
    alert.runModal()
    return
}

let alert = NSAlert(message: currentTrack.title!,
                    style: .informational)
alert.runModal()

締め

以上、macOS 10.14 Mojave から Swift 4.2 で Scripting Bridge を用いて他のアプリケーションの情報を取得したり操作する手順でした
既存のコードで楽曲情報を取得できなくなっていて少し手間取りましたが、Mojave の仕様に沿うように修正するのに必要な部分は少しでした。procNotFound で起動チェックが出来るので、後方互換を気にしなければ別の起動チェックを省けていいかもしれません

コメント