Post

Replies

Boosts

Views

Activity

Reply to My Notifications Message Extension doesn't seem to run after distributing my app via Enterprise IPA
Since it works on one of my devices (with developer mode enabled) but not the other (with just trusting the app), are you able to give me any things to try to help narrow those things down? It's very difficult to troubleshoot on the device that it's not working on when you can't see where it's failing , at any of those stages you mention above?
1w
Reply to My Notifications Message Extension doesn't seem to run after distributing my app via Enterprise IPA
Here is the code of my message extension, if that helps. I am indeed trying to write to the shared storage of the App Groups import os.log // Apple's modern, fast, privacy-safe logging system class NotificationService: UNNotificationServiceExtension { private let log = OSLog( subsystem: Bundle.main.bundleIdentifier!, category: "pushnotificationsmessageextension" ) var contentHandler: ((UNNotificationContent) -> Void)! // A mutable copy of the notification content — this is what we'll modify or save var bestAttemptContent: UNMutableNotificationContent? // Main entry point — called every time a push arrives with `mutable-content: 1` override func didReceive( _ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void ) { // Save the handler so we can call it later (required!) self.contentHandler = contentHandler // Make a mutable copy so we can modify title, body, attachments, etc. bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent // If something went wrong making the mutable copy, just pass through the original guard let bestAttemptContent = bestAttemptContent else { contentHandler(request.content) return } // 1. Create a mutable dictionary to work with var mutablePayload = request.content.userInfo // extract Title and Body from the 'aps' dictionary let aps = mutablePayload["aps"] as? [String: Any] let alert = aps?["alert"] as? [String: Any] let title = alert?["title"] as? String ?? "No Title" let body = alert?["body"] as? String ?? "No Body" // 2. Add the current timestamp as an ISO 8601 string let now = Date() let formatter = ISO8601DateFormatter() // Set the timezone to America/Toronto (covers both Toronto and New York Eastern Time) if let easternTimeZone = TimeZone(identifier: "America/Toronto") { formatter.timeZone = easternTimeZone } else { // Fallback: If the specified timezone isn't found, use UTC (Good for reliability) formatter.timeZone = TimeZone(secondsFromGMT: 0) print( "WARNING: 'America/Toronto' TimeZone not found, falling back to UTC for timestamp." ) } // Set the format to include the time and timezone offset (e.g., 2025-12-08T11:34:21-05:00) formatter.formatOptions = [ .withInternetDateTime, .withFractionalSeconds, .withTimeZone, ] let timestampString = formatter.string(from: now) let uuid = UUID() let minimalPayload: [String: Any] = [ "unread": true, "timestamp": timestampString, "title": title, "body": body, "uuid": uuid.uuidString ] // 3. Serialize the MODIFIED dictionary into a JSON string let jsonData = try? JSONSerialization.data( withJSONObject: minimalPayload, options: [] ) let newJsonString = jsonData.flatMap { String(data: $0, encoding: .utf8) } // Access shared container (App Groups) between main app and extension guard let shared = UserDefaults( suiteName: "group.com.mycompany.pushnotifications" ) else { print( "FATAL ERROR: Could not initialize shared UserDefaults (App Group may be missing or incorrect)." ) return } if let stringToSave = newJsonString { // 4. Read the existing HISTORY string (not array) // If the key doesn't exist, it defaults to an empty JSON array string "[]" let existingHistoryString = shared.string(forKey: "push_notification_history_json") ?? "[]" // 5. Convert the existing JSON string back into a Swift array of strings var notificationHistory: [String] = [] if let data = existingHistoryString.data(using: .utf8), let array = try? JSONSerialization.jsonObject( with: data, options: [] ) as? [String] { notificationHistory = array } // 6. Add the new, timestamped JSON string to the list notificationHistory.append(stringToSave) // Optional: Limit the size of the history to prevent the storage file from growing infinitely. // E.g., keep only the last 100 notifications. let maxHistoryCount = 100 if notificationHistory.count > maxHistoryCount { // Keeps the latest 'maxHistoryCount' items notificationHistory.removeFirst(notificationHistory.count - maxHistoryCount) } // 7. Serialize the ENTIRE array of JSON strings back into ONE single JSON string if let dataToWrite = try? JSONSerialization.data( withJSONObject: notificationHistory, options: [] ), let finalHistoryString = String( data: dataToWrite, encoding: .utf8 ) { // 8. Save the final JSON string under a new key (renamed for clarity) shared.set( finalHistoryString, forKey: "push_notification_history_json" ) shared.synchronize() print( "Successfully saved entire history as one JSON string. Current count: \(notificationHistory.count)" ) } else { print( "FATAL ERROR: Could not re-serialize history array for saving." ) } } else { print( "WARNING: Could not serialize payload. Nothing was saved to history." ) } // FINALLY: tell iOS to show the notification (with our modifications if any) contentHandler(bestAttemptContent) } // Called by iOS when it's about to kill the extension due to timeout (~30 seconds) // If we haven't called contentHandler yet, we do it now with whatever we have // Prevents notification from being dropped entirely override func serviceExtensionTimeWillExpire() { // iOS is about to kill the extension – deliver what we have if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } }
1w
Reply to My Notifications Message Extension doesn't seem to run after distributing my app via Enterprise IPA
Plugging a non-developer phone into my Mac, with the app installed, I opened the Console.app and watched the logs as it received a push notification. I could see messages like this error 07:39:39.072279-0500 SpringBoard [com.mycompany.pushnotifications] No service extension record found for app error 07:39:39.072396-0500 SpringBoard [com.mycompany.pushnotifications] No valid extension available for bundle error 07:39:39.072530-0500 SpringBoard [com.mycompany.pushnotifications] Error was encountered trying to find service extension: error=Error Domain=UNErrorDomain Code=1904 "Unknown application" UserInfo={NSLocalizedDescription=Unknown application}
1w
Reply to My Notifications Message Extension doesn't seem to run after distributing my app via Enterprise IPA
I have verified that in Xcode, my main target "Runner" has a bundle identifier of com.mycompany.pushnotifications and my extension target has a bundle identifier of com.mycompany.pushnotifications.pushnotificationsmessageextension I unzipped my .IPA file and see Payload/Runner.app/pushnotificationsmessageextension.appex In my uncompiled app, I looked in the pushnotificationsmessageextension/Info.plist file and see the following <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>NSExtension</key> <dict> <key>NSExtensionPointIdentifier</key> <string>com.apple.usernotifications.service</string> <key>NSExtensionPrincipalClass</key> <string>$(PRODUCT_MODULE_NAME).NotificationService</string> </dict> </dict> </plist>
1w