Post

Replies

Boosts

Views

Activity

MusicKit Content Rights, Age Rating and App Encryption
I built an app that makes playing audio plays easier using MusicKit. Now I am about to release the app to the app store. Following questions occured while doing so: Am I accessing/showing third party content in my app when I am music (in this case radio plays) from MusicKit? I am getting all of that data directly from Apple. Is Apple a third party in this case? The publisher has an app that can playback all of the content that can be accessed in my app. This app has an age rating of 4+ years. Can I just copy that? I've heard that referring to other apps doesn't convince the App Review Team if they disagree. None of the titles are marked explicit in Apple Music. Under the hood MusicKit is using HTTPS to get the data from Apple's servers. I have no code that has anything to do with encryption or HTTPS. Does my app still uses Non Exempt Encryption because MusicKit does so? Can I access music through MusicKit that is otherwise not available in this region or does MusicKit take care of this for me? In other words do I have to restrict the availability of my app to certain regions so I don't bypass any geo blockings by accident? Thank you
0
0
734
May ’24
MusicKit lastPlayedDate always nil
I am having trouble accessing the lastPlayedData for any given album or track using MusicKit. The value is always nil, both on numerous albums and tracks I tested. Afaik this is not a property that has to be fetched separately like tracks for example. I am running this on my physical iPhone 12 18.1.1 with Xcode 16.1. The albums and tracks have definitely been played multiple times before. The app has permission to the library using MusicAuthorization.request() This post mentions the same problem but offers no solution. Thanks for any help
0
0
465
Dec ’24
Requesting permission for MusicKit in Xcode Cloud
I am experimenting with Swift Testing and Xcode Cloud and would like to write some tests that require to use MusicKit functionality. For example I'd like to fetch an album via MusicCatalogRessourceRequest to test an initializer of another struct. However this test fails because the permission to access the music library is not granted. Once the permission is granted, the test works as expected. Things I have tried: Add NSPrivacyAccessedAPITypes to the Info.plist. This did not show any effect. Below is the corresponding snippet Trying to tap the button programmatically. Once again this did not show any effect. The Info.plist snippet: <key>NSPrivacyAccessedAPITypes</key> <array> <string>NSPrivacyAccessedAPIMediaLibrary</string> </array> The code snippet to tap the button: let systemAlerts = XCUIApplication(bundleIdentifier: "com.apple.springboard") let allowButton = systemAlerts.buttons["Allow"] if allowButton.exists { allowButton.tap() } What am I doing wrong here? I need access to MusicKit functionalities to write meaningful tests. Thank you
0
0
390
Feb ’25
How to check for cancellation of background task
When using the old withTaskCancellationHandler(operation:onCancel:isolation:) to run background tasks, you were notified that the background task gets cancelled via the handler being called. SwiftUI provides the backgroundTask(_:action:) modifier which looks quite handy. However how can I check if the background task will be cancelled to avoid being terminated by the system? I have tried to check that via Task.isCancelled but this always returns false no matter what. Is this not possible when using the modifier in which case I should file a bug report? Thanks for your help
0
0
259
Mar ’25
MusicKit: Best way to check if all tracks of albums are added to library.
I prefer to use the album fetched from the library instead of the catalog since this is faster. If doing so, how can I check if all tracks of an album are added to the library. In this case I'd like to fetch the catalog version or throw an error (for example when offline). Using .with(.tracks) on the library album fetches the tracks added to the library. The trackCount property is referring to the tracks that can be fetched from the library. The isComplete property is always nil when fetching from the library. One possible way is checking the trackNumber and discCount properties. However this only detects that not all tracks of an album are added to the library if there is a song not added ahead of one that is. I'd like to be able to handle this edge case as well. Is there currently a way to do this? I'd prefer to not rely on the apple music catalog for this since this is supposed to work offline as well. Fetching and storing all trackIDs when connected and later comparing against these would work, but this would potentially mean storing tens of thousands of track ids. Thank you
0
0
73
Mar ’25
Xcodebuild does not find any simulators
I am trying to integrate fastlane, which relies on xcodebuild. So this is my first experience with xcodebuild. Whenever I run a command to test or build the target in the folder where all the files of the project are stored, the action failes with Unable to find a device matching the provided destination specifier For example I might be running this command: xcodebuild \ -project Hoerspielzentrale.xcodeproj \ -scheme HoerspielzentraleUITests \ -destination 'platform=iOS Simulator,name="Screenshot Simulator”' \ test However the mentioned error is returned: xcodebuild: error: Unable to find a device matching the provided destination specifier: { platform:iOS Simulator, OS:latest, name:"Screenshot Simulator” } The requested device could not be found because no available devices matched the request. I can confirm that the simulator exists, is available and it can be booted. I have tried different simulators, different schemas, referencing them by their identifier, switching Xcode Versions, reset all simulators, derived data and build folder. After the error a complete list of all available destinations can be found, where I can see the simulator I try to use. Available destinations for the "HoerspielzentraleUITests" scheme: { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device } { platform:iOS Simulator, id:dvtdevice-DVTiOSDeviceSimulatorPlaceholder-iphonesimulator:placeholder, name:Any iOS Simulator Device } { platform:iOS Simulator, id:961DC569-9931-419A-B46E-769AAFA73EA2, OS:18.5, name:Screenshot Simulator } { platform:iOS Simulator, id:961DC569-9931-419A-B46E-769AAFA73EA2, OS:18.5, name:Screenshot Simulator } { platform:iOS Simulator, id:5E51FD98-C451-472F-9CDE-08D49E6B737B, OS:18.5, name:Screenshot Simulator Pro } { platform:iOS Simulator, id:5E51FD98-C451-472F-9CDE-08D49E6B737B, OS:18.5, name:Screenshot Simulator Pro } The rest of the list was omitted. I am currently completely stuck. Thank you
1
0
148
Jul ’25
SwiftData not syncing with iCloud
Hello everyone, I followed this (https://www.hackingwithswift.com/quick-start/swiftdata/how-to-sync-swiftdata-with-icloud) guide from Paul Hudson on how to sync swiftdata with iCloud. I tried it on my device directly and it worked exactly as I would expect. Now I tried the same version of the app on another device installed through TestFlight external tester group. It no longer works. When deleting the app, the alert reads "Deleting this app will also delete its data, but any documents or data will be stored in iCloud will not be deleted" so the app should have said something in iCloud. When looking in Settings -> Your Name -> iCloud -> Manage Account Storage, on the working device I can see around 300 KB saved in iCloud, on the other device my app is not listed. Both have a fast and working internet connection, almost fully charged, low data mode turned off, running 17.4.1, Background modes enabled, Mobile data enabled, more than enough unused iCloud storage and plenty of time to sync. I was streaming the logs from the Cloudkit dashboard but nothing appeared there. The data saved neither syncs to another device of the same apple id nor reappears after app removal. The model Container is initialized without any configuration, the only relationship is optional and every value has a default value. There is A LOT of log noise when launching the app and I am unable to get any meaningful information from that. I can only get the log from the device where it is working as expected. I have triple checked that it is exactly the same app version and no debug conditions anywhere. I have absolutely no idea what is causing this. Thanks for any help :)
2
0
3.1k
Mar ’24
Memory usage unstoppably increasing when updating SwiftData Object from Timer
For a kind of podcast player I need to periodically update a swiftData object to keep track of the listening progress. (Happy to hear if there are better ways) I need to do this in many places in my app so I wanted to extract the modelContext into a Singleton so I can write a global function that starts the timer. In doing so I stumbled upon a problem: The memory used by my app is steadily increasing and the device is turning hot. @Observable class Helper { static let shared = Helper() var modelContext: ModelContext? } @main struct SingletontestApp: App { let modelContainer: ModelContainer init() { do { modelContainer = try ModelContainer( for: Item.self, Item.self ) } catch { fatalError("Could not initialize ModelContainer") } Helper.shared.modelContext = modelContainer.mainContext } var body: some Scene { WindowGroup { ContentView() } .modelContainer(modelContainer) } } struct ContentView: View { @Query private var items: [Item] var body: some View { NavigationSplitView { List { ForEach(items) { item in Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard)) } } .toolbar { ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } ToolbarItem { Button(action: updateItemPeriodically) { Label("Change random", systemImage: "dice") } } } } detail: { Text("Select an item") } } func addItem() { withAnimation { let newItem = Item(timestamp: Date()) Helper.shared.modelContext!.insert(newItem) } } @MainActor func updateItemPeriodically() { // Doesn't matter if run as global or local func let descriptor = FetchDescriptor<Item>(sortBy: [SortDescriptor(\.timestamp)]) let results = (try? Helper.shared.modelContext?.fetch(descriptor)) ?? [] let element = results.randomElement() let timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { timer in // Smaller time intervals worsen the problem element?.timestamp = Date.now } } } Calling save() manually or automatically in the timer does not have any effect. I am not sure about my general way of keeping track of listening process so if you think there is a better way, feel free to correct me. Thanks for your help
3
0
1.1k
May ’24
Outputvolume of AVAudioSession returning rounded values
Using the hardware volume buttons on the iPhone, you have 16 steps you can adjust your volume to. I want to implement a volume control slider in my app. I am updating the value of the slider using AVAudioSession.sharedInstance().outputVolume. The problem is that this returns values rounded to the nearest 0 or 5. This makes the slider jump around. .formatted() is not causing this problem. You can recreate the problem using code below. @main struct VolumeTestApp: App { init() { try? AVAudioSession.sharedInstance().setActive(true) } var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @State private var volume = Double() @State private var difference = Double() var body: some View { VStack { Text("The volume changed by \(difference.formatted())") Slider(value: $volume, in: 0...1) } .onReceive(AVAudioSession.sharedInstance().publisher(for: \.outputVolume), perform: { value in volume = Double(value) }) .onChange(of: volume) { oldValue, newValue in // Only used to make the problem more obvious if oldValue > newValue { difference = oldValue - newValue } else { difference = newValue - oldValue } } } } Here is a video of the problem in action: https://share.icloud.com/photos/00fmp7Vq1AkRetxcIP5EXeAZA What am I doing wrong or what can I do to avoid this? Thank you
1
0
1.3k
Jun ’24
"Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races"
I'm currently in the process of migrating to Swift 6. A lot of my code triggers the warning from the title. Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races. I depend on the .task/.refreshable modifiers and buttons that trigger asynchronous work that cannot be done on the Main Actor since it takes way to long. The below code demonstrates the problem. Some comments explain my problems further. I read a lot of articles and documentations but couldn't find an answer to such a seemingly simple error struct ContentView: View { // Marking Senable as suggested by the warning causes different warning for @State @State private var authorizationStatus: MusicAuthorization.Status = .notDetermined // Sole purpose to trigger the errors var body: some View { VStack { Text("Hello, world!") Button("Some button") { Task { await doingSomeAsyncWork() // WARNING: Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races } } } .task { // Or refreshable I believe both behave the same await doingSomeAsyncWork() // WARNING: Passing argument of non-sendable type 'ContentView' outside of main actor-isolated context may introduce data races } } // Marking @MainActor is not an option since some of these functions might be running for more than 10 seconds // Tried marking func as nonisolated but that obviously had no effect func doingSomeAsyncWork() async { authorizationStatus = await MusicAuthorization.request() // Just to have a easy asynchronous function. Without some async code in here, the errors disappear } } Thank you
1
0
3.0k
Jul ’24
SwiftData @ModelActor Memory usage skyrocketing when changing properties
When changing a property of a SwiftData Model from a ModelActor the memory needed slightly increases. Once you do that more often, you can see that the usage is linearly increasing. I modified the Swiftdata template as little as possible. This is the least code I need to reproduce the problem: Changes In the @main struct : ContentView(modelContainer: sharedModelContainer) ContentView: struct ContentView: View { @Query private var items: [Item] let dataHanndler: DataHandler @State var timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { t in }) var body: some View { NavigationSplitView { List { ForEach(items) { item in NavigationLink { Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))") } label: { Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard)) } } } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } ToolbarItem { Button { timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { t in Task { await dataHanndler.updateRandom() // Obviously this makes little sense but I need to update a lot of entities in my actual app. This is the simplest way to demonstrate that. updateRandom() could also be a function of a view but that doesn't make a difference } } } label: { Label("Do a lot of writing", systemImage: "gauge.with.dots.needle.100percent") } } ToolbarItem { Button { timer.invalidate() } label: { Label("Invalidate", systemImage: "stop.circle") } } } } detail: { Text("Select an item") } } private func addItem() { Task { await dataHanndler.insert(timestamp: Date.now) } } init(modelContainer: ModelContainer) { self.dataHanndler = DataHandler(modelContainer: modelContainer) } } ModelActor: @ModelActor actor DataHandler { public func update<T>(_ persistentIdentifier: PersistentIdentifier, keypath: ReferenceWritableKeyPath<Item, T>, to value: T) throws { let model = modelContext.model(for: persistentIdentifier) as! Item model[keyPath: keypath] = value } public func insert(timestamp: Date) { let item = Item(timestamp: timestamp) modelContext.insert(item) } public func updateRandom() { let count = try! modelContext.fetchCount(FetchDescriptor<Item>()) var descriptor = FetchDescriptor<Item>() descriptor.fetchOffset = Int.random(in: 0..<count) descriptor.fetchLimit = 1 let model = try! modelContext.fetch(descriptor) model.first!.timestamp = Date.now } } I filed a bug report FB14876920 but I am looking for other ideas to solve this before it will be fixed in a future update. The modelContext I use is created and managed by the @ModelActor macro. Happy to hear ideas
2
0
713
Aug ’24
Disable MusicKit logs without disabling manual Logs via Logger()
I want to switch from using print statements to using OSLog because of the filtering options and so on. I am using MusicKit. To mute all the log noise mostly coming from CoreData I pass these arguments on launch: -com.apple.CoreData.SQLDebug 0 -com.apple.CoreData.MigrationDebug 0 -com.apple.CoreData.ConcurrencyDebug 0 -com.apple.CoreData.CloudKitDebug 0 -com.apple.CoreData.Logging.stderr 0 This works for all the Core Data related warnings but I also need such an argument for MusicKit. Setting the environment variable OS_ACTIVITY_MODE to disable hides all the noise but also hides the log statements I sent via Logger().debug() for example. In particular these log messages appear in great quantities. Attempted to register account monitor for types client is not authorized to access: {( "com.apple.account.iTunesStore" )} <ICMonitoredAccountStore: 0x303c5c9f0> Failed to register for account monitoring. err=Error Domain=com.apple.accounts Code=7 "(null)" My application works fine and these log messages mean absolutely nothing to me. These two threads mention a similar problem but can't offer a solution. https://forums.developer.apple.com/forums/thread/720835 https://forums.developer.apple.com/forums/thread/743795 Thank you
2
0
816
Sep ’24
[MusicKit] Check for availability of songs
Songs can be unavailable (greyed out) in Apple Music. How can I check if a song is unavailable via the MusicKit framework? Obviously the playback will fail with MPMusicPlayerControllerErrorDomain Code=6 "Failed to prepare to play" but how can I know that in advance? I need to check the availability of hundreds of albums and therefore initiating a playback for each of them is not an option. Things I have tried: Checking if the release date property is set to a future date. This filters out all future releases but doesn't solve the problem for already released songs. Checking if the duration is 0. This does not work since the duration of unavailable songs does not have to be 0. Initiating a playback and checking for the "Failed to prepare to play" error. This is not suitable for a huge amount of Albums. I couldn't find a solution yet but somehow other third-party-apps are able ignore/don't shows these albums. I believe the Apple Music app is only displaying albums where at least one song is available. I am using this function to fetch all albums of an artist. private func fetchAlbumsFor(_ artist: Artist) async throws -> [Album] { let artistWithAlbums = try await artist.with(.albums) var allAlbums = [Album]() guard var currentBadge = artistWithAlbums.albums else { return [] } allAlbums.append(contentsOf: currentBadge) while currentBadge.hasNextBatch { if let nextBatch = try await currentBadge.nextBatch() { currentBadge = nextBatch allAlbums.append(contentsOf: nextBatch) } else { break } } return allAlbums } Here is an example album where I am unable to detect its unavailability (at least in Germany): https://music.apple.com/de/album/die-haferhorde-immer-den-n%C3%BCstern-nach-h%C3%B6rspiel-zu-band-3/1755774804 Furthermore I was unable to navigate to this album via the Apple Music app directly. Thanks for any help Edit: Apparently this album is not included in an apple music subscription but can be bought seperately. The question remains: How can I check that?
1
0
567
Feb ’25