I want to display Push Notifications in Foreground State for iOS 8.0. I'm receiving notifications in background state, but not in foreground state.
extension AppDelegate: UNUserNotificationCenterDelegate {
// Receive displayed notifications for iOS 10 devices.
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(UNNotificationPresentationOptions.alert)
//completionHandler([.alert,.badge])
let userInfo = notification.request.content.userInfo
if let messageID = userInfo[gcmMessageIDKey] {
}
// Print full message.
print(userInfo)
completionHandler([])
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response:UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
completionHandler()
}
}
Related
I have push notification on my app (works well) and I would like to redirect my users to my "Messages" view when they click on the notification, how to do that in SwiftUI (no Storyboard)?
I know that i have to implement the code in this function (in AppDelegate) :
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
}
My main view is a Tabview and "Messages" view is in it in a navigation View.
Thanks for your help!
So i think that we just have to modify these lines ...
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
// retrieve the root view controller (which is a tab bar controller)
guard let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController else {
return
}
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// instantiate the view controller we want to show from storyboard
// root view controller is tab bar controller
// the selected tab is a navigation controller
// then we push the new view controller to it
if let conversationVC = storyboard.instantiateViewController(withIdentifier: "ConversationViewController") as? ConversationViewController,
let tabBarController = rootViewController as? UITabBarController,
let navController = tabBarController.selectedViewController as? UINavigationController {
// we can modify variable of the new view controller using notification data
// (eg: title of notification)
conversationVC.senderDisplayName = response.notification.request.content.title
// you can access custom data of the push notification by using userInfo property
// response.notification.request.content.userInfo
navController.pushViewController(conversationVC, animated: true)
}
// tell the app that we have finished processing the user’s action / response
completionHandler()
}
So i think that we can change :
guard let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController else {
return
}
to
guard let rootViewController = UIApplication.shared.currentUIWindow()?.rootViewController else {
return
}
But for the rest I don't know how to make the changes
I am showing a camera preview view on a .sheet.
I need to detect when the user's finger touches the preview area and when the user's finger leaves the preview area.
The only solution I have found to do that was this
CameraPreview()
.gesture(DragGesture(minimumDistance: 0)
.onChanged { _ in
// finger touches
}
.onEnded { _ in
// finger leaves
})
but as this preview is being displayed on a sheet and sheets must be closed by dragging them from the top down, this drag gesture prevents the sheet drag gesture from working.
Any ideas?
NOTE: I do not need to detect dragging. I need to detect single tap on a view and then receive a callback when the finger leaves that view.
You need to use UIViewRepresentable for this. Here are the steps:
Create a custom version of AnyGestureRecognizer taken from here:
class AnyGestureRecognizer: UIGestureRecognizer {
var onCallback: () -> Void
var offCallback: () -> Void
init(target: Any?, onCallback: #escaping () -> Void, offCallback: #escaping () -> Void) {
self.onCallback = onCallback
self.offCallback = offCallback
super.init(target: target, action: nil)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
if let touchedView = touches.first?.view, touchedView is UIControl {
state = .cancelled
offCallback()
} else if let touchedView = touches.first?.view as? UITextView, touchedView.isEditable {
state = .cancelled
offCallback()
} else {
state = .began
onCallback()
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
state = .ended
offCallback()
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
state = .cancelled
offCallback()
}
}
Create a custom UIViewRepresentable view and attach the AnyGestureRecognizer to it:
struct GestureView: UIViewRepresentable {
var onCallback: () -> Void
var offCallback: () -> Void
func makeUIView(context: UIViewRepresentableContext<GestureView>) -> UIView {
let view = UIView(frame: .zero)
let gesture = AnyGestureRecognizer(
target: context.coordinator,
onCallback: onCallback,
offCallback: offCallback
)
gesture.delegate = context.coordinator
view.addGestureRecognizer(gesture)
return view
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<GestureView>) {}
class Coordinator: NSObject {}
func makeCoordinator() -> GestureView.Coordinator {
Coordinator()
}
}
extension GestureView.Coordinator: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
true
}
}
Use it as an overlay:
struct ContentView: View {
var body: some View {
Color.blue
.sheet(isPresented: .constant(true)) {
Color.red
.overlay(
GestureView(onCallback: { print("start") }, offCallback: { print("end") })
)
}
}
}
I have done this in my AppDelegate
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: {(didAllow, error) in
if didAllow{
print("Notification access granted")
}
else{
print(error?.localizedDescription as Any)
}
})
And in my ViewController class i have done this method to call on a button action
func sendNotification(inSecond: TimeInterval, completion: #escaping (_ Success: Bool) -> ()){
let notify = UNMutableNotificationContent()
notify.title = "Break Oil"
notify.subtitle = "Please renew your Break Oil"
notify.sound = UNNotificationSound(named: "carsHrn.mp3")
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: inSecond, repeats: false)
let request = UNNotificationRequest(identifier: "myNotification", content: notify, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: { error in
if error != nil{
print(error!)
completion(false)
}
else {
completion(true)
}
})
}
Fixed by using
extension DignoSViewController : UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert])
}
}
I have been attempting to get local notifications going within my code and have been having a problem with it showing up as an alert and in the local Notification Center. I've tried different codes from online and even tried implementing the example code Apple provides in the manual. Still, no notification drops down on the screen but if I implement a badge count, that shows. Here's what I put in the App Delegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: {granted, Error in})
UNUserNotificationCenter.current().delegate = self
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.alert)
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
//
}
And Here's what's in my ViewController:
#IBAction func addReminder(sender: UIButton) {
taskMgr.addTask(name: textField.text!)
//self.animateOut()
let content = UNMutableNotificationContent()
content.title = NSString.localizedUserNotificationString(forKey: "The alert was successful", arguments: nil)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: "timerDone", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
If everything is correct, could there be something else I'm missing with the simulator? I have already made sure that the notifications for the app is turned on, allowed and banners on.
I was implemented apple push notification demo app in Xcode 7.3. Its was working fine . Recently i download Xcode 8. Now my demo app is not working in either Xcode 7 nor Xcode 8. Delegate method didn't getting called. I have no idea, what went wrong. Xcode suggested to create entitlements and i did. Please any one help me out.
Thanks,
Vikash
On Push Notification From Capabilities and Add UserNotification frame work in BuildPhase
in AppDelegate add delegate method UNUserNotificationCenterDelegate
import UserNotifications
In didFinishingLaunching...
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
if error == nil{
UIApplication.shared.registerForRemoteNotifications()
}
}
} else {
// Fallback on earlier versions
}
Add These methods
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print(deviceTokenString)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("i am not available in simulator \(error)")
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
}
#available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
}
Hope this is issue is solved.
If not please add capability (Push Notification) to both debug and release.