Post

Replies

Boosts

Views

Activity

Intermittent errSecNotAvailable on some devices when storing keychain
I released an update to my app a few days ago, the user can add their account info, which gets sent to a SAML2 webservice, returns a refresh token, and stores it in the iOS Keychain using the following method:+(void)saveString:(NSString *)inputString forKey:(NSString *)account { / / NSMutableDictionary *query=[NSMutableDictionary dictionary]; [query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; [query setObject:account forKey:(__bridge id)kSecAttrAccount]; [query setObject:(__bridge id)kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible]; OSStatus error=SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL); if (error == errSecSuccess) { / NSDictionary *attributesToUpdate=@{(__bridge id)kSecAttrAccount: account, (__bridge id)kSecValueData: [inputString dataUsingEncoding:NSUTF8StringEncoding]}; error = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributesToUpdate); / if (error != errSecSuccess) { NSLog(@"SecItemUpdate failed: %d", error); } }else if (error == errSecItemNotFound) { [query setObject:account forKey:(__bridge id)kSecAttrAccount]; [query setObject:[inputString dataUsingEncoding:NSUTF8StringEncoding] forKey:(__bridge id)kSecValueData]; error=SecItemAdd((__bridge CFDictionaryRef)query, NULL); / if (error != errSecSuccess) { NSLog(@"SecItemUpdate failed: %d", error); } }else { / NSLog(@"SecItemCopyMatching failed: %d", error); } }Depending on who has the app installed, it seems like it's not storing the refresh token to the keychain, and silently failing. When I plugged in one of the affected user's phones into XCode and ran a debug build, it gave me an "errSecNotAvailable" message (code -25291).When the user (via the process of logging into an authenticated app screen) attempt to pull the token out of the keychain using the following method, it pulls out a nil value, and doesn't log them in (as expected):+(NSString *)getStringForKey:(NSString *)account { / if (account != nil) { NSMutableDictionary *query=[NSMutableDictionary dictionary]; [query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; [query setObject:account forKey:(__bridge id)kSecAttrAccount]; [query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData]; CFDataRef dataFromKeychain=nil; OSStatus error=SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&dataFromKeychain); NSData *dataResult=(__bridge_transfer NSData *)dataFromKeychain; NSString *stringToReturn=nil; if (error == errSecSuccess) { stringToReturn=[[NSString alloc] initWithData:dataResult encoding:NSUTF8StringEncoding]; } return stringToReturn; }else { return nil; } }This has been very frustrating for both my users, as well as myself, since the keychain works on most devices (including my personal and test iPhones), but not on others. Is there a reason for this error to occur on some devices but not others? I couldn't even determine a pattern (i.e. device model, iOS Version, etc). It seems to be indiscriminate.Thanks in advance!- Scott
2
0
1.7k
Jan ’18
ID Card for a University
I'm in the process of exploring using Passkit to host and distribute our University Digital ID card. I understand that Apple has worked with a few Universities in this Vertical and that there is a means to apply for this program. The only issue is that we don't have a one card solution, and our cards aren't distributed through Blackboard. We would like to handle this ourselves though with NFC readers deployed at strategic locations throughout campus (i.e. the Library, shared printers (Where students are required to swipe their ID's to release print jobs) as well as Dining locations, where they use their ID cards for a declining balance.Is there a way to work with Apple to get an NFC certificate for this using the system I described (barring having to work with Blackboard)?
4
2
2.2k
Feb ’20
Best Practices for Multiple BGProcessingTasks in an App
Hi all, My app downloads data from various API endpoints and stores it in corresponding CoreData entities for fast offline access. It does an initial sync the first time the app launches, and users can pull to refresh the data from the appropriate endpoints on the corresponding screens. I’m also using a BGProcessingTask to handle these data syncs passively when the app is backgrounded. I’m hitting quite a few API endpoints in a chained series of completion handlers, and if the user is logged in, I’m hitting a few more on top of that.  I understand that BGProcessingTasks are designed for long running processes. My question is are there any best (or wrong) practices for having multiple BGProcessingTasks in your app? I’m looking to split everything up into 3 or 4 separate tasks so that each one can complete faster, and hopefully with a higher success rate.  Thank you in advance! Scott
0
0
738
Apr ’22
Open Source IMDF file creators / editors
Are there any solutions to convert floor plans to IMDF files for Indoor Mapping (or at least plans to create a conversion tool)? Most of the tools such as ERSI and Autodesk seem to be developed more for building engineers and architects. Is there anything for content managers to ingest floor plans (provided by our facilities dept), and create and update locations in buildings as they change, and publish to an in-app Apple map implementation? Thanks in advance, Scott
0
0
1.1k
Apr ’22
Batch updating one to many relationships between two entities
Hi all, I have 2 CoreData entities, "Person" (staff members) and "Role" (their job title, which they can have more than one of). I'm syncing all of these entities from two corresponding API endpoints. After syncing everything, I'm trying to run a method that loops through all of the roles (there are a few thousand of them) and assign them to the corresponding "person" (there are slightly less people, but still in the low 1000's). The following works, but it's understandable slow: public func setPeopleToRoles() async throws {         DataStore.shared.backgroundContext.performAndWait {             let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Role")             do {                 guard let roles = try DataStore.shared.backgroundContext.fetch(fetchRequest) as? [Role] else { return }                 let _ = roles.map { $0 }.compactMap {                     if let personModel = PeopleFetcher.shared.fetchPersonFromCache(personId: $0.employee) {                         $0.person = personModel                     }                 }             }catch {                 print(error)             }             if DataStore.shared.backgroundContext.hasChanges {                 do {                     try DataStore.shared.backgroundContext.save()                     print("People to Roles Saved")                 }catch {                     print("Error caching events to CoreData: \(error)")                 }                 DataStore.shared.backgroundContext.reset()             }         }     } Is there a way I can refactor this into an NSBatchUpdate? All the information I found involves updating properties with the same value (i.e. setting "completed" to true). Thanks in advance, Scott
0
0
519
May ’22
Trying to pull Song metadata from ApplicationMusicPlayer.shared.queue
I'm building a SwiftUI music app that displays the "currently playing" song info based on ApplicationMusicPlayer.shared.queue.currentEntry. This is what the debug description looks like for currentEntry: Optional(MusicPlayer.Queue.Entry(id: "4Nknkwlke∆wNEXFpkFF", item = Song(id: "1452351734", title: "Piano Sonata No. 14 in C-Sharp Minor, Op. 27 No. 2 "Moonlight": I. Adagio sostenuto", artistName: "Vladimir Ashkenazy"))) after I unwrap the above, I'm able to get the song title and artwork object without a problem: guard let currentEntry = appleMusicManager.queue.currentEntry else { return } self.songTitle = currentEntry.title) self.albumArtwork = currentEntity.artwork } However, my issue is that I cannot get the artist name from the embedded "item" object: print(currentEntry.item.artistName) I tried everything from attempting to cast currentEntry.item to Song , but nothing seemed to work. Is there any way to get access to all the song instance properties from within the player queue? TIA. Scott
0
0
551
Jan ’23