app推送中的文告和音讯差别,公告与音讯机制

By admin in 4858美高梅 on 2019年4月21日

前者时间商量应用程式新闻推送的体制,由于机型、版本的碎片化,信息推送的建制不太好理解,所以总括下,放在博文里以备后续查阅。

前者时间研究APP新闻推送的编写制定,由于机型、版本的碎片化,信息推送的机制不太好通晓,所以计算下,放在博文里以备后续查阅。

iOS开垦种类–布告与消息机制,ios开垦–机制

不久前在做mqtt及其他音信推送的效益,推送服务挺多的,HUAWEI推,极光推,三星推,个推等,当然还有苹果的apns。以为都大致,尝试了apns,HUAWEI推和个推,各样厂家都提供的有sdk,demo。

安卓Android系统的音讯推送:

安卓Android系统的音信推送:

概述

在一大半活动选拔中任哪一天候都不得不有2个应用程序处于活跃状态,假若其它使用此刻爆发了1部分用户感兴趣的那么通过文告机制就足以告知用户此时发出的事务。iOS中通报机制又叫新闻机制,其包涵两类:一类是本地公告;另壹类是推送文告,也叫远程通告。两种通知在iOS中的表现同样,能够透过横幅也许弹出提醒二种样式报告用户,并且点击通告能够会展开应用程序,可是达成原理却完全分化。明天就和豪门壹块去看一下什么在iOS中落实那三种体制,并且在著作前边会补充布告大旨的内容幸免初专家对二种概念的模糊。

  1. 本地布告
  2. 推送公告
  3. 补给–iOS开荒证书、秘钥
  4. 增加补充–通告中央

有关文告和音信的差距:

通告:发送后会在系统通知栏收到展现,同时响铃或振动提示用户。
( mqtt不知情能还是不能发送文告,还在斟酌中…)
新闻:以透传的款式传递给客户端,无突显,发送后不会在系统文告栏彰显,第一方选择后必要开拓者写代码技术见到。

 

如何是透传?透传正是透明传送,即传送互连网无论传输业务怎么,只承担将索要传送的作业传送到目标节点,同时确定保证传输的身分就能够,而不对传输的作业拓展拍卖。透传新闻,正是音讯体格式及内容,对于传递的大道来说是不去过问的,通道只承担新闻的传递,对新闻不做任何管理,当客户端接收到透传新闻后,由客户端本人来支配如何管理消息。即是因为透传音信能够自定义音信体,也能够自定义音信的展现格局及后续动作处理,所以弥补了文告栏音讯的有的不足之处(公告栏音讯是一向展现出来,相关的动作客户端不能够捕获到)。

透传音讯至关心珍视要有如下多少个方面包车型大巴性状

  1. 后台处理,用户无感知。
  2. 前台突显,提示用户。
  3. 呈现的四种化。

整整透传音讯的流水生产线如下:

据说个推提供的API接口或在个推开垦者平台上推送透传音讯,个推服务端接收到推送的音讯后,不做任何管理,直接发送给目的用户。

当客户端SDK接收到透传信息后,以广播方式发送给客户端,客户端在安插的第一方布罗兹Receiver里接收到透传新闻后进行处理。

透传新闻的音信体,能够依赖不相同的供给传递差别的参数或格式。如传递多少个大约的字符串,或传递贰个Json字符串,里面遵照须求传递要求的字段。

用户无感知的透传,如:更新相关新闻,在主分界面中相关栏位用红点标记进行弱提示,推送一条命令用来检查实验用户是不是有记名等。布告栏音信即便方便人民群众的晋升用户,但也在料定程度上给用户带来了干扰,用户无感知的新闻推送有时效果会更加好。
用户有感知的透传:把透传音信管理成文告栏突显出来,提示用户方便点击查占星关音讯(如个人帐单音信),直接展开应用或跳转到钦赐的接纳分界面中(依据透传新闻的有关参数来决断跳转到哪贰个内定的分界面,相关参数字传送递要张开的分界面包车型大巴类名或Intent就可以)等。对于开采者,管理成布告栏的相关事件也是足以捕获的,如布告栏的显示、点击等事件都足以开始展览捕获,以造福开始展览延续的操作。

因透传新闻能够协和解和管理理成公告栏内容体现,所以通告栏的体制也能够依照要求来做相应的改观。在Android
四.四及以上的连串,通告栏能够是体制丰盛的文告栏,放入图片和录制等;能够显示平时的打招呼,也能够来得种种化的公告。

 

参考:

 

 

 

地方通告

本地布告是由地点使用触发的,它是根据时间表现的1种通告情势,举例石英钟按时、待办事项提醒,又只怕2个行使在1段时候后不选择普通会唤起用户使用此采用等都是地点文告。创立三个地点布告经常分为以下多少个步骤:

下边就以2个程序更新后用户短期未有使用的升迁为例对该地布告做1个简易的掌握。在这些进度中并不曾牵涉太多的分界面操作,全体的逻辑都在AppDelegate中:进入应用后若是未有登记公告,须要首先注册公告请求用户同意通告;1旦调用完登记情势,无论用户是或不是采用允许文告此刻都会调用应用程序的
(void)application:(UIApplication *)application
didRegisterUserNotificationSettings:(UIUserNotificationSettings
*)notificationSettings
代理方法,在这几个艺术中根据用户的采纳:假诺是同意文告则会鲁人持竿后面的步骤创建文告并在必然时间后推行。

AppDelegate.m

//
//  AppDelegate.m
//  LocalNotification
//
//  Created by Kenshin Cui on 14/03/28.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "AppDelegate.h"
#import "KCMainViewController.h"

@interface AppDelegate ()

@end

@implementation AppDelegate

#pragma mark - 应用代理方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    _window=[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];

    _window.backgroundColor =[UIColor colorWithRed:249/255.0 green:249/255.0 blue:249/255.0 alpha:1];

    //设置全局导航条风格和颜色
    [[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:23/255.0 green:180/255.0 blue:237/255.0 alpha:1]];
    [[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];

    KCMainViewController *mainController=[[KCMainViewController alloc]init];
    _window.rootViewController=mainController;

    [_window makeKeyAndVisible];

    //如果已经获得发送通知的授权则创建本地通知,否则请求授权(注意:如果不请求授权在设置中是没有对应的通知设置项的,也就是说如果从来没有发送过请求,即使通过设置也打不开消息允许设置)
    if ([[UIApplication sharedApplication]currentUserNotificationSettings].types!=UIUserNotificationTypeNone) {
        [self addLocalNotification];
    }else{
        [[UIApplication sharedApplication]registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound  categories:nil]];
    }

    return YES;
}

#pragma mark 调用过用户注册通知方法之后执行(也就是调用完registerUserNotificationSettings:方法之后执行)
-(void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{
    if (notificationSettings.types!=UIUserNotificationTypeNone) {
        [self addLocalNotification];
    }
}

#pragma mark 进入前台后设置消息信息
-(void)applicationWillEnterForeground:(UIApplication *)application{
    [[UIApplication sharedApplication]setApplicationIconBadgeNumber:0];//进入前台取消应用消息图标
}

#pragma mark - 私有方法
#pragma mark 添加本地通知
-(void)addLocalNotification{

    //定义本地通知对象
    UILocalNotification *notification=[[UILocalNotification alloc]init];
    //设置调用时间
    notification.fireDate=[NSDate dateWithTimeIntervalSinceNow:10.0];//通知触发的时间,10s以后
    notification.repeatInterval=2;//通知重复次数
    //notification.repeatCalendar=[NSCalendar currentCalendar];//当前日历,使用前最好设置时区等信息以便能够自动同步时间

    //设置通知属性
    [email protected]"最近添加了诸多有趣的特性,是否立即体验?"; //通知主体
    notification.applicationIconBadgeNumber=1;//应用程序图标右上角显示的消息数
    [email protected]"打开应用"; //待机界面的滑动动作提示
    [email protected]"Default";//通过点击通知打开应用时的启动图片,这里使用程序启动图片
    //notification.soundName=UILocalNotificationDefaultSoundName;//收到通知时播放的声音,默认消息声音
    [email protected]"msg.caf";//通知声音(需要真机才能听到声音)

    //设置用户信息
    [email protected]{@"id":@1,@"user":@"Kenshin Cui"};//绑定到通知上的其他附加信息

    //调用通知
    [[UIApplication sharedApplication] scheduleLocalNotification:notification];
}

#pragma mark 移除本地通知,在不需要此通知时记得移除
-(void)removeNotification{
    [[UIApplication sharedApplication] cancelAllLocalNotifications];
}
@end

请求获得用户同意布告的效益:

 

动用退出到后弹出通知的机能:

 

锁屏状态下的通报效果(从那些分界面能够见到alertAction配置为“伸开应用”):

注意:

  • 在使用通告以前必须登记公告类型,即便用户区别意应用程序发送文告,则现在就无法发送文告,除非用户手动到iOS设置中开辟文告。
  • 本地通告是有操作系统统一调治的,只有在应用退出到后台也许关闭技巧采取通告。(注意:那一点对此背后的推送布告也是完全适用的。
  • 照会的声响是由iOS系统播放的,格式必须是Linear
    PCM、M西玛(IMA/ADPCM)、µLaw、aLaw中的一种,并且播放时间必须在30s内,不然将被系统声音替换,同时自定义声音文件必须置于main
    boundle中。
  • 地面文告的数额是有限定的,近来的本地文告最八只好有陆拾五个,超越那几个数据将被系统忽略。
  • 若果想要移除本地布告能够调用UIApplication的cancelLocalNotification:cancelAllLocalNotifications移除内定通告或具有布告。

从地点的顺序能够见见userInfo这一个性情我们设置了参数,那么那一个参数怎样吸收呢?

在iOS中若是点击二个弹出通告(或许锁屏分界面滑动查看文告),暗中认可会自动打开当前利用。由于告示由系统调整那么此时跻身应用有二种状态:若是应用程序已经完全退出那么此时会调用
(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary
*)launchOptions
格局;假使那时候应用程序还在运作(无论是在前台照旧在后台)则会调用app推送中的文告和音讯差别,公告与音讯机制。-(void)application:(UIApplication
*)application didReceiveLocalNotification:(UILocalNotification
*)notification
主意接收音讯参数。当然若是是后世当然不用多说,因为参数中早就得以得到notification对象,只要读取userInfo属性就能够。假设是前者的话则能够访问launchOptions中键为UIApplicationLaunchOptionsLocalNotificationKey的对象,那几个目的正是发送的照料,因而对象再去访问userInfo。为了演示这一个进程在底下的顺序中校userInfo的故事情节写入文件以便模拟关闭程序后再经过点击布告打开应用获取userInfo的进度。

AppDelegate.m

//
//  AppDelegate.m
//  LocalNotification
//
//  Created by Kenshin Cui on 14/03/28.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "AppDelegate.h"
#import "KCMainViewController.h"

@interface AppDelegate ()

@end

@implementation AppDelegate

#pragma mark - 应用代理方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    _window=[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];

    _window.backgroundColor =[UIColor colorWithRed:249/255.0 green:249/255.0 blue:249/255.0 alpha:1];

    //设置全局导航条风格和颜色
    [[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:23/255.0 green:180/255.0 blue:237/255.0 alpha:1]];
    [[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];

    KCMainViewController *mainController=[[KCMainViewController alloc]init];
    _window.rootViewController=mainController;

    [_window makeKeyAndVisible];

    //添加通知
    [self addLocalNotification];

    //接收通知参数
    UILocalNotification *notification=[launchOptions valueForKey:UIApplicationLaunchOptionsLocalNotificationKey];
    NSDictionary *userInfo= notification.userInfo;

    [userInfo writeToFile:@"/Users/kenshincui/Desktop/didFinishLaunchingWithOptions.txt" atomically:YES];
    NSLog(@"didFinishLaunchingWithOptions:The userInfo is %@.",userInfo);

    return YES;
}

#pragma mark 接收本地通知时触发
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    NSDictionary *userInfo=notification.userInfo;
    [userInfo writeToFile:@"/Users/kenshincui/Desktop/didReceiveLocalNotification.txt" atomically:YES];
    NSLog(@"didReceiveLocalNotification:The userInfo is %@",userInfo);
}

#pragma mark 调用过用户注册通知方法之后执行(也就是调用完registerUserNotificationSettings:方法之后执行)
-(void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{
    if (notificationSettings.types!=UIUserNotificationTypeNone) {
        [self addLocalNotification];
    }
}

#pragma mark 进入前台后设置消息信息
-(void)applicationWillEnterForeground:(UIApplication *)application{
    [[UIApplication sharedApplication]setApplicationIconBadgeNumber:0];//进入前台取消应用消息图标
}

#pragma mark - 私有方法
#pragma mark 添加本地通知
-(void)addLocalNotification{

    //定义本地通知对象
    UILocalNotification *notification=[[UILocalNotification alloc]init];
    //设置调用时间
    notification.fireDate=[NSDate dateWithTimeIntervalSinceNow:10.0];//通知触发的时间,10s以后
    notification.repeatInterval=2;//通知重复次数
    //notification.repeatCalendar=[NSCalendar currentCalendar];//当前日历,使用前最好设置时区等信息以便能够自动同步时间

    //设置通知属性
    [email protected]"最近添加了诸多有趣的特性,是否立即体验?"; //通知主体
    notification.applicationIconBadgeNumber=1;//应用程序图标右上角显示的消息数
    [email protected]"打开应用"; //待机界面的滑动动作提示
    [email protected]"Default";//通过点击通知打开应用时的启动图片
    //notification.soundName=UILocalNotificationDefaultSoundName;//收到通知时播放的声音,默认消息声音
    [email protected]"msg.caf";//通知声音(需要真机)

    //设置用户信息
    [email protected]{@"id":@1,@"user":@"Kenshin Cui"};//绑定到通知上的其他额外信息

    //调用通知
    [[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
@end

地方的顺序能够分成二种景况去运维:1种是运维程序关闭程序,等到接收到通告今后点击布告重新进入程序;另一种是运维程序后,进入后台(其实在前台也足以,可是为了显著的体验这一个进度提议进入后台),接收到文告后点击公告进入应用。另种状态会独家按照前边说的情形调用区别的艺术接收到userInfo写入当和姑件系统。有了userInfo一般的话就能够根据这么些新闻实行部分拍卖,举个例子能够依据差异的参数消息导航到分歧的分界面,如果是立异的打招呼则能够导航到更新内容分界面等。

 

 

推送布告

和地面公告不一样,推送公告是由应用服务提供商发起的,通过苹果的APNs(Apple
Push Notification
Server)发送到应用客户端。下边是苹果官方关于推送通告的经过暗示图:

推送布告的进度能够分为以下几步:

理所当然,那只是1个轻易的流水生产线,有了那些流程大家还不许出手工编织写程序,将方面包车型客车流程细化能够收获如下流程图(图片来自互连网),在这么些历程中会也会涉及怎么样在先后中达成这一个步骤:

一.应用程序注册APNs推送新闻。

说明:

a.唯有登记过的使用才有望收取到音信,程序中常见通过UIApplication的registerUserNotificationSettings:办法注册,iOS第88中学通告注册的章程产生了变动,倘诺是iOS柒及从前版本的iOS请参考其余代码。

b.注册之前有多少个前提条件必须希图好:开拓配置文件(provisioning
profile,也正是.mobileprovision后缀的文件)的App
ID不能够选取通配ID必须采纳钦点应用程式 ID并且调换配置文件中挑选Push
Notifications服务,一般的开垦配置文件不可能到位登记;应用程序的Bundle
Identifier必须和转移配置文件使用的应用程式 ID完全一致。

二.iOS从APNs接收device token,在应用程序获取device token。

说明:

a.在UIApplication的-(void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData
*)deviceToken
代理方法中赢得令牌,此方法发生在注册之后。

b.要是不可能正确拿到device
token能够在UIApplication的-(void)application:(UIApplication
*)application didFailToRegisterForRemoteNotificationsWithError:(NSError
*)error
代办方法中查阅详细错误新闻,此方式产生在获得device
token战败之后。

c.必须真机调节和测试,模拟器无法获得device token。

三.iOS使用将device
token发送给应用程序提供商,告诉服务器端当前配备允许抽出音讯。

说明:

a.device
token的更改算法唯有Apple精晓,为了保障算法产生变化后还是能够够平常接收服务器端发送的通告,每回应用程序运行都再一次得到device
token(注意:device
token的收获不会促成质量难点,苹果官方已经做过优化)。

b.日常能够创立1个网络连接发送给应用程序提供商的劳动器端,
在这几个进度中最棒将上一次得到的device
token存款和储蓄起来,防止再度发送,一旦发觉device
token产生了转换最棒将原有的device
token一块发送给服务器端,服务器端删除原有令牌存储新令牌幸免服务器端发送无效音信。

4.应用程序提供商在服务器端依照前边发送过来的device
token协会音讯发送给APNs。

说明:

a.发送时钦点device
token和消息内容,并且完全依据苹果官方的音信格式协会新闻内容,日常状态下得以依据别的第3方新闻推送框架来实现。

伍.APNs依据音讯中的device token查找已登记的配备推送音信。

说明:

a.经常意况下得以依靠device
token将新闻成功推送到客户端设备中,可是也不排除用户卸载程序的情形,此时推送音信战败,APNs会将以此荒唐音讯通知服务器端以免止能源浪费(服务器端此时能够依附错误删除已经积攒的device
token,下次不再发送)。

上面将轻便演示一下推送文告的大概流程:

第三,看一下iOS客户端代码:

//
//  AppDelegate.m
//  pushnotification
//
//  Created by Kenshin Cui on 14/03/27.
//  Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//

#import "AppDelegate.h"
#import "KCMainViewController.h"

@interface AppDelegate ()

@end

@implementation AppDelegate

#pragma mark - 应用程序代理方法
#pragma mark 应用程序启动之后
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    _window=[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];

    _window.backgroundColor =[UIColor colorWithRed:249/255.0 green:249/255.0 blue:249/255.0 alpha:1];

    //设置全局导航条风格和颜色
    [[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:23/255.0 green:180/255.0 blue:237/255.0 alpha:1]];
    [[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];

    KCMainViewController *mainController=[[KCMainViewController alloc]init];
    _window.rootViewController=mainController;

    [_window makeKeyAndVisible];

    //注册推送通知(注意iOS8注册方法发生了变化)
    [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
    [application registerForRemoteNotifications];

    return YES;
}
#pragma mark 注册推送通知之后
//在此接收设备令牌
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    [self addDeviceToken:deviceToken];
    NSLog(@"device token:%@",deviceToken);
}

#pragma mark 获取device token失败后
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
    NSLog(@"didFailToRegisterForRemoteNotificationsWithError:%@",error.localizedDescription);
    [self addDeviceToken:nil];
}

#pragma mark 接收到推送通知之后
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
    NSLog(@"receiveRemoteNotification,userInfo is %@",userInfo);
}

#pragma mark - 私有方法
/**
 *  添加设备令牌到服务器端
 *
 *  @param deviceToken 设备令牌
 */
-(void)addDeviceToken:(NSData *)deviceToken{
    NSString *[email protected]"DeviceToken";
    NSData *oldToken= [[NSUserDefaults standardUserDefaults]objectForKey:key];
    //如果偏好设置中的已存储设备令牌和新获取的令牌不同则存储新令牌并且发送给服务器端
    if (![oldToken isEqualToData:deviceToken]) {
        [[NSUserDefaults standardUserDefaults] setObject:deviceToken forKey:key];
        [self sendDeviceTokenWidthOldDeviceToken:oldToken newDeviceToken:deviceToken];
    }
}

-(void)sendDeviceTokenWidthOldDeviceToken:(NSData *)oldToken newDeviceToken:(NSData *)newToken{
    //注意一定确保真机可以正常访问下面的地址
    NSString *[email protected]"http://192.168.1.101/RegisterDeviceToken.aspx";
    urlStr=[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url=[NSURL URLWithString:urlStr];
    NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:10.0];
    [requestM setHTTPMethod:@"POST"];
    NSString *bodyStr=[NSString stringWithFormat:@"oldToken=%@&newToken=%@",oldToken,newToken];
    NSData *body=[bodyStr dataUsingEncoding:NSUTF8StringEncoding];
    [requestM setHTTPBody:body];
    NSURLSession *session=[NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask= [session dataTaskWithRequest:requestM completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"Send failure,error is :%@",error.localizedDescription);
        }else{
            NSLog(@"Send Success!");
        }

    }];
    [dataTask resume];
}
@end

iOS客户端代码的代码相比轻松,注册推送文告,获取device
token存款和储蓄到偏好设置中,并且只要新获得的device
token不一样于偏好设置中贮存的数额则发送给服务器端,更新服务器端device
token列表。

说不上,由于device
token需求发送给服务器端,那里运用多少个Web应用作为服务器端接收device
token,那里运用了ASP.NET程序来拍卖令牌接收注册专门的职业,当然你使用任何本事一样没非凡。下边是呼应的后台代码:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using CMJ.Framework.Data;

namespace WebServer
{
    public partial class RegisterDeviceToken : System.Web.UI.Page
    {
        private string _appID = @"com.cmjstudio.pushnotification";
        private SqlHelper _helper = new SqlHelper();
        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                string oldToken = Request["oldToken"] + "";
                string newToken = Request["newToken"] + "";
                string sql = "";
                //如果传递旧的设备令牌则删除旧令牌添加新令牌
                if (oldToken != "")
                {
                    sql = string.Format("DELETE FROM dbo.Device WHERE AppID='{0}' AND DeviceToken='{1}';", _appID, oldToken);
                }
                sql += string.Format(@"IF NOT EXISTS (SELECT ID FROM dbo.Device WHERE AppID='{0}' AND DeviceToken='{1}')
                                        INSERT INTO dbo.Device ( AppID, DeviceToken ) VALUES ( N'{0}', N'{1}');", _appID, newToken);
                _helper.ExecuteNonQuery(sql);
                Response.Write("注册成功!");
            }
            catch(Exception ex)
            {
                Response.Write("注册失败,错误详情:"+ex.ToString());
            }
        }
    }
}

以此进度首要就是保存device
token到数据库中,当然假若还要传递旧的设备令牌还供给先删除就的装置令牌,那里差不离的在数据库中创建了一张Device表来保存设备令牌,在那之中记录了应用程序Id和道具令牌。

其三步正是劳动器端发送消息,如若要给APNs发送新闻就亟须根据Apple的专门的工作音信格式协会音信内容。不过幸好当前曾经有那一个开源的第二方类库供我们选拔,具体新闻咋样包装完全不用自身团队,那里运用多个开源的类库Push
Sharp来给APNs发送音信 ,除了能够给Apple设备推送音讯,Push
Sharp还帮助Android、Windows
Phone等各样设备,越多详细内容大家能够参考官方认证。后面说过如若要开垦音信推送应用不能够利用相似的耗费配置文件,那里还亟需专注:假使服务器端要给APNs发送新闻其秘钥也必须是通过APNs
Development iOS
种类的证书来导出的,一般的iOS Development
类型的注解导出的秘钥不能用作服务器端发送秘钥。下边通过在二个简短的WinForm程序中调用Push
Sharp给APNs发送音信,那里读取以前Device表中的全体设施令牌循环发送音讯:

using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using PushSharp;
using PushSharp.Apple;
using CMJ.Framework.Data;
using CMJ.Framework.Logging;
using CMJ.Framework.Windows.Forms;

namespace PushNotificationServer
{
    public partial class frmMain : PersonalizeForm
    {
        private string _appID = @"com.cmjstudio.pushnotification";
        private SqlHelper _helper = new SqlHelper();
        public frmMain()
        {
            InitializeComponent();
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            List<string> deviceTokens = GetDeviceToken();
            SendMessage(deviceTokens, tbMessage.Text);
        }

        #region 发送消息
        /// <summary>
        /// 取得所有设备令牌
        /// </summary>
        /// <returns>设备令牌</returns>
        private List<string> GetDeviceToken()
        {
            List<string> deviceTokens = new List<string>();
            string sql = string.Format("SELECT DeviceToken FROM dbo.Device WHERE AppID='{0}'",_appID);
            DataTable dt = _helper.GetDataTable(sql);
            if(dt.Rows.Count>0)
            {
                foreach(DataRow dr in dt.Rows)
                {
                    deviceTokens.Add((dr["DeviceToken"]+"").TrimStart('<').TrimEnd('>').Replace(" ",""));
                }
            }
            return deviceTokens;
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="deviceToken">设备令牌</param>
        /// <param name="message">消息内容</param>
        private void SendMessage(List<string> deviceToken, string message)
        {
            //创建推送对象
            var pusher = new PushBroker();
            pusher.OnNotificationSent += pusher_OnNotificationSent;//发送成功事件
            pusher.OnNotificationFailed += pusher_OnNotificationFailed;//发送失败事件
            pusher.OnChannelCreated += pusher_OnChannelCreated;
            pusher.OnChannelDestroyed += pusher_OnChannelDestroyed;
            pusher.OnChannelException += pusher_OnChannelException;
            pusher.OnDeviceSubscriptionChanged += pusher_OnDeviceSubscriptionChanged;
            pusher.OnDeviceSubscriptionExpired += pusher_OnDeviceSubscriptionExpired;
            pusher.OnNotificationRequeue += pusher_OnNotificationRequeue;
            pusher.OnServiceException += pusher_OnServiceException;
            //注册推送服务
            byte[] certificateData = File.ReadAllBytes(@"E:\KenshinCui_Push.p12");
            pusher.RegisterAppleService(new ApplePushChannelSettings(certificateData, "123"));
            foreach (string token in deviceToken)
            {
                //给指定设备发送消息
                pusher.QueueNotification(new AppleNotification()
                    .ForDeviceToken(token)
                    .WithAlert(message) 
                    .WithBadge(1)
                    .WithSound("default"));
            }
        }

        void pusher_OnServiceException(object sender, Exception error)
        {
            Console.WriteLine("消息发送失败,错误详情:" + error.ToString());
            PersonalizeMessageBox.Show(this, "消息发送失败,错误详情:" + error.ToString(), "系统提示");
        }

        void pusher_OnNotificationRequeue(object sender, PushSharp.Core.NotificationRequeueEventArgs e)
        {
            Console.WriteLine("pusher_OnNotificationRequeue");
        }

        void pusher_OnDeviceSubscriptionExpired(object sender, string expiredSubscriptionId, DateTime expirationDateUtc, PushSharp.Core.INotification notification)
        {
            Console.WriteLine("pusher_OnDeviceSubscriptionChanged");
        }

        void pusher_OnDeviceSubscriptionChanged(object sender, string oldSubscriptionId, string newSubscriptionId, PushSharp.Core.INotification notification)
        {
            Console.WriteLine("pusher_OnDeviceSubscriptionChanged");
        }

        void pusher_OnChannelException(object sender, PushSharp.Core.IPushChannel pushChannel, Exception error)
        {
            Console.WriteLine("消息发送失败,错误详情:" + error.ToString());
            PersonalizeMessageBox.Show(this, "消息发送失败,错误详情:" + error.ToString(), "系统提示");
        }

        void pusher_OnChannelDestroyed(object sender)
        {
            Console.WriteLine("pusher_OnChannelDestroyed");
        }

        void pusher_OnChannelCreated(object sender, PushSharp.Core.IPushChannel pushChannel)
        {
            Console.WriteLine("pusher_OnChannelCreated");
        }

        void pusher_OnNotificationFailed(object sender, PushSharp.Core.INotification notification, Exception error)
        {
            Console.WriteLine("消息发送失败,错误详情:" + error.ToString());
            PersonalizeMessageBox.Show(this, "消息发送失败,错误详情:"+error.ToString(), "系统提示");
        }

        void pusher_OnNotificationSent(object sender, PushSharp.Core.INotification notification)
        {
            Console.WriteLine("消息发送成功!");
            PersonalizeMessageBox.Show(this, "消息发送成功!", "系统提示");
        }
        #endregion
    }
}

劳务器端信息发送应用运营效果:

iOS客户端接收的新闻的成效:

到目前截至通过劳务器端应用能够顺遂发送消息给APNs并且iOS应用已经打响接到推送音讯。

安卓

安卓

补充–iOS开辟证书、秘钥

iOS开垦进度中假设急需展开真机调节和测试、宣布供给登记报名许多证书,对于初学者往往吸引不解,再加上前些天的篇章中会牵扯到有个别出奇陈设,那里就轻便的对iOS开垦的常用证书和秘钥等做壹验证。

推送格局

推送格局

证书

iOS常用的证书包蕴支付证书和公布证书,无论是真机调节和测试照旧最终揭露应用到App
Store那么些证书都以必须的,它是iOS开荒的着力评释。

a.开辟证书:开拓证书又分为一般开垦证书和推送证书,倘若只是是一般的利用则前者就可以满意,不过假设开荒推送应用则必须选取推送证书。

b.发表证书:发表证书又有什么不可分成一般公布证书、推送证书、Pass Type
ID证书、站点公布证书、VoIP服务证书、苹果支付表明。一样的,对于急需采取异乎寻平常服装务的施用则必须挑选相应的证书。

选用状态

应用状态

利用标识

App ID,应用程序的唯一标记,对应iOS应用的Bundle Identifier,App
ID在苹果开辟者中央中分成通配应用ID和显然的接纳ID,前者一般用于一般应用开拓,1个ID能够适用于四个不相同标记的行使;可是对于利用消息推送、Passbook、站点揭橥、iCloud等劳务的使用必须配备鲜明的应用ID。

类型

类型

设备标记

UDID,用于标记每壹台硬件设施的标示符。注意它不是device token,device
token是基于UDID使用四个唯有Apple自身才掌握的算法生成的壹组标示符。

新闻中央

消息宗旨

安排简单介绍

Provisioning Profiles,日常又称作PP文件。将UDID、App
ID、开拓证书打包在一块儿的配备文件,一样分为开荒和公布两类配置文件。

触发receive

触发receive

秘钥

在提请开辟证书时必必要首先付多数少个秘钥请求文件,对于扭转秘钥请求文件的mac,假使要做开拓则只须求下载证书和配置简要介绍就可以支付。但是假如要想在其它机器上做开荒则必须将证件中的秘钥导出(导出之后是多少个.p12文本),然后导入别的机器。同时对于类似于推送服务器端应用假若要给APNs发送新闻,同样须求选拔.p12秘钥文件,并且那一个秘钥文件需倘若推送证书导出的对应秘钥。

4858美高梅,触发click

触发click

补给–布告中央

对于许多初学者往往会把iOS中的本地文告、推送文告和iOS通告中央的概念弄混。其实2者之间并从未任何关系,事实上它们都不属于八个框架,前者属于UIKit框架,后者属于Foundation框架。

布告大旨实际上是iOS程序内部之间的一种信息广播机制,重要为了化解应用程序内部区别对象之间解耦而规划。它是依赖观看者情势设计的,不可能跨应用程序进程通讯,当布告中央吸收接纳到消息随后会依据在那之中的消息转公布,将新闻发送给订阅者。上边是一个轻巧易行的流程暗暗提示图:

叩问通告中央须要熟识NSNotificationCenter和NSNotification多个类:

NSNotificationCenter:是打招呼系统的着力,用于注册和出殡和埋葬布告,下表列出常用的法子。

方法 说明
– (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject 添加监听,参数:
observer:监听者
selector:监听方法(监听者监听到通知后执行的方法)
  name:监听的通知名称
object:通知的发送者(如果指定nil则监听任何对象发送的通知)
– (id <NSObject>)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block 添加监听,参数:
name:监听的通知名称
object:通知的发送者(如果指定nil则监听任何对象发送的通知)
queue:操作队列,如果制定非主队线程队列则可以异步执行block
block:监听到通知后执行的操作
– (void)postNotification:(NSNotification *)notification 发送通知,参数:
notification:通知对象
– (void)postNotificationName:(NSString *)aName object:(id)anObject 发送通知,参数:
aName:通知名称
anObject:通知发送者
– (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo 发送通知,参数:
aName:通知名称
anObject:通知发送者
aUserInfo:通知参数
– (void)removeObserver:(id)observer 移除监听,参数:
observer:监听对象
– (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject 移除监听,参数:
observer:监听对象
aName:通知名称
anObject:通知发送者

NSNotification:代表通报内容的载体,首要有多个属性:name代表通报名称,object代表通报的发送者,userInfo代表文告的附加音讯。

就算目前的篇章中并未有涉及过通报中央,不过其实布告中央我们并不目生,前边小说中多数剧情都以经过公告中央来进展应用中各种零部件通讯的,只是未有单身拿出以来而已。举个例子前边的篇章中钻探的应用程序生命周期难题,当应用程序运行后、进入后台、进入前台、获得宗旨、失去宗旨,窗口大小退换、隐藏等都会发送布告。这一个布告能够通过前面NSNotificationCenter进行订阅就能够吸收对应的音讯,上边包车型地铁以身作则演示了怎么样增添监听得到UIApplication的进去后台和赚取核心的照看:

//
//  KCMainViewController.m
//  NotificationCenter
//
//  Created by Kenshin Cui on 14/03/27.
//  Copyright (c) 2014年 cmjstudio. All rights reserved.
//

#import "KCMainViewController.h"

@interface KCMainViewController ()

@end

@implementation KCMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self addObserverToNotificationCenter];

}

#pragma mark 添加监听
-(void)addObserverToNotificationCenter{
    /*添加应用程序进入后台监听
     * observer:监听者
     * selector:监听方法(监听者监听到通知后执行的方法)
     * name:监听的通知名称(下面的UIApplicationDidEnterBackgroundNotification是一个常量)
     * object:通知的发送者(如果指定nil则监听任何对象发送的通知)
     */
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:[UIApplication sharedApplication]];

    /* 添加应用程序获得焦点的通知监听
     * name:监听的通知名称
     * object:通知的发送者(如果指定nil则监听任何对象发送的通知)
     * queue:操作队列,如果制定非主队线程队列则可以异步执行block
     * block:监听到通知后执行的操作
     */
    NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];
    [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:[UIApplication sharedApplication] queue:operationQueue usingBlock:^(NSNotification *note) {
        NSLog(@"Application become active.");
    }];
}

#pragma mark 应用程序启动监听方法
-(void)applicationEnterBackground{
    NSLog(@"Application enter background.");
}
@end

自然很多时候利用通告主旨是为了充裕自定义布告,并得到自定义通告新闻。在前头的篇章“iOS开采类别–视图切换”中涉及过什么进行多视图之间参数字传送递,其实选取自定义公告也得以展开参数字传送递。平日3个施用登陆后会呈现用户音讯,而登入消息方可因此登入分界面获取。上面就以那样1种情状为例,在主分界面中增多监听,在报到分界面发送通告,1旦登五分三功将向文告中央发送成功登入的照应,此时主分界面中由于已经拉长布告监听所以会收到公告并更新UI分界面。

主界面KCMainViewController.m:

//
//  KCMainViewController.m
//  NotificationCenter
//
//  Created by Kenshin Cui on 14/03/27
//  Copyright (c) 2014年 cmjstudio. All rights reserved.
//

#import "KCMainViewController.h"
#import "KCLoginViewController.h"
#define UPDATE_LGOGIN_INFO_NOTIFICATION @"updateLoginInfo"

@interface KCMainViewController (){
    UILabel *_lbLoginInfo;
    UIButton *_btnLogin;
}

@end

@implementation KCMainViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self setupUI];
}

-(void)setupUI{
    UILabel *label =[[UILabel alloc]initWithFrame:CGRectMake(0, 100,320 ,30)];
    label.textAlignment=NSTextAlignmentCenter;
    label.textColor=[UIColor colorWithRed:23/255.0 green:180/255.0 blue:237/255.0 alpha:1];
    _lbLoginInfo=label;
    [self.view addSubview:label];

    UIButton *button=[UIButton buttonWithType:UIButtonTypeSystem];
    button.frame=CGRectMake(60, 200, 200, 25);
    [button setTitle:@"登录" forState:UIControlStateNormal];
    [button addTarget:self action:@selector(loginOut) forControlEvents:UIControlEventTouchUpInside];
    _btnLogin=button;

    [self.view addSubview:button];
}

-(void)loginOut{
    //添加监听
    [self addObserverToNotification];

    KCLoginViewController *loginController=[[KCLoginViewController alloc]init];

    [self presentViewController:loginController animated:YES completion:nil];
}

/**
 *  添加监听
 */
-(void)addObserverToNotification{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateLoginInfo:) name:UPDATE_LGOGIN_INFO_NOTIFICATION object:nil];
}

/**
 *  更新登录信息,注意在这里可以获得通知对象并且读取附加信息
 */
-(void)updateLoginInfo:(NSNotification *)notification{
    NSDictionary *userInfo=notification.userInfo;
    _lbLoginInfo.text=userInfo[@"loginInfo"];
    [email protected]"注销";
}

-(void)dealloc{
    //移除监听
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end

登入分界面KCLoginViewController.m:

//
//  KCLoginViewController.m
//  NotificationCenter
//
//  Created by Kenshin Cui on 14/03/27.
//  Copyright (c) 2014年 cmjstudio. All rights reserved.
//

#import "KCLoginViewController.h"
#define UPDATE_LGOGIN_INFO_NOTIFICATION @"updateLoginInfo"

@interface KCLoginViewController (){
    UITextField *_txtUserName;
    UITextField *_txtPassword;
}

@end

@implementation KCLoginViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self setupUI];
}

/**
 *  UI布局
 */
-(void)setupUI{
    //用户名
    UILabel *lbUserName=[[UILabel alloc]initWithFrame:CGRectMake(50, 150, 100, 30)];
    [email protected]"用户名:";
    [self.view addSubview:lbUserName];

    _txtUserName=[[UITextField alloc]initWithFrame:CGRectMake(120, 150, 150, 30)];
    _txtUserName.borderStyle=UITextBorderStyleRoundedRect;
    [self.view addSubview:_txtUserName];

    //密码
    UILabel *lbPassword=[[UILabel alloc]initWithFrame:CGRectMake(50, 200, 100, 30)];
    [email protected]"密码:";
    [self.view addSubview:lbPassword];

    _txtPassword=[[UITextField alloc]initWithFrame:CGRectMake(120, 200, 150, 30)];
    _txtPassword.secureTextEntry=YES;
    _txtPassword.borderStyle=UITextBorderStyleRoundedRect;
    [self.view addSubview:_txtPassword];

    //登录按钮
    UIButton *btnLogin=[UIButton buttonWithType:UIButtonTypeSystem];
    btnLogin.frame=CGRectMake(70, 270, 80, 30);
    [btnLogin setTitle:@"登录" forState:UIControlStateNormal];
    [self.view addSubview:btnLogin];
    [btnLogin addTarget:self action:@selector(login) forControlEvents:UIControlEventTouchUpInside];

    //取消登录按钮
    UIButton *btnCancel=[UIButton buttonWithType:UIButtonTypeSystem];
    btnCancel.frame=CGRectMake(170, 270, 80, 30);
    [btnCancel setTitle:@"取消" forState:UIControlStateNormal];
    [self.view addSubview:btnCancel];
    [btnCancel addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside];
}

#pragma mark 登录操作
-(void)login{
    if ([_txtUserName.text isEqualToString:@"kenshincui"] && [_txtPassword.text isEqualToString:@"123"] ) {
        //发送通知
        [self postNotification];
        [self dismissViewControllerAnimated:YES completion:nil];
    }else{
        //登录失败弹出提示信息
        UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:@"系统信息" message:@"用户名或密码错误,请重新输入!" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil];
        [alertView show];
    }

}

#pragma mark 点击取消
-(void)cancel{
    [self dismissViewControllerAnimated:YES completion:nil];
}

/**
 *  添加通知,注意这里设置了附加信息
 */
-(void)postNotification{
    NSDictionary *[email protected]{@"loginInfo":[NSString stringWithFormat:@"Hello,%@!",_txtUserName.text]};
    NSLog(@"%@",userInfo);
    NSNotification *notification=[NSNotification notificationWithName:UPDATE_LGOGIN_INFO_NOTIFICATION object:self userInfo:userInfo];
    [[NSNotificationCenter defaultCenter] postNotification:notification];
//也可直接采用下面的方法
//    [[NSNotificationCenter defaultCenter] postNotificationName:UPDATE_LGOGIN_INFO_NOTIFICATION object:self userInfo:userInfo];

}
@end

运转作效果果:

注意:
通过上面的介绍大家应该可以发现其实通知中心是一种低耦合设计,和前面文章中提到的代理模式有异曲同工之妙。相对于后者而言,通知中心可以将一个通知发送给多个监听者,而每个对象的代理却只能有一个。当然代理也有其优点,例如使用代理代码分布结构更加清晰,它不像通知一样随处都可以添加订阅等,实际使用过程中需要根据实际情况而定。

概述
在繁多移动应用中别的时候都不得不有3个应用程序处于活跃状态,假设别的使用此刻爆发…

长距离推送

长途推送

选用在前台

应用在前台

一、普通音信

一、普通音信

进入

进入

不触发

不触发

不触发

不触发

二、透传新闻且适合格式

贰、透传音讯且适合格式

进入

进入

不触发

不触发

触发

触发

三、透传消息且不相符格式

叁、透传新闻且不吻合格式

不进入

不进入

触发

触发

不触发

不触发

动用不在前台

使用不在前台

进程
存活

进程
存活

一、普通音信

一、普通音信

进入

进入

不触发

不触发

不触发

不触发

二、透传新闻且适合格式

二、透传音讯且适合格式

进入

进入

不触发

不触发

触发

触发

叁、透传消息且不适合格式

三、透传消息且不相符格式

不进入

不进入

不触发

不触发

不触发

不触发

本地推送

本地推送

运用在前台

动用在前台

 

 

 

 

进入

进入

不触发

不触发

不触发

不触发

 

 

苹果iOS系统的新闻推送:

苹果iOS系统的新闻推送:

 

 

 

 

iOS

iOS

推送情势

推送格局

动用状态

使用状态

音信大旨

消息大旨

触发receive

触发receive

触发click

触发click

长途推送
APNs

远程推送
APNs

选取在前台

应用在前台

不进入

不进入

触发

触发

不触发

不触发

选取不在前台

运用不在前台

进入

进入

不触发

不触发

触发

触发

地面推送

本地推送

应用在前台

利用在前台

进入

进入

触发

触发

不触发

不触发

 

 

Android:

Android:

触发click事件: 发送透传数据同时格式为规范格式。

触发click事件: 发送透传数据同时格式为正规格式。

触发receive事件:发送透传数据且格式为非规范格式且使用在运动。(新闻栏不会有提醒!)

触发receive事件:发送透传数据且格式为非标准格式且使用在移动。(音讯栏不会有提醒!)

 

 

iOS:

iOS:

在线:只可以响应receive,但音讯中央无新闻;

在线:只好响应receive,但新闻中央无信息;

不在线:音讯中心有音讯,且响应click事件.

不在线:新闻中央有音讯,且响应click事件.

转自:

转自:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有