didReceiveRemoteNotification not being called on MacCatalyst - swift

When I create a CKSubscription, didReceiveRemoteNotification gets called on iOS just fine but not on MacOS. I came across a 2015 SO thread talking about a bug and the suggested workaround was to set the notification info's soundName to an empty string - unfortunately that didn't resolve the issue for me.
Here is how I register my remote notifications:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let subscription = CKQuerySubscription(recordType: "Reminder", predicate: NSPredicate(format: "TRUEPREDICATE"), options: [.firesOnRecordCreation, .firesOnRecordUpdate])
// Here we customize the notification message
let info = CKSubscription.NotificationInfo()
info.shouldSendContentAvailable = true
info.desiredKeys = ["identifier", "title", "date"]
info.soundName = ""
subscription.notificationInfo = info
// Save the subscription to Private Database in Cloudkit
CKContainer.default().privateCloudDatabase.save(subscription, completionHandler: { subscription, error in
if error == nil {
// Subscription saved successfully
} else {
// Error occurred
}
})
}

This has to do with the bundle identifier being different on Mac Catalyst. Thanks to the soon to be introduced universal app purchase, catalyst apps can now bear the same bundle identifier as their iOS counterpart, and that fixes the issue.
Note that I was also experiencing issues with cloudkit key values not syncing on Mac (NSUbiquitousKeyValueStore). Having a single bundle id for Mac and iOS fixed the problem too.

Related

Swift Realm issue in iOS 14+

------LE: We ended up removing the encryption of the database because with realm team suggestions it got worse - all we could do was to remove the database and loose all stored info. Now we encrypt in keychain only the fields we need.------
I have an app released in store and after updating their iOS version to 14+, users started to complain about info not being populated from database. Not all users with iOS 14+ have this issue, it appears randomly on some devices.
The issue goes away for awhile if they reinstall the app or after they update it to another version, but after using it for a few minutes it happens again.
My database uses encryption as documented here.
The store version of my app uses Realm 5.4.8, but I tested their last version (10.0.0) and the issue is still present.
I checked this issue but it's not the case for me, I don't have a shared app group container or a share extension.
Here's how the initialisation of realm looks like:
override init() {
super.init()
do {
guard let config = getMigrationAndEncryptionConfiguration() else {
realmConfigured = try Realm()
return
}
realmConfigured = try Realm(configuration: config)
} catch let error as NSError {
// this is where I got the error:
//"Encrypted interprocess sharing is currently unsupported.DB has been opened by pid: 4848. Current pid is 5806."
}
}
func getMigrationAndEncryptionConfiguration() -> Realm.Configuration? {
let currentSchemaVersion: UInt64 = 19
if Keychain.getData(for: .realmEncryptionKey) == nil {
var key = Data(count: 64)
_ = key.withUnsafeMutableBytes { bytes in
SecRandomCopyBytes(kSecRandomDefault, 64, bytes)
}
Keychain.save(data: key, for: .realmEncryptionKey)
}
guard let key = Keychain.getData(for: .realmEncryptionKey) else {
return nil
}
let fileUrl = Realm.Configuration().fileURL!.deletingLastPathComponent()
.appendingPathComponent("Explorer.realm")
var config = Realm.Configuration(fileURL: fileUrl,
encryptionKey: key,
schemaVersion: currentSchemaVersion, migrationBlock: { (migration, oldVersion) in
if oldVersion != currentSchemaVersion {
print("we need migration!")
}
})
return config
}
I had another question opened for the same issue on SO, but it was closed because I didn't have enough details. After another release of my app with more logs, I could find the error that appears at initialisation of realm:
"Encrypted interprocess sharing is currently unsupported.DB has been opened by pid: 4848. Current pid is 5806. "
This appears after the app goes to background, it gets terminated (crash or closed by the system/user) and when the users opens it again, realm fails to init.
I read all about encrypted realm not being supported in app groups or in a share extension, but I didn't implement any of that in my app, is there any other reason why this error happens?
I also removed Firebase Performance from my app because I read that this module could generate issues on realm database, but it didn't help.
I opened an issue on realm github page, but I got no answer yet.
Does anyone have any idea how to fix this or why is this happening?
Thank you.

Crashlytics - can't add custom keys, they are not caught on crash

I have a problem with crashlitycs for iOS - I cant set custom keys (they are not registered online).
Everything else is working, I can record the same data in customlogs - that works perfectly, but custom keys doesn't show whatsoever.
Part of the code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
setCrashlitycsKeys()
}
internal func setCrashlitycsKeys() {
if let userId: Int64 = UserDefaultsHelper.get(for: .UserId) {
Logger.shared.log.warning("User Id: \(userId)")
Crashlytics.sharedInstance().setUserIdentifier(String(describing: userId))
Crashlytics.sharedInstance().setObjectValue(userId, forKey: "userId")
}
if let jsonString: String = UserDefaultsHelper.get(for: .InstanceModuleConfigJson) {
let instancesModuleConfigModel = InstancesModuleConfigModel(JSONString: jsonString)
if let instance = instancesModuleConfigModel?.id {
Crashlytics.sharedInstance().setObjectValue(instance, forKey: "instanceId")
Logger.shared.log.warning("Instance Id: \(instance)")
}
}
}
Logger is just a custom CLSLogv and it works perfectly -
screenshot for log
while theres nothing in keys
screenshot no keys
(it says that no keys found)
Any ideas what can I do or check to make this working? I've spend several hours trying different types of keys, different places and so on but nothings working.
I Use Xdode Version 11.2.1 (11B53),
pod 'Fabric', '~> 1.10.2'
pod 'Crashlytics', '~> 3.14.0'
Ok I found a bug after few hours of searching, in my project I have few targets (mainApp, AppCommon etc) - project is big, so I import smaller functionalities. I had to use Crashlytics pod in 2 of them and that caused an error

NSAlert() runmodal this class is not key value coding-compliant for the key modalWindow

Recently i upgraded my mac to Catalina and seeing weird issues with NSAlert().
When ever any alert is opened i am getting bellow error in console and the alert is automatically closing, without any user clicking on OK button.
Error in console :
this class is not key value coding-compliant for the key modalWindow.' with user dictionary {
NSTargetObjectUserInfoKey = "<ProjectName.AppDelegate: 0x100b07400>";
NSUnknownUserInfoKey = modalWindow;
}
Below is my code for displaying Alert.
let myPopup: NSAlert = NSAlert()
myPopup.messageText = messageText
myPopup.informativeText = infoText
myPopup.alertStyle = NSAlert.Style.warning
myPopup.addButton(withTitle: NSLocalizedString("OK", comment: "Button Text"))
let res = myPopup.runModal()
FYI : This is Mac App, using swift, Xcode11 (tried with Xcode 11.1 & 11.2)
Finally figured it,
In my application we do support for scripting so i added below code in AppDelegate file :
func application(_ sender: NSApplication, delegateHandlesKey key: String) -> Bool {
return true
}
Since i am returning true always it is creating issues with NSOpenPanels, NSSavePanels and NSAlert, and i changed the code as below and it is working fine without any issues.
func application(_ sender: NSApplication, delegateHandlesKey key: String) -> Bool {
if key == "[.sdf file KEY HERE]"{
return true
}
return false
}
Please note i am getting this issues only in latest OS Catalina, in previous OS i didn't got any issues.

Determine login type using AWS Cognito during resume session (Swift)

I'm having a hard time trying to figure out how to determine the login type during a resume session using AWS Cognito. My code is based upon the MobileHub sample (below).
I've integrated a name/password mode for user pools (account creation and login) as well as as a Facebook login button which all works perfectly.
I have some logic in my application that needs to behave differently depending on the login type but I can't figure out how to do it.
Anyone done this?
func didFinishLaunching(_ application: UIApplication, withOptions launchOptions: [AnyHashable: Any]?) -> Bool {
print("didFinishLaunching:")
// Register the sign in provider instances with their unique identifier
AWSSignInManager.sharedInstance().register(signInProvider: AWSFacebookSignInProvider.sharedInstance())
AWSIdentityProfileManager.sharedInstance().register(FacebookIdentityProfile.sharedInstance(), forProviderKey: AWSFacebookSignInProvider.sharedInstance().identityProviderName)
AWSSignInManager.sharedInstance().register(signInProvider: AWSCognitoUserPoolsSignInProvider.sharedInstance())
AWSIdentityProfileManager.sharedInstance().register(UserPoolsIdentityProfile.sharedInstance(), forProviderKey: AWSCognitoUserPoolsSignInProvider.sharedInstance().identityProviderName)
setupAPIGateway()
setupS3()
let didFinishLaunching: Bool = AWSSignInManager.sharedInstance().interceptApplication(application, didFinishLaunchingWithOptions: launchOptions)
if (!isInitialized) {
AWSSignInManager.sharedInstance().resumeSession(completionHandler: { (result: Any?, authState: AWSIdentityManagerAuthState, error: Error?) in
print("didFinishLaunching Result: \(String(describing: result)) AuthState: \(authState) \n Error:\(String(describing: error))")
if authState == .authenticated {
// Facebook or Cognito???
AWSCognitoUserAuthHelper.getCurrentUserAttribute(name: "sub", completionHandler: { (userid) in
// we need to fetch the user
ObjectManager.instance.getUser(userid: userid, completionHandler: { (user) in
ObjectManager.instance.setCurrentUser(user: user)
})
})
}
}) // If you get an EXC_BAD_ACCESS here in iOS Simulator, then do Simulator -> "Reset Content and Settings..."
// This will clear bad auth tokens stored by other apps with the same bundle ID.
isInitialized = true
}
return didFinishLaunching
}
One solution I found was to cast to the different identity profile types such as the following:
let identityManager = AWSIdentityManager.default()
if let fbIdentityProfile = identityManager.identityProfile as? FacebookIdentityProfile {
print("didFinishLaunching - Facebook login")
} else if let upIdentityProfile = identityManager.identityProfile as? UserPoolsIdentityProfile {
print("didFinishLaunching - User Pools login")
}
I can model logic in my application around this. Not sure if there is a cleaner approach using the MobileHub helper classes or AWS APIs but this works.

firebase token is null and token refresh is called continously in my testFlight

First of all, i have no problem for FCM, firebase token is never null every time tokenRefreshNotification is called. But after, i add Google analytics, i got weird problem for Firebase token. Every time i turn off and turn on notification in my app settings used
UIApplication.shared.registerForRemoteNotifications()
my tokenRefreshNotification is called continously and it doesn't stop looping until i force close my apps. At first, my app crash, and when i try to trace it with NsLog, i found that Firebase token is null. The problem occurs only when i`m using my apps installed from TestFlight / production. When i try it from my Xcode builder, firebase token is null only once, but the second call, firebase token is exist and it stop working.
For google Analytics, it works fine and in my GoogleService-info.plist,
i have set IS_ANALYTICS_ENABLED to YES and IS_GCM_ENABLED to YES also. For the other, IS_ADS_ENABLED = YES, IS_APPINVITE_ENABLED = NO, and IS_SIGNIN_ENABLED = YES
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FIRApp.configure()
NotificationCenter.default.addObserver(self, selector: #selector(self.registerNotification), name: NSNotification.Name(rawValue: "registerNotification"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.tokenRefreshNotification(_:)), name: .firInstanceIDTokenRefresh, object: nil)
setupGoogleAnalytics()
return true
}
//when firebase token is null, this function is working continously until my firebase token is exist
func tokenRefreshNotification(_ notification: Notification) {
print("token Refresh")
if FIRInstanceID.instanceID().token() == nil{
NSLog("firebase token is null")
}
if (UserDefaults.standard.object(forKey: "id") != nil) && FIRInstanceID.instanceID().token() != nil{
FIRInstanceID.instanceID().getWithHandler({ (instanceID, error) in
NSLog("instanceID: \(instanceID!)")
//save firebase token to my database, sorry i can`t show it
})
}
// Connect to FCM since connection may have failed when attempted before having a token.
connectToFcm()
}
Note: At the first launch, i called my RegisterForRemoteNotifications, at TestFlight version, when tokenRefreshNotification is called, the firebase token is null, but the second call, firebase token is exist, so it could stop. But, when i run my app from Xcode, the first call is success because firebase token is not null.
i have figured it out! just change ANPS Type token from Sandbox to Unknown!
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// With swizzling disabled you must set the APNs token here.
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.unknown)
}