iOS 13.1 doesn't receive silent CKQuerySubscription notifications - ios

My app uses CloudKit Query subscriptions and notifications as part of a CloudKit-based synchronization solution. This works perfectly with iOS 12, macOS 10.14 and even macOS 10.15 beta, but NOT with iOS 13.0, iOS 13.1, iPadOS 13.1 and tvOS 13.0.
Removing and recreating the subscriptions doesn't solve this.
Is this a known problem?
According to the documentation, nothing has changed with CloudKit subscriptions. Or did I miss something?

To receive silent CKQuerySubscription notifications in iOS 13.x and tvOS 13.x, the soundName and alertBody parameters of the NotificationInfo of your CKQuerySubscription must not be set.
In the past we have learned to use an empty string for said parameters, to make the whole CloudKit subscription thing working, but that's now history. Apparently Apple has fixed an old bug, causing problems with apps that used this 'workaround'.
I have tested this on iOS 12.4.2, iOS 13.1.2, tvOS 13.0, macOS 10.14.6 and macOS 10.15 GM.
let info = CKSubscription.NotificationInfo()
info.shouldSendContentAvailable = true
// info.soundName = "" // Don't set this property
// info.alertBody = "" // And also leave this this property alone
let subscription = CKQuerySubscription(recordType: "yourRecordType", predicate: NSPredicate(value: true), subscriptionID: "yourSubscription", options: [CKQuerySubscription.Options.firesOnRecordUpdate, CKQuerySubscription.Options.firesOnRecordDeletion])
subscription.notificationInfo = info
// You must first delete the old subscription to change the sound name
let deleteOperation = CKModifySubscriptionsOperation(subscriptionsToSave: nil, subscriptionIDsToDelete: ["yourSubscription"])
yourContainer.privateCloudDatabase.add(deleteOperation)
let createOperation = CKModifySubscriptionsOperation(subscriptionsToSave: [subscription], subscriptionIDsToDelete: nil)
createOperation.addDependency(deleteOperation)
yourContainer.privateCloudDatabase.add(createOperation)

Silent Notifications stopped working for my app as well in iOS 13.
On my iOS 12 devices and MacBook, silent notifications kept working correctly.
Recreated subscriptions multiple times without success.
Checked all steps in
https://developer.apple.com/library/archive/qa/qa1917/_index.html
When I saw Ely's answer, I immediately went to check if I had a soundName set for the notification. Though I did not have any, I saw the alertBody empty string and decided to try it without it. After recreating the subscription, silent notifications started working again in iOS 13. When reading the documentation, it seems obvious that you do not want an alert message on a silent notification. However, I do remember adding it at some point to make it work on another iOS version.
In my case, I was creating a RecordZoneSubscription like this:
CKSubscription * subscription = [[CKRecordZoneSubscription alloc] initWithZoneID:self.dataZone.zoneID subscriptionID:[self mainPrivateSubscriptionID]];
CKNotificationInfo *notificationInfo = [CKNotificationInfo new];
notificationInfo.shouldBadge = false;
notificationInfo.alertBody = #""; // THE CULPRIT
notificationInfo.shouldSendContentAvailable = true;
subscription.notificationInfo = notificationInfo;
Solution:
CKSubscription * subscription = [[CKRecordZoneSubscription alloc] initWithZoneID:self.dataZone.zoneID subscriptionID:[self mainPrivateSubscriptionID]];
CKNotificationInfo *notificationInfo = [CKNotificationInfo new];
notificationInfo.shouldBadge = false;
notificationInfo.shouldSendContentAvailable = true;
subscription.notificationInfo = notificationInfo;

Related

How to get access into push notification with UI tests (Xcode 12, iOS14)?

I'm during migration to work with new Xcode 12, but I have a problem with UI tests.
Code
let springBoard = XCUIApplication(bundleIdentifier: appleBundleIdentifier) let notification = springBoard.otherElements["NotificationShortLookView"]
not working anymore and I can't find how to indicate notification view. How was it changed?
It seems like notification elements have a slightly different accessibility hierarchy in iOS 14. This should work:
let springBoard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
let notification = springBoard.otherElements["Notification"].descendants(matching: .any)["NotificationShortLookView"]
It's interesting to observe that the actual XCUIElement that represents the push notification has type "BannerNotification" (an XCUIElementType with a rawValue representation 83) which I couldn't find in the public headers. Might be a private type at the moment. Hence the workaround with decendants(matching: .any).
Also accessing/asserting inside the notification is possible:
let notification = springBoard.otherElements["Notification"].descendants(matching: .any)["APPNAME, now, TITLE, BODY"]
if notification.waitForExistence(timeout: 10) {
notification.tap()
}
If anyone is looking for testing if a notification has an attachment, add "Attachment" after notification Body
let notification = springBoard.otherElements["Notification"].descendants(matching: .any)["APPNAME, now, TITLE, BODY, Attachment"]

IOS 13 doesn't play a notification sound using FirebasePushNotificationPlugin

I use Firebase to push notifications to the users at a certain time. They receive the notification but no alert sound is played. In the settings, the allow sound/notifications are turned on and other IOS13 and other apps play sound.
Version Number of FirebasePushNotificationPlugin Plugin: 3.3.10
Device Tested On: iphone X, OS: 13.4.1
Simulator Tested On: N/A (simulators don't receive notifications)
Version of VS: VS for Mac Community, 8.6.6 (build 11)
Version of Xamarin: Xamarin.IOS 13.18.2.1, Xamarin.Forms v4.6.0.847
AppDelegate.cs:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
bool fbaseStarted = false;
try
{
// This method does all the UNUserNotificationCenter.Current.RequestAuthorization() code so we don't have to.
FirebasePushNotificationManager.Initialize(options, true);
fbaseStarted = true;
}
catch
{ }
LoadApplication(new App());
if (!fbaseStarted)
{
try
{
FirebasePushNotificationManager.Initialize(options, true);
}
catch { }
}
FirebasePushNotificationManager.CurrentNotificationPresentationOption = UNNotificationPresentationOptions.Badge | UNNotificationPresentationOptions.Alert | UNNotificationPresentationOptions.Sound;
}
Within one of the pages of my code, I subscribe a list of tags (please note that I unsubscribe because the first time the code runs it fails silently if the notifications aren't approved - resulting in the model thinking the notifications was subscribed when it wasn't):
CrossFirebasePushNotification.Current.UnsubscribeAll();
CrossFirebasePushNotification.Current.Subscribe(Constants.NotificationTagsArray);
I keep coming across payload json solutions but unless I am wrong, I don't think that applies to me as I am using Xamarin and the FirebasePushNotificationPlugin. Is there any additional permissions that were added in ios 13 for playing notifications with sound that I have missed?
I have also posted here: https://github.com/CrossGeeks/FirebasePushNotificationPlugin/issues/348 but nobody has been able to assist me yet.
Thanks
The issue actually lies with the sending of the notifications nothing to do with the Xamarin App. The issue resided in the services that sends the notifications to firebase (to then be sent out to the phones).
In the service we were sending a FirebaseNet.Messaging.Message() to the phones:
Message FireBasemessage = new Message()
{
To = "/topics/" + PushNote.Tag,
TimeToLive = 86400,
Priority = MessagePriority.high,
ContentAvailable = true,
Notification = new AndroidNotification()
{
Tag = "/topics/" + PushNote.Tag,
Body = enhancedMessage,
Title = xtitle,
}
,
Data = new Dictionary<string, string>
{
{ "param", PushNote.Tag },
{ "text", enhancedMessage}
}
};
In the AndroidNotification() object required Sound = "default" to be added for it to work. Please note that this works for both Android and IOS notifications despite the fact it is an AndroidNotification object.

Siri shortcuts work on iPhone, but not on HomePod

I’m working on app that uses Siri Shortcuts, and I’ve met one strange issue:
If I run a shortcut on iPhone, it works well. If I do the same with HomePod, connected to the same iPhone, I get “There is a problem with your app” from Siri. My shortcuts are created within the app.
if #available(iOS 12.0, *) {
let activity = NSUserActivity(activityType: command.rawValue)
activity.title = selectTitle(activityType: command)
activity.isEligibleForSearch = true
activity.isEligibleForPrediction = true
activity.persistentIdentifier = NSUserActivityPersistentIdentifier(command.rawValue)
responder.userActivity = activity
activity.becomeCurrent()
}
Any ideas how to make them work via HomePod?
Thanks in advance!

Google Nearby API on iOS background scanning

I've got the Nearby API set up in my Swift app and I can receive messages when the app is in the foreground. Following the instructions in the docs
I try to include params.allowInBackground = true in the appropriate place but I get an error:
Value of type 'GNSBeaconStrategyParams' has no member 'allowInBackground'
So, I can't do that and my GNSSubscription object looks like this:
subscription = messageManager.subscriptionWithMessageFoundHandler(
messageFoundHandler, messageLostHandler: messageLostHandler,
paramsBlock: { (params: GNSSubscriptionParams!) in
params.deviceTypesToDiscover = .BLEBeacon
params.permissionRequestHandler = { (permissionHandler: GNSPermissionHandler!) in
// TODO: Show custom dialog here, and call permissionHandler after it is dismissed
// show the dialogue
}
params.beaconStrategy = GNSBeaconStrategy(paramsBlock: { (params: GNSBeaconStrategyParams!) in
params.includeIBeacons = true
//params.allowInBackground = true //*** THIS DOESN'T WORK ***
})
})
My messageHandlers look like this:
messageFoundHandler = {[unowned self](message: GNSMessage!) -> Void in
print("Found handler:", message.type, "->", String(data: message.content!, encoding:NSUTF8StringEncoding)!)
if UIApplication.sharedApplication().applicationState != .Active {
let localNotification = UILocalNotification()
localNotification.alertBody = "Message received" + String(data: message.content!, encoding:NSUTF8StringEncoding)!
UIApplication.sharedApplication().presentLocalNotificationNow(localNotification)
}
}
messageLostHandler = {(message: GNSMessage!) -> Void in
print("Lost Handler:", message.type, "->", String(data: message.content, encoding:NSUTF8StringEncoding)!)
}
With this set up and an Eddystone beacon in range I now get notifications in the background! Since this is what I want I should be happy. However, if I leave the device connected to xcode with the app in the background I start to see a stream of messages like this (seems to be roughly every 5 seconds):
2016-07-23 19:35:08.243 Hoc[1269:622746] Can't endBackgroundTask: no background task exists with identifier 2f3, or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.
I'm using v0.10.0 of NearbyMessages. If anyone can point me in the right direction to get background scanning working reliably on iOS that would be great.
This was caused by an issue with Cocoapods. Even though I used $ pod update and similar approaches to remove/re-added the NearbyMessages cocoaPod from my project, for some reason I couldn't get the latest version (1.0.1) of the Nearby SDK installed. The solution was to manually download the spec from Github and overwrite the files in ~/.cocoapods/repos/master.
Then to make sure I had the latest version installed, I changed my podfile to include pod 'NearbyMessages', '~> 1.0.1' which worked.
Now I can set the appropriate params on the GNSBeaconStrategy object and background scanning for Eddystone beacons works in the background on iOS. :-)
I hope this helps.

Local notifications sent to background works in simulator but not on device

In the simulator I'm able to get the exact result I want: When I trigger a notification and my simulator phone is locked, then the notification gets pushed to the watch.
This used to work on device (my iPhone 6 on iOS 9.1 and Watch on watchOS 2.0). For some reason it stopped working and I don't know how to debug the problem.
So on device, I make sure that the app is in background by going to home screen and locking the phone and making sure my watch is asleep. When the notification is triggered, nothing happens. When I open up the app, that's when the notifications finally gets triggered. I.E. if I trigger 3 notifications, none of them register until I open the app back into foreground. This is not how it works in simulator (simulator has correct behavior described above).
The notification is triggered by me changing a text object that is stored in my Firebase db. The change calls the sendNotification function. Again, this works perfectly fine in the simulator and used to work on device but for some reason doesn't work anymore.
In app delegate I have:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
UIApplication.sharedApplication().registerUserNotificationSettings(UIUserNotificationSettings(forTypes: .Alert, categories: nil))
// Setting up Local Notification
let assistAction = UIMutableUserNotificationAction()
assistAction.activationMode = UIUserNotificationActivationMode.Background
assistAction.identifier = categoryID
assistAction.title = "Assist"
assistAction.authenticationRequired = false
assistAction.destructive = false
// Category
let assistCategory = UIMutableUserNotificationCategory()
assistCategory.identifier = categoryID
assistCategory.setActions([assistAction], forContext: UIUserNotificationActionContext.Default)
// Only way to get this to work with parameter
let categories = NSSet(object: assistCategory)
// Settings
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: categories as? Set<UIUserNotificationCategory>)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
// UIApplication.sharedApplication().registerForRemoteNotifications()
return true
}
Then in my view controller I have:
func sendNotification(customerName: String, helpText: String) {
// Local Notification
let notification = UILocalNotification()
notification.alertBody = "\(customerName) \(helpText)"
notification.soundName = UILocalNotificationDefaultSoundName
notification.fireDate = NSDate()
notification.category = categoryID
UIApplication.sharedApplication().presentLocalNotificationNow(notification)
print("Sent notification");
}
Simulator seems to work differently than device. It's weird that simulator local notifications was acting like remote push notifications.
I ended up giving up on trying to make local notifications show up while app is in background on device because I've learned that that is not the expected behavior.
The correct solution is to just set up remote push notification, which I used Parse to do. And now it's working as expected. I have a web server that uses the Parse REST API to send a POST request to Parse and my iOS app is then set up to receive remote push notifications which now show up on my watch when my phone is locked.

Resources