From 6224dfad031e2cb34e1b148aac3c39f3d3ab39f1 Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Mon, 18 May 2020 08:39:22 +0800 Subject: [PATCH] Notification Permission Requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #2057 • On app launch, the app checks if notification permissions are granted and registers with APNS if that is the case. It will not request permissions as part of the app launch. • When a user requests to be notified of new articles, the authorizationStatus is checked: - if `notDetermined` or `provisional`, an authorization request is made, and if successful, the Notify of New Articles status is updated (otherwise it is reverted) - if `denied`, an alert is thrown asking the user to enable in settings (and the change to notify of new articles is reverted) - if `authorized` the update is made. `WebFeedInspectorViewController` also monitors for the app entering the foreground so that it can get the latest notification auth settings. --- iOS/AppDelegate.swift | 6 +- .../WebFeedInspectorViewController.swift | 65 ++++++++++++++++++- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/iOS/AppDelegate.swift b/iOS/AppDelegate.swift index 0dd99bad3..b5c7244b8 100644 --- a/iOS/AppDelegate.swift +++ b/iOS/AppDelegate.swift @@ -90,9 +90,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD DispatchQueue.main.async { self.unreadCount = AccountManager.shared.unreadCount } - - UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .sound, .alert]) { (granted, error) in - if granted { + + UNUserNotificationCenter.current().getNotificationSettings { (settings) in + if settings.authorizationStatus == .authorized { DispatchQueue.main.async { UIApplication.shared.registerForRemoteNotifications() } diff --git a/iOS/Inspector/WebFeedInspectorViewController.swift b/iOS/Inspector/WebFeedInspectorViewController.swift index 9a39d6a78..a518a8777 100644 --- a/iOS/Inspector/WebFeedInspectorViewController.swift +++ b/iOS/Inspector/WebFeedInspectorViewController.swift @@ -9,6 +9,7 @@ import UIKit import Account import SafariServices +import UserNotifications class WebFeedInspectorViewController: UITableViewController { @@ -38,6 +39,8 @@ class WebFeedInspectorViewController: UITableViewController { return webFeed.homePageURL == nil } + private var userNotificationSettings: UNNotificationSettings? + override func viewDidLoad() { tableView.register(InspectorIconHeaderView.self, forHeaderFooterViewReuseIdentifier: "SectionHeader") @@ -51,6 +54,14 @@ class WebFeedInspectorViewController: UITableViewController { feedURLLabel.text = webFeed.url NotificationCenter.default.addObserver(self, selector: #selector(webFeedIconDidBecomeAvailable(_:)), name: .WebFeedIconDidBecomeAvailable, object: nil) + + NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main, using: { _ in + self.updateNotificationSettings() + }) + } + + override func viewDidAppear(_ animated: Bool) { + updateNotificationSettings() } override func viewDidDisappear(_ animated: Bool) { @@ -67,7 +78,30 @@ class WebFeedInspectorViewController: UITableViewController { } @IBAction func notifyAboutNewArticlesChanged(_ sender: Any) { - webFeed.isNotifyAboutNewArticles = notifyAboutNewArticlesSwitch.isOn + guard let settings = userNotificationSettings else { + notifyAboutNewArticlesSwitch.isOn = !notifyAboutNewArticlesSwitch.isOn + return + } + if settings.authorizationStatus == .denied { + notifyAboutNewArticlesSwitch.isOn = !notifyAboutNewArticlesSwitch.isOn + present(notificationUpdateErrorAlert(), animated: true, completion: nil) + } else if settings.authorizationStatus == .authorized { + webFeed.isNotifyAboutNewArticles = notifyAboutNewArticlesSwitch.isOn + } else { + UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .sound, .alert]) { (granted, error) in + self.updateNotificationSettings() + if granted { + DispatchQueue.main.async { + self.webFeed.isNotifyAboutNewArticles = self.notifyAboutNewArticlesSwitch.isOn + UIApplication.shared.registerForRemoteNotifications() + } + } else { + DispatchQueue.main.async { + self.notifyAboutNewArticlesSwitch.isOn = !self.notifyAboutNewArticlesSwitch.isOn + } + } + } + } } @IBAction func alwaysShowReaderViewChanged(_ sender: Any) { @@ -158,3 +192,32 @@ extension WebFeedInspectorViewController: UITextFieldDelegate { } } + +// MARK: UNUserNotificationCenter + +extension WebFeedInspectorViewController { + + func updateNotificationSettings() { + UNUserNotificationCenter.current().getNotificationSettings { (settings) in + DispatchQueue.main.async { + self.userNotificationSettings = settings + if settings.authorizationStatus == .authorized { + UIApplication.shared.registerForRemoteNotifications() + } + } + } + } + + func notificationUpdateErrorAlert() -> UIAlertController { + let alert = UIAlertController(title: NSLocalizedString("Enable Notifications", comment: "Notifications"), + message: NSLocalizedString("Notifications need to be enabled in the Settings app.", comment: "Notifications need to be enabled in the Settings app."), preferredStyle: .alert) + let openSettings = UIAlertAction(title: NSLocalizedString("Open Settings", comment: "Open Settings"), style: .default) { (action) in + UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly : false], completionHandler: nil) + } + let dismiss = UIAlertAction(title: NSLocalizedString("Dismiss", comment: "Dismiss"), style: .cancel, handler: nil) + alert.addAction(openSettings) + alert.addAction(dismiss) + return alert + } + +}