iOS 13 local notification not sending - uilocalnotification

I have a reoccurring local notification set up every day at 8am. This has worked completely fine in every iOS except for when I updated to iOS 13+, it no longer sends my local notification. There has been no code changes on that part. I have seen people having issues with push notifications on iOS 13, but this is a local one so I have no idea why it suddenly stopped working on iOS 13. I have tried using xcode 10 & 11.
If anyone needs code posted I can get that, but I'm curious if anyone else has had this issue with local notifications and iOS 13.

I think I figured it out!
At least for me, setting the trigger with UNCalendarNotificationTrigger didn't work. However, if I used UNTimeIntervalNotificationTrigger instead, it works great!
Here's my code:
let now = Date(timeIntervalSinceNow: 0)
// If event has already occured, silently fail.
if (timelineEvent.event.time < now) {
return
}
// Otherwise, let's calculate the time until the next event
let interval = timelineEvent.event.time.timeIntervalSince(Date(timeIntervalSinceNow: 0))
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: false)
If you're strictly targeting iOS 13 and newer, the date comparison can be simplified slightly:
let now = Date(timeIntervalSinceNow: 0)
// If event has already occured, silently fail.
if (timelineEvent.event.time < now) {
return
}
// Otherwise, let's calculate the time until the next event
let interval = now.distance(to: timelineEvent.event.time)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: false)
Strangely, Date().distance(to: Date) appears to be iOS 13+ only, however the documentation says it's available since iOS 7.0.

Related

iOS Xamarin scheduled timer not firing

We have a scheduler logic in an Xamarin (not Forms) project, which existed for quite some time and once worked. With one of the iOS upgrades (could be quite some time ago), the scheduler stopped firing events.
Why is the timer below not firing every 20 seconds? The app is active, the screen is on and I validated that the initialization code runs exactly once.
var interval = TimeSpan.FromSeconds(20);
Timer = NSTimer.CreateRepeatingScheduledTimer(interval, HandleScheduledEventMethod);
// ...
public void HandleScheduledEventMethod(NSTimer timer)
{
// never executed, except for each call to Timer.Fire()
}
I added it to the NSRunLoop as advised in the Apple docs, but that did not help either.
NSRunLoop.Main.AddTimer(Timer, NSRunLoopMode.Common);
AddTimer must be called on the main thread, it does not work when called on a background thread.
DispatchQueue.MainQueue.DispatchQueue(() => {
Timer = NSTimer.CreateRepeatingScheduledTimer(interval, HandleScheduledEventMethod);
NSRunLoop.Main.AddTimer(Timer, NSRunLoopMode.Common);
})

Geolocation.GetLastKnownLocationAsync() sometimes returns null

This is on iOS 12.1.4 on an iPhone 6s. Usually Geolocation.GetLastKnownLocationAsync() works but sometimes it doesn't. It's the exact same code but if I sit here and press my "get latitude and longitude" button over and over eventually Geolocation.GetLastKnownLocationAsync() spits out a null.
Do you know why this happens and how I might handle it? Perhaps put it in a loop that tries ten times, waiting a second between each try?
var location = await Essentials.Geolocation.GetLastKnownLocationAsync(); // works most of the time but sometimes it doesn't work.
This is my proposed work around:
Essentials.Location location = null;
for(var i = 0; i < 10; i++)
{
location = await Essentials.Geolocation.GetLastKnownLocationAsync();
if(location == null)
{
Thread.Sleep(1000);
}
else
{
break;
}
}
First, it is really bad practice to use Thread.Sleep (unless you are not on the main/UI loop) as you are hanging the run loop, if you really need a delay, use await Task.Delay(.... Also CLLocationManager on iOS is running on the main loop and if you are blocking it, the message pump is hung and the location manager manager can not report back to the app.
"Spamming" CLLocationManager.Location (which Essentials is using on iOS) can (and will) result in null returns due to OS rate limiting updates (mainly a battery conservation measure) and if the OS is powering up the GPS radio to update its location, this method will timeout on from the OS, thus report nil back to GetLastKnownLocationAsync and thus you get a return of null.
CLLocationManager.Location on iOS is meant for a quick low-power return from the OS to app as is updated upon app launch, device reboot, etc... not every time you call it.
You can get the last known location of the device by calling the GetLastKnownLocationAsync method. This is often faster then doing a full query, but can be less accurate.
Otherwise you should be using GetLocationAsync in order to do a full GPS power up to obtain an updated accurate location.
To query the current device's location coordinates, the GetLocationAsync can be used. It is best to pass in a full GeolocationRequest and CancellationToken since it may take some time to get the device's location.
Typically I recommend using GetLastKnownLocationAsync as a quick way to get the general area of the user knowing that this might also return null. Then proceed to do a GetLocationAsync (passing both a GeolocationRequest and CancellationToken instance) in the background and update the app accordingly upon the more accurate and recent position.
re: https://learn.microsoft.com/en-us/xamarin/essentials/geolocation?tabs=ios

Arduino crashes only if I set the time

I'm VERY puzzled and was hoping that someone here could provide some sanity.
I have a fairly elaborate Arduino sketch that is responding to scheduled events
at the time designated in the event. In order to do this I have setup a loop that examines a queue of events and checks the event time to see if it matches the current time. I also have code in the loop that checks the current temp and sends a serial message with a timestamp.
I noticed that it is no longer running for more than 10 - 15 minutes before it crashes (goes silent). I assumed it was some of my code, so I started commenting out pieces until it started working again... I was astounded to find that it only started working (ran for 14+ hours) after I removed the call to setTime()!
I can't understand how a call to the setTime() library function would cause a crash 10 minutes later. I assumed that this was a very stable library...
Any ideas would be welcome!
if(timeStatus() != timeSet) {
if (processSyncMessage()) {;
Serial.println(F("Time sync completed.\n"));
}
else { // Time sync failed for some reason, resend request.
Serial.println(F("Waiting for sync message\n"));
}
}
else { // time is set.
...
I have 'simplified' the following routine to remove the serial message receipt and parsing to further isolate the problem...
int processSyncMessage() {
// if time sync available from serial port, update time and return true
Serial.println(F("Processing time sync message"));
time_t pctime = 1371118147;
setTime(pctime); // Sync Arduino clock to the time received on the serial port
return true;
}

Firefox 5, Geolocating and "Not Now" Issue

Has anyone out there had to deal with and managed to find a viable workaround for the Firefox 5 geolocation issue I posted in the following bug report. It's easier to link to the report than re-describe it here.
https://bugzilla.mozilla.org/show_bug.cgi?id=675533
Surely I'm not the only one on the planet this has bitten.
This doesn't really solve the root of your problem but my strategy for handling this is setting a default location point that I use right away (not waiting for the geolocation question to be answered).
If I get a location from the user, I just change it to the new location. If I get a rejection or no answer at all, I just stay on the default location.
It's also my experience that a desktop client (in my case Firefox on a stationary Windows computer) takes much longer to respond than a mobile client (in my case Safari on iPhone). I was forced to set the timeout to 10 seconds (10000) to give the desktop client enough time to respond. So if you have a map, initializing it and centering on a default location directly will give the user a map on the screen much faster than if you have to wait for a response.
Good luck with your positioning project!
I might be a bit late but hope I can help others.
My workaround is based on a delayed call. If there is no fix when the delayed call is fires, I become suspicious :)
var timeIsPassig = false;
function anyThing(){
timeIsPassig = true;
setTimeout(
function(){
if (timeIsPassig) {
timeIsPassig = false;
console.log("Waiting too much... Or did you say not now? :-P");
}
},
10000
);
navigator.geolocation.getCurrentPosition(
function (pos) {timeIsPassig = false; /* rest of positioning*/},
function (err) {timeIsPassig = false; /* rest of error handling*/},
{maximumAge: 30000, timeout: 10000, enableHighAccuracy: true}
)
}

How can I get notified of a system time change in my Cocoa application?

I have a Cocoa application that records datestamps on events. I need to know when the system time is reset and by how much, but I can't seem to fine a notification anywhere that tells me such a thing has happened. This change could happen because NTP reset the clock or because the user reset (e.g. from System Preferences). It would be great if there was just a NSNotification I could register to receive, but I'm open to any suggestions.
Apple added in NSSystemClockDidChangeNotification, part of NSDate, in Snow Leopard (10.6). There doesn't appear to be a way to do it in Leopard (10.5) or earlier. Per the Apple NSDate docs:
Posted whenever the system clock is changed. This can be initiated by a call to settimeofday() or the user changing values in the Date and Time Preference panel. The notification object is null. This notification does not contain a userInfo dictionary.
This doesn't appear to tell you "how much" time has changed. You could possibly calculate that by periodically (say, every 5 seconds in a NSTimer) capturing the system time with [NSDate date], saving it into a variable, and then after NSSystemClockDidChangeNotification fires, grab the new date and compare the two together using NSDate's timeIntervalSinceDate: method to get the difference.
Not millisecond or even second accurate, but pretty close.
EDIT: See this post. You could possibly use the UpTime() C command to grab the system uptime in CPU tics (which you can later convert to seconds). You could use this to figure out by how much time has changed (assuming no system restart or sleep). This works even if the system clock is changed by the user or network time protocol.
If some on is looking for solution know system date change change event from 10.4
OSStatus DateChangeEventHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData)
{
NSLog(#"Event received!\n");
return 0;
}
- (void)SystemTimeChangeHandler
{
EventTypeSpec eventType;
eventType.eventClass = kEventClassSystem;
eventType.eventKind = kEventSystemTimeDateChanged;
EventHandlerUPP eventHandlerUPP =
NewEventHandlerUPP(DateChangeEventHandler);
EventHandlerRef eventHandlerRef = NULL;
(void)InstallApplicationEventHandler(
eventHandlerUPP,
1,
&eventType,
self,
&eventHandlerRef);
}
Time moves constantly. A notification every time the current time changed would be a constant, CPU-soaking stream of notifications.
What you need to do is get the current time in your event handler—the one that receives the events you're datestamping. You get the current time by calling [NSDate date].
I don't think there's a single way to do that because of the different mechanisms by which the time could change. But it wouldn't be very expensive (too expensive? Don't know, have you profiled it yet? ;-) to set an NSTimer once a second to check the time and compare it with the previous value. If it's not advanced by about a second, something interesting happened and you can notify your audit object.

Resources