Skip to content
This repository has been archived by the owner on Feb 27, 2019. It is now read-only.

Swift3 UserNotifications support #191

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions PermissionScope-example/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,7 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSContactsUsageDescription</key>
<string>Explanation why you need contacts access on iOS 10</string>
</dict>
</plist>
118 changes: 89 additions & 29 deletions PermissionScope/PermissionScope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import EventKit
import CoreBluetooth
import CoreMotion
import Contacts
import UserNotifications

public typealias statusRequestClosure = (_ status: PermissionStatus) -> Void
public typealias authClosureType = (_ finished: Bool, _ results: [PermissionResult]) -> Void
Expand Down Expand Up @@ -82,6 +83,9 @@ typealias resultsForConfigClosure = ([PermissionResult]) -> Void

/// Default status for Core Motion Activity
var motionPermissionStatus: PermissionStatus = .unknown

/// Default status for Notifications
var notificationsPermissionStatus: PermissionStatus = .unknown

// MARK: - Internal state and resolution

Expand Down Expand Up @@ -201,6 +205,7 @@ typealias resultsForConfigClosure = ([PermissionResult]) -> Void
contentView.addSubview(closeButton)

_ = self.statusMotion() //Added to check motion status on load
_ = self.statusNotifications() // Added to check Notifications status on load
}

/**
Expand Down Expand Up @@ -311,6 +316,8 @@ typealias resultsForConfigClosure = ([PermissionResult]) -> Void
triggerBluetoothStatusUpdate()
} else if permission.type == .motion && askedMotion {
triggerMotionStatusUpdate()
} else if permission.type == .notifications && askedNotifications {
triggerNotificationStatusUpdate()
}
}

Expand Down Expand Up @@ -547,16 +554,10 @@ typealias resultsForConfigClosure = ([PermissionResult]) -> Void
- returns: Permission status for the requested type.
*/
public func statusNotifications() -> PermissionStatus {
let settings = UIApplication.shared.currentUserNotificationSettings
if let settingTypes = settings?.types , settingTypes != UIUserNotificationType() {
return .authorized
} else {
if defaults.bool(forKey: Constants.NSUserDefaultsKeys.requestedNotifications) {
return .unauthorized
} else {
return .unknown
}
if askedNotifications {
triggerNotificationStatusUpdate()
}
return notificationsPermissionStatus
}

/**
Expand Down Expand Up @@ -632,27 +633,87 @@ typealias resultsForConfigClosure = ([PermissionResult]) -> Void
let status = statusNotifications()
switch status {
case .unknown:
let notificationsPermission = self.configuredPermissions
.first { $0 is NotificationsPermission } as? NotificationsPermission
let notificationsPermissionSet = notificationsPermission?.notificationCategories

NotificationCenter.default.addObserver(self, selector: #selector(showingNotificationPermission), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)

notificationTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(finishedShowingNotificationPermission), userInfo: nil, repeats: false)

UIApplication.shared.registerUserNotificationSettings(
UIUserNotificationSettings(types: [.alert, .sound, .badge],
categories: notificationsPermissionSet)
)
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound], completionHandler: { (success, error) in
self.triggerNotificationStatusUpdate()
})
} else {
NotificationCenter.default.addObserver(self, selector: #selector(self.showingNotificationPermission), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)

self.notificationTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.finishedShowingNotificationPermission), userInfo: nil, repeats: false)

let notificationsPermission = self.configuredPermissions
.first { $0 is NotificationsPermission } as? NotificationsPermission
let notificationsPermissionSet = notificationsPermission?.notificationCategories
UIApplication.shared.registerUserNotificationSettings(
UIUserNotificationSettings(types: [.alert, .sound, .badge],
categories: notificationsPermissionSet))
}
return
case .unauthorized:
showDeniedAlert(.notifications)
self.showDeniedAlert(.notifications)
case .disabled:
showDisabledAlert(.notifications)
self.showDisabledAlert(.notifications)
case .authorized:
detectAndCallback()
self.detectAndCallback()
}
}

/**
Gets the Notifications status.
*/
fileprivate func triggerNotificationStatusUpdate() {
let tmpNotificationPermissionStatus = notificationsPermissionStatus

if #available(iOS 10.0, *) {
askedNotifications = true
waitingForNotification = true
defaults.set(true, forKey: Constants.NSUserDefaultsKeys.requestedNotifications)
defaults.synchronize()
UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { (settings) in
if settings.authorizationStatus == .authorized {
self.notificationsPermissionStatus = .authorized
} else if settings.authorizationStatus == .denied {
self.notificationsPermissionStatus = .unauthorized
} else if settings.authorizationStatus == .notDetermined {
self.notificationsPermissionStatus = .unknown
}
self.waitingForNotification = false
if tmpNotificationPermissionStatus != self.notificationsPermissionStatus {
self.detectAndCallback()
}
})
} else {
// Fallback on earlier versions
let settings = UIApplication.shared.currentUserNotificationSettings
if let settingTypes = settings?.types , settingTypes != UIUserNotificationType() {
self.notificationsPermissionStatus = .authorized
} else {
if defaults.bool(forKey: Constants.NSUserDefaultsKeys.requestedNotifications) {
self.notificationsPermissionStatus = .unauthorized
} else {
self.notificationsPermissionStatus = .unknown
}
self.waitingForNotification = false
self.detectAndCallback()
}
}
}

/// Returns whether Notification access was asked before or not.
fileprivate var askedNotifications:Bool {
get {
return defaults.bool(forKey: Constants.NSUserDefaultsKeys.requestedNotifications)
}
set {
defaults.set(newValue, forKey: Constants.NSUserDefaultsKeys.requestedNotifications)
defaults.synchronize()
}
}

/// Returns whether PermissionScope is waiting for the user to enable/disable Notification access or not.
fileprivate var waitingForNotification = false

// MARK: Microphone

/**
Expand Down Expand Up @@ -1003,7 +1064,7 @@ typealias resultsForConfigClosure = ([PermissionResult]) -> Void
onCancel = cancelled

DispatchQueue.main.async {
while self.waitingForBluetooth || self.waitingForMotion { }
while self.waitingForBluetooth || self.waitingForMotion || self.waitingForNotification { }
// call other methods that need to wait before show
// no missing required perms? callback and do nothing
self.requiredAuthorized({ areAuthorized in
Expand Down Expand Up @@ -1217,7 +1278,7 @@ typealias resultsForConfigClosure = ([PermissionResult]) -> Void
- parameter type: Permission type to be requested
- parameter completion: Closure called when the request is done.
*/
func statusForPermission(_ type: PermissionType, completion: statusRequestClosure) {
func statusForPermission(_ type: PermissionType, completion: @escaping statusRequestClosure) {
// Get permission status
let permissionStatus: PermissionStatus
switch type {
Expand All @@ -1227,10 +1288,10 @@ typealias resultsForConfigClosure = ([PermissionResult]) -> Void
permissionStatus = statusLocationInUse()
case .contacts:
permissionStatus = statusContacts()
case .notifications:
permissionStatus = statusNotifications()
case .microphone:
permissionStatus = statusMicrophone()
case .notifications:
permissionStatus = statusNotifications()
case .camera:
permissionStatus = statusCamera()
case .photos:
Expand All @@ -1244,7 +1305,6 @@ typealias resultsForConfigClosure = ([PermissionResult]) -> Void
case .motion:
permissionStatus = statusMotion()
}

// Perform completion
completion(permissionStatus)
}
Expand Down