Post

Replies

Boosts

Views

Activity

Music Kit HTML Embeds move an 490 px and below
Apple provides HTML Embeds for Music Kit JS, as mentioned here. There is a tool here that you can use to create embeds. Scroll to Preview Player. Now, if you set your browser width to less than 490 (right when the thumbnail gets smaller), the player will move vertically if you drag up. Not by much, it's hard to see without a contrasting background.. It's more noticeable in dark mode, as a white background shows clearly, like this: I'm misusing "drag" here: a simple, vertical scroll will cause this. Since this happens on Apple's own site, I'm fairly certain that this is not a "me problem," but who knows! Anyhow, I'm not sure if anyone has come across this. These embeds are pretty handy, and I'm loathe to roll my own player just to fix this. Any constructive advice would be appreciated.
2
0
208
Oct ’24
The Info.plist must contain a LSApplicationCategoryType key
I've created a Safari Extension app using the MultiPlanform option. I can successfully distribute the iOS app for beta testing with TestFlight, but when I try to do this with the macOS version, I get the following error: The product archive is invalid. The Info.plist must contain a LSApplicationCategoryType key, whose value is the UTI for a valid category. For more details, see "Submitting your Mac apps to the App Store". For the record, I searched for the mentioned document and couldn't find it. A link would be nice. Regardless, when I look at the macOS (App) in the Navigator Panel, there is no Info.plist file. There is one, however, in iOS (App). When I open Test Flight on my Mac, I see the app, but that's most likely because I have an M1 chip. I can't find any documentation on this, so I'm asking: Do I need to create an Info.plist file for the macOS (App), and if so, what do I need to put in there? If I don't need this, how do I deal with this error? Thanks in advance for any helpful advice.
3
0
4.5k
Sep ’23
iOS 16 Music Kit MusicLibrary methods have stopped working
Hi there, I have a related forum thread here and a Feedback Assistant ticket open, but this issue seems different. Sometime within the last 2-3 weeks, code related to MusicLibrary has stopped working. None of my code has changed. For example, the below two snippets used to work fine:  for track in newTracks {    try await MusicLibrary.shared.add(track, to: targetPlaylist)  } try await MusicLibrary.shared.edit(targetPlaylist, items: items) newTracks and items are both fetched using: try await targetPlaylist.with(.tracks, preferredSource: .catalog).tracks Using preferredSource: .catalog was a workaround used to address the issue in the aforementioned post above. All iOS 16 capable functions are decorated with: @available(iOS 16, *) or in an if block: if #available(iOS 16, *) {... What's happening is that the following is showing up in the console: 2022-11-28 23:31:11.279648+0700 MyApp[38653:6736450] [core] Attempted to register account monitor for types client is not authorized to access: {(     "com.apple.account.iTunesStore" )} 2022-11-28 23:31:11.279718+0700 MyApp[38653:6736450] [Default] <ICUserIdentityStoreACAccountBackend: 0x282adb520> Failed to register for account monitoring. err=Error Domain=com.apple.accounts Code=7 "(null)" 2022-11-28 23:31:11.279758+0700 MyApp[38653:6736450] [Default] ICUserIdentity - Unable to retrieve DSID for userIdentity=<ICUserIdentity 0x2806eb120: [Active Account: <unresolved>]> - error=Error Domain=com.apple.accounts Code=7 "(null)" These errors are not caught by a do/catch block, but I assume they are related to the issue, and I believe they have to do with MyApp trying to access things that Music Kit thinks it's not supposed to. For example, if MyApp attempts to work with a playlist that it did not create, errors would be expected, thrown errors. The thing is that I know I'm working with resources that are created by MyApp. In fact, in trying to test this, I just tried to create a playlist with the below, and the same behavior is occurring: @available(iOS 16, *) func createPlaylist2(name: String, description: String) async -> MusicKit.Playlist? {     do {         Logger.log(.info, "Creating Playlist: \(name)")         Logger.log(.shrug, "Does this work?")         let newPlaylist = try await MusicLibrary.shared.createPlaylist(name: name, description: description) // <= Things stop here!         Logger.log(.success, "New playlist created: \(newPlaylist)") // <= this isn't logged.         return newPlaylist // <= nothing is returned     } catch {         Logger.log(.error, "Could not create new playlist: \(error)") // <= no error logged.     }     return nil } The result is: 2022-11-29 00:15:01.875064+0700 MyApp[38794:6760471] [core] Attempted to register account monitor for types client is not authorized to access: {(     "com.apple.account.iTunesStore" )} 2022-11-29 00:15:01.875372+0700 MyApp[38794:6760471] [Default] <ICUserIdentityStoreACAccountBackend: 0x283005720> Failed to register for account monitoring. err=Error Domain=com.apple.accounts Code=7 "(null)" 2022-11-29 00:15:01.876677+0700 MyApp[38794:6760323] [EntityQuery] Finished executing query in 0.000999928s 2022-11-29 00:15:01.889055+0700 MyApp[38794:6760323] [EntityQuery] Finished fetching results in 0.0120001s 2022-11-29 00:15:01.891235+0700 MyApp[38794:6760329] [core] Attempted to register account monitor for types client is not authorized to access: {(     "com.apple.account.iTunesStore" )} 2022-11-29 00:15:01.891684+0700 MyApp[38794:6760329] [Default] <ICUserIdentityStoreACAccountBackend: 0x283005720> Failed to register for account monitoring. err=Error Domain=com.apple.accounts Code=7 "(null)" 📘 Creating Playlist: TEST PLAYLIST 🤷🏻‍♀️ Does this work? 2022-11-29 00:15:06.697374+0700 MyApp[38794:6760329] [] nw_path_necp_check_for_updates Failed to copy updated result (22) What's really nasty is that errors are not thrown, so they can't be caught and handled in a catch block. I know that iOS 16.1 got released around the end of October, but I really don't know what's going on here. The behavior is showing up in both prod and when testing locally. Any help would be most appreciated. @JoeKhun: Did I miss the memo?
10
1
4.6k
Nov ’22
How to develop for impending beta features while supporting older iOS versions
Hi there, This is more of a "how-to," "am I doing this right?" question, as I've never done this before, and I couldn't find any definitive write up for how to do this, so I'm asking here. With the release of iOS16 beta, I've been implementing some new MusicKit features in an iOS app I'm working on that was initially built for iOS 15. Setup: dev machine: masOS Monterey 12.4 test device 1: iOS 15.4 test device 2: iOS 16 beta 2 Xcode versions: 14.0 beta 2 (14A5229c) 13.4.1 (13F100) The original app was written, using Xcode 13 and has an iOS Development Target of 15.0 Steps: create new branch off main called beta16 open Xcode beta2 and switch to new branch set the iOS Development Target for the project to 15.0 make code changes in the new branch, using ifavailable to handle both iOS 16 and fallback version code. Results: When I test the new code using Xcode 14 beta 2 on an iOS 16 device, things work as expected. When I test the new code using Xcode 14 beta on an iOS 15 device, the app builds and then crashes immediately upon open with: dyld[38909]: Symbol not found: _$s8MusicKit0A20CatalogSearchRequestV17includeTopResultsSbvs   Referenced from: /private/var/containers/Bundle/Application/4BB8F74F-FDA6-4DF1-8B04-010EA87BA80C/MyApp.app/MyApp   Expected in: /System/Library/Frameworks/MusicKit.framework/MusicKit Symbol not found: _$s8MusicKit0A20CatalogSearchRequestV17includeTopResultsSbvs   Referenced from: /private/var/containers/Bundle/Application/4BB8F74F-FDA6-4DF1-8B04-010EA87BA80C/MyApp.app/MyApp   Expected in: /System/Library/Frameworks/MusicKit.framework/MusicKit When coding, I followed all of Xcodes prompting that says when a potentially unsupported new feature is being used. When I look to where .includeTopResults is being used, I can see that it was not wrapped with ifavailable: var request = MusicCatalogSearchRequest(term: searchString, types: [Song.self])     request.includeTopResults = true let response = try await request.response() If I comment out the line with .includeTopResults, the app runs on the iOS 15 device w/o issue. If I wrap it in ifavailable, like this, it crashes as before: var request = MusicCatalogSearchRequest(term: searchString, types: [Song.self]) if #available(iOS 16, *) {     request.includeTopResults = true } let response = try await request.response() If I check the docs here, I think I'm using .includeTopResults correctly. Question: My main question here is if I'm correctly developing the app toward the goal of supporting new iOS 16 features, while also supporting devices using iOS 15, via fallback. Ultimately, I plan to merge the beta16 branch into a branch from which I'll deploy the app. The app crashing when using .includeTopResults has me hesitant because I don't know if that's a bug or if I'm the bug. Usually, it's the latter. It seems like the steps outlined above are the correct way to develop toward supporting upcoming features and "legacy iOS versions", but I'm not sure. Any clarity on this would be most appreciated. Thanks!
3
0
1.3k
Jun ’22
MusicLibraryRequest to get all tracks from a playlist (iOS 16 beta)
Hi there, tl;dr: What's the best way to get all tracks (with catalog IDs) from a playlist that has more than 100 tracks, using MusicLibraryRequest. I'm doing something dumb, not understanding something, and possibly both. I've got an existing, kinda okay function that uses the MusicDataRequest and the Apple Music API to fetch all tracks from a playlist, with pagination like this: func getTracksFromAppleMusicLibraryPlaylist(playlist: AppleMusicPlaylist) async throws -> [MusicKit.Track]? {     var tracksToReturn: [MusicKit.Track] = []     var libraryTracks: [AppleMusicLibraryTrack] = []     @Sendable     func fetchTracks(playlist: AppleMusicPlaylist, offset: Int) async -> AppleMusicPlaylistFetchResponse? {         do {             let playlistId = playlist.id             var playlistRequestURLComponents = URLComponents()             playlistRequestURLComponents.scheme = "https"             playlistRequestURLComponents.host = "api.music.apple.com"             playlistRequestURLComponents.path = "/v1/me/library/playlists/\(playlistId)/tracks"             playlistRequestURLComponents.queryItems = [                 URLQueryItem(name: "include", value: "catalog"),                 URLQueryItem(name: "limit", value: "100"),                 URLQueryItem(name: "offset", value: String(offset)),             ]             if let playlistRequestURL = playlistRequestURLComponents.url {                 let playlistRequest = MusicDataRequest(urlRequest: URLRequest(url: playlistRequestURL))                 let playlistResponse = try await playlistRequest.response()                 let decoder = JSONDecoder()                 // print("Get Tracks Dump")                 // print(String(data: playlistResponse.data, encoding: .utf8)!)                            let response = try decoder.decode(AppleMusicPlaylistFetchResponse.self, from: playlistResponse.data)                 return response             } else {                 print("Bad URL!")             }         } catch {             print(error)         }         return nil     }     Logger.log(.info, "Fetching inital tracks from \(playlist.attributes.name)")     if let response = await fetchTracks(playlist: playlist, offset: 0) {         if let items = response.data {             libraryTracks = items         }         if let totalItemCount = response.meta?.total {             Logger.log(.info, "There are \(totalItemCount) track(s) in \(playlist.attributes.name)")             if totalItemCount > 100 {                 let remainingItems = (totalItemCount - 100)                 let calls = remainingItems <= 100 ? 1 : (totalItemCount - 100) / 100                 Logger.log(.info, "Total items: \(totalItemCount)")                 Logger.log(.info, "Remaining items: \(remainingItems)")                 Logger.log(.info, "Calls: \(calls)")                 await withTaskGroup(of: [AppleMusicLibraryTrack]?.self) { group in                     for offset in stride(from: 100, to: calls * 100, by: 100) {                         Logger.log(.info, "Fetching additional tracks from \(playlist.attributes.name) with offset of \(offset)")                         group.addTask {                             if let response = await fetchTracks(playlist: playlist, offset: offset) {                                 if let items = response.data {                                     return items                                 }                             }                             return nil                         }                     }                     for await (fetchedTracks) in group {                         if let tracks = fetchedTracks {                             libraryTracks.append(contentsOf: tracks)                         }                     }                 }             }         }     } // props to @JoeKun for this bit of magic     Logger.log(.info, "Matching library playlist tracks with catalog tracks...")     for (i, track) in libraryTracks.enumerated() {         if let correspondingCatalogTrack = track.relationships?.catalog?.first {             tracksToReturn.append(correspondingCatalogTrack)             print("\(i) => \(track.id) corresponds to catalog track with ID: \(correspondingCatalogTrack.id).")         } else {             Logger.log(.warning, "\(i) => \(track.id) doesn't have any corresponding catalog track.")         }     }     if tracksToReturn.count == 0 {         return nil     }     return tracksToReturn } While not the most elegant, it gets the job done, and it's kinda quick due to the use of withTaskGroup .esp with playlists containing more than 100 songs/tracks. Regardless, I'm kinda stuck, trying to do something similar with the new MusicLibraryReqeust in iOS 16. The only way I can think of to get tracks from a playlist, using MusicLibraryRequest, having read the new docs, is like this: @available(iOS 16.0, *) func getAllTracksFromHugePlaylist(id: MusicItemID) async throws -> [MusicKit.Track]? {     do {         var request = MusicLibraryRequest<MusicKit.Playlist>()         request.filter(matching: \.id, equalTo: id)         let response = try await request.response()         if response.items.count > 0 {             if let tracks = try await response.items[0].with(.tracks, preferredSource: .catalog).tracks {                 Logger.log(.info, "Playlist track count: \(tracks.count)")                 return tracks.compactMap{$0}             }         }     } catch {         Logger.log(.error, "Could not: \(error)")     }     return nil } The problem with this is that .with seems to be capped at 100 songs/tracks, and I can't see any way to change that. Knowing that, I can't seem to tell MusicLibraryRequest that I want the tracks of the playlist with the initial request, where before I could use request.properties = .tracks, which I could then paginate if available. Any help setting me on the right course would be greatly appreciated.
8
0
2.8k
Jun ’22
Editing a Library Playlist (MusicKit: iOS 16 beta)
I've just begun to dip my toes into the iOS16 waters. One of the first things that I've attempted is to edit a library playlist using: try await MusicLibrary.shared.edit(targetPlaylist, items: tracksToAdd) Where targetPlaylist is of type MusicItemCollection<MusicKit.Playlist>.Element and tracksToAdd is of type [Track] The targetPlaylist was created, using new iOS16 way, here: let newPlaylist = try await MusicLibrary.shared.createPlaylist(name: name, description: description) tracksToAdd is derived by performing a MusicLibraryRequest on a specific playlist ID, and then doing something like this: if let tracksToAdd = try await playlist.with(.tracks).tracks {    // add tracks to target playlist } My problem is that when I perform attempt the edit, I am faced with a rather sad looking crash. libdispatch.dylib`dispatch_group_leave.cold.1:     0x10b43d62c <+0>:  mov    x8, #0x0     0x10b43d630 <+4>:  stp    x20, x21, [sp, #-0x10]!     0x10b43d634 <+8>:  adrp   x20, 6     0x10b43d638 <+12>: add    x20, x20, #0xfbf          ; "BUG IN CLIENT OF LIBDISPATCH: Unbalanced call to dispatch_group_leave()"     0x10b43d63c <+16>: adrp   x21, 40     0x10b43d640 <+20>: add    x21, x21, #0x260          ; gCRAnnotations     0x10b43d644 <+24>: str    x20, [x21, #0x8]     0x10b43d648 <+28>: str    x8, [x21, #0x38]     0x10b43d64c <+32>: ldp    x20, x21, [sp], #0x10 ->  0x10b43d650 <+36>: brk    #0x1 I assume that I must be doing something wrong, but I frankly have no idea how to troubleshoot this. Any help would be most appreciated. Thanks. @david-apple?
10
0
2.9k
Jun ’22
How to get a catalog playlists of a curator?
Hi there, tl;dr:  How can I get the id of a curator and then with that get a listing of their playlists? I asked about curators a while back, here in this forum, but I can’t find that post, so I’m writing a new one, esp. now new curator features have been added to MusicKit as of WWDC22. Let's say that userB wants to access one of userA's playlists. Since userB has no way of accessing userA’s library, userA’s playlist needs to be accessible as a catalog resource.  This is accomplished by userA manually performing an action in the Music App on macOS or iOS (I wish this could be done programmatically, but no, and that’s off topic). At present, the only way that I know of to determine if a playlist available as a catalog resource is by checking for the hasCatalog property under attributes and/or the globalId property under attributes.playParams. @JoeKun once told me that globalId should be considered opaque and should not be relied upon.  That said, adding "include=catalog" to the request properties of a MusicDataRequest that fetches playlists from userA's Library, like the below will give me access to catalog ID. var playlistRequestURLComponents = URLComponents()     playlistRequestURLComponents.scheme = "https"     playlistRequestURLComponents.host = "api.music.apple.com"     playlistRequestURLComponents.path = "/v1/me/library/playlists"     playlistRequestURLComponents.queryItems = [         URLQueryItem(name:"limit", value: "100"),         URLQueryItem(name:"include", value: "catalog")     ] Note that this can only be performed by userA. And here comes the curator question: If userB wants to get a list of all userA’s catalog playlists (or a specific one) how can that be done? It seems I need to know userA’s curator ID and do some sort of request on that, or I could perhaps get the curator info by performing a MusicCatalogResourceRequest<Playlist> request, adding [.tracks, .moreByCurator] to the request. On the former, I got no idea how to find userA’s curator ID, even if I’m coding with a scope that has Library access for userA. The best I can seem to do is get a curatorName when adding "include-catalog" (as above) to a MusicDataRequest that gets a user's library playlists. On the latter, getting the catalog ID of a playlist requires userA to perform a MusicDataRequest against their library and passing that catalogID to userB so that userB can then access the tracks. This is what my app does now. Ideally though, I'd like to somehow have userB get userA's curator ID and then have userB get userA's catalog playlists without having userA having to do the above. Any thoughts on how to do this would be most appreciated.
4
0
1.7k
Jun ’22
Can we remove tracks from a user's Library Playlist yet?
Hi there, I just watched the WWDC22 vids on MusicKit enhancements. In the Explore More Content with MusicKit video, there is a brief mention of "edit playlists" at 24:33. I asked about this a couple years ago here in this forum. The ever-helpful @JoeKun suggested that I submit a Feedback Assistant ticket on the need/justification for this feature, which I did some time ago: FB9798928. Sadly, there's been no traction on that. I'm super hopeful that the ability to remove tracks from a library playlist is now, or at least will soon be, possible; however, I can't find anything in the docs yet to support this notion. Am I being overly optimistic, or are we finally going to get this much requested feature? Thanks.
7
0
3.2k
Jun ’22
How to prevent macOS archive in Xcode Cloud build?
HI there, I just started using Xcode cloud. When building Xcode cloud, two archives are being generated: iOS and macOS. The macOS archive always errors out with: xcodebuild: error: Unable to find a destination matching the provided destination specifier: {generic:1, platform:macOS} I have no intention of my app running on macOS, but if I knew how to fix that, it might be kinda neat. But really, it's unnecessary, so how do I turn it off? Thanks, Kim
1
0
1.4k
Jun ’22
Get Songs from Apple Music API recently added
I'm working on an idea to use recently added tracks in my app. From what I can tell, the following endpoint will only supply albums and the id's are not related to any catalog resource: https://api.music.apple.com/v1/me/library/recently-added However, if I use the following endpoint, I get access to a semi-deeply-nested data value that contains the goodies I'm looking for: https://api.music.apple.com/v1/me/library/recently-added?include=catalog This seems better than doing a search for each item, as I have access to a catalog resource id. The data in the response is like the below. You can see under relationships, there's catalog, and in there is data, and in there is href, which is what I want. My problem is that I'm doing something dumb with the the decode. I'm using MusicKit's MusicDataRequest, as I don't see a way to get this info via MusicKit methods. And because of that, I gotta setup the request manually. If I just decode with the following, using Album as a type, the info I want isn't there for understood reasons. struct AppleMusicRecentlyAddedRequest: Decodable {   // var next: String?     var items: [Album]?     enum CodingKeys: String, CodingKey {         case next         case data     }     init (from decoder: Decoder) throws {         let container = try decoder.container(keyedBy: CodingKeys.self)         self.items = try container.decodeIfPresent([Album].self, forKey: .data)     } } I've attempted to go down the rabbit hole to get at catalog's data with: struct AppleMusicRecentlyAddedRequest: Decodable {     var items: [???]?        enum CodingKeys: String, CodingKey {         case next         case data         case relationships         case catalog     }     init (from decoder: Decoder) throws {         let container = try decoder.container(keyedBy: CodingKeys.self)         let dataContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .data)         let relationshipsContainer = try dataContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .relationships)         let catalogContainer = try relationshipsContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .catalog)         self.items = try catalogContainer.decodeIfPresent([???].self, forKey: .data)     } } But anything I try for ???, including a complete manual copy of the response in a struct, isn't working, mainly because I'm not very good tat this. The main error I get is: Expected to decode Dictionary<String, Any> but found an array instead Which makes me think I gotta decode catalog data, or something, but I'm at my wits end at this point. Any tips on how to get at data would be awesome; even better would be just to the the href inside catalog/data for each item in the main response. @JoeKun, if there's anyway that MusicKit can make this easier, kindly advise. Thanks. [     {     "id":"l.WAiAqm3",     "type":"library-albums",     "href":"/v1/me/library/albums/l.WAiAqm3",     "attributes":{         "releaseDate":"2010-12-23",         "artwork":{             "width":1200,             "height":1200,             "url":"https://is4-ssl.mzstatic.com/image/thumb/Music/df/48/bb/mzi.wxowhcmy.jpg/{w}x{h}bb.jpg"         },         "dateAdded":"2022-04-13T07:07:50Z",         "name":"Play With Me Papa",         "artistName":"John Keawe",         "genreNames":[             "New Age"         ],         "playParams":{             "id":"l.WAiAqm3",             "kind":"album",             "isLibrary":true         },         "trackCount":1     },     "relationships":{         "catalog":{             "href":"/v1/me/library/albums/l.WAiAqm3/catalog",             "data":[                 {                     "id":"417478467",                     "type":"albums",                     "href":"/v1/catalog/us/albums/417478467",                     "attributes":{                         "artwork":{                             "width":600,                             "height":600,                             "url":"https://is4-ssl.mzstatic.com/image/thumb/Music/df/48/bb/mzi.wxowhcmy.jpg/{w}x{h}bb.jpg",                             "bgColor":"ecf2fe",                             "textColor1":"3a2212",                             "textColor2":"3f2b1b",                             "textColor3":"5e4b41",                             "textColor4":"615349"                         },                         "artistName":"John Keawe",                         "isSingle":false,                         "url":"https://music.apple.com/us/album/play-with-me-papa/417478467",                         "isComplete":true,                         "genreNames":[                             "New Age",                             "Music",                             "Worldwide"                         ],                         "trackCount":13,                         "isMasteredForItunes":false,                         "releaseDate":"2010-12-23",                         "name":"Play With Me Papa",                         "recordLabel":"Homestead Productions",                         "upc":"704565719925",                         "copyright":"℗ 2010 John Keawe",                         "playParams":{                             "id":"417478467",                             "kind":"album"                         },                         "isCompilation":false                     }                 }             ]         } ]
2
0
1.3k
Apr ’22
Songs are not always added to Playlist when using Music iOS
First let me state that this is not an issue with MusicKit, but I've raised a radar on this and have received 0 response, which is, sadly, kinda normal. However, it's kind of an important issue and my app relies on this feature to work consistently, so I thought I'd mention it and that the amazing @JoeKun might have an idea how to escalate it. Here's the problem in the iOS Music app: Add a song to an existing playlist Add another song to the same playlist Add another View the playlist More often than not, one of the newly added songs is missing in the playlist to which the song was added. There are entries in Recently Added for newly added songs that are not in the playlist where the songs were added. View the songs in the Music app on Mac. Query the playlist to get all songs via the Apple Music API. The Music app on Mac and the API results align, yet differ from iOS Music app. There are entries in Recently Added for newly added songs that are not in the playlist where the songs were added. In summary, when adding a song to a playlist using the iOS Music app, it sometimes does not add the song. For the record, I am awaiting the confirmation message each time a song is added. Adding tracks via the macOS Music app, seems to always work. This issue only occurs with the iOS app.
6
0
1.6k
Mar ’22
MusicCatalogSearchRequest does not find Albums that are found when using the Music app with the same search string
I am using the MusicKit library for Swift. With this: let searchString = “led zeppelin iv deluxe edition” var albumSearchRequest = MusicCatalogSearchRequest(term: searchString, types: [Album.self]) The response from: let response = try await albumSearchRequest.response() returns no albums; however searching manually for that exact string in the Music App on either iOS or macOS will return results. This is really weird and problematic if one is trying to search for albums or tracks specific to certain albums.
2
0
1.1k
Mar ’22
Missing play parameters when trying to play with MusicKit - potential storefront issue
I've got an iOS app build on Swift MusicKit that retrieves Apple Music tracks and presents them to a user in a list. Tapping the track attempts to the track using this function: func handlePlayThisTrack(track: AppleMusicTrack) async {   do {     let tracksToQueue = sortedTracks.compactMap{$0.track}     if let track = tracksToQueue.first(where: {$0.id.rawValue == track.id}) {       print("track", track)       player.queue = ApplicationMusicPlayer.Queue(for: tracksToQueue, startingAt: track )       try await player.play()     } else {       Logger.log(.error, "Track does not exist in sorted tracks!")     }   } catch {     print(error)   } } Sometimes, however, the track does not play, and checking the logs, I see the below. This only happens on some tracks, but on those that don't work it happens consistently. When printing the details for a track that doesn't work, it looks like this: track Track.song(Song(id: "1443100129", title: "She's Not There", artistName: "The Zombies")) And this looks like all the other tracks that do play. So I don't know where to look for said missing play parameters mentioned in the error. I have an inkling that this may have to do with the track not being available due to the country/storefront, and that the error message is misleading. I'm using the following to get the tracks: MusicCatalogResourceRequest<Song>(matching: \.isrc, equalTo: isrc) // <= the ISRC of the track I want to fetch My assumption is that the MusicCatalogResourceRequest would only respond with tracks in my country/storefront, but I think this may not be the case. Is there any way to create a MusicCatalogRequest in such a way that I only get results that are playable in my country/storefront? Any advice would be most appreciated. Thanks! 2022-02-25 02:24:56.971343+0700 MusicApp[19452:1186508] [Playback] Failed to insert MusicPlayer.Queue.Entry(id: "F6A04D56-F5C5-4628-B136-5438E188FDA5", transientItem: Track.song(Song(id: "1443100129", title: "She's Not There", artistName: "The Zombies"))) into queue descriptor because it's missing play parameters. 2022-02-25 02:24:57.102432+0700 MusicApp[19452:1186733] [Entitlements] MSVEntitlementUtilities - Process MusicApp PID[19452] - Group: (null) - Entitlement: com.apple.accounts.appleaccount.fullaccess - Entitled: NO - Error: (null) 2022-02-25 02:24:57.104579+0700 MusicApp[19452:1186733] [core] Attempted to register account monitor for types client is not authorized to access: {(   "com.apple.account.iTunesStore" )}
2
1
3.1k
Feb ’22
Run async tasks using Background Tasks
I've got an iOS app that performs a series of operations when initialized and when a refresh is performed. In short, that app has: An obervable object (appManager) that houses variables that act as "state" for the app. Methods in the observable object that perform a variety of operations. Here's an example: Perform an API operation to get tokens to perform API actions on remote API service. Perform a fetch on an external database to retrieve some data. Decode that data an place the data into @Published variables, using (DispatchQueue.main.async). Perform another remote API fetch operation on a different endpoint. Put more variables in "state" So when the user opens the app and after init runs, they see what they expect to see. And when they tap a "refresh" button, another function (e.g. getUpdatedAppData()) is called with similar steps to the above, and the app updates the published variables and the view(s) update. The above steps are all performed using async functions, using Swift's new async/await functionality. Everything works swimmingly when the app is in the foreground. What I'd like to do is perform the updateAppData() function using Background tasks as described here.. I have successfully setup the app to register and schedule a task, using BGTaskScheduler, and I can successfully emulate the triggerring of that task by setting a breakpoint and running the following code in the console: e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.example.task"] If the background tasks is something simple, like printing to the console, it seems to work    private func configureBackgroundTasks() {     Logger.log(.info, "Registering background tasks...")     let bgTaskIdentifier = "com.example.task"     BGTaskScheduler.shared.register(forTaskWithIdentifier: bgTaskIdentifier, using: DispatchQueue.main) { (task) in       Logger.log(.info, "Performing background task \(bgTaskIdentifier)")       task.setTaskCompleted(success: true)       backgroundTaskManager.scheduleAppRefresh()     }   } However, if the function is something like the below, I can see the function being triggered, when simulating the running of the task, but the function hangs at the start of the first async operation (e.g. fetch tokens above). It seems to "try to complete" (and usuually fails) once the app is brought to the foreground, but that's obviously not what I want to happen. Surely, I'm misunderstanding something and/or doing something wrong, so I'm hoping to get some help here. Thanks in advance for any assistance toward achieving what I'm trying to do here.    private func configureBackgroundTasks() {     Logger.log(.info, "Registering background tasks...")     let bgTaskIdentifier = "com.example.task"     BGTaskScheduler.shared.register(forTaskWithIdentifier: bgTaskIdentifier, using: DispatchQueue.main) { (task) in       Logger.log(.info, "Performing background task \(bgTaskIdentifier)")       Task.init {         if let updatedData = await appManager.getUpdateAppData() {           DispatchQueue.main.async {             appManager.data = updatedData           }         }       }       task.setTaskCompleted(success: true)       backgroundTaskManager.scheduleAppRefresh()     }   }
8
0
4.6k
Dec ’21