Can't stop iOS scheduleLocalNotification - swift

I'm not sure if it is technical issues. I tried to implement a scheduled local notification by calling this:
// Schedule the notification ********************************************
if UIApplication.sharedApplication().scheduledLocalNotifications.count == 0 {
let notification = UILocalNotification()
notification.alertBody = "This is local push notification"
notification.soundName = UILocalNotificationDefaultSoundName
notification.fireDate = NSDate()
notification.category = categoryID
notification.repeatInterval = NSCalendarUnit.Minute
UIApplication.sharedApplication().scheduleLocalNotification(notification)
}
from
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
}
It works fine. However, when I revert the code to the origin version without any line of codes related to the scheduleLocalNotification() the local notification still running.
I can't stop it even I clean the project/remove the application from devices before a rebuild.
Please help if possible, thank you!

You have created a repeating local notification and handed it to the system. At that point it is out of your hands. You have told the system to repeat this notification, and it will do so, forever.
Your only choice at this point is to delete your app.
What you have done is a classic mistake — one, unfortunately, that many apps do in fact make. And I have had to delete those apps from my device as well, as there is no other way to stop the repeating notification.
The right thing to do would have been to build into your app a cancelation of that local notification, i.e. you stop the notification in code. For example, you tell the UIApplication shared instance to cancelAllLocalNotifications. But you failed to do that.

Related

backgroundTask not receiving BGTaskScheduler in Swift / SwiftUI

I want to execute something in the background the check data every one hour.
For this, I am following the Apple Documentation video.
Here is the App Delegate code
import SwiftUI
import UserNotifications
import BackgroundTasks
#main
struct notificationtestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onAppear(perform: {
AppCheckData()
})
}.backgroundTask(.appRefresh("notifyuser")) {
print("In Background Task")
//Check data
}
}
}
func AppCheckData() {
var startDate = Date()
let calendar = Calendar.autoupdatingCurrent
var checkTime = calendar.date(byAdding: .minute, value: 2, to: startDate)!
print(checkTime)
let notifyrequest = BGAppRefreshTaskRequest(identifier: "notifyuser")
notifyrequest.earliestBeginDate = checkTime
try? BGTaskScheduler.shared.submit(notifyrequest)
print("Done Scheduling")
}
For testing purposes, I changed addition of time to 2 minutes.
According to this code, it should print out the date after adding 2 minutes to the current date, then print out a confirmation that the BGTaskScheduler had been submitted. From there, after 2 minutes, it should print out the "In background task" in the console.
However, my app is not receiving the scheduled background task. I am not sure what I am missing here, is it the limits that Apple creates, or something else.
Please help
A BGAppRefreshTaskRequest is a request, and it is scheduled with earliestBeginDate. You are not requesting a specific time to run. You are indicating the earliest time it makes sense to run so that the OS doesn't call this unnecessarily.
As the docs note (emphasis mine):
The system decides the best time to launch your background task, and provides your app up to 30 seconds of background runtime.
In order to test your background operations, see Starting and Terminating Tasks During Development. IMO it is quite awkward, but it does work.
I want to execute something in the background the check data every one hour.
You will need to send a push notification in that case. This is not possible with BGTaskScheduler. As a rule, however, you should avoid this kind of polling and rather send the push notification only when there is new information. The point of BGAppRefreshTask is to periodically update your app's information at some point soon before the user is anticipated to need it so the user doesn't have to wait. It is not to facilitate polling.
There is no mechanism in iOS to allow you to do something at specific time intervals, without the user's intervention, except silent push notifications (and there are limits on those). This is by design. If you do not have a system for sending push notifications, then this is impossible, and you will need to redesign to not require it.

Swift: Cocoa, local notification not showing in mac OS Catalina

Hello notifications are not displayed on Mac OS Catalina, here is my code:
func showNotification() {
let notification = NSUserNotification()
// All these values are optional
notification.title = "Test of notification"
notification.subtitle = "Subtitle of notifications"
notification.informativeText = "Main informative text"
notification.soundName = NSUserNotificationDefaultSoundName
NSUserNotificationCenter.default.deliver(notification)
}
I noticed that in my mac application now when I open the application a notification request appears. Maybe I have to implement that? But I can not find any documentation on it. How to view local notification...
Even with UserNotification it does not work
The NSUserNotification has been deprecated past MacOS 10.14 as per https://developer.apple.com/documentation/foundation/nsusernotification
Instead you might want to have a look at the UserNotification framework as in https://developer.apple.com/documentation/usernotifications?language=objc
And in addition it is now crucial to request permission from users to authorize notifications.

Local Notification overrides previous local notification

I have a macOS Swift app where I am using local notifications. Here is a small methode for sending these:
func sendPushMessage(title: String, message: String, userInfo: [String:Any]) {
let notification: NSUserNotification = NSUserNotification()
notification.title = title
notification.informativeText = message
notification.userInfo = userInfo
notification.soundName = NSUserNotificationDefaultSoundName
notification.deliveryDate = Date()
self.center.scheduledNotifications = [notification]
}
This works for a long time and I have received all my notification (as well all notifications were shown in notification center). But actually the latest notification overrides the previous one. Let's say there is only one notification slot that always get overridenn with the latest notification.
In my notification center there is also only a single notification visible (the latest) instead of all received notifications. I have no idea when this "stops working" but I think one or two month ago? I am still on 10.13.6 high sierra.
The notification settings are correct.
I have no idea whatg I have done "wrong".
Fixed the issue by changing notification order (in notification settings) to manually by app and then it worked. After that I could change it back to newest and still working. Was only a bug in macOS for sure.
As refer documentation, you should set different identifier for each notification.
The identifier is unique to a notification. A notification delivered
with the same identifier as an existing notification replaces the
existing notification rather than causing the display of a new
notification.
You can set like that
notification.identifier = "yourIdentifier"

Using NSLocalNotification for multiple reminders

I am creating a reminder based app and my only problem right now is being able to implement reminders on my app.
Basically the user is presented with a UITableView where the user can add events and I'd like to fire these dates with a notification to the user reminding them of the event on a date saved to Core Data.
At this time, I still do not understand how NSLocalNotification works an I have heard some users here say how apple only allows 64 notifications to be processed at a time and I only managed to create 1 but when creating another event, It is down to 0 and randomly goes back to 1 event when I debug my app with the
UIApplication.sharedApplication().scheduledLocalNotifications?
and I can see the notification I set but not the other ones.
Any sample app in swift would greatly help me understand how I can set multiple notifications to add, edit, delete them.
Thanks in advance and happy coding
The easiest way to tackle this is to just create notifications and schedule them. If you want to remove specific notifications you will have to hold on to their references and persist them across app launches, however you can always remove all the currently scheduled notifications with UIApplication.sharedApplication().cancelAllLocalNotifications()
This is an example of scheduling a notification to fire once a day at the same time for 5 days:
let secondsInADay = 60 * 60 * 24
for i in 1...5 {
var dayString = "\(i) days"
if i == 1 {
dayString = "\(i) day"
}
let notification = UILocalNotification()
notification.fireDate = NSDate(timeInterval: Double(i * secondsInADay), sinceDate: NSDate())
notification.alertBody = "It has been \(dayString) since you last opened the app."
notification.soundName = UILocalNotificationDefaultSoundName
if notification.fireDate?.timeIntervalSinceNow > 0 {
UIApplication.sharedApplication().scheduleLocalNotification(notification)
}
}
Also, you are correct, each app is given a queue for local notifications that have yet to fire. That queue can hold 64 individual notifications (a repeating notification counts as only 1 of those 64).

Check a web page periodically in background

I need to check periodically a web page.
My idea is to set a local notification periodically, for example every 20 minutes. When notification leaves, device should load the web page, check a condition and if the condition is true, device should rang, otherwise nothing.
(NOTIFICATION) -> (LOAD WEB PAGE) -> [VERIFY CONDITION]-|if true|-> (RING)
Is this technically possible to do? How can I load a web page while app isn't running?
My sketch of code was like this:
func check () {
pageCode = // find a way to load the page
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(NSEC_PER_MSEC * 100))
dispatch_after(delayTime, dispatch_get_main_queue()){
let readCode = self.pageCode.stringByEvaluatingJavaScriptFromString("document.getElementsByTagName('body')[0].outerHTML")
if letturaCodice?.containsString("Some text") == true {
ringPhone()
}
}
}
Not possible using UILocalNotification, you could do it with a remote notification though.
Apple has a guide here: See - "Using Push Notifications to Initiate a Download"
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
A remote notification platform I've used before is called OneSignal, it's completely free and allows you to schedule notifications. https://onesignal.com
Edit:
Doesn't answer question about ringing, not sure about that bit sorry!
Option 1:
You could build the app to use background app refresh function that you could cause an alert if lets say you do not get an http status code of 200.
If you use this option you could build in the function to have a custom tone to play that you build into the app.
Option 2:
Use a server side script todo the checking and have it fire off a push notification. This method would depend on phone settings as to how the notification would function.
You can try to use Grand Central Dispatch to run a background process and inside it add notification observer.
UPD: Like this:
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
() -> Void in
// catch notifications here
}