Notice: Undefined index: HTTP_USER_AGENT in /home/kPherox/public_html/blog.kr-kp.com/wordpress/wp-content/themes/cocoon-master/lib/utils.php on line 1624
macOS MojaveでSwift 4.2 + Scripting Bridge – kPherox Blog
Notice: Undefined index: HTTP_USER_AGENT in /home/kPherox/public_html/blog.kr-kp.com/wordpress/wp-content/themes/cocoon-master/lib/utils.php on line 1214
Notice: Undefined index: HTTP_USER_AGENT in /home/kPherox/public_html/blog.kr-kp.com/wordpress/wp-content/themes/cocoon-master/lib/utils.php on line 1624
class="post-template-default single single-post postid-376 single-format-standard public-page page-body categoryid-24 ff-rounded-mplus-1c fz-18px fw-400 hlt-center-logo-wrap ect-entry-card-wrap rect-entry-card-wrap no-scrollable-sidebar no-scrollable-main sidebar-right mblt-slide-in author-admin mobile-button-slide-in no-mobile-sidebar" itemscope itemtype="https://schema.org/WebPage">

macOS MojaveでSwift 4.2 + Scripting Bridge

スポンサーリンク

NowPlayingTweetで利用しているScripting Bridgeが、Mojaveからユーザーに許可をもらわないと利用できないようにセキュリティが強化されているのでその許可を求める方法とか

作るもの

私が作っているアプリ同様、iTunesの再生中の楽曲情報を取得できるようにします
Scripting Bridgeで値を取得するライブラリはGitHubに転がってるので利用します。今回は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つです

procNotFoundはアクセス権を確認及び要求しようとしているアプリ(ここではiTunes)が起動していないことを表す値です
errAEEventNotPermittedはアクセス権を要求したことがあるアプリで現在拒否されていることを表す値です
noErrはそのままズバリでアクセス権を保有していることを表します
グローバルな定数ですがnoErrのみOSStatus型で他は数値型なので以下のサンプルのようにswitchで条件分岐させるときは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の仕様に沿うように修正するのに必要な部分は少しでした。起動チェックが楽になるので後方互換を気にしなければ無駄が省けるかなと思いました

コメント