我的问题是我想显示初始推送通知提示的加载屏幕“该应用想要向您发送推送通知。”
因此,如果用户点击yes
,我可以继续使用随后调用的委托方法启动应用程序:
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
[self hideLoadingScreen];
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
[self hideLoadingScreen];
}
但是,如果用户点击no
,则不会调用这些方法,这是有道理的。我的问题是,是否有一个不同的委托方法,如果他拒绝会被解雇?
我的问题是如果选择no
,加载屏幕永远不会消失。所以我需要知道用户何时完成选择。
答案 0 :(得分:31)
在iOS 7中,当系统的推送通知提示出现时,应用程序变为非活动状态,并且UIApplicationWillResignActiveNotification将触发。类似地,当用户响应提示时(按“是”或“否”),应用程序再次变为活动状态,并且UIApplicationDidBecomeActiveNotification将触发。
因此,您可以收听此通知,然后隐藏加载屏幕。
注意:显示提示时,“主页”按钮,“通知中心”和“控制中心”将被禁用,因此无法触发误报UIApplicationDidBecomeActiveNotification。但是,如果用户按下“锁定”按钮,则会触发UIApplicationDidBecomeActiveNotification。
答案 1 :(得分:6)
您始终可以从以下位置获取当前允许的通知类型:
UIRemoteNotificationType notificationTypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
请注意,用户还可以在手机设置中停用通知。
如果你在didRegisterForRemoteNotificationsWithDeviceToken上检查,你应该看看你要求的类型是否已启用。
答案 2 :(得分:2)
你不能做以下事情:
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
BOOL pushEnabled = notificationSettings.types & UIUserNotificationTypeAlert;
}
此方法应该是对该推送通知提示的回调,并且从那里,您可以检查位掩码以查看是否启用了推送通知。
答案 3 :(得分:2)
以下是我在Swift 3中的表现。这里的关键是在内部跟踪应用程序的生命周期状态。显示推送提示时,应用程序将重新激活,但不会进入后台。这都在我的AppDelegate.swift中。
这是一个非常大的黑客,不建议在生产中使用。 Apple可以改变这些警报的呈现方式,这可能会随时中断。这是使用运行iOS 9和10的各种iPhone和iPad进行测试的。
/// An internal value used to track application lifecycle state
enum ApplicationLifecycleState {
case willResignActive
case didEnterBackground
case willEnterForeground
case didBecomeActive
case unknown
}
/// This is used purely for tracking the application lifecycle for handling the system push notification alert
var internalLifecycleState: ApplicationLifecycleState = .unknown {
didSet {
// If we're not in the middle of asking for push permissions, none of the below applies, just bail out here
if !isAskingForPushPermissions { return }
// WARNING: Application lifecycle trickery ahead
// The normal application lifecycle calls for backgrounding are as follows:
// applicationWillResignActive -> applicationDidEnterBackground -> applicationWillEnterForeground -> applicationDidBecomeActive
// However, when the system push notification alert is presented, the application resigns active, but does not enter the background:
// applicationWillResignActive -> [user taps on alert] -> applicationDidBecomeActive
// We can use this discrepancy to our advantage to detect if the user did not allow push permissions
// If applicationDidBecomeActive
// AND the previous state was applicationWillResignActive
// AND the notification types bitmask is 0, we know that the user did not allow push permissions
// User denied permissions
if internalLifecycleState == .didBecomeActive
&& oldValue == .willResignActive
&& UIApplication.shared.currentUserNotificationSettings?.types.rawValue == 0 {
// We're done
firePushCompletionBlockAndCleanup(registered: false)
} else {
// The state below can only be entered on iOS 10 devices.
// If the user backgrounds the app while the system alert is being shown,
// when the app is foregrounded the alert will dismiss itself without user interaction.
// This is the equivalent of the user denying push permissions.
// On iOS versions below 10, the user cannot background the app while a system alert is being shown.
if #available(iOS 10, *), internalLifecycleState == .didBecomeActive {
firePushCompletionBlockAndCleanup(registered: false)
}
}
}
}
/// Used internally to track if the system push notification alert is currently being presented
var isAskingForPushPermissions = false
typealias PushNotificationRegistrationCompletionBlock = ((_ registered: Bool) -> Void)
// ...
func applicationWillResignActive(_ application: UIApplication) {
internalLifecycleState = .willResignActive
}
func applicationDidEnterBackground(_ application: UIApplication) {
internalLifecycleState = .didEnterBackground
}
func applicationWillEnterForeground(_ application: UIApplication) {
internalLifecycleState = .willEnterForeground
}
func applicationDidBecomeActive(_ application: UIApplication) {
internalLifecycleState = .didBecomeActive
}
// ...
func setupPushNotifications(_ application: UIApplication = UIApplication.shared, completion: @escaping PushNotificationRegistrationCompletionBlock) {
isAskingForPushPermissions = true
pushCompletionBlock = completion
let settings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
}
fileprivate func firePushCompletionBlockAndCleanup(registered: Bool) {
pushCompletionBlock?(registered)
pushCompletionBlock = nil
isAskingForPushPermissions = false
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// application:didRegisterForRemoteNotificationsWithDeviceToken may be called more than once (once for each notification type)
// By checking that the notification types bitmask is greater than 0, we can find the final time this is called (after the user actually tapped "allow")
// If the user denied push permissions, this function is never called with a positive notification type bitmask value
if UIApplication.shared.currentUserNotificationSettings?.types.rawValue ?? 0 > 0 {
firePushCompletionBlockAndCleanup(registered: true)
}
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register for notifications with error: " + error.localizedDescription)
firePushCompletionBlockAndCleanup(registered: false)
}
用法:
appDelegate.setupPushNotifications(completion: { [weak self] (registered) in
// If registered is false, the user denied permissions
})
答案 4 :(得分:2)
由于UserNotifications框架和iOS 10,您可以轻松获得以下数据:
let center = UNUserNotificationCenter.current()
// Request permission to display alerts and play sounds.
center.requestAuthorization(options: [.alert, .sound])
{ (granted, error) in
// Enable or disable features based on authorization.
}
答案 5 :(得分:1)
Swift 3 和 Swift 4.0
使用NotificationCenter和AppDelegate方法didRegister notificationSettings
。 NotificationSettings显示用户是否选择了徽章,声音等,如果拒绝推送通知则会显示为空数组。当用户响应推送通知提示并且似乎是大多数开发人员使用时,它会被特别触发,因为它比检查didBecomeActive更具体。但苹果可能会改变这一点。谁知道?
不幸的是,NotificationCenter没有预设的通知名称,因此您必须设置和扩展(请参阅结束)或使用原始值(SO有更多内容)。
在AppDelegate中:
func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {
// if not registered users will have an empty set of settings
let accepted: Bool = !notificationSettings.types.isEmpty
NotificationCenter.default.post(name: Notification.Name(rawValue: "didRespondToPrompt"), object: self, userInfo: ["didAccept" : accepted])
}
然后观察您需要的位置,例如在视图控制器中:
class MyViewController: UIViewController {
//MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.didRespondToPushPrompt(_:)), name: NSNotification.Name(rawValue: "didRespondToPrompt"), object: nil)
}
@objc func didRespondToPushPrompt(_ notification: Notification) {
if let userInfo: [AnyHashable : Any] = notification.userInfo, let didAccept: Bool = userInfo[NSNotificationKeyNames.didAccept] as? Bool, !didAccept {
//if user doesn't accept, do this...
} else {
//all other situations code goes here
}
}
}
一些事情:首先,对于Swift 4.0,我在一个方法前使用“@objc”,但Swift 3没有必要。
另外,对于使用NotificationCenter,实际上我没有使用“rawValue”。相反,我做了一个像这样的扩展:
import Foundation
extension NSNotification.Name {
static let DidRegisterForPushNotifications = NSNotification.Name("DidRegisterForPushNotifications")
}
我可以这样使用:
NotificationCenter.default.post(name: Notification.Name.DidRegisterForPushNotifications, object: self, userInfo: ["didAccept" : myBool])
等等。
答案 6 :(得分:0)
我想你可以在你的AppDelegate中有一个BOOL变量来检查它,因为除了使用外部API之外似乎没办法。请参阅this。
AppDelegate.m
// declare a BOOL
BOOL allow = NO;
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
allow = YES;
[self hideLoadingScreen];
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
allow = YES;
[self hiedLoadingScreen];
}
现在我想你可以访问这个BOOL变量来区分何时不按下。
答案 7 :(得分:0)
这是一个 SWIFT 2 代码示例,对你们来说......这有点复杂,但我希望我的评论可以帮助你理解它。
定义变量
var appDidBecomeActiveCount = 0
var userDefaults:NSUserDefaults!
AppDelegate - didFinishLaunchingWithOptions
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
userDefaults = NSUserDefaults.standardUserDefaults()
if userDefaults.valueForKey("FirstLaunche") == nil {
userDefaults.setBool(true, forKey: "FirstLaunche")
userDefaults.synchronize()
}
// Register for notification
//iOS 8+
let settings:UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [UIUserNotificationType.Alert , UIUserNotificationType.Badge ,UIUserNotificationType.Sound], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
}
AppDelegate - applicationDidBecomeActive
func applicationDidBecomeActive(application: UIApplication) {
//Delay until alert get dismissed and notification type setted in app
delay(0.5, closure: { () -> () in
self.checkTheDilemma()
})
}
//I love this short method <3_<3
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
检查操作
func checkTheDilemma (){
//Checking if this user turned off push notifications or didn't allow it at all
let notificationType = UIApplication.sharedApplication().currentUserNotificationSettings()?.types
if userDefaults.valueForKey("FirstLaunche") as! Bool == true {
//User now is asked for notification permission because it's app's first launche
// if appDidBecomeActiveCount == 0 --> Pop up message will appeare
// if appDidBecomeActiveCount == 1 --> Pop up message dismissed
// if notificationType?.rawValue == 0 --> Notifications off
// if notificationType?.rawValue > 0 --> Notifications on
if notificationType?.rawValue == 0
&& appDidBecomeActiveCount == 1 { //If user disabled notifications from pop up alert
// ** User just tapped "Don't allow" btn :\
// Do what ever you are here for
//Now set FirstLaunche = false
userDefaults.setBool(false, forKey: "FirstLaunche")
userDefaults.synchronize()
}
} else {
if notificationType?.rawValue == 0
&& appDidBecomeActiveCount == 0 { // This guy is not registered for push notification
// ** User disabled notifications in past (because this is not his first launch)
}
}
appDidBecomeActiveCount++
}
答案 8 :(得分:0)
您可以通过查看didRegisterUserNotificationSettings
来检测用户是否已在registerForRemoteNotificationTypes
方法中取消了通知提示,该方法在致电notificationSettings.types
后触发。
如果您请求了许多设置,但notificationSettings.types == UIUserNotificationTypeNone
表示该用户已取消提示。
但不要忘记现在已弃用registerForRemoteNotificationTypes
方法!
答案 9 :(得分:0)
2019年5月2日
这是检查通知是否在您的应用程序中的任何时间得到实现的实现,只需调用此函数即可。
private func checkNotificationsAuthorizationStatus() {
let userNotificationCenter = UNUserNotificationCenter.current()
userNotificationCenter.getNotificationSettings { (notificationSettings) in
switch notificationSettings.authorizationStatus {
case .authorized:
print("The app is authorized to schedule or receive notifications.")
case .denied:
print("The app isn't authorized to schedule or receive notifications.")
case .notDetermined:
print("The user hasn't yet made a choice about whether the app is allowed to schedule notifications.")
case .provisional:
print("The application is provisionally authorized to post noninterruptive user notifications.")
}
}
}
答案 10 :(得分:0)
从iOS 13开始使用C#Xamarin的好方法
我将其放在计时器上提示并检查授权状态的页面上
可能可以获取实际的回调,但是这种方式对我有用
using System.Timers;
Timer notificationsPermissionTimer = new Timer();
public override void ViewDidLoad()
{
SetupNotificationsPermissionTimer();
base.ViewDidLoad();
}
public override void ViewWillDisappear(bool animated)
{
this.notificationsPermissionTimer.Elapsed -= NotificationsPermissionTimer_Elapsed;
base.ViewWillDisappear(animated);
}
private void SetUpNotificationsPermissionTimer()
{
this.notificationsPermissionTimer = new Timer();
this.notificationsPermissionTimer.Interval = 500;
this.notificationsPermissionTimer.Start();
this.notificationsPermissionTimer.Elapsed += NotificationsPermissionTimer_Elapsed;
}
private void NotificationsPermissionTimer_Elapsed(object sender, ElapsedEventArgs e)
{
Task.Run(CheckNotificationsAuthorizationStatus);
}
private async Task CheckNotificationsAuthorizationStatus()
{
var userNotificationCenter = await UNUserNotificationCenter.Current.GetNotificationSettingsAsync();
switch(userNotificationCenter.AuthorizationStatus)
{
case UNAuthorizationStatus.Authorized:
// Do Something
break;
case UNAuthorizationStatus.Denied:
// Do Something
break;
case UNAuthorizationStatus.NotDetermined:
// Do Nothing
break;
case UNAuthorizationStatus.Provisional:
break;
}
}