Post

Replies

Boosts

Views

Activity

Request Notification Service Entitlement to filter remote notifications IOS
I have a sample app to test push notifications. The app has a Notification Service Extension to intercept remote notifications, update/enhance the content and then display it to user. But there are some scenarios where the app shouldn't end up displaying a notification to user... Like, due to slow internet, the time taken to download media content (like images) exceeds the 30 sec time limit. There are more app specific scenarios. Basically, every push received from APNS need not be shown to user. Notification Service Extension did not have this power to suppress remote notifications. In the end, it will always display a notification to user. From iOS 13.3 onwards, Notification Service Extension has the ability to filter out these remote notifications. The first step is (quoting form the documentation), This entitlement allows a notification service extension to receive remote notifications without displaying the notification to the user. To apply for this entitlement, see Request Notification Service Entitlement. When I click on the hyperlink (you need to be an account holder to view that page), Apple asks for some info like 'App Store URL', 'When extension runs, what system and network resources does it need?' and so on. I only have a sample app to help understand the aspects of notifications. I don't have any full-fledged app in AppStore... yet... and I have no clue what all my full-fledged app will be doing in the extension (since I'm just in learning stage). I only have a sample app, where I log and perform some basic string operations when my extension is invoked. Due to this, I'm unable to see the extension filtering out notifications. How does anyone test this feature? Has anyone tried it? Really appreciate any guidance. I'm not sure how to proceed..
0
0
1.4k
May ’23
Exclude notification delegate methods for tvOS using @available
UserNotifications framework helps the app to handle all notification related aspects. The userNotificationCenter(_:didReceive:withCompletionHandler:) delegate method is used to handle user's action (dismiss, selected button, tap, text input etc.). As evident from the documentation, this method is available in iOS and iPadOS but not tvOS. The @available attribute is one way to exclude methods. @available(iOS 10.0, *) func userNotificationCenter (_ pNotificationCenter: UNUserNotificationCenter, didReceive pResponse: UNNotificationResponse, withCompletionHandler pCompletionHandler: @escaping () -> Void) -> Void { // Handle user's action on a notification. ... } When the delegate method is declared as above, I expect it to be included only for iPadOS and iOS. When building for tvOS, I get the following error: error: 'UNNotificationResponse' is unavailable in tvOS error: cannot override 'userNotificationCenter' which has been marked unavailable Clearly, it is included for tvOS also. Another approach is using #if os(iOS) and it does work... I don't get the above errors, meaning the code is not included for tvOS. But I want to understand how to achieve this using @available attribute because I have other situations where I need to exclude methods for certain versions of the same OS. How do I exclude userNotificationCenter(_:didReceive:withCompletionHandler:) for tvOS using @available attribute?
1
0
942
May ’23
Periodic iOS background execution
An app has some periodic light background work, which is expected to run even when app is suspended. Ofc, if user has swiped up, nothing can be done. When swiped from app switcher, if app was in Suspended state, its not informed else, in every other state (including background), applicationWillTerminate(_:) is invoked When application is not killed by user and is in suspended state, I want to run some small tasks at certain intervals. According to this documentation, Background fetch is the way to go. This post by Apple DTS also suggests the same i.e., Background Fetch (BGAppRefreshTask) for periodic background execution. Example: The sample background task is to count 10s in multiple of 10s. Launch handler is registered with the background task ID configured in info.plist file in application(_:didFinishLauchingWithOptions:). I have the following code invoked from in applicationDidEnterBackground(_:), func initiateBackgroundTask(id: String) {         let currentDate: Date = Date.now         guard let futureDate: Date = Calendar.current.date(byAdding: .minute, value: 1, to: currentDate) else {             NSLog(AppDelegate.TAG + "Error in obtaining future date!")             return         }         let taskRequest: BGAppRefreshTaskRequest = BGAppRefreshTaskRequest(identifier: id)         // Schedule background task         taskRequest.earliestBeginDate = futureDate         do {             // Note: Background processing doesn't work in Simulator.             // Submitting in Simulator leads to BGTaskScheduler.Error.Code.unavailable error.             try BGTaskScheduler.shared.submit(taskRequest)             NSLog(AppDelegate.TAG + "Task submitted successfully!")         } catch {             NSLog(AppDelegate.TAG + "error = " + String(describing: error))             return         }         NSLog(AppDelegate.TAG + "Background task scheduled successfully!!")         NSLog(AppDelegate.TAG + "Scheduled date = %@ | Present date = %@", String(describing: taskRequest.earliestBeginDate), String(describing: Date.now))     } The following method is invoked from launch handler: func taskRefreshCount1Min(task: BGAppRefreshTask) {              // Set expiration handler         task.expirationHandler = {            NSLog(AppDelegate.TAG + "Background execution time about to expire!")            NSLog(AppDelegate.TAG + "Remaining time = %fsec | %@", AppDelegate.app.backgroundTimeRemaining, String(describing: Date.now))             NSLog(AppDelegate.TAG + "Unable to complete task!!")             task.setTaskCompleted(success: false)         }         for i in 1...6 {             let presentDate: Date = Date.now             NSLog(AppDelegate.TAG + "%d) %@", i, String(describing: presentDate))             Thread.sleep(forTimeInterval: 10)         }         NSLog(AppDelegate.TAG + "Task complete!")         task.setTaskCompleted(success: true)     } My expectation is that iOS will execute the launch handler 1 min after scheduling the background task. But that never happens, even after hours. Task did get executed within 20 mins (Sample output shown below), but every other time, I waited for more than an hour and task was never executed. // Output ... Task submitted successfully! Background task scheduled successfully!! Scheduled date = Optional(2023-02-06 09:19:46 +0000) | Present date = 2023-02-06 09:18:46 +0000 TaskRefreshCount1Min(task:) 1) 2023-02-06 09:35:12 +0000 2) 2023-02-06 09:35:22 +0000 3) 2023-02-06 09:35:32 +0000 The documentation does state, However, the system doesn’t guarantee launching the task at the specified date, but only that it won’t begin sooner. But I didn't expect the results to differ by such a huge margin. Apparently others have also faced this 'inconsistent scheduling' in iOS. Background fetch with BGTaskScheduler works perfectly with debug simulations but never works in practice How make iOS app running on background Every one minute in Swift? In links I have pasted above, despite Background Fetch being the most suitable for periodic light tasks, Silent Push Notifications were suggested. I'm currently checking out Silent Push Notifications, but iOS recommends a frequency of not more than 3 per hour. Summarising my questions from this exercise: Is there something wrong with the code? What technique should I use? Background fetch, silent notifications or anything else? In Background Fetch, how do you schedule background tasks periodically? There's an instance property called earliestBeginDate to denote the minimum time after which the task can happen.
2
3
2.8k
Feb ’23
Set swift macros from cmake
I have a swift project which uses macros for conditional compilation. How to set macro: Go to Target -> BuildSettings -> Swift Compiler - Custom Flags -> Active Compilation Conditions and add your macro (Ex: sample macro - ELDIABLO in this case). Then the following swift code, #if ELDIABLO NSLog("ELDIABLO macro detected!") #else NSLog("ELDIABLO macro not detected!") #endif ...produces the desired output. ELDIABLO macro detected! Now, how do I achieve this through cmake? When I do the following, set(CMAKE_Swift_FLAGS "${CMAKE_Swift_FLAGS} ELDIABLO") the macro gets added to Swift Compiler - Custom Flags -> Other Swift Flags (shown in the above image besides Active Compilation Conditions). But it must be added in Swift Compiler - Custom Flags -> Active Compilation Conditions, else (here's why), it will not get detected in swift files. How can I set swift macros in Active Compilation Conditions through cmake?
0
0
712
Sep ’22