I'm face the problem after upgraded to iOS 10 about push notification (I am using Swift3).
In normal case when application open or application still in background everything work as well (can receive push notification and update data as my logic).
But when application is terminated i can't handle push notification when application become active.
Here is my test case.
Edit Scheme to Wait for executable to be launched.
Double press home button and swipe application up.
Run Xcode wait until "Wait for application to launch" shown.
Test send push notification from server.
Device received push notification.
Start application from application icon.
After that application start and didFinishLaunchingWithOptions being called but launchOptions aways null so i can't handle push notification (But if i open application from notification in notification center or popup notification launchOptions is not null)
Does anybody has any idea to check this problem ?
Thank you in advance.
You need to open the application by tapping the push notification in the notification tray.
When you launch the application from the icon, launchOptions will be nil. Launching from the push notification will provide you launchOptions.
https://developer.apple.com/reference/uikit/uiapplicationdelegate/1622921-application
Try this:
Add delegate on AppDelegate.
UNUserNotificationCenterDelegate
And..
//Called when a notification is delivered to a foreground app.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("User Info = ",notification.request.content.userInfo)
completionHandler([.alert, .badge, .sound])
}
//Called to let your app know which action was selected by the user for a given notification.
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("ActionIdentifier = ",response.actionIdentifier)
print("User Info = ",response.notification.request.content.userInfo)
completionHandler()
}
Related
Has anyone experienced problems with [.provisional] notifications on iOS 15? Can't get anything to show up in Notification Center in 'Quiet Delivery' mode. I'm clueless..
These are relevant extracts:
UNUserNotificationCenter.current().requestAuthorization([.provisional, .alert])
// -> granted: true
let content = UNMutableNotificationContent()
content.title = "Test"
content.body = "Test"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "some_id...", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)}
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification, ...)
// This is called -> returning [.banner] (so it should show in foreground, not that it matters since it's provisional...)
BUT ... notifications center is empty.
The same code works fine using non-provisional mode (user granting explicit consent to notifications).
Is there something obvious I might be missing here?
--
UPDATE: Ok, not much of an answer, but clear observation:
Putting app into background -> above code does deliver notification into notification center.
This means that .provisional mode completely ignores 'willPresent notification:' return value [which allows presentation in foreground] AND does not deliver notification into notification center if app is in foreground.
I guess I can live with that and it kind of makes sense... (?).
I implemented firebase notification in Xcode 12 via cocoapod and basic step by step... notification ARE working all nice and good, even when app in background.
this tutorial : https://www.appcoda.com/firebase-push-notifications/
the only thing I need is this condition : when App in background and user hit the notification, it opens the APP, but I want the webview to reload.
i think it would be in this part of the code
// [START receive_message]
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
but what code and I add to reload the view ?
// [START receive_message]
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// Messaging.messaging().appDidReceiveMessage(userInfo)
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: (messageID)")
}
// Print full message.
print(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
I'm creating a custom dynamic notification to show the user. Once i receive this notification at didReceiveNotification function at NotificationController I set the interface outlets with the right data. My problem is that i did not realize how can i add a custom button above the default dismiss button, since the notification storyboard doesnt allow buttons insertion and Apple Documentation says that
Do not include buttons, switches, or other interactive controls.
But i saw a lot of watch applications that have their custom actions, as Messages and Facebook Messenger. There is any way to add custom actions to the dynamic interface at watchOS?
You simply cannot add buttons to Dynamic notification interfaces. If you try to do this, you will receive the error
Illegal Configuration: Buttons are not supported in Notification interfaces.
However, you can add system buttons to your notifications other than the Dismiss button. When setting up the categories for the notification center, you can specify custom UNNotificationActions to be added to your notification category.
var categories = Set<UNNotificationCategory>()
let myCategory = UNNotificationCategory(identifier: "MyCategory", actions: [/*your custom actions go here*/], intentIdentifiers: [], options: []) //set up the actions here
categories.insert(myCategory)
center.setNotificationCategories(categories)
Then you can handle the user interactions with these actions (which as displayed as normal buttons on your dynamic notification interface) in your the UNUserNotificationCenterDelegate method, userNotificationCenter(_:didReceive:withCompletionHandler:) like this:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
switch response.actionIdentifier {
case "Ok":
print("Ok action tapped")
case "Dismiss":
print("Dismiss action tapped")
default:
break
}
completionHandler()
}
I am currently writing a tvOS app. I've been detecting and overriding the menu button with tapRecognizer to switch between storyboards and other functions. My issue is when I am on my home screen and press menu it does not exit the app. Instead it remembers the last function I used when overriding the menu button and performs that function. Any thoughts on how to clear the tapRecognizer? Or a function that will exit the app?
I'm overriding the menu button with
in Storyboard1
tapRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(home)];
tapRecognizer.allowedPressTypes = #[[NSNumber numberWithInteger:UIPressTypeMenu]];
[self.view addGestureRecognizer:tapRecognizer];
in my home subroutine I send the user back to my home page storyboard. But from then on the menu button will not exit the app but send me back to storyboard1.
thanks,
SW
Instead of using your own gesture recognizer, override pressesBegan:
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
if(presses.first?.type == UIPressType.Menu) {
// handle event
} else {
// perform default action (in your case, exit)
super.pressesBegan(presses, withEvent: event)
}
}
If you are using UIGestureRecognizer instead of responding to presses, all you need to do is to disable the recognizer:
tapRecognizer.enabled = NO;
So if no recognizer with UIPressTypeMenu is listening, tvOS suspends the app and displays the home screen. (I've tested this)
You have to override 2 methods to prevent exiting app by pressing Menu button.
Here is ready-to-use template:
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for press in presses {
switch press.type {
case .Menu:
break
default:
super.pressesBegan(presses, withEvent: event)
}
}
}
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
for press in presses {
switch press.type {
case .Menu:
//Do some staff there!
self.menuButtonPressed()
default:
super.pressesEnded(presses, withEvent: event)
}
}
}
If you overwrite the menu button, the app won't be accepted:
EDIT: You can overwrite, but the menu button has to work as a back button to homescreen from the entry point of the app.
10.1 Details
The Menu button on the Siri Remote does not behave as expected in your
app.
Specifically, when the user launches the app and taps the Menu button
on the Siri remote, the app does not exit to the Apple TV Home screen.
Next Steps
Please revise your app to ensure that the Siri remote buttons behave
as expected and comply with the Apple TV Human Interface Guidelines.
It may be help you...
it is swift code.
let menuPressRecognizer = UITapGestureRecognizer()
menuPressRecognizer.addTarget(self, action: #selector(YourViewController.menuButtonAction(_:)))
menuPressRecognizer.allowedPressTypes = [NSNumber(integer: UIPressType.Menu.hashValue)]
self.view.addGestureRecognizer(menuPressRecognizer)
As per Apple's documentation, for custom press handling, we should override all four of these methods-
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
This is the official documentation from XCode:
Generally, all responders which do custom press handling should
override all four of these methods.
Your responder will receive either pressesEnded:withEvent or pressesCancelled:withEvent: for each
press it is handling (those presses it received in pressesBegan:withEvent:).
pressesChanged:withEvent: will be invoked for presses that provide
an analog value
(like thumbsticks or analog push buttons)
*** You must handle cancelled presses to ensure correct behavior in
your application. Failure to
do so is very likely to lead to incorrect behavior or crashes.
SwiftUI Seekers:
I don't know how much this answer helps, but just adding available actions in SwiftUI.
YourAnyView
.onExitCommand(perform: {
print("onExitCommand")
})
.onMoveCommand { direction in
print("onMoveCommand", direction)
}
REF:
onmovecommand
onexitcommand
I try to make an app, and now i shoud make some changes when screen resolution will change, but i coudn't find how to intercept this event.
Do you have any ideea how can i take that event?
The NSApplicationDidChangeScreenParametersNotification is posted when the configuration of the displays attached to the computer is changed, so
you can register for that notification, e.g. with
NSNotificationCenter.defaultCenter().addObserverForName(NSApplicationDidChangeScreenParametersNotification,
object: NSApplication.sharedApplication(),
queue: NSOperationQueue.mainQueue()) {
notification -> Void in
println("screen parameters changed")
}
Note that there can be various reasons why this notification is
fired, e.g. a change in the dock size (as observed in Cocoa Dock fires NSApplicationDidChangeScreenParametersNotification), so you have to
"remember" the old resolution and compare it with the new resolution.
Swift 4:
The didChangeScreenParametersNotification is posted when the configuration of the displays attached to the computer is changed.
Inside the func applicationDidFinishLaunching() in AppDelegate class or func viewDidLoad() in ViewController class, insert the following code:
NotificationCenter.default.addObserver(forName: NSApplication.didChangeScreenParametersNotification,
object: NSApplication.shared,
queue: OperationQueue.main) {
notification -> Void in
print("screen parameters changed")}
I personally, used it to center the position of my application when switching between the Mac and the external screen.
Here is the updated Swift 3 code:
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSApplicationDidChangeScreenParameters,
object: NSApplication.shared(),
queue: OperationQueue.main) {
notification -> Void in
print("screen parameters changed")
}
Code for Swift 5+
NotificationCenter.default.addObserver(
forName: NSNotification.Name(rawValue: "NSApplicationDidChangeScreenParametersNotification"),
object: NSApplication.shared,
queue: .main) { notification in
self.adjustUIIfNeeded()
}