你知道吗?APNs和APNs Server不一样。
APNs(英文全称:Apple Push Notification service)中文翻译为:苹果推送通知服务。该技术由苹果公司提供的APNs服务。
APNs Server(英文全称:Apple Push Notification service Server)中文翻译为:苹果推送通知服务服务器。
以下图片来自网络
从上图我们可以看到:
1、应用程序注册消息推送。
2、iOS从APNs获取device Token,应用程序接收device Token。
3、应用程序将device token发送给PUSH服务端程序。
4、服务端程序向APNS服务发送消息。
5、APNS服务将消息发送给iPhone应用程序。
推送原理、流程
1.应用程序Application(简称:APP)注册远程通知。
if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 // Xcode8及以上编译 会调用
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
// 让当前控制器成为UNUserNotificationCenter的代理
center.delegate = self;
NSLog(@"当前控制器成为UNUserNotificationCenter的代理");
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionCarPlay) completionHandler:^(BOOL granted, NSError *_Nullable error) {
if (!error) {
NSLog(@"request authorization succeeded!");
}
}];
// 当前应用程序注册远程通知
[[UIApplication sharedApplication] registerForRemoteNotifications];
#else // Xcode 7编译会调用
UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerForRemoteNotifications];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
NSLog(@"注册通知了呀");
#endif
} else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
UIUserNotificationType types = (UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerForRemoteNotifications];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
NSLog(@"大于iOS8 注册通知了呀");
} else {// 小于8
UIRemoteNotificationType apn_type = (UIRemoteNotificationType)(UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeSound |
UIRemoteNotificationTypeBadge);
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:apn_type];
}
2.iOS从APNS Server接收到了一个deviceToken。即通过如下代理方法接收deviceToken。
3.然后在该方法中访问 registerDeviceToken:
来实现将deviceToken传递给个推服务器。
/** 远程通知注册成功委托 */
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];
NSLog(@"\n>>>[DeviceToken Success]:%@\n\n", token);
// 向个推服务器注册deviceToken
[GeTuiSdk registerDeviceToken:token];
}
4.雇主发单的那一刻是触发推送的动作 [这个很重要,这个很重要,这个很重要]。即:雇主发单访问后台提供的某个接口(我们公司是blog_add这个接口)的时候,后台(PHP服务端)拿到前端的订单数据,通过个推提供的SDK将这些订单数据传递给个推服务器,
set_isOffline(true);//是否离线
$message->set_offlineExpireTime(3600*12*1000);//离线时间
$message->set_data($template);//设置推送消息类型
// $message->set_PushNetWorkType(0);//设置是否根据WIFI推送消息,1为wifi推送,0为不限制推送
//接收方
$target = new IGtTarget();
$target->set_appId($appid);
$target->set_clientId($clientID);
// $target->set_alias(Alias);
try {
$rep = $igt->pushMessageToSingle($message, $target);
sys_log($rep);
var_dump($rep);
echo ("
");
}catch(RequestException $e){
$requstId =e.getRequestId();
$rep = $igt->pushMessageToSingle($message, $target,$requstId);
sys_log($rep."--");
var_dump($rep);
echo ("
");
}
}
//多推接口案例
function pushMessageToList($cid_list,$msgContent,$keyType,$keyId,$temp_ietm="",$client_notice){
putenv("gexin_pushList_needDetails=true");
$deviceType = 1;
$host = HOST;
if($deviceType == 1){//苹果
$appid = IOS_APPID;
$appkey = IOS_APPKEY;
$mastersecret = IOS_MASTERSECRET;
}
else{//安卓
$appid = ANDROID_APPID;
$appkey = ANDROID_APPKEY;
$mastersecret = ANDROID_MASTERSECRET;
}
$igt = new IGeTui($host,$appkey,$mastersecret);
//消息模版:透传功能模板
$template = IGtTransmissionTemplateDemo($appid,$appkey,$msgContent,$keyType,$keyId,$temp_ietm,$client_notice);
//个推信息体
$message = new IGtListMessage();
$message->set_isOffline(true);//是否离线
$message->set_offlineExpireTime(3600*12*1000);//离线时间
$message->set_data($template);//设置推送消息类型
//$message->set_PushNetWorkType(1);//设置是否根据WIFI推送消息,1为wifi推送,0为不限制推送
$contentId = $igt->getContentId($message);
//接收方1
sys_log(4);
$cid_list_a = explode(",",$cid_list);
$targetList = array();
foreach ($cid_list_a as $cid){
$target1 = new IGtTarget();
$target1->set_appId($appid);
$target1->set_clientId($cid);
$targetList[] = $target1;
}
$rep = $igt->pushMessageToList($contentId, $targetList);
}
//推送到整个APP
function pushMessageToApp($msgContent,$keyType,$keyId){
sys_log($msgContent);
$deviceType = 1;
$host = HOST;
if($deviceType == 1){//苹果
$appid = IOS_APPID;
$appkey = IOS_APPKEY;
$mastersecret = IOS_MASTERSECRET;
}
else{//安卓
$appid = ANDROID_APPID;
$appkey = ANDROID_APPKEY;
$mastersecret = ANDROID_MASTERSECRET;
}
$igt = new IGeTui($host,$appkey,$mastersecret);
//消息模版:透传功能模板
$template = IGtTransmissionTemplateDemo($appid,$appkey,$msgContent,$keyType,$keyId);
//个推信息体
//基于应用消息体
$message = new IGtAppMessage();
$message->set_isOffline(true);
$message->set_offlineExpireTime(3600*12*1000);//离线时间单位为毫秒,例,两个小时离线为3600*1000*2
$message->set_data($template);
//$message->set_PushNetWorkType(1);//设置是否根据WIFI推送消息,1为wifi推送,0为不限制推送
$message->set_speed(100);// 设置群推接口的推送速度,单位为条/秒,例如填写100,则为100条/秒。仅对指定应用群推接口有效。
$message->set_appIdList(array($appid));
$rep = $igt->pushMessageToApp($message);
}
function IGtTransmissionTemplateDemo($appid,$appkey,$msgContent,$keyType,$keyId,$temp_ietm="",$client_notice="default"){
$msg = array(
'keyType' => $keyType,
'keyId' => $keyId,
'msg' => $msgContent,
'nickname' => $temp_ietm
);
$msg = json_encode($msg);
$template = new IGtTransmissionTemplate();
$template->set_appId($appid);//应用appid
$template->set_appkey($appkey);//应用appkey
$template->set_transmissionType(2);//透传消息类型
$template->set_transmissionContent($msg);//透传内容
//APN高级推送
$apn = new IGtAPNPayload();
$alertmsg=new DictionaryAlertMsg();
$alertmsg->body=$msgContent;
$alertmsg->actionLocKey="ActionLockey";
$alertmsg->locKey=$msgContent;
$alertmsg->locArgs=array("locargs");
$alertmsg->launchImage="launchimage";
// IOS8.2 支持
$alertmsg->title=SYS_ZH_NAME;
$alertmsg->titleLocKey=SYS_ZH_NAME;
$alertmsg->titleLocArgs=array("TitleLocArg");
$apn->alertMsg=$alertmsg;
$apn->badge=1;
$apn->sound=$client_notice;
$apn->add_customMsg("payload","payload");
$apn->add_customMsg("keyType",$keyType);
$apn->add_customMsg("keyId",$keyId);
$apn->add_customMsg("nickname",$nickname);
$apn->add_customMsg("msg",$msgContent);
$apn->contentAvailable=0;
$apn->category="ACTIONABLE";
$template->set_apnInfo($apn);
return $template;
}
?>
5.个推服务器通过后台传给它的IOS_APPID,找到IOS_APPID所绑定的CID, 然后个推服务器将订单数据和CID一起发送给了 APNs Server。
个推服务器能直接与APNs Server沟通的原因是:之前已经将deviceToken交给个推服务器了,并且生产证书、开发证书等已经放在个推平台上了。
- 应用程序之前注册个推的代码,以及在个推提供的代理方法中收到个推返回的cid。我觉得这里有必要粘贴出来。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
...
// 应用程序注册个推
[GeTuiSdk startSdkWithAppId:kGtAppId appKey:kGtAppKey appSecret:kGtAppSecret delegate:self];
...
}
/** SDK启动成功返回cid */
- (void)GeTuiSdkDidRegisterClient:(NSString *)clientId{
// 我的clientId为:513a8ec3ae28a63f0dae0499b894f868
// 个推SDK已注册,返回clientId
NSLog(@"\n>>>[GeTuiSdk RegisterClient]:%@\n\n", clientId);
//--------------------把clientId通过硬件注册接口(在requestSaveDeviceLogin方法里)传给服务器。。。
_mychannelid = clientId;
if (_isLogin) {
[self requestSaveDeviceLogin];
}
}
6.APNs在自身的已注册Push服务的设备列表中,查找相应标识的手机设备,并把消息发到手机设备上。
7.手机设备把发来的消息传递给一秒xxAPP, 并且以 通知栏通知/顶部弹框/角标的形式 展示到手机上。
8.在实现的个推提供的代理方法中会收到个推的回调,可以得到个推的透传消息(分为离线和在线),我们一秒xxAPP可以拿到里面的json数据做想要的操作,比如更新UI,文字转语音,跳转界面等等。
.......................