Как получить в настоящее время воспроизводящуюся песню на Ma c (Swift) - PullRequest
0 голосов
/ 03 апреля 2020

На Ма c сенсорная панель может автоматически определять, какое приложение воспроизводит звук, и позволяет воспроизводить / приостанавливать, пропускать и даже искать по аудио. Это работает для Spotify, Quicktime и даже веб-сайтов в вашем браузере, например, на вкладке YouTube в Google Chrome. Как я могу получить ту же информацию (название песни, эскиз, приложение, которое воспроизводит песню, продолжительность и т. Д. c.) С помощью Swift?

1 Ответ

1 голос
/ 29 апреля 2020

macOS имеет гораздо больше системных интеграций с медиа-плеерами. Например, вы можете запросить у Siri текущую песню или использовать виджет Now Playing Today:

image image

Все эти интеграции используют частные API-интерфейсы в частной структуре Media Remote. Так как это частная структура, Apple отклонит ваше приложение, если вы попытаетесь отправить его в Ma c App Store. Вы все еще можете нотариально заверить это для распространения за пределами App Store.

Чтобы использовать эту платформу, вы можете попробовать это:

// Load framework
let bundle = CFBundleCreate(kCFAllocatorDefault, NSURL(fileURLWithPath: "/System/Library/PrivateFrameworks/MediaRemote.framework"))

// Get a Swift function for MRMediaRemoteGetNowPlayingInfo
guard let MRMediaRemoteGetNowPlayingInfoPointer = CFBundleGetFunctionPointerForName(bundle, "MRMediaRemoteGetNowPlayingInfo" as CFString) else { return }
typealias MRMediaRemoteGetNowPlayingInfoFunction = @convention(c) (DispatchQueue, @escaping ([String: Any]) -> Void) -> Void
let MRMediaRemoteGetNowPlayingInfo = unsafeBitCast(MRMediaRemoteGetNowPlayingInfoPointer, to: MRMediaRemoteGetNowPlayingInfoFunction.self)

// Get a Swift function for MRNowPlayingClientGetBundleIdentifier
guard let MRNowPlayingClientGetBundleIdentifierPointer = CFBundleGetFunctionPointerForName(bundle, "MRNowPlayingClientGetBundleIdentifier" as CFString) else { return }
typealias MRNowPlayingClientGetBundleIdentifierFunction = @convention(c) (AnyObject?) -> String
let MRNowPlayingClientGetBundleIdentifier = unsafeBitCast(MRNowPlayingClientGetBundleIdentifierPointer, to: MRNowPlayingClientGetBundleIdentifierFunction.self)

// Get song info
MRMediaRemoteGetNowPlayingInfo(DispatchQueue.main, { (information) in
    NSLog("%@", information["kMRMediaRemoteNowPlayingInfoArtist"] as! String)
    NSLog("%@", information["kMRMediaRemoteNowPlayingInfoTitle"] as! String)
    NSLog("%@", information["kMRMediaRemoteNowPlayingInfoAlbum"] as! String)
    NSLog("%@", information["kMRMediaRemoteNowPlayingInfoDuration"] as! String)
    let artwork = NSImage(data: information["kMRMediaRemoteNowPlayingInfoArtworkData"] as! Data)

    // Get bundle identifier
    let _MRNowPlayingClientProtobuf: AnyClass? = NSClassFromString("_MRNowPlayingClientProtobuf")
    let handle : UnsafeMutableRawPointer! = dlopen("/usr/lib/libobjc.A.dylib", RTLD_NOW)
    let object = unsafeBitCast(dlsym(handle, "objc_msgSend"), to:(@convention(c)(AnyClass?,Selector?)->AnyObject).self)(_MRNowPlayingClientProtobuf,Selector("a"+"lloc"))
    unsafeBitCast(dlsym(handle, "objc_msgSend"), to:(@convention(c)(AnyObject?,Selector?,Any?)->Void).self)(object,Selector("i"+"nitWithData:"),information["kMRMediaRemoteNowPlayingInfoClientPropertiesData"] as AnyObject?)
    NSLog("%@", MRNowPlayingClientGetBundleIdentifier(object))
    dlclose(handle)
})

Я предполагаю, что в качестве эскиза вы имели в виду обложку альбома. Spotify, QuickTime и Google Chrome, поскольку вы упомянули их, не делятся обложками альбомов с этим частным API.

...