如何在任意UIViewController中调用UIUserNotificationSettings注册通知?
当然可以把远程推送的注册逻辑移到UIViewController的按钮点击事件里,下面是具体的实现思路和代码示例,完全适配你的需求:
实现思路与步骤
1. 在UIViewController中触发推送注册
因为UIApplication是全局单例,所以在VC里直接通过[UIApplication sharedApplication]就能调用注册方法,和你在AppDelegate里的逻辑几乎一致,只是触发时机改成按钮点击。
给按钮绑定点击事件后,实现如下代码:
- (IBAction)registerPushNotification:(UIButton *)sender { UIApplication *app = [UIApplication sharedApplication]; UIUserNotificationSettings *currentSettings = [app currentUserNotificationSettings]; // 先判断当前是否已有通知权限,避免重复弹权限弹窗 if (currentSettings.types == UIUserNotificationTypeNone) { // 请求通知权限 UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil]; [app registerUserNotificationSettings:settings]; [app registerForRemoteNotifications]; } else { // 已有权限,可选择重新注册device token(比如用户之前取消后又开启) [app registerForRemoteNotifications]; NSLog(@"已经拥有通知权限,重新注册device token"); } }
2. 把AppDelegate的回调传递到VC
系统的推送回调(比如获取deviceToken、接收通知)还是会默认发到AppDelegate,所以得把这些信息传递到你的VC里,这里推荐两种常用方式:
方式一:用NSNotificationCenter转发(推荐)
这是低耦合的方案,在AppDelegate的回调里发送通知,VC里监听即可:
第一步:修改AppDelegate的回调方法
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // 发送通知传递deviceToken [[NSNotificationCenter defaultCenter] postNotificationName:@"PushDeviceTokenRegistered" object:deviceToken]; } - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { NSLog(@"Register Remote Notifications error:{%@}",[error localizedDescription]); // 转发注册失败的错误信息 [[NSNotificationCenter defaultCenter] postNotificationName:@"PushRegisterFailed" object:error]; } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { NSLog(@"Receive remote notification : %@",userInfo); // 转发收到的通知内容 [[NSNotificationCenter defaultCenter] postNotificationName:@"PushNotificationReceived" object:userInfo]; }
第二步:在VC里监听并处理通知
在viewDidLoad里添加监听,记得在dealloc里移除,避免内存泄漏:
- (void)viewDidLoad { [super viewDidLoad]; // 注册通知监听 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeviceTokenReceived:) name:@"PushDeviceTokenRegistered" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePushRegisterFailed:) name:@"PushRegisterFailed" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePushNotificationArrived:) name:@"PushNotificationReceived" object:nil]; } // 处理deviceToken获取成功 - (void)handleDeviceTokenReceived:(NSNotification *)notification { NSData *deviceToken = notification.object; // 这里可以把deviceToken上传到你的服务器 NSLog(@"VC中拿到deviceToken: %@", deviceToken); } // 处理注册失败 - (void)handlePushRegisterFailed:(NSNotification *)notification { NSError *error = notification.object; NSLog(@"VC中收到注册失败提示: %@", error.localizedDescription); // 可以给用户弹个提示框告知失败原因 } // 处理收到远程通知 - (void)handlePushNotificationArrived:(NSNotification *)notification { NSDictionary *userInfo = notification.object; NSLog(@"VC中收到远程通知内容: %@", userInfo); // 在这里处理通知展示逻辑,比如弹Alert或者更新UI } - (void)dealloc { // 移除所有监听 [[NSNotificationCenter defaultCenter] removeObserver:self]; }
方式二:直接持有VC引用(不推荐)
如果你的VC是全局唯一的(比如根VC),可以在AppDelegate里直接持有它的指针,然后调用VC的对应方法。但这种方式会增加代码耦合,项目复杂时容易出问题,所以不建议使用。
3. 额外注意事项
- 确保
Info.plist里配置了推送相关权限:如果需要后台推送,要在UIBackgroundModes里添加remote-notification; - 你的代码是基于iOS 8-9的旧API,iOS 10及以后推荐使用
UNUserNotificationCenter框架,如果你需要兼容高版本,可以做版本适配; - 重复请求权限会被系统限制,所以先检查当前权限状态再请求是很有必要的。
内容的提问来源于stack exchange,提问作者user2688045
相关产品推荐
相关产品推荐

