好久沒(méi)有發(fā)動(dòng)態(tài)了浊仆,今天介紹一下極光推送,關(guān)于apple通知的一些原理豫领,這里就不做細(xì)致的介紹了抡柿,想要了解內(nèi)部推送的原理,大家可以在簡(jiǎn)書(shū)搜索iOS開(kāi)發(fā)知識(shí)匯總
專(zhuān)題,點(diǎn)擊鏈接http://www.reibang.com/collection/b9235769faa3 可直接進(jìn)入等恐,或者搜索微信公眾號(hào)iOS開(kāi)發(fā)知識(shí)匯總
now,我們從創(chuàng)建好極光應(yīng)用開(kāi)始洲劣,獲得appkey之后,打開(kāi)xcode课蔬,進(jìn)入項(xiàng)目囱稽,如圖,可以看到有個(gè)開(kāi)關(guān)二跋,push notifications
打開(kāi)開(kāi)關(guān)之后战惊,會(huì)生成一個(gè)
項(xiàng)目名.entitlements
的文件but在這之前,很多人沒(méi)有push notificaitons
開(kāi)關(guān)扎即,don't worry吞获,進(jìn)入極光主頁(yè),你會(huì)發(fā)現(xiàn)谚鄙,需要導(dǎo)入各種依賴(lài)庫(kù)
我們?cè)趚code下的Build Phases逐個(gè)添加依賴(lài)庫(kù)各拷,如圖
導(dǎo)入依賴(lài)庫(kù)之后,在這里最關(guān)鍵的依賴(lài)庫(kù)是UserNotificationcations.framework(xcode8及以上)襟锐,關(guān)閉程序撤逢,重新啟動(dòng),開(kāi)關(guān)就會(huì)出現(xiàn)粮坞,然后打開(kāi)開(kāi)關(guān),如圖
在開(kāi)關(guān)下面蚊荣,steps有兩個(gè)項(xiàng)目,第一個(gè)如果爆紅莫杈,說(shuō)明沒(méi)有導(dǎo)入項(xiàng)目所需的證書(shū)及配置文件(即在apple developer 生成的證書(shū)及配置文件) 互例,導(dǎo)入即可;如果第二個(gè)爆紅筝闹,可能是因?yàn)槟悴恍⌒膭h除了項(xiàng)目名.entitlements
文件媳叨,解決方法是,關(guān)閉push Notifications開(kāi)關(guān)之后再打開(kāi)即可生成关顷,如果不行的話糊秆,關(guān)閉程序,在關(guān)閉打開(kāi)開(kāi)關(guān)即可议双,如果 如果再不行痘番,去你的廢紙簍里面找被你刪除的項(xiàng)目名.entitlements
文件,重新拖到項(xiàng)目中重啟項(xiàng)目即可
Build Settings
如果你的工程需要支持小于7.0的iOS系統(tǒng),請(qǐng)到Build Settings 關(guān)閉 bitCode 選項(xiàng)汞舱,否則將無(wú)法正常編譯通過(guò)伍纫。
設(shè)置 Search Paths 下的 User Header Search Paths 和 Library Search Paths,比如SDK文件夾(默認(rèn)為lib)與工程文件在同一級(jí)目錄下昂芜,則都設(shè)置為"$(SRCROOT)/{靜態(tài)庫(kù)所在文件夾名稱(chēng)}"即可 莹规。《來(lái)自極光文檔》
2.允許Xcode7支持Http傳輸方法
如果您使用的是2.1.9及以上的版本則不需要配置此步驟
如果用的是Xcode7或更新版本泌神,需要在App項(xiàng)目的plist手動(dòng)配置下key和值以支持http傳輸:
選擇1:根據(jù)域名配置
在項(xiàng)目的info.plist中添加一個(gè)Key:NSAppTransportSecurity良漱,類(lèi)型為字典類(lèi)型。
然后給它添加一個(gè)NSExceptionDomains腻扇,類(lèi)型為字典類(lèi)型债热;
把需要的支持的域添加給NSExceptionDomains。其中jpush.cn作為Key幼苛,類(lèi)型為字典類(lèi)型窒篱。
每個(gè)域下面需要設(shè)置2個(gè)屬性:NSIncludesSubdomains、NSExceptionAllowsInsecureHTTPLoads舶沿。 兩個(gè)屬性均為Boolean類(lèi)型墙杯,值分別為YES、YES括荡「吒洌《來(lái)自極光文檔》 。如圖
配置完以上之后畸冲,進(jìn)入項(xiàng)目的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)方法里面申請(qǐ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]; // 這里是沒(méi)有advertisingIdentifier的情況邑闲,有的話算行,大家在自行添加
//注冊(cè)遠(yuǎn)端消息通知獲取device token
[application registerForRemoteNotifications];
}
注意:appkey一定不要忘了從極光復(fù)制過(guò)來(lái)
獲取deviceToken
// 獲取deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[JPUSHService registerDeviceToken:deviceToken];
}
// 注意 :此方法在ios 3 以后可以使用,但是在很多朋友可能會(huì)遇到不調(diào)用此方法的情況苫耸,也就無(wú)法獲取deviceToke州邢,這里提供一種解決方案
-(void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[application registerForRemoteNotifications];
}
關(guān)于這個(gè)deviceToken,iOS10系統(tǒng)上褪子,每次卸載重裝將產(chǎn)生新的app量淌,如果沒(méi)有卸載重裝,每次請(qǐng)求獲得的device token是不變的嫌褪。
另外官網(wǎng)也對(duì)device token的變化進(jìn)行了說(shuō)明:
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 處于前臺(tái)時(shí)接收到通知
// ios 10 support 處于前臺(tái)時(shí)接收到通知
- (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);
// 處于前臺(tái)時(shí),添加需求残吩,一般是彈出alert跟用戶(hù)進(jìn)行交互,這時(shí)候completionHandler(UNNotificationPresentationOptionAlert)這句話就可以注釋掉了倘核,這句話是系統(tǒng)的alert泣侮,顯示在app的頂部,
}
*/ 如果處于前臺(tái)時(shí)需要自定義彈框或者彈出alert紧唱,可以看一下http://www.reibang.com/p/d2a42072fad9 這篇文章
// iOS 10 Support 點(diǎn)擊處理事件
// iOS 10 Support 點(diǎn)擊處理事件
- (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];
//推送打開(kāi)
if (userInfo)
{
// 取得 APNs 標(biāo)準(zhǔn)信息內(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í)行這個(gè)方法
}
// iOS7 及以上接收到通知
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// Required, iOS 7 Support
[JPUSHService handleRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}
這里在iOS7及以上系統(tǒng)的方法中绰疤,如果需要在前臺(tái)和后臺(tái)做不同的處理的時(shí)候铜犬,需要判斷一下app 的狀態(tài),判斷方式如下
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
// 處于前臺(tái)時(shí) 轻庆,添加各種需求代碼癣猾。。余爆。纷宇。
}else if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
{
// app 處于后臺(tái) ,添加各種需求
}
那么問(wèn)題來(lái)了蛾方,前臺(tái)后臺(tái)收到推送的方法都有了像捶,還有一種情況。桩砰。拓春。。五芝。程序完全退出的時(shí)候痘儡,這種情況下,點(diǎn)擊通知會(huì)走下面這個(gè)方法(即注冊(cè)通知時(shí)的方法枢步,程序的入口)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
}
在這個(gè)方法里沉删,我們需要判斷一下程序是否處于完全退出狀態(tài),判斷方法如下
NSDictionary *remoteNotification = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteNotification)
{
// 程序完全退出時(shí)醉途,點(diǎn)擊通知矾瑰,添加需求。隘擎。殴穴。
}
# 需要注意的地方:
有可能有些小伙伴在集成過(guò)程中用ios10的手機(jī)測(cè)試的時(shí)候,
在推送通知的時(shí)候ios10和ios7的兩個(gè)代理方法都走了,具體原因具體對(duì)待采幌,如果實(shí)在找
不到問(wèn)題所在劲够,這里提供兩個(gè)方法,one:在ios10的兩個(gè)代理方法的首尾加入以下語(yǔ)句
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#endif // ios10中加入這兩句話
在ios7的代理方法首尾加入以下語(yǔ)句
#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)為正在前臺(tái)或者點(diǎn)擊通知欄的通知消息征绎,那么此函數(shù)將被調(diào)用,并且可通過(guò)AppDelegate的applicationState是否為UIApplicationStateActive判斷程序是否在前臺(tái)運(yùn)行磨取。此種情況在此函數(shù)中處理:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// Required,For systems with less than or equal to iOS6
// iOS 10 以下 Required
[JPUSHService handleRemoteNotification:userInfo];
}
//最后清除角標(biāo)
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[UIApplication alloc] setApplicationIconBadgeNumber:0];
}
// 點(diǎn)擊之后badge清零
- (void)applicationWillEnterForeground:(UIApplication *)application {
[application setApplicationIconBadgeNumber:0];
[[UNUserNotificationCenter alloc] removeAllPendingNotificationRequests];
}
其他功能:
1 . 后臺(tái)傳入不同的值人柿,點(diǎn)擊通知進(jìn)入不同的界面,可以在極光的官網(wǎng)發(fā)送通知界面忙厌,展開(kāi)可選設(shè)置凫岖,使用附加字段,這里我加了一個(gè)鍵值對(duì)key和值可以自行設(shè)置逢净,然后在工程中需要進(jìn)行判斷哥放,
代碼如下:大家可以在點(diǎn)擊通知會(huì)走的方法中調(diào)用此方法
// 傳入字段,根據(jù)字段改變需求
- (void)ExtrasOfNotificationWithUserInfo:(NSDictionary *)userInfo
{
if (userInfo)
{
// 取得 APNs 標(biāo)準(zhǔn)信息內(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婶芭,進(jìn)入相應(yīng)的頁(yè)面
if ([customizeField1 integerValue] == 1){
//是推送打開(kāi)
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
MainTabbarVC *rootTabBarC = [sb instantiateViewControllerWithIdentifier:@"MainTabbarVC"];
[UIApplication sharedApplication].delegate.window.rootViewController = rootTabBarC;
// 下面的方法是自己封裝的
[rootTabBarC enterToElectronicInvoice];
}
}
}
注意:這里的跳轉(zhuǎn)方法可能不適用所有項(xiàng)目,大家可以看一下下面的鏈接着饥,或許能夠找到適合你工程的跳轉(zhuǎn)方法
1.2 極光的點(diǎn)擊通知的方法- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler 是對(duì)系統(tǒng)方法的封裝犀农,他的userInfo中含有自定義添加的key,但是其他三方庫(kù)例如AWS的推送機(jī)制中就不包含自定義添加的key宰掉,這時(shí)候只能通過(guò)aps中的默認(rèn)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":"標(biāo)題", //
"subtitle":"子標(biāo)題", // 一般使用title就能滿(mǎn)足需求
"body":"內(nèi)容"
},
"badge":1, //角標(biāo)數(shù)
"sound":"default", //聲音
"userinfo":{ //通知內(nèi)容信息
"playid":"123",
"username":"tom",
"sex":1
}
}
}
如果只傳遞一串字符串或者不是按照上述格式發(fā)送通知消息孟害,那么會(huì)默認(rèn)把你傳遞的字符串全部轉(zhuǎn)化成alert的內(nèi)容,全部彈出來(lái)挪拟,所以在aws中我們可以這樣定義
APNS_SANDBOX : "{"aps":{"alert":" title message", "userInfo":"username"}}"
這樣在app中收到的彈出消息僅僅為title message 挨务,而userInfo可以用來(lái)做其他的用處
2 . 指定用戶(hù)發(fā)送遠(yuǎn)程通知,這里指定用戶(hù)不能只根據(jù)DeviceToken來(lái)進(jìn)行發(fā)送玉组,在極光的官網(wǎng)也沒(méi)有可以使用DeviceToken發(fā)送的選項(xiàng)谎柄,如下圖
這里的Registration ID 并不是DeviceToken,話不多說(shuō)惯雳,下面我們介紹一種使用別名Alias的方法朝巫,我們知道指定用戶(hù)發(fā)送,無(wú)非是已經(jīng)注冊(cè)了本公司賬號(hào)的人群石景,你想給不同的人推不同的消息劈猿,那么我們指定用戶(hù)的時(shí)候拙吉,實(shí)際上是根據(jù)用戶(hù)在我們公司注冊(cè)的賬號(hào)進(jìn)行發(fā)送特定消息,例如用戶(hù)的賬單狀態(tài)等等揪荣,所以我們可以在用戶(hù)登陸賬號(hào)之后筷黔,給用戶(hù)分配一個(gè)id用做唯一標(biāo)示,綁定極光的別名或者tag仗颈,當(dāng)然這里綁定別名還是tag可以和后臺(tái)商量一下必逆,用什么其實(shí)都是可以的,代碼如下
[JPUSHService setTags:nil alias:USER_INFO.userID fetchCompletionHandle:^(int iResCode, NSSet *iTags, NSString *iAlias) {
NSLog(@"設(shè)置結(jié)果:%i 用戶(hù)別名:%@",iResCode,USER_INFO.userID);
}];
// 這是極光提供的方法揽乱,USER_INFO.userID是用戶(hù)的id,你可以根據(jù)賬號(hào)或者其他來(lái)設(shè)置粟矿,只要保證唯一便可
// 不要忘了在登出之后將別名置空
[JPUSHService setTags:nil alias:@"" fetchCompletionHandle:^(int iResCode, NSSet *iTags, NSString *iAlias) {
NSLog(@"設(shè)置結(jié)果:%i 用戶(hù)別名:%@",iResCode,USER_INFO.userID);
}];
綁定完別名之后凰棉,指定用戶(hù)發(fā)送消息的任務(wù)就可以交給后臺(tái)了。如果你想自己測(cè)試一下陌粹,那就打印一下USER_INFO.userID
,然后自己用極光給自己推送撒犀,如圖
有些朋友問(wèn)我為啥收到通知有些方法就是不調(diào)用,這里要細(xì)心一點(diǎn)掏秩,有些方法是需要點(diǎn)擊alert才會(huì)走或舞,如果發(fā)送通知沒(méi)有走進(jìn)你想調(diào)試的方法里注意一下,是不是需要點(diǎn)擊一下alert
至此蒙幻,ios極光推送的集成就簡(jiǎn)單說(shuō)到這里映凳,未完。邮破。诈豌。待續(xù)。抒和。矫渔。覺(jué)得好的,就點(diǎn)個(gè)贊摧莽,有問(wèn)題的可以私信我庙洼,或者加我qq:1162719523,同不同意那就不知道了
ios 收到遠(yuǎn)程通知镊辕,彈出提示框油够,點(diǎn)擊確定跳轉(zhuǎn)到消息界面:http://www.reibang.com/p/d2a42072fad9