I am developing an app which makes use of actionable notifications.
On my code (the func userNotificationCenter function), I need to read my users from the local storage on the iPhone:
let query: [String: Any] = [
kSecAttrService as String: "uio-auth",
kSecAttrAccount as String: "users",
kSecClass as String: kSecClassGenericPassword,
kSecReturnData as String: true
]
var result: AnyObject?
SecItemCopyMatching(query as CFDictionary, &result)
let ref = result as? Data
But when the same code execute when I tap on the notification on the Apple Watch, it doesn't fetch anything. It now occurs to to me:
Does it mean that when an actionable notification programmed for the iOS is displayed on the Apple Watch, it tries to access its own storage, and not the iPhone? If so, is there a nice way to pass the values to the watchOS so that when the callback for the actionable notifications run, it has then the data it needs?
Notifications
RSS for tagLearn about the technical aspects of notification delivery on device, including notification types, priorities, and notification center management.
Post
Replies
Boosts
Views
Activity
Hello,
since updating (last night) to developer beta 18.2, I no longer have email count numbers / badges showing. I don’t know if others are experiencing this, but thought I should report it.
Over the past few weeks I've seen several people mention pushes sent via the sandbox haven't been getting delivered.
Today I'm also seeing that (though pushes sent via production are fine).
So it would appear to be down again. What's going on recently, any reason it's so unstable these last few weeks?
I am using a Key to connect my notification server with APNS in order to send out notifications to users. I have recently added notifications to a second app of mine, using the same notification server to fire off notifications for both apps. However, any notifications going to the second app return the error InvalidProviderToken, where as I get no such issues when send notifications to the first app. Everything, including the payloads, are exactly the same between the two apps, the only difference is that the device IDs are attached to different apps.
Does anyone know why/how this would happen and how I can resolve it?
Hey there, i created a independent Watch OS app and I configure push notification there.
so on watch simulator I am able to get push notification every time.
but today I test watch app to my real watch series 6 WatchOS 11.
I got the permission alert I allowed it, and I am able to get the device token as well now if I try to send push notification to my real watch app I get this logs.
Oct 22, 2024, 11:09:12.024 AM GMT+5
received by APNS Server
Oct 22, 2024, 11:09:12.334 AM GMT+5
discarded as application was not registered
why is that ? is there any body know's ? why i am not receiving remote notification on my real watch instead i get that my application is not register...
Regarding the latest news from apple below. I am not able to understand what exactly needs to be done. I can download RSA certificate from the link given but to include it in Trust store is something i am not able to get.
can someone help me out here?
" The Certification Authority (CA) for Apple Push Notification service (APNs) is changing. APNs will update the server certificates in sandbox on January 20, 2025, and in production on February 24, 2025. All developers using APNs will need to update their application’s Trust Store to include the new server certificate: SHA-2 Root : USERTrust RSA Certification Authority certificate.
To ensure a smooth transition and avoid push notification delivery failures, please make sure that both old and new server certificates are included in the Trust Store before the cut-off date for each of your application servers that connect to sandbox and production.
At this time, you don’t need to update the APNs SSL provider certificates issued to you by Apple."
I have an iOS and watchOS app where both can run independently, I am not using WatchConnectivity to send data back and fourth. The issue I'm having is that if I schedule a local notification on the watch and the phone is unlocked, it will not show on the watch for about 10-15 seconds. If I uninstall the iOS app or have the phone locked, it will show immediately on the watch.
To my understanding, this is somewhat the expected functionality but is there a way to bypass it? My app is a timer app and it really should not have a delay.
The Certification Authority (CA) for Apple Push Notification service (APNs) is changing. APNs will update the server certificates in sandbox on January 20, 2025, and in production on February 24, 2025. All developers using APNs will need to update their application’s Trust Store to include the new server certificate: SHA-2 Root : USERTrust RSA Certification Authority certificate.
To ensure a smooth transition and avoid push notification delivery failures, please make sure that both old and new server certificates are included in the Trust Store before the cut-off date for each of your application servers that connect to sandbox and production.
At this time, you don’t need to update the APNs SSL provider certificates issued to you by Apple.
Hi,
I'm building an app that allows users to get real time data about trains in Portugal and the Metro system in Lisbon. I'm using SwiftUI for frontend.
I would like to add a feature to the app, where the User can add a specific Train to their Favourites list and subscribe to notifications about the status of that Train so that they are aware of any disturbances.
For example, 10 minutes before the train departure time, there would be an API call to fetch the train information, and a notification would be sent to the end-user with the status of the Train.
Can someone tell me if this is possible to do? And if so, how to do it?
Basically, I want to trigger an API call more-or-less at a specific time and, based on the data from the API, send a push notification to the User.
Thanks in advance
I'm attempting to leverage notifications in an app that is in Swift 6 language mode. I have the following code:
func startLocationUpdates() {
//if self.manager.authorizationStatus == .notDetermined {
// self.manager.requestWhenInUseAuthorization()
//}
self.logger.info("Starting location updates")
Task {
do {
let updates = CLLocationUpdate.liveUpdates()
for try await update in updates {
if !self.updatesStarted { break } // End location updates by breaking out of the loop.
self.lastUpdate = update
if let loc = update.location {
self.lastLocation = loc
self.isStationary = update.stationary
self.count += 1
self.logger.info("Location \(self.count): \(self.lastLocation)")
}
if lastUpdate!.insufficientlyInUse {
let notification = UNNotificationRequest(identifier: "com.example.mynotification", content: notificationContent, trigger: nil)
try await UNUserNotificationCenter.current().add(notification)
}
}
} catch {
self.logger.error("Could not start location updates")
}
return
}
}
As an aside, the above is directly taken from the following sample:
https://developer.apple.com/documentation/CoreLocation/adopting-live-updates-in-core-location.
With Swift 6 language mode enable, this generates a compiler error for the statement:
try await UNUserNotificationCenter.current().add(notification)
Sending main actor-isolated 'notification' to nonisolated instance method 'add' risks causing data races between nonisolated and main actor-isolated uses
How can I fix this?
Hi Everyone,
I noticed that applicationIconBadgeNumber has been deprecated in iOS17. While there's a new method to set the badge number using setBadgeCount(_:withCompletionHandler:), I couldn't find a way to retrieve the current value.
Previously we used to call UIApplication.shared.applicationIconBadgeNumber, to get the current value, which is deprecated now.
Does anyone know how to get the current badge count?
Thanks!
Our application streams live video with AVCaptureSession. When application is active and Airpods case is being opened at this time, popup message "Not Your Airpods..." is appeared over application and video session is suspended.
I can see that application receives notification UIApplicationWillResignActiveNotification, so application becomes inactive at this time.
Is there any ability to disable such pairing popup from Airpods or maybe intercept it inside our application? Because it affects our video streaming feature.
Thanks.
Hello everyone,
We have an app that implements in-app purchases, and we're using the notification settings outlined in this Apple Developer guide. Everything is functioning correctly in TestFlight, and our server successfully receives notifications from Apple.
However, after releasing the app to production, we're no longer receiving these notifications, while the TestFlight version continues to work as expected.
Has anyone encountered a similar issue or have any suggestions on how to resolve this?
Thank you for your help!
I keep getting 401 Unauthorized error when fetching Apple's public keys.
In [14]: print(f"Error fetching public keys: {response.status_code} {response.text}")
Error fetching public keys: 401 Unauthenticated
I've verified that the Key ID, Issuer ID, and private key file are all correct, with the private key having admin access. The server time is correctly set to UTC. Given this, I can't identify what might be causing the issue. Any insights?
def generate_apple_developer_token():
# Load the private key in PEM format
with open(PRIVATE_KEY_FILE, 'rb') as key_file:
private_key = serialization.load_pem_private_key(
key_file.read(),
password=None,
backend=default_backend()
)
# JWT header
headers = {
"alg": "ES256",
"kid": KEY_ID,
"typ": "JWT"
}
# JWT payload
payload = {
"iss": ISSUER_ID,
"iat": int(datetime.utcnow().timestamp()),
"exp": int((datetime.utcnow() + timedelta(minutes=10)).timestamp()),
"aud": "appstoreconnect-v1",
}
# Encode the header and payload as base64
header_base64 = base64.urlsafe_b64encode(json.dumps(headers).encode()).decode().rstrip("=")
payload_base64 = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=")
# Concatenate header and payload
message = f"{header_base64}.{payload_base64}".encode()
# Sign the message using ECDSA with SHA256
signature = private_key.sign(
message,
ec.ECDSA(hashes.SHA256())
)
# Convert the DER-encoded signature to raw format (r and s concatenated)
der_to_raw_ecdsa_format = lambda der: der[4:36] + der[-32:]
# Convert the signature to raw format (64 bytes)
signature_64 = der_to_raw_ecdsa_format(signature)
# Base64 URL-encode the signature
signature_base64 = base64.urlsafe_b64encode(signature_64).decode().rstrip("=")
# Concatenate header, payload, and signature to form the JWT
jwt_token = f"{header_base64}.{payload_base64}.{signature_base64}"
return jwt_token
def get_apple_public_keys():
try:
# Generate a fresh JWT
developer_token = generate_apple_developer_token()
# Set up headers with the authorization token
headers = {
"Authorization": f"Bearer {developer_token}"
}
# Fetch the public keys from Apple
response = requests.get('https://api.storekit.itunes.apple.com/in-app-purchase/publicKeys', headers=headers)
# Log the response if it's not successful
if response.status_code != 200:
print(f"Error fetching public keys: {response.status_code} {response.text}")
response.raise_for_status() # Raises an exception for 4xx/5xx errors
# Parse and return the public keys
response_data = response.json()
keys = response_data.get('keys')
if not keys:
print("No 'keys' found in the response from Apple.")
return []
return keys
except requests.exceptions.RequestException as e:
print(f"Error fetching Apple's public keys: {e}")
return []
Hello,
I'm trying to use critical alerts on the CarPlay, but I'm facing couple of issues:
Sound of critical alerts is not played by the CarPlay's speakers (played by the iPhone's speakers)
Tapping on a critical alert doesn't open the app like other notifications.
Critical alerts of the app are always shown if the CarPlay is connected, even if the app doesn't have the CarPlay entitlement.
didReceive is not called if the user taps on a notification on the CarPlay.
Any help would be greatly appreciated
I would like to do exactly this but the API doens't seem to allow it. Was wondering if there were any creative workarounds? Basically, I have a reminder app that needs to send reminders at a certain time each day (there are several of these reminders per day). Each reminder has a couple of follow-ups scheduled at 5 min intervals.
If a user takes action on the task before the reminder is sent however, I would like to unschedule that notification (and follow ups) until the next day. The unscheduling part is easy, but there seems to be no reliable way to re-schedule it for the next day and continue repeating.
Looked into background tasks and they don't seem intended for these purposes nor do they seem reliable. The user isn't guaranteed to take action on notifications nor open the app within a 24-hour period after they have taken action on their task.
When I request channel list for bundle id "com.apnspush.LiveActivityPushDemo", the request returns "TopicMismatch".
Then when I request channel list for bundle id "com.apnspush.liveactivitypush", the request return is normal.
I have tried all my bundle ids that include capital letters, they all failed with "TopicMismatch".
Does anyone know the reason?
curl -v -X GET \
-H "authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg" \
-H "apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127" \
--http2 \
https://api-manage-broadcast.sandbox.push.apple.com:2195/1/apps/com.apnspush.LiveActivityPushDemo/all-channels
Note: Unnecessary use of -X or --request, GET is already inferred.
* Host api-manage-broadcast.sandbox.push.apple.com:2195 was resolved.
* IPv6: (none)
* IPv4: 17.138.176.4
* Trying 17.138.176.4:2195...
* Connected to api-manage-broadcast.sandbox.push.apple.com (17.138.176.4) port 2195
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Request CERT (13):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Certificate (11):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
* subject: C=US; ST=California; O=Apple Inc.; CN=api-manage-broadcast.sandbox.push.apple.com
* start date: May 30 17:31:41 2024 GMT
* expire date: Apr 10 00:00:00 2025 GMT
* subjectAltName: host "api-manage-broadcast.sandbox.push.apple.com" matched cert's "api-manage-broadcast.sandbox.push.apple.com"
* issuer: CN=Apple Public Server RSA CA 12 - G1; O=Apple Inc.; ST=California; C=US
* SSL certificate verify ok.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://api-manage-broadcast.sandbox.push.apple.com:2195/1/apps/com.apnspush.LiveActivityPushDemo/all-channels
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: api-manage-broadcast.sandbox.push.apple.com:2195]
* [HTTP/2] [1] [:path: /1/apps/com.apnspush.LiveActivityPushDemo/all-channels]
* [HTTP/2] [1] [user-agent: curl/8.7.1]
* [HTTP/2] [1] [accept: */*]
* [HTTP/2] [1] [authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg]
* [HTTP/2] [1] [apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127]
> GET /1/apps/com.apnspush.LiveActivityPushDemo/all-channels HTTP/2
> Host: api-manage-broadcast.sandbox.push.apple.com:2195
> User-Agent: curl/8.7.1
> Accept: */*
> authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg
> apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127
>
* Request completely sent off
< HTTP/2 403
< apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127
<
* Connection #0 to host api-manage-broadcast.sandbox.push.apple.com left intact
{"reason":"TopicMismatch"}%
curl -v -X GET \
-H "authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg" \
-H "apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127" \
--http2 \
https://api-manage-broadcast.sandbox.push.apple.com:2195/1/apps/com.apnspush.liveactivitypush/all-channels
Note: Unnecessary use of -X or --request, GET is already inferred.
* Host api-manage-broadcast.sandbox.push.apple.com:2195 was resolved.
* IPv6: (none)
* IPv4: 17.138.176.4
* Trying 17.138.176.4:2195...
* Connected to api-manage-broadcast.sandbox.push.apple.com (17.138.176.4) port 2195
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Request CERT (13):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Certificate (11):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
* subject: C=US; ST=California; O=Apple Inc.; CN=api-manage-broadcast.sandbox.push.apple.com
* start date: May 30 17:31:41 2024 GMT
* expire date: Apr 10 00:00:00 2025 GMT
* subjectAltName: host "api-manage-broadcast.sandbox.push.apple.com" matched cert's "api-manage-broadcast.sandbox.push.apple.com"
* issuer: CN=Apple Public Server RSA CA 12 - G1; O=Apple Inc.; ST=California; C=US
* SSL certificate verify ok.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://api-manage-broadcast.sandbox.push.apple.com:2195/1/apps/com.apnspush.liveactivitypush/all-channels
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: api-manage-broadcast.sandbox.push.apple.com:2195]
* [HTTP/2] [1] [:path: /1/apps/com.apnspush.liveactivitypush/all-channels]
* [HTTP/2] [1] [user-agent: curl/8.7.1]
* [HTTP/2] [1] [accept: */*]
* [HTTP/2] [1] [authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg]
* [HTTP/2] [1] [apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127]
> GET /1/apps/com.apnspush.liveactivitypush/all-channels HTTP/2
> Host: api-manage-broadcast.sandbox.push.apple.com:2195
> User-Agent: curl/8.7.1
> Accept: */*
> authorization: bearer eyJhbGciOiJFUzI1NiIsImtpZCI6IkdZSDM5WEZMREEifQ.eyJpYXQiOjE3Mjg3MDM4MDksImlzcyI6IjNXSkdFRjI4R1kifQ.wruX6J4qaovq2X-ZlO7g0YyMWjt50g8YoMoZ4G9ZsLDI5wC8u7PFTaG05BmDvbEzLpzrK9ifwPeo5BJ2eZ3hTg
> apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127
>
* Request completely sent off
< HTTP/2 200
< apns-request-id: 2288cf3f-70d8-46a6-97d7-dd5d00867127
<
* Connection #0 to host api-manage-broadcast.sandbox.push.apple.com left intact
{"channels":["vtVPwIhLEe8AAG79CdMNuQ=="]}%
From last 10 days, apns suddenly stopped working. We have raised the firewall request from our servers to apple servers. Even then it's not working. Could you please advise if there is anything changed in this api. Please take it as high priority. Thank you.
My app uses custom notifications with custom images. Why do these images get mixed up with those from other apps, causing my notifications to display images from other apps?
`INImage *avatarImage = [INImage imageWithImageData:imageData];
NSPersonNameComponents *nameComponents = [[NSPersonNameComponents alloc] init];
nameComponents.nickname = content.title;
INPersonHandle *handle = [[INPersonHandle alloc] initWithValue:nil type:INPersonHandleTypeUnknown];
INPerson *messageSender = [[INPerson alloc] initWithPersonHandle:handle
nameComponents:nameComponents
displayName:content.title
image:avatarImage
contactIdentifier:nil
customIdentifier:customIdentifier
isMe:NO
suggestionType:(INPersonSuggestionTypeNone)];
INSpeakableString *speakableString = [[INSpeakableString alloc] initWithSpokenPhrase:content.subtitle.length ? content.subtitle : @""];
INSendMessageIntent *intent = [[INSendMessageIntent alloc] initWithRecipients:@[messageSender]
outgoingMessageType:(INOutgoingMessageTypeOutgoingMessageText)
content:content.body
speakableGroupName:speakableString
conversationIdentifier:identifier
serviceName:nil
sender:messageSender
attachments:nil];
[intent setImage:avatarImage forParameterNamed:@"speakableGroupName"];
INInteraction *interaction = [[INInteraction alloc]initWithIntent:intent response:nil];
interaction.direction = INInteractionDirectionIncoming;
[interaction donateInteractionWithCompletion:nil];
UNNotificationContent *_content = [content contentByUpdatingWithProvider:intent error:nil];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier
content:_content
trigger:trigger];
[UNUserNotificationCenter.currentNotificationCenter addNotificationRequest:request withCompletionHandler:completionHandler];`
I am looking for advice for debugging a wallet pass not updating for some customers after successfully posting an APNS notification (pass identifier as topic, no expiration, priority 10).
Is there an exhaustive list of reasons for a wallet pass not updating or a guide for making sure updates happen reliably? Are there are any guarantees made as to when the pass is updated? We noticed it is either never updating or the update happens much later for some customers. Usually toggling "Automatic Updates" in Pass Details updates the pass immediately for affected customers.
Can it be caused by an error in the implementation of the Wallet Passes Web Service? We generate passes on the fly as a response to /v1/passes/{passTypeIdentifier}/{serialNumber}. I noticed that we also sometimes receive HEAD requests to this endpoint despite the documentation only mentioning the GET method. I was previously returning a HTTP status code 405 (Method Not Allowed). I have now updated it to also respond with headers (Content-Type, Content-Disposition and Last-Modified) for the pass for HEAD requests, but I don't know if it makes a difference.
Here is a list of issues on the customer side I was thinking of:
No connection to the internet
Low power mode (does it prevent or throttle updates?)
What happens if there is an error? Does it keep trying or does it just fail silently? In the latter case it might make sense to keep sending APNS notifications until the pass is requested successfully.
I know that you can use the PassKit framework in iOS apps to update (replace) passes. Would this be more reliable than a stand-alone Wallet pass?