在簡單項目中,有使用到apns推送服務,許多文章有涉及到卻沒有講清楚。最近做福路通項目,有使用到,做一個總結。
推送步驟為注冊推送,接收推送進行處理,推送的類型分為1.程序運行時推送 2.程序未運行時推送。
1.注冊推送,分為IOS8.0以下,IOS8.0以上IOS10.0以下,IOS10.0以上版本;在didRegisterForRemoteNotificationsWithDeviceToken方法中獲取到deviceToken
1.程序運行時推送,又分為IOS7.0以下,IOS7.0以上IOS10.0以下,IOS10.0以上版本
2.程序未運行推送,在appdelegate中進行didFinishLaunchingWithOptions方法中進行處理
1.注冊推送
在didFinishLaunchingWithOptions中注冊
[self registerRemoteNotification];
注冊方法:
#pragma mark 推送->注冊
- (void)registerRemoteNotification
{
#ifdef __IPHONE_8_0
if([SYSTEM_VERSION floatValue]>=10.0){
//iOS10特有
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
// 必須寫代理,不然無法監聽通知的接收與點擊
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
// 點擊允許
NSLog(@"注冊成功");
} else {
// 點擊不允許
NSLog(@"注冊失敗");
}
}];
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
NSLog(@"========%@",settings);
}];
}
else if ([SYSTEM_VERSION floatValue] >= 8.0) {
UIUserNotificationSettings *uns = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound) categories:nil];
//? ? ? ? [[UIApplication sharedApplication] registerForRemoteNotifications];
[[UIApplication sharedApplication] registerUserNotificationSettings:uns];
} else {
UIRemoteNotificationType apn_type = (UIRemoteNotificationType)(UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeBadge);
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:apn_type];
}
// 注冊獲得device Token
[[UIApplication sharedApplication] registerForRemoteNotifications];
#else
UIRemoteNotificationType apn_type = (UIRemoteNotificationType)(UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeBadge);
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:apn_type];
#endif
[[UIApplication sharedApplication] cancelAllLocalNotifications];
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
}
獲取deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
_cid = [NSString stringWithFormat:@"%@", deviceToken];
//獲取終端設備標識,這個標識需要通過接口發送到服務器端,服務器端推送消息到APNS時需要知道終端的標識,APNS通過注冊的終端標識找到終端設備。
NSLog(@"My token is:%@", _cid);
}
2. 推送接收和點擊跳轉
//處理收到的消息推送->iOS版本7.0后
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler{
//在此處理接收到的消息。
NSLog(@"Receive remote notification : %@",userInfo);
//當APP在前臺運行時
if( [UIApplication sharedApplication].applicationState == UIApplicationStateActive)
{
//前臺無法顯示遠程推送,所以添加了本地推送
[self addLocalNotification:userInfo];
}
//當APP在后臺運行時,當有通知欄消息時
else if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive)
{
NSLog(@"通知后臺測試");
[self jumpToBillInfo:userInfo];
}
else{
}
}
// iOS 10收到通知->前臺
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
NSDictionary * userInfo = notification.request.content.userInfo;
if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
NSLog(@"iOS10 前臺收到遠程通知:");
}
else {
// 判斷為本地通知
NSLog(@"iOS10 前臺收到本地通知:{\\\\nbody:%@,\\\\ntitle:%@,\\\\nsubtitle:%@,\\\\nbadge:%@,\\\\nsound:%@,\\\\nuserInfo:%@\\\\n}",body,title,subtitle,badge,sound,userInfo);
}
completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert); // 需要執行這個方法,選擇是否提醒用戶,有Badge、Sound、Alert三種類型可以設置
}
// iOS 10通知的點擊事件->前臺、后臺
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
NSDictionary * userInfo = response.notification.request.content.userInfo;
UNNotificationRequest *request = response.notification.request; // 收到推送的請求
UNNotificationContent *content = request.content; // 收到推送的消息內容
NSNumber *badge = content.badge;? // 推送消息的角標
NSString *body = content.body;? ? // 推送消息體
UNNotificationSound *sound = content.sound;? // 推送消息的聲音
NSString *subtitle = content.subtitle;? // 推送消息的副標題
NSString *title = content.title;? // 推送消息的標題
if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
NSLog(@"iOS10 收到遠程通知:");
[self jumpToBillInfo:userInfo];
}
else {
// 判斷為本地通知
NSLog(@"iOS10 收到本地通知:{\\\\nbody:%@,\\\\ntitle:%@,\\\\nsubtitle:%@,\\\\nbadge:%@,\\\\nsound:%@,\\\\nuserInfo:%@\\\\n}",body,title,subtitle,badge,sound,userInfo);
[self jumpToBillInfo:userInfo];
}
completionHandler();? // 系統要求執行這個方法
}
3.發送本地通知
//發布本地通知
-(void)addLocalNotification:(NSDictionary*)userInfo{
//定義本地通知對象
UILocalNotification *notification=[[UILocalNotification alloc]init];
//設置調用時間
notification.fireDate=[NSDate dateWithTimeIntervalSinceNow:5];//通知觸發的時間,10s以后
//? ? notification.repeatInterval=2;//通知重復次數
notification.repeatCalendar=[NSCalendar currentCalendar];//當前日歷,使用前最好設置時區等信息以便能夠自動同步時間
//設置通知屬性
notification.alertBody=[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]; //通知主體
notification.applicationIconBadgeNumber=1;//應用程序圖標右上角顯示的消息數
notification.alertAction=@"打開應用"; //待機界面的滑動動作提示
notification.alertLaunchImage=@"Default";//通過點擊通知打開應用時的啟動圖片,這里使用程序啟動圖片
notification.soundName=UILocalNotificationDefaultSoundName;//收到通知時播放的聲音,默認消息聲音
//? ? notification.soundName=@"msg.caf";//通知聲音(需要真機才能聽到聲音)
//設置用戶信息
notification.userInfo=userInfo;//綁定到通知上的其他附加信息
//調用通知
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
4.app未打開時,在didFinishLaunchingWithOptions中寫入:[self jumpViewController:launchOptions];
/**
當APP沒有打開時,跳轉
@param dic
*/
-(void)jumpViewController:(NSDictionary *)dic{
NSDictionary *remoteNotification = [dic objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(remoteNotification){
_isLaunchedByNotification = YES;
[self jumpToBillInfo:remoteNotification];
}
}
5.點擊通知跳轉ViewController
//跳轉到BillInfoController頁面
-(void)jumpToBillInfo:(NSDictionary*)userInfo{
//讀取userNO和loginToken
NSString *userNO = [NSUserDefaultsUtils readUserDataWithKey:KEY_USERNO];
NSString *loginToken = [NSUserDefaultsUtils readUserDataWithKey:KEY_LOGIN_TOKEN];
if(![FormatUtils isNull:userNO]&&![FormatUtils isNull:loginToken]&&userInfo)
{
BillInfoController *_viewController =? [[BillInfoController alloc]init];
_viewController.extras = @{@"platformNo":[userInfo objectForKey:@"PLNO"],@"ordType":[userInfo objectForKey:@"ORDTYPE"]};
UIViewController *result = nil;
UIWindow * window = [[UIApplication sharedApplication] keyWindow];
//app默認windowLevel是UIWindowLevelNormal,如果不是,找到UIWindowLevelNormal的
if (window.windowLevel != UIWindowLevelNormal)
{
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow * tmpWin in windows)
{
if (tmpWin.windowLevel == UIWindowLevelNormal)
{
window = tmpWin;
break;
}
}
}
id? nextResponder = nil;
UIViewController *appRootVC=window.rootViewController;
//? ? 如果是present上來的appRootVC.presentedViewController 不為nil
if (appRootVC.presentedViewController) {
nextResponder = appRootVC.presentedViewController;
}else{
UIView *frontView = [[window subviews] objectAtIndex:0];
nextResponder = [frontView nextResponder];
}
if ([nextResponder isKindOfClass:[UITabBarController class]]){
UITabBarController * tabbar = (UITabBarController *)nextResponder;
UINavigationController * nav = (UINavigationController *)tabbar.viewControllers[tabbar.selectedIndex];
//? ? ? ? UINavigationController * nav = tabbar.selectedViewController ; 上下兩種寫法都行
result=nav.childViewControllers.lastObject;
}else if ([nextResponder isKindOfClass:[UINavigationController class]]){
UIViewController * nav = (UIViewController *)nextResponder;
result = nav.childViewControllers.lastObject;
}else{
result = nextResponder;
}
[result.navigationController pushViewController:_viewController animated:YES];
//刪除所有的通知
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
}