好久沒有發(fā)動態(tài)了,今天介紹一下極光推送,關(guān)于apple通知的一些原理,這里就不做細致的介紹了,想要了解內(nèi)部推送的原理,大家可以在簡書搜索iOS開發(fā)知識匯總專題,點擊鏈接http://www.itdecent.cn/collection/b9235769faa3 可直接進入,或者搜索微信公眾號iOS開發(fā)知識匯總

now,我們從創(chuàng)建好極光應(yīng)用開始,獲得appkey之后,打開xcode,進入項目,如圖,可以看到有個開關(guān),push notifications

打開開關(guān)之后,會生成一個
項目名.entitlements的文件
but在這之前,很多人沒有push notificaitons開關(guān),don't worry,進入極光主頁,你會發(fā)現(xiàn),需要導(dǎo)入各種依賴庫

我們在xcode下的Build Phases逐個添加依賴庫,如圖

導(dǎo)入依賴庫之后,在這里最關(guān)鍵的依賴庫是UserNotificationcations.framework(xcode8及以上),關(guān)閉程序,重新啟動,開關(guān)就會出現(xiàn),然后打開開關(guān),如圖

在開關(guān)下面,steps有兩個項目,第一個如果爆紅,說明沒有導(dǎo)入項目所需的證書及配置文件(即在apple developer 生成的證書及配置文件) ,導(dǎo)入即可;如果第二個爆紅,可能是因為你不小心刪除了項目名.entitlements文件,解決方法是,關(guān)閉push Notifications開關(guān)之后再打開即可生成,如果不行的話,關(guān)閉程序,在關(guān)閉打開開關(guān)即可,如果 如果再不行,去你的廢紙簍里面找被你刪除的項目名.entitlements文件,重新拖到項目中重啟項目即可
Build Settings
如果你的工程需要支持小于7.0的iOS系統(tǒng),請到Build Settings 關(guān)閉 bitCode 選項,否則將無法正常編譯通過。
設(shè)置 Search Paths 下的 User Header Search Paths 和 Library Search Paths,比如SDK文件夾(默認為lib)與工程文件在同一級目錄下,則都設(shè)置為"$(SRCROOT)/{靜態(tài)庫所在文件夾名稱}"即可 。《來自極光文檔》
2.允許Xcode7支持Http傳輸方法
如果您使用的是2.1.9及以上的版本則不需要配置此步驟
如果用的是Xcode7或更新版本,需要在App項目的plist手動配置下key和值以支持http傳輸:
選擇1:根據(jù)域名配置
在項目的info.plist中添加一個Key:NSAppTransportSecurity,類型為字典類型。
然后給它添加一個NSExceptionDomains,類型為字典類型;
把需要的支持的域添加給NSExceptionDomains。其中jpush.cn作為Key,類型為字典類型。
每個域下面需要設(shè)置2個屬性:NSIncludesSubdomains、NSExceptionAllowsInsecureHTTPLoads。 兩個屬性均為Boolean類型,值分別為YES、YES?!秮碜詷O光文檔》 。如圖

配置完以上之后,進入項目的appdelegate里面,首先導(dǎo)入頭文件和遵循代理
#import "AppDelegate.h"
#import "JPUSHService.h"
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif
@interface AppDelegate ()<JPUSHRegisterDelegate>
在系統(tǒng)方法里面申請通知權(quán)限,這里最高只適用到xcode8.1(iOS10.1.2),以后如果出現(xiàn)iOS11在做更新改變
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
entity.types = UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound;
[JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
}
else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
//可以添加自定義categories
[JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge |
UIUserNotificationTypeSound |
UIUserNotificationTypeAlert)
categories:nil];
}
else {
//categories 必須為nil
[JPUSHService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound |
UIRemoteNotificationTypeAlert)
categories:nil];
}
[JPUSHService setupWithOption:launchOptions appKey:appKey
channel:channel
apsForProduction:isProduction
advertisingIdentifier:nil]; // 這里是沒有advertisingIdentifier的情況,有的話,大家在自行添加
//注冊遠端消息通知獲取device token
[application registerForRemoteNotifications];
}
注意:appkey一定不要忘了從極光復(fù)制過來
獲取deviceToken
// 獲取deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[JPUSHService registerDeviceToken:deviceToken];
}
// 注意 :此方法在ios 3 以后可以使用,但是在很多朋友可能會遇到不調(diào)用此方法的情況,也就無法獲取deviceToke,這里提供一種解決方案
-(void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[application registerForRemoteNotifications];
}
關(guān)于這個deviceToken,iOS10系統(tǒng)上,每次卸載重裝將產(chǎn)生新的app,如果沒有卸載重裝,每次請求獲得的device token是不變的。
另外官網(wǎng)也對device token的變化進行了說明:
To protect user privacy, do not use device tokens to identify user devices. Device tokens change when the user updates the operating system and when a device’s data and settings are erased. As a result, apps should always request the current device token at launch time.
// ios 10 support 處于前臺時接收到通知
// ios 10 support 處于前臺時接收到通知
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler
{
NSDictionary * userInfo = notification.request.content.userInfo;
if ([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[JPUSHService handleRemoteNotification:userInfo];
// 添加各種需求。。。。。
}
completionHandler(UNNotificationPresentationOptionAlert);
// 處于前臺時,添加需求,一般是彈出alert跟用戶進行交互,這時候completionHandler(UNNotificationPresentationOptionAlert)這句話就可以注釋掉了,這句話是系統(tǒng)的alert,顯示在app的頂部,
}
*/ 如果處于前臺時需要自定義彈框或者彈出alert,可以看一下http://www.itdecent.cn/p/d2a42072fad9 這篇文章
// iOS 10 Support 點擊處理事件
// iOS 10 Support 點擊處理事件
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
// Required
NSDictionary * userInfo = response.notification.request.content.userInfo;
if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[JPUSHService handleRemoteNotification:userInfo];
//推送打開
if (userInfo)
{
// 取得 APNs 標準信息內(nèi)容
// NSDictionary *aps = [userInfo valueForKey:@"aps"];
// NSString *content = [aps valueForKey:@"alert"]; //推送顯示的內(nèi)容
// NSInteger badge = [[aps valueForKey:@"badge"] integerValue]; //badge數(shù)量
// NSString *sound = [aps valueForKey:@"sound"]; //播放的聲音
// 添加各種需求。。。。。
[JPUSHService handleRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}
completionHandler(); // 系統(tǒng)要求執(zhí)行這個方法
}
// iOS7 及以上接收到通知
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// Required, iOS 7 Support
[JPUSHService handleRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}
這里在iOS7及以上系統(tǒng)的方法中,如果需要在前臺和后臺做不同的處理的時候,需要判斷一下app 的狀態(tài),判斷方式如下
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
// 處于前臺時 ,添加各種需求代碼。。。。
}else if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
{
// app 處于后臺 ,添加各種需求
}
那么問題來了,前臺后臺收到推送的方法都有了,還有一種情況。。。。。程序完全退出的時候,這種情況下,點擊通知會走下面這個方法(即注冊通知時的方法,程序的入口)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
}
在這個方法里,我們需要判斷一下程序是否處于完全退出狀態(tài),判斷方法如下
NSDictionary *remoteNotification = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteNotification)
{
// 程序完全退出時,點擊通知,添加需求。。。
}
# 需要注意的地方:
有可能有些小伙伴在集成過程中用ios10的手機測試的時候,
在推送通知的時候ios10和ios7的兩個代理方法都走了,具體原因具體對待,如果實在找
不到問題所在,這里提供兩個方法,one:在ios10的兩個代理方法的首尾加入以下語句
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#endif // ios10中加入這兩句話
在ios7的代理方法首尾加入以下語句
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_7_1
#endif // ios7中加入這兩句話
第二種方法是直接在ios7的代理方法中加入判斷:
if ([[UIDevice currentDevice].systemVersion floatValue] < 10.0)
// 基于iOS 6 及以下的系統(tǒng)版本 接收到通知
// 基于iOS 6 及以下的系統(tǒng)版本,如果 App狀態(tài)為正在前臺或者點擊通知欄的通知消息,那么此函數(shù)將被調(diào)用,并且可通過AppDelegate的applicationState是否為UIApplicationStateActive判斷程序是否在前臺運行。此種情況在此函數(shù)中處理:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// Required,For systems with less than or equal to iOS6
// iOS 10 以下 Required
[JPUSHService handleRemoteNotification:userInfo];
}
//最后清除角標
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[UIApplication alloc] setApplicationIconBadgeNumber:0];
}
// 點擊之后badge清零
- (void)applicationWillEnterForeground:(UIApplication *)application {
[application setApplicationIconBadgeNumber:0];
[[UNUserNotificationCenter alloc] removeAllPendingNotificationRequests];
}
其他功能:
1 . 后臺傳入不同的值,點擊通知進入不同的界面,可以在極光的官網(wǎng)發(fā)送通知界面,展開可選設(shè)置,使用附加字段,這里我加了一個鍵值對key和值可以自行設(shè)置,然后在工程中需要進行判斷,

代碼如下:大家可以在點擊通知會走的方法中調(diào)用此方法
// 傳入字段,根據(jù)字段改變需求
- (void)ExtrasOfNotificationWithUserInfo:(NSDictionary *)userInfo
{
if (userInfo)
{
// 取得 APNs 標準信息內(nèi)容
// NSDictionary *aps = [userInfo valueForKey:@"aps"];
// NSString *content = [aps valueForKey:@"alert"]; //推送顯示的內(nèi)容
// NSInteger badge = [[aps valueForKey:@"badge"] integerValue]; //badge數(shù)量
// NSString *sound = [aps valueForKey:@"sound"]; //播放的聲音
// 取得Extras字段內(nèi)容
NSString *customizeField1 = [userInfo valueForKey:@"key"]; //服務(wù)端中Extras字段,key是自己定義的,需要與極光的附加字段一致
// 若傳入字段的值為1,進入相應(yīng)的頁面
if ([customizeField1 integerValue] == 1){
//是推送打開
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
MainTabbarVC *rootTabBarC = [sb instantiateViewControllerWithIdentifier:@"MainTabbarVC"];
[UIApplication sharedApplication].delegate.window.rootViewController = rootTabBarC;
// 下面的方法是自己封裝的
[rootTabBarC enterToElectronicInvoice];
}
}
}
注意:這里的跳轉(zhuǎn)方法可能不適用所有項目,大家可以看一下下面的鏈接,或許能夠找到適合你工程的跳轉(zhuǎn)方法
1.2 極光的點擊通知的方法- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler 是對系統(tǒng)方法的封裝,他的userInfo中含有自定義添加的key,但是其他三方庫例如AWS的推送機制中就不包含自定義添加的key,這時候只能通過aps中的默認userInfo傳遞特定的值,aps的結(jié)構(gòu)如下
iOS 10 之前
{
"aps":{
"alert":"內(nèi)容",
"badge":1,
"sound":"default",
"userinfo":{"username":"tom"}
}
}
iOS 10及之后(iOS7、iOS8、iOS9可通用此模板)
{
"aps":{
"alert":{
"title":"標題", //
"subtitle":"子標題", // 一般使用title就能滿足需求
"body":"內(nèi)容"
},
"badge":1, //角標數(shù)
"sound":"default", //聲音
"userinfo":{ //通知內(nèi)容信息
"playid":"123",
"username":"tom",
"sex":1
}
}
}
如果只傳遞一串字符串或者不是按照上述格式發(fā)送通知消息,那么會默認把你傳遞的字符串全部轉(zhuǎn)化成alert的內(nèi)容,全部彈出來,所以在aws中我們可以這樣定義
APNS_SANDBOX : "{"aps":{"alert":" title message", "userInfo":"username"}}"
這樣在app中收到的彈出消息僅僅為title message ,而userInfo可以用來做其他的用處
2 . 指定用戶發(fā)送遠程通知,這里指定用戶不能只根據(jù)DeviceToken來進行發(fā)送,在極光的官網(wǎng)也沒有可以使用DeviceToken發(fā)送的選項,如下圖

這里的Registration ID 并不是DeviceToken,話不多說,下面我們介紹一種使用別名Alias的方法,我們知道指定用戶發(fā)送,無非是已經(jīng)注冊了本公司賬號的人群,你想給不同的人推不同的消息,那么我們指定用戶的時候,實際上是根據(jù)用戶在我們公司注冊的賬號進行發(fā)送特定消息,例如用戶的賬單狀態(tài)等等,所以我們可以在用戶登陸賬號之后,給用戶分配一個id用做唯一標示,綁定極光的別名或者tag,當然這里綁定別名還是tag可以和后臺商量一下,用什么其實都是可以的,代碼如下
[JPUSHService setTags:nil alias:USER_INFO.userID fetchCompletionHandle:^(int iResCode, NSSet *iTags, NSString *iAlias) {
NSLog(@"設(shè)置結(jié)果:%i 用戶別名:%@",iResCode,USER_INFO.userID);
}];
// 這是極光提供的方法,USER_INFO.userID是用戶的id,你可以根據(jù)賬號或者其他來設(shè)置,只要保證唯一便可
// 不要忘了在登出之后將別名置空
[JPUSHService setTags:nil alias:@"" fetchCompletionHandle:^(int iResCode, NSSet *iTags, NSString *iAlias) {
NSLog(@"設(shè)置結(jié)果:%i 用戶別名:%@",iResCode,USER_INFO.userID);
}];
綁定完別名之后,指定用戶發(fā)送消息的任務(wù)就可以交給后臺了。如果你想自己測試一下,那就打印一下USER_INFO.userID ,然后自己用極光給自己推送,如圖

有些朋友問我為啥收到通知有些方法就是不調(diào)用,這里要細心一點,有些方法是需要點擊alert才會走,如果發(fā)送通知沒有走進你想調(diào)試的方法里注意一下,是不是需要點擊一下alert
至此,ios極光推送的集成就簡單說到這里,未完。。。待續(xù)。。。覺得好的,就點個贊,有問題的可以私信我,或者加我qq:1162719523,同不同意那就不知道了
ios 收到遠程通知,彈出提示框,點擊確定跳轉(zhuǎn)到消息界面:http://www.itdecent.cn/p/d2a42072fad9