I have a problem below:
When minimize app to background by press home button, create a local notification for pop-up every 5 minutes.
Remove app from background.
-->My expected then pup-up just only show when app exist and it's discarded when remove app from background.
My issue that local notification still active and it still showing pop-up every 5 minutes after remove it from background.
How can i stop it?
Please help me!
Thanks in advanced.
Put this in application delegate. It will remove all local notifications when the application enters background.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
If you don't want to cancel all notifications... I've set up a unique identifier stored in the notification's userInfo dictionary. When I want to delete I fast enumerate through all notifications and pick out the correct one for deletion.
My stumbling blocks here were remembering to store the UUID I'd created for the notification and also remembering to use isEqualToString in the fast enumeration. I guess I could also have used a specific name string instead of a unique identifier. If anyone can let me know a better method than fast enumerating please let me know.
#interface myApp () {
NSString *storedUUIDString;
}
- (void)viewDidLoad {
// create a unique identifier - place this anywhere but don't forget it! You need it to identify the local notification later
storedUUIDString = [self createUUID]; // see method lower down
}
// Create the local notification
- (void)createLocalNotification {
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil) return;
localNotif.fireDate = [self.timerPrototype fireDate];
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertBody = #"Hello world";
localNotif.alertAction = #"View"; // Set the action button
localNotif.soundName = UILocalNotificationDefaultSoundName;
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:storedUUIDString forKey:#"UUID"];
localNotif.userInfo = infoDict;
// Schedule the notification and start the timer
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}
// Delete the specific local notification
- (void) deleteLocalNotification {
// Fast enumerate to pick out the local notification with the correct UUID
for (UILocalNotification *localNotification in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
if ([[localNotification.userInfo valueForKey:#"UUID"] isEqualToString: storedUUIDString]) {
[[UIApplication sharedApplication] cancelLocalNotification:localNotification] ; // delete the notification from the system
}
}
}
// Create a unique identifier to allow the local notification to be identified
- (NSString *)createUUID {
CFUUIDRef theUUID = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
return (__bridge NSString *)string;
}
Most of the above has probably been lifted from StackOverflow at sometime in the last 6months. Hope this helps
Related
iOS 14 introduced GCKeyboard. I was able to successfully connect a BlueTooth NumberPad in my app but I need to be able to connect two of them in tandem. Could anyone please point me to sample code?
In the GCController class there is a "controllers" method which returns an array of all connected controllers, but there isn't anything similar for GCKeyboard.
Here is my code:
- (void)viewDidLoad {
[super viewDidLoad];
[[UIApplication sharedApplication]setIdleTimerDisabled:YES];
// notifications for keyboard (dis)connect
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(keyboardWasConnected:) name:GCKeyboardDidConnectNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(keyboardWasDisconnected:) name:GCKeyboardDidDisconnectNotification object:nil];
}
GCKeyboard *leftKeyboard;
GCKeyboard *rightKeyboard;
- (void)keyboardWasConnected:(NSNotification *)notification {
if (!self.leftKeyboard) {
leftKeyboard = (GCKeyboard *)notification.object;
NSLog(#"Left Keyboard connected: %#\n", leftKeyboard.description);
NSString *keyboardStatus = [NSString stringWithFormat:#"Left Keyboard CONNECTED:\n%#", leftKeyboard.description];
self.statusLabel.text = keyboardStatus;
self.leftKeyboard = leftKeyboard;
[self reactToKeyboardInput];
}
else if (!self.rightKeyboard) {
NSLog(#"Right Keyboard connected: %#\n", rightKeyboard.description);
rightKeyboard = (GCKeyboard *)notification.object;
NSString *keyboardStatus = [NSString stringWithFormat:#"Right Keyboard CONNECTED:\n%#", rightKeyboard.description];
self.statusLabel.text = keyboardStatus;
self.rightKeyboard = rightKeyboard;
[self reactToKeyboardInput];
}
}
- (void)keyboardWasDisconnected:(NSNotification *)notification {
if (self.leftKeyboard) {
GCKeyboard *keyboard = (GCKeyboard *)notification.object;
NSString *status = [NSString stringWithFormat:#"Left Keyboard DISCONNECTED:\n%#", keyboard.description];
self.statusLabel.text = status;
self.leftKeyboard = nil;
}
else if (self.rightKeyboard) {
GCKeyboard *keyboard = (GCKeyboard *)notification.object;
NSString *status = [NSString stringWithFormat:#"Right Keyboard DISCONNECTED:\n%#", keyboard.description];
self.statusLabel.text = status;
self.rightKeyboard = nil;
}
}
When a keyboard or number pad is connected I get the message:
2020-09-18 13:09:15.845943-0700 Controller[1653:351628] Left Keyboard connected: GCController 0x280bb8dd0 ('Keyboard' - 0x27c3dc28cec4d818)
"Bring keyboard and mouse gaming to iPad" WWDC video transcript states:
In the case of keyboards, you can't differentiate multiple keyboards, and all keyboard events from multiple keyboards are instead coalesced for you. So while you might use notifications to notice when a keyboard disconnects and perhaps pause the game to prompt for different input, in general, you'll find that just using GCKeyboard-Device.coalesced to check on the key state when non-nil is the right path.
So while you may have multiple keyboards connected, it sounds like they all get coalesced into a single GCKeyboard instance and you can't differentiate between them. That is why there's no +[GCKeyboard keyboards] method. Instead there is +[GCKeyboard coalescedKeyboard]
While using NSURLSession to download files and display them in UICollectionView I found a problem where cells do not update correctly from NSOperationQueue block. Download part and file store works correctly every time. But update cell progress or images works only on initial load of controller. If I navigate to root and then again to my Collection controller download works but cells no longer update. I found this interesting discussion but it did not help in my case.
More details, the controller that starts URL session and handles tasks gets loaded from storyboard segue. I noticed app is creating new controller instance every time. On 2nd navigation visit cells do not show progress or update but task/files are download correctly. It seem that my download tasks are getting copy of cells from some other controller instance. But it does not make sense from what I see in debugger, delegates are working correctly, task completes with success.
Here is code method that fail to update cells on 2nd visit to controller:
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
if (totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown) {
NSLog(#"Unknown transfer size");
}
else{
// Locate the FileDownloadInfo object in array based on my unique key in URL.
int index = [self getFileDownloadInfoIndexWithTaskURL:downloadTask.originalRequest.URL.lastPathComponent];
// Get singleton download object list from app delegate
NSMutableArray *globalFileDownloadData = [self getGlobalDownloadFileList];
FileDownloadInfo *fdi = [globalFileDownloadData objectAtIndex:index];
// Get the progress view of the appropriate cell and update its progress.
NSArray *arr = [self.fileDispCollection visibleCells];
for(FileItemCell* cell in arr){
if ([fdi.contentId isEqualToString:cell.testLbl.text]){
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// This code works when app start initial visit to controller
// but does not work on2nd 3rd or other revisit
// even cells found correctly, files also loaded saved
// the progress does not show and no update
cell.downloadProgress.hidden = NO;
cell.downloadProgress.progress = fdi.downloadProgress;
}];
}
}
}
}
I initialize my singleton session using this method:
- (NSURLSession *)backgroundSession {
//disptach_once ensure that multiple background sessions are not
//created in this instance of the application.
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
self.docDirectoryURL = [URLs objectAtIndex:0];
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#"com.Transport.demo"];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 3;
sessionConfiguration.discretionary = NO;
session = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:nil];
});
return session;
}
What can cause a 2nd copy of cells or simply collection cell not to respond to calls or data reload on 2nd navigation round? Hope somebody have a solution for this problem.
try to put you update UI code in the main thread like this:
dispatch_async(dispatch_get_main_queue(), ^{
//your update UI code
});
The answer turned out in my question. The storyboard segue was creating new controller that was creator and handler for URLSession download tasks. Session was singleton that kept initial controller stack and delegate. So new controller instance will start downloads but all responses will go to old controller instance.
Fix was simple not use performSegueWithIdentifier, instead create single controller instance, in this case is actually better solution.
if (!self.library){
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle: nil];
self.library = [storyboard instantiateViewControllerWithIdentifier:#"libraryScene"];
}
self.library.model = self.selectNode;
[self.navigationController pushViewController:self.library animated:YES];
NOTE: Need to know how to Set a number of alarm or notification in between two given dates regularly?
I have to create an app where,i have to enable/disable multiple UILocalnotification set in a tableview.'
If i choose a date i have to then set time on that perticular date and also need to set the notification before timePlay (5,10,15,20 min prior).
And End date: the date until when the notification plays regularly.
How to set all the notification for a perticular notification ID at once?
How to disable a perticular notification?
ALSO PLEASE TELL ME : CAN HOW CAN I SET UILOCALNOTIFICATION using database?
I have create a database having
Notification ID //unique id of notification
Notification Name //notification title
Time1 //can set five time the notification will show
Time2(optional)
Time3(optional)
Time4(optional)
Time5(optional)
Before timePlay//can show the notification before time of notification 1 to 5 above
Start Date // the date from which the notification start
End Date //the date when the notification stops.
i can set simple notification like this
// UILocalNotification properties:
// alertBody - the message displayed in the notification
// alertAction - if notification is displayed as an alert, this is the label of the action button, if not specified, "Launch" will be used
// soundName - the name of a sound file (AIFF, CAF or WAV) to be played when the notification appears, if not specified, no sound will be played. To use the default sound UILocalNotificationDefaultSoundName can be provided.
// userInfo - you can pass an NSDictionary object with additional data to be used by our app after the notification fires (optional)
// fireDate - an NSDate object specifying the date and time for the local notification to be fired (obligatory)
// timeZone - an NSTimeZone object. If specified, the fireDate is measured against the user's local time zone, if not against universal time
// repeatCalendar - the calendar (NSCalendar) the system should refer to when it reschedules a repeating notification
// repeatInterval - the calendar interval (NSCalendarUnit) at which to reschedule the notification, the default is 0, which means don't repeat
// alertLaunchImage - will be presented when your app is run or summoned from the background
// Create a new local notification
UILocalNotification *notif = [[UILocalNotification alloc] init];
notif.alertBody = #"Wake up! Its tuition time!";
notif.fireDate = [NSDate dateWithTimeIntervalSinceNow:60]; // 60 seconds
notif.soundName = UILocalNotificationDefaultSoundName;
notif.applicationIconBadgeNumber += 1;
Try scheduling which will enable the notification and use cancel which will be disable the notification:-
-(void)enableNotification
{
[self cancelAlarm]; //clear any previous alarms
UILocalNotification *alarm = [[UILocalNotification alloc] init];
alarm.alertBody = #"alert msg";
alarm.fireDate = [NSDate dateWithTimeInterval:alarmDuration sinceDate:startTime];
alarm.soundName = UILocalNotificationDefaultSoundName;
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:self.name forKey:kTimerNameKey];
alarm.userInfo = userInfo;
[[UIApplication sharedApplication] scheduleLocalNotification:alarm];
}
-(void)disableNotification{
for (UILocalNotification *notification in [[[UIApplication sharedApplication] scheduledLocalNotifications] copy]){
NSDictionary *userInfo = notification.userInfo;
if ([self.name isEqualToString:[userInfo objectForKey:kTimerNameKey]]){
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
at time of notification schedule give a unique notification key in notification's userinfo and to cancel notification you can use below code as where
UIApplication *app = [UIApplication sharedApplication];
NSArray *eventArray = [app scheduledLocalNotifications];
for (int i=0; i<[eventArray count]; i++)
{
UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
NSDictionary *userInfoCurrent = oneEvent.userInfo;
NSString *uid=[NSString stringWithFormat:#"%#",[userInfoCurrent valueForKey:#"uid"]];
if ([uid isEqualToString:uidtodelete])
{
//Cancelling local notification
[app cancelLocalNotification:oneEvent];
break;
}
}
Since Apple has shut down their developer portal pending security upgrades they've created a status page so we can monitor what features they've brought back online. I've written a simple program to monitor this status page for changes.
My Mac is set up to receive iMessages sent to my iPhone. I'm wondering if anyone knows if its possible to have the program I've written send an iMessage to my iPhone when there's been a change in the status page Apple has up.
I usually develop for iPhone, so I appreciate any insight people can offer. The simple program I've written below checks every fifteen minutes if there's been an update and brings the update page up on Safari if there has been.
#import "AppDelegate.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
NSDateFormatter *format = [NSDateFormatter new];
[format setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:8*3600]];
[format setDateFormat:#"YYYY-MM-DD HH:mm:ss"];
NSString *text = #"";
bool no_connection;
do {
text = [[NSString alloc]initWithContentsOfURL:[NSURL URLWithString:#"https://developer.apple.com/support/system-status/"] encoding:NSASCIIStringEncoding error:NULL]; // pulls the source html from Apple's update page
NSString *status = #"No change";
if ([text rangeOfString:[self currentStatus]].location == NSNotFound) { // if cannot find the old text, then there has been a change
status = #"Update!";
}
no_connection = text == nil || [text length] == 0; // if no text or nil text then connection issue
if (no_connection) {
status = #"error making connection";
}
NSLog(#"status: %#",status); // report on status
if (no_connection) { // if no connection then try again in a minute
sleep(60);
continue;
}
sleep(900); // wait 15 minutes (60 x 15 = 900) and check again
} while ([text rangeOfString:[self currentStatus]].location != NSNotFound); // continue checking until there has been a change
NSURL *url = [NSURL URLWithString:#"https://developer.apple.com/support/system-status/"]; // bring up the update page in the browser
if( ![[NSWorkspace sharedWorkspace] openURL:url] )
NSLog(#"Failed to open url: %#",[url description]);
}
-(NSString*)currentStatus { /* returns the specific text in the html source that I'm checking for a change
"<span>" will be replaced with a hyperlink tag */
return #"<span>Certificates, Identifiers & Profiles";
}
#end
I tried to do this once and never came up with an Objective-C solution. However, you could have your app run AppleScript. Here's how you'd do it from the command line:
osascript -e 'tell application "Messages" to send "Test Message" to buddy "MyBuddy"'
And the answer here describes how to run AppleScript from Objective C:
Run AppleScript from Cocoa Application
I am facing a problem with push notification application badge number value updation.
I am doing like:
-(void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive) {
// do stuff when app is active
}else{
// do stuff when app is in background
[UIApplication sharedApplication].applicationIconBadgeNumber =
[UIApplication sharedApplication].applicationIconBadgeNumber+1;
/* to increment icon badge number */
}
}
But, the icon is showing the badge number as '1' always, and it is not incrementing when more notifications are there/ one notification came after another.
Any advice is appreciable...
The badge number is set by the operating system when you receive a JSON notification payload that resembles the following:
{
"aps" : {
"alert" : "New notification!",
"badge" : 2
}
}
As you see, it's the server who is responsible for setting the correct number in the badge key. Your server needs to track or compute the number of pending notifications for each user and generate the badge number before sending the notification to Apple.
The client responsibility is to clear the notification badge, or decrement it, when the user sees a notification. The code to do so is
application.applicationIconBadgeNumber = application.applicationIconBadgeNumber - 1; // Decrement counter
or
application.applicationIconBadgeNumber = 0; // Reset counter assuming the user is able to see all notifications at once.
you can create a static variable instead, and assign it to the applicationIconBadgeNumber:
static int i=1;
[UIApplication sharedApplication].applicationIconBadgeNumber = i++;
I had the same problem and solved it by creating int. variable in class.h
like this :
a custom class.H
#property int badge;
a custom class.M
-(id)init{
_badge=0;
self = [super init];
if (self) {
}
return self;}
-(void)reminderCreator:(NSDate*)onTime withText:(NSString*)text{
_badge += 1;
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = onTime;
localNotification.alertBody = text;
localNotification.soundName=UILocalNotificationDefaultSoundName;
localNotification.applicationIconBadgeNumber=_badge;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification]; }
so if you initialize this custom class, somewhere (maybe at your viewController) and then call the reminderCreator method several times to setup few localNotifications, it will assign incremented number to each notification.
+1 if this helped :)
The -(void)application:didReceiveRemoteNotification: will only be called when your app is running in the foreground.
If you want the badge to be increase when your app isn't running you should set the badge number in the push notification payload.
You should there for keep track of the badge number server side, since the badge property of the push notification payload will be use as the badge number. It will not increment the badge number for you.
Since the system handles the incoming push notifications your app is not informed of received push notifications for you app. Only when you app is running in foreground will the -(void)application:didReceiveRemoteNotification: be called. There is no way to get you app to repsond to push notification when it is not in the foreground.
Yes it seems that it always returns badgeNumber 1 in spite it has value increased to 2.
when using such code:
// update badge count
let currentBadgeCount = UIApplication.shared.applicationIconBadgeNumber
let badge = (aps["badge"] as? Int) ?? 1
UIApplication.shared.applicationIconBadgeNumber = currentBadgeCount + badge
so I think the only solution will be to store it in UserDefaults and then update value of UserDafaults and then it is set then update badge count?
This should work:
static var notificationsCount: Int {
set {
let userDefaults = UserDefaults(suiteName: SharedAppData.appGroup)
userDefaults?.set(newValue, forKey: "notificationsCount")
UIApplication.shared.applicationIconBadgeNumber = newValue
}
get {
let userDefaults = UserDefaults(suiteName: SharedAppData.appGroup)
return userDefaults?.integer(forKey: "notificationsCount") ?? 0
}
}
And then
SharedAppData.notificationsCount = 0 // to reset badge count
And this to increment
// update badge count
SharedAppData.notificationsCount += 1