How to navigate To and Back from Push Notification setup Page after user enabled it - swift3

I used below code to detect if user has enabled push notification.
**Problem**.
1) How to open or navigate to the Push Notification setting Page in the phone
2) How to return from this Push Notification page after user enabled it or
how user return to previous page if decide to enable later.
VC_Check --> Push Notification settings
in VC_check:
if UIApplication.shared.isRegisteredForRemoteNotifications {
print("YES")
// goto other VC
} else {
// goto Phone setting page
}
//-- I dont want this Pop Up to enable Push Notification:
// detected not enabled, use below pop Up
pageUIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
UIApplication.shared.registerForRemoteNotifications()
Please help.
Thanks

You can ask to enable push notification like this:
func requestNotificationPermission() {
let app = UIApplication.shared
// --- from right here
if #available(iOS 10.0, *) {
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
// For iOS 10 data message (sent via FCM)
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
app.registerUserNotificationSettings(settings)
}
app.registerForRemoteNotifications()
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
// DO SOMETHING HERE AFTER USER AUTHORIZES, CALL A FUNCTION TO RELOAD VIEW?
}
app.registerForRemoteNotifications()
} else {
// Fallback on earlier versions
}
}
To check if user has granted permission use this:
func checkNotificationStatus() {
let current = UNUserNotificationCenter.current()
current.getNotificationSettings(completionHandler: { (settings) in
if settings.authorizationStatus == .notDetermined {
// Notification permission has not been asked yet, go for it!
print("Not yet asked for permission")
}
if settings.authorizationStatus == .denied {
// Notification permission was previously denied, go to settings & privacy to re-enable
print("Permission denied")
}
if settings.authorizationStatus == .authorized {
// Notification permission was already granted
print("Permission Granted")
}
})
}

Related

Implement SwiftUI Notifications

I am trying to implement notifications in my SwiftUI app, but have not managed to do so after extensive research on Google and other search engines.
Here's a simple example on how to use notifications in a SwiftUI app. It requests for permissions and checks if they are granted, and allows you to send a notification if so.
Do note that notifications from apps won't appear if the app they originate from is in the foreground, so I demonstrate closing the app quickly before the notification is sent to view it.
Here's the whole example code the demo uses:
import SwiftUI
import UserNotifications
struct ContentView: View {
#State private var permissionGranted = false
private func requestPermissions() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
if success {
permissionGranted = true
} else if let error = error {
print(error.localizedDescription)
}
}
}
private func sendNotification() {
let notificationContent = UNMutableNotificationContent()
notificationContent.title = "Hello world!"
notificationContent.subtitle = "Here's how you send a notification in SwiftUI"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
// you could also use...
// UNCalendarNotificationTrigger(dateMatching: .init(year: 2022, month: 12, day: 10, hour: 0, minute: 0), repeats: true)
let req = UNNotificationRequest(identifier: UUID().uuidString, content: notificationContent, trigger: trigger)
UNUserNotificationCenter.current().add(req)
}
var body: some View {
VStack {
if !permissionGranted {
Button("Request Permission") {
requestPermissions()
}
}
if permissionGranted {
Button("Send Notification") {
sendNotification()
}
}
}
.onAppear {
// Check if we already have permissions to send notifications
UNUserNotificationCenter.current().getNotificationSettings { settings in
if settings.authorizationStatus == .authorized {
permissionGranted = true
}
}
}
.padding()
}
}
And here's a demo video of the following code:

Prevent view dismissing after the request access to the AVCaptureDevice

How can we prevent the view from going to the previous view after user clicks OK button on camera access prompt? Here is our code:
func RequestCameraAccess() {
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { (granted: Bool) -> Void in
if granted == true {
print("User Granted")
DispatchQueue.main.async {
self.Cam();
}
} else {
print("User Rejected")
DispatchQueue.main.async {
self.image1.isHidden = true
}
}
})
}
Thanks
the problem was that in the moment of camera access granting the following method occurs:
func applicationDidBecomeActive(_ application: UIApplication) {}
In my application I had logic to move to home screen in case of inactivity for a certain amount of time.
Thanks anyway.

timing issue after completion of URLRequest

i have a behavior i cant resolve.
I have a controller (controller 1) where i check some defaults value. if not present (first time use of app: check login and pwd) i present (modal) a settings vc:
IN CONTROLLER 1
override func viewDidAppear(_ animated: Bool) {
if(!isKeyPresentInUserDefaults(key: "username")) {
NSLog("username not present")
let vc = self.storyboard?.instantiateViewController(withIdentifier: "settings") as! SettingsViewController
self.present(vc, animated: true, completion: nil)
}
}
in this vc (controller 2) (also in the main storyboard) i have a button done. When pressed, it is associated to the:
IN CONTROLLER 2: SettingsVc -> ID : settings
#IBAction func doneSettings(sender: AnyObject) {
if(isInternetAvailable()) {
NSLog("internet available")
login { (result) in
switch result
{
case .Success(let result):
//print(result)
self.dismissSelf()
break
case .Failure(let error):
print(error)
break
}
}
}
else {
NSLog("internet not available")
}
}
the dismissSelf func is defined in the Settingsvc as:
func dismissSelf() {
NSLog("dismissSettingsVC")
self.dismiss(animated: false, completion: nil)
}
the login func is defined in another class, dealing with networking stuff and is as is:
func login(completion: #escaping (AsyncResult<[CustomUserObject]>)->())
{
let myUrl = URL(string: "http://www.xxxx.com/api/api.php");
var request = URLRequest(url:myUrl!)
request.httpMethod = "POST"// Compose a query string
let postString = "u=login&s=password&cmd=login";
request.httpBody = postString.data(using: String.Encoding.utf8);
let session = URLSession.shared
let task = session.dataTask(with: request as URLRequest){
(data, response, error) -> Void in
if let error = error
{
completion(AsyncResult.Failure(error as NSError?))
} else {
let result: [CustomUserObject] = []//deserialization json data into array of [CustomUserObject]
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("*********response data = \(responseString)")
completion(AsyncResult.Success(result))
}
}
task.resume()
}
So, I launch the app for the first time (no login, no pwd in defaults), then the Settingvc is presented. I press the done button with param hardcoded. The login is correctly called, I receive the answer correctly, and on completion i should dismiss the Settingvc.
thing is, i see the NSLOG for dismiss, but the dismiss appears seconds after the network func completion (from 10 secs to up to a minute), which I can't understand. Why such a delay? any idea?
2017-11-27 21:54:33.262892 app[998:211517] username not present
2017-11-27 21:54:36.119754 app[998:211517] internet available
*********response data =
Optional({"cmd":"login","success":"true","message":"login succeded"})
2017-11-27 21:54:38.472306 app[998:211542] dismissSettingsVC
2017-11-27 21:54:48.048095 app[998:211517] username not present
in this case, it took 10 sec to dismiss the Settingsvc after receiving the login results.
another one:
2017-11-27 22:04:20.364097 app[998:211517] internet available
*********response data =
Optional({"cmd":"login","success":"true","message":"login succeded"})
2017-11-27 22:04:22.495642 app[998:212974] dismissSettingsVC
2017-11-27 22:05:00.049177 app[998:211517] username not present
in this other case, it took 38 sec to dismiss the Settingsvc after receiving the login results.
EDITED
I tried not using a vc presented. Instead in controller 1, i added a view that i first set as visible if username in defaults does not exist and then that I will hide after the login completion. in this view, i added a button to call the loginAction.
#IBAction func loginAction(sender: AnyObject) {
if(isInternetAvailable()) {
NSLog("internet available")
login { (result) in
switch result
{
case .Success(let users):
print(users)
self.loginView.isHidden = true
NSLog("login ok: hiding view")
break
case .Failure(let error):
print(error ?? "ERROR")
break
}
}
}
else {
NSLog("internet not available")
}
}
Same result:
I see the completion and the received data:
2017-11-28 18:17:34.314706 cellar[1270:311710] username not present
2017-11-28 18:17:35.066333 cellar[1270:311710] internet available
2017-11-28 18:17:35.076930 cellar[1270:311710] done login
Optional({"cmd":"login","success":"true","message":"login succeded"})
2017-11-28 18:17:37.655829 cellar[1270:311763] login ok: hiding view
the view should be hidden before the NSLOG "login ok: hiding view". Instead, the UI is updated seconds after (about a min, but variable)
What would avoid the UI to be updated for so long as I wait the completion of the network stuff to perform the UI update?
UPDATE:
weird situation:
as soon as I get the network completion result, by changing the orientation, the dismiss appears right away:
Optional({"cmd":"login","success":"true","message":"login succeded"})
2017-11-28 22:28:30.620408 cellar[1461:360470] dismiss
2017-11-28 22:28:31.537588 cellar[1461:360413] username not present
2017-11-28 22:28:32.126759 cellar[1461:360413] [App] if we're in the
real pre-commit handler we can't actually add any new fences due to CA
restriction
your help is much that appreciated. Thanks
Not sure if this is the reason for your problem but it looks like you aren't running the dismiss() call on the main thread. You should call all UI code on the main thread. Wrap it as follows
case .Success(let result):
//print(result)
DispatchQueue.main.async {
self.dismissSelf()
}
break

Local notification in swift 3 with new UI

I know to how to create local notification in Swift 3( I am new in this part), However, I want to create something like below image. All tutorials in the web are too old and I do not what should I do.
As you can see before extending notification , there are 2 buttons. after extending also there are 2 buttons with red and blue color.
Updated
Thanks Joern
The slide gesture only show clear. Is there any settings for showing both clear and view
The red and blue buttons are only available in iOS versions prior to iOS 10. With iOS 10 the notifications design changed. The slide gesture is used for the standard actions Clear and View. The custom actions Snooze and Confirm will be displayed when you force touch the notification or pull it down (for devices without force touch). If you are using a device with force touch the View button might not be shown.
The buttons look different now:
So, here is how you implement Local Notifications with Swift 3 / 4:
For iOS versions prior to iOS 10:
If you are supporting iOS versions prior to iOS10 you have to use the old (deprecated with iOS 10) UILocalNotification:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
registerLocalNotification()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
scheduleLocalNotification()
}
func scheduleLocalNotification() {
let localNotification = UILocalNotification()
localNotification.alertTitle = "Buy milk"
localNotification.alertBody = "Remember to buy milk from store"
localNotification.fireDate = Date(timeIntervalSinceNow: 3)
localNotification.soundName = UILocalNotificationDefaultSoundName
localNotification.category = "reminderCategory" // Category to use the specified actions
UIApplication.shared.scheduleLocalNotification(localNotification) // Scheduling the notification.
}
func registerLocalNotification() {
let reminderActionConfirm = UIMutableUserNotificationAction()
reminderActionConfirm.identifier = "Confirm"
reminderActionConfirm.title = "Confirm"
reminderActionConfirm.activationMode = .background
reminderActionConfirm.isDestructive = false
reminderActionConfirm.isAuthenticationRequired = false
let reminderActionSnooze = UIMutableUserNotificationAction()
reminderActionSnooze.identifier = "Snooze"
reminderActionSnooze.title = "Snooze"
reminderActionSnooze.activationMode = .background
reminderActionSnooze.isDestructive = true
reminderActionSnooze.isAuthenticationRequired = false
// Create a category with the above actions
let shoppingListReminderCategory = UIMutableUserNotificationCategory()
shoppingListReminderCategory.identifier = "reminderCategory"
shoppingListReminderCategory.setActions([reminderActionConfirm, reminderActionSnooze], for: .default)
shoppingListReminderCategory.setActions([reminderActionConfirm, reminderActionSnooze], for: .minimal)
// Register for notification: This will prompt for the user's consent to receive notifications from this app.
let notificationSettings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: [shoppingListReminderCategory])
UIApplication.shared.registerUserNotificationSettings(notificationSettings)
}
}
This will register the local notification and fires it 3 seconds after the user closes the app (for testing purposes)
For iOS 10 and later:
If you target your app to iOS 10 you can use the new UserNotifications framework:
import UIKit
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
registerUserNotifications()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
scheduleLocalNotification()
}
func registerUserNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
guard granted else { return }
self.setNotificationCategories()
}
}
func setNotificationCategories() {
// Create the custom actions
let snoozeAction = UNNotificationAction(identifier: "SNOOZE_ACTION",
title: "Snooze",
options: .destructive)
let confirmAction = UNNotificationAction(identifier: "CONFIRM_ACTION",
title: "Confirm",
options: [])
let expiredCategory = UNNotificationCategory(identifier: "TIMER_EXPIRED",
actions: [snoozeAction, confirmAction],
intentIdentifiers: [],
options: UNNotificationCategoryOptions(rawValue: 0))
// Register the category.
let center = UNUserNotificationCenter.current()
center.setNotificationCategories([expiredCategory])
}
func scheduleLocalNotification() {
let content = UNMutableNotificationContent()
content.title = "Buy milk!"
content.body = "Remember to buy milk from store!"
content.categoryIdentifier = "TIMER_EXPIRED"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false)
// Create the request object.
let request = UNNotificationRequest(identifier: "Milk reminder", content: content, trigger: trigger)
// Schedule the request.
let center = UNUserNotificationCenter.current()
center.add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
}
}
}
}
You can check out a demo app that uses the UserNotifications framework here

fired local notification at specific time

please i have an issue about how can i trigger the local notification at specific time ? without user trigger it and need the app at specific time fired local notification
the following my code :
this is for get permission from the user
func registerLocal() {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
if granted {
print("Yay!")
} else {
print("D'oh")
}
}
}
// this i schedule local notification
func scheduleLocal() {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Late wake up call"
content.body = "The early bird catches the worm, but the second mouse gets the cheese."
content.categoryIdentifier = "alarm"
content.userInfo = ["customData": "fizzbuzz"]
content.sound = UNNotificationSound.default()
var dateComponents = DateComponents()
dateComponents.hour = 3
dateComponents.minute = 19
dateComponents.day = 3
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.add(request)
center.removeAllPendingNotificationRequests()
}
// her i call theses methods
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
registerLocal()
scheduleLocal()
return true
}
and when i close my app i have no receive the notification , please help about how can i trigger the local notification at specific time
thanks
You should not call center.removeAllPendingNotificationRequests() after adding your notification, since it will cancel the previously added pending notification as well. You should rather check after calling center.addRequest(request) whether your request has actually been added or not by
center.getPendingNotificationRequests(completionHandler: { pendingRequest in
print("Pending notifications: \(pendingRequest)") //Just for debugging
})
Or you can also specify a completion handler to addRequest, which will return an error if the request hasn't been added succesfully:
center.add(request, withCompletionHandler: { error in
print(error)
})