天天看点

iOS远程推送(Objective-C & Swift)

iOS远程推送

iOS远程推送(Objective-C & Swift)

APNS远程推送的流程:

1、app 注册到 APNS。

2、APNS 下发 devicetoken 给 app。

3、app 将 device token 发送给 app Server。

4、app Serve 将[消息+device token]发送给 APNS。

5、APNS 根据 device token 推送消息给iOS设备上的app。

实现上述步骤需要一个前提:应用程序的推送证书(开发环境&生产环境两类推送证书)和描述文件(Provisioning Profile)配置完备。苹果会在推送前根据描述文件和 App ID 等信息对应用程序的合法性进行验证。`

Objective-C相关代码

//推送相关逻辑
@interface AppDelegate (AppPush)<UNUserNotificationCenterDelegate>

- (void)registerRemoteNotifications:(UIApplication *)application;

@end

@implementation AppDelegate (AppPush)

- (void)registerRemoteNotifications:(UIApplication *)application {
    
    if (@available(iOS 10, *)) {
        UNUserNotificationCenter *notificationCenter = [UNUserNotificationCenter currentNotificationCenter];
        notificationCenter.delegate = self;
        // 申请权限
        [notificationCenter requestAuthorizationWithOptions:UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound completionHandler:^(BOOL granted, NSError * _Nullable error) {
            NSLog(@"申请权限granted = %d", granted);
            if (!error && granted) {
                NSLog(@"远程通知注册成功");
            } else {
                NSLog(@"远程通知注册失败error-%@", error);
            }
        }];
        
        // 获取权限设置 可以获取到用户设定通知的信息
        [notificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
            NSLog(@"settings = %@", settings);
        }];
        
    } else if ([[UIDevice currentDevice] systemVersion].floatValue >= 8.0) {
        [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge categories:nil]];
    }
    
    // 注册远程通知,获得device Token
    [[UIApplication sharedApplication] registerForRemoteNotifications];
    
}

#pragma mark - <UIApplicationDelegate>
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    // 将devicetoken发送给服务端
    NSUInteger length = deviceToken.length;
    const unsigned char *buffer = deviceToken.bytes;
    NSMutableString *token  = [NSMutableString stringWithCapacity:(length * 2)];
    for (int i = 0; i < length; ++i) {
      [token appendFormat:@"%02x", buffer[i]];
    }
    [kUserDefaults setObject:token forKey:kApp_DeviceToken];
    [kUserDefaults synchronize];
    NSLog(@"token = %@ ", token);
}

// 适配iOS10之前系统
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    NSLog(@"didReceiveRemoteNotification-userInfo = %@",userInfo);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    completionHandler(UIBackgroundFetchResultNewData);
    if (application.applicationState == UIApplicationStateActive) {
        NSLog(@"点击推送唤起app userInfo = %@", userInfo);
    } else {
        NSLog(@"前台收到推送 userInfo = %@", userInfo);
    }
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"didFailToRegisterForRemoteNotificationsWithError-error = %@",error);
}

#pragma mark - <UNUserNotificationCenterDelegate>
// app在前台收到通知时触发
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler  API_AVAILABLE(ios(10.0)){
    // 前台收到推送,也是可以跟后台收到推送一样,弹出横幅,播放声音并震动的。这要在completionHandler中传入相应的UNNotificationPresentationOptions
    completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound |UNNotificationPresentationOptionAlert);
}

// 当用户点击通知时,会触发
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler  API_AVAILABLE(ios(10.0)){
    completionHandler();  // 系统要求执行这个方法
}

#pragma mark - <private method>


@end
           

Swift相关代码

extension AppDelegate {
    
    // MARK: - 注册远程推送
    func registerRemoteNotifications(with application: UIApplication) {
        
        let notificationCenter = UNUserNotificationCenter.current()
        notificationCenter.requestAuthorization(options: [.alert,.badge,.sound]) { (isGrand, error) in
            DispatchQueue.main.async {
                if error != nil && isGrand {
                    print("用户允许了推送权限")
                }else{
                    print("用户拒绝了推送权限")
                }
            }
        }
        
        // 适配iOS10以前的设备
        UIApplication.shared.registerUserNotificationSettings(.init(types:[.alert,.badge,.sound], categories:nil))
        
        // 注册远程通知,获得device Token
        UIApplication.shared.registerForRemoteNotifications()
    }
    
    // MARK: iOS10以前的设备 registerUserNotificationSettings会触发notificationSettings
    func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {
        if notificationSettings.types.isEmpty {
                print("用户拒绝了推送权限")
        }else{
                print("用户允许了推送权限")
        }
    }
    
    
    // MARK: - <UIApplicationDelegate>
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        // 将devicetoken发送给服务端
        let deviceTokenString = deviceToken.reduce("",{$0 + String(format:"%02x",$1)})
    }
    
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("didFailToRegisterForRemoteNotificationsWithError-error = \(error)")
    }
    // MARK: - 收到推送
    // 适配iOS10之前系统
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
        if application.applicationState == .inactive {
            print("点击推送唤起app userInfo=\(userInfo)")
        }else{
            print("前台收到推送 userInfo=\(userInfo)")
        }
    }
    
    
    // MARK: <UNUserNotificationCenterDelegate>
    // MARK: app在前台收到通知时触发
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        // 前台收到推送,也是可以跟后台收到推送一样,弹出横幅,播放声音并震动的。这要在completionHandler中传入相应的UNNotificationPresentationOptions
        completionHandler([.sound,.alert])
    }
    // MARK: 当用户点击通知时,会触发
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        //handleUserResponse(userInfo:userInfo)
        // 系统要求执行这个方法
        completionHandler()
    }
    
}

// MARK: -  如果app已经被杀死,那么app会被重新启动,我们需要在app加载完成后处理用户的响应。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    if let removePushUserInfo = launchOptions?[UIApplication.LaunchOptionsKey.remoteNotification]{
    	// 处理用户收到推送后的响应
   NotificationUtil.shared.handleUserResponse(userInfo:removePushUserInfo as! [AnyHashable:Any])
    }
    return true
}