布告与音讯机制,APP音讯推送是还是不是进入新闻宗旨和click

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

前者时间探讨APP音讯推送的体制,由于机型、版本的碎片化,音讯推送的建制不太好精晓,所以计算下,放在博文里以备后续查阅。

iOS开辟种类–通知与音信机制,ios开拓–机制

近年在做mqtt及任何新闻推送的作用,推送服务挺多的,Nokia推,极光推,三星(Samsung)推,个推等,当然还有苹果的apns。感到都差不离,尝试了apns,BlackBerry推和个推,各种厂商都提供的有sdk,demo。

安卓Android系统的音讯推送:

安卓Android系统的消息推送:

概述

在多数移动使用中其余时候都只好有2个应用程序处于活跃状态,如果其余使用此刻发出了部分用户感兴趣的那么通过布告机制就能够告诉用户此时产生的业务。iOS中通报机制又叫音信机制,其包含两类:一类是地面公告;另一类是推送文告,也叫远程布告。三种布告在iOS中的表现1致,能够通过横幅只怕弹出提醒两种格局报告用户,并且点击通告可以会张开应用程序,不过贯彻原理却截然两样。前天就和豪门一块去看一下什么在iOS中实现那二种体制,并且在篇章后面会补充文告中央的始末幸免初大方对二种概念的歪曲。

  1. 本土通告
  2. 推送通告
  3. 补偿–iOS开拓证书、秘钥
  4. 填补–文告核心

有关公告和音信的分别:

公告:发送后会在系统通告栏收到展现,同时响铃或振动提示用户。
( mqtt不明白能否发送通告,还在研究中…)
音信:以透传的款式传递给客户端,无展现,发送后不会在系统布告栏彰显,第1方使用后需求开荒者写代码本领看出。

 

什么样是透传?透传便是透明传送,即传送网络无论传输业务怎么,只担当将供给传送的事情传送到目标节点,同时确认保证传输的材料就可以,而不对传输的政工展开始拍录卖。透传音讯,正是新闻体格式及内容,对于传递的大路来说是不去过问的,通道只承担音讯的传递,对音讯不做任何管理,当客户端接收到透传新闻后,由客户端自身来决定哪些管理新闻。正是因为透传新闻能够自定义消息体,也足以自定义务消防队息的显得方式及后续动作管理,所以弥补了文告栏音信的有的不足之处(通知栏新闻是平素显示出来,相关的动作客户端不可能捕获到)。

透传音讯根本有如下多少个地点的特征

  1. 后台管理,用户无感知。
  2. 前台体现,提示用户。
  3. 展现的三种化。

全部透传新闻的流程如下:

依照个推提供的API接口或在个推开荒者平台上推送透传新闻,个推服务端接收到推送的音信后,不做任何管理,直接发送给目的用户。

当客户端SDK接收到透传音讯后,以广播格局发送给客户端,客户端在配备的第一方BroadReceiver里接收到透传音信后开始展览拍卖。

透传新闻的新闻体,能够依据不相同的供给传递不一致的参数或格式。如传递1个简短的字符串,或传递2个Json字符串,里面依据需求传递须要的字段。

用户无感知的透传,如:更新相关音信,在主界面中相关栏位用红点标记进行弱提醒,推送一条命令用来检查实验用户是还是不是有记名等。通告栏消息即使方便人民群众的提示用户,但也在明确水平上给用户带来了干扰,用户无感知的新闻推送有时效果会更加好。
用户有感知的透传:把透传音信管理成通告栏呈现出来,提示用户方便点击查占星关新闻(如个人帐单消息),直接张开应用或跳转到钦命的运用分界面中(依照透传音信的相关参数来判别跳转到哪3个点名的分界面,相关参数字传送递要打开的界面包车型大巴类名或Intent就能够)等。对于开垦者,管理成公告栏的连带事件也是能够捕获的,如文告栏的显得、点击等事件都得以打开捕获,以有益进行继续的操作。

因透传新闻能够友善管理成文告栏内容突显,所以通知栏的样式也得以依照须求来做相应的变动。在Android
四.四及以上的种类,通告栏能够是样式丰裕的通告栏,放入图片和录像等;能够显得平日的料理,也得以显得三种化的文告。

 

参考:

 

布告与音讯机制,APP音讯推送是还是不是进入新闻宗旨和click。 

 

地面文告

地点布告是由地面利用触发的,它是依据时间作为的一种文告方式,举例时钟按期、待办事项提醒,又大概1个利用在1段时候后不使用普通会唤醒用户使用此接纳等都以地点公告。创建贰个地点文告平常分为以下多少个步骤:

下边就以三个顺序更新后用户长时间并未有应用的提示为例对地点通告做1个简短的垂询。在这么些历程中并从未牵涉太多的分界面操作,全体的逻辑都在AppDelegate中:进入应用后若是未有注册布告,要求首先注册通告请求用户同意布告;一旦调用完登记情势,无论用户是还是不是选取允许公告此刻都会调用应用程序的
(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设置中开采通告。
  • 当地布告是有操作系统统1调解的,只有在运用退出到后台也许关闭本领接到布告。(注意:那点对于背后的推送布告也是一点一滴适用的。
  • 通报的响声是由iOS系统播放的,格式必须是Linear
    PCM、名爵IENIA(IMA/ADPCM)、µLaw、aLaw中的1种,并且播放时间必须在30s内,不然将被系统声音替换,同时自定义声音文件必须置于main
    boundle中。
  • 本土通告的多寡是有限制的,近日的本地公告最七只可以有6贰拾二个,超越这些数目将被系统忽略。
  • 一经想要移除当地公告能够调用UIApplication的cancelLocalNotification:cancelAllLocalNotifications移除钦点通告或享有文告。

从地点的顺序可以见到userInfo这几个本性我们设置了参数,那么这一个参数怎么着吸收呢?

在iOS中一旦点击三个弹出布告(只怕锁屏分界面滑动查看通告),私下认可会自动张开当前选择。由于公告由系统调整那么此时跻身应用有三种景况:假使应用程序已经完全退出那么此时会调用
(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary
*)launchOptions
艺术;若是此时应用程序还在运作(无论是在前台照旧在后台)则会调用-(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种是开行程序关闭程序,等到接收到通报之后点击文告重新进入程序;另壹种是开发银行程序后,进入后台(其实在前台也能够,可是为了分明的感受那么些进度提议进入后台),接收到通报后点击文告进入应用。另种景况会分别根据后边说的状况调用分歧的不2法门接收到userInfo写入当半夏件系统。有了userInfo一般的话就能够凭仗那个新闻举办部分拍卖,比如能够依照不一致的参数音信导航到差别的分界面,假使是创新的照看则足以导航到更新内容界面等。

 

 

推送通告

和地面布告分裂,推送公告是由应用服务提供商发起的,通过苹果的APNs(Apple
Push Notification
Server)发送到应用客户端。下边是苹果官方关于推送通知的进程暗指图:

推送文告的长河可以分成以下几步:

当然,那只是三个轻巧易行的流程,有了这么些流程大家还得不到动手工编织写程序,将方面包车型大巴流程细化能够博得如下流程图(图片源于互连网),在那个历程中会也会涉及怎么样在程序中成就那几个手续:

一.应用程序注册APNs推送音信。

说明:

a.唯有登记过的利用才有相当的大只怕收到到消息,程序中数见不鲜通过UIApplication的registerUserNotificationSettings:办法注册,iOS第88中学公告注册的法子发生了变动,假诺是iOS7及在此之前版本的iOS请参考别的代码。

b.注册从前有四个前提条件必须筹算好:开拓配置文件(provisioning
profile,也正是.mobileprovision后缀的文书)的App
ID无法采纳通配ID必须选取钦赐APP ID并且转换配置文件中挑选Push
Notifications服务,一般的支出配置文件不只怕成功登记;应用程序的Bundle
Identifier必须和扭转配置文件使用的APP 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.平常能够创立三个网络连接发送给应用程序提供商的服务器端,
在那个历程中最佳将上贰次拿走的device
token存款和储蓄起来,防止重新发送,①旦开采device
token爆发了转变最佳将原始的device
token1块发送给服务器端,服务器端删除原有令牌存款和储蓄新令牌防止服务器端发送无效音讯。

4.应用程序提供商在服务器端依据前边发送过来的device
token组织新闻发送给APNs。

说明:

a.发送时内定device
token和音讯内容,并且完全依照苹果官方的音信格式协会新闻内容,日常情状下能够依据任何第一方音讯推送框架来形成。

伍.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的正规音讯格式组织新闻内容。然则还好近年来1度有好多开源的第三方类库供大家选用,具体音信怎样包装完全不用自个儿组织,那里运用2个开源的类库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开采的常用证书和秘钥等做1证实。

推送格局

推送格局

证书

iOS常用的证书包蕴开辟证书和宣布证书,无论是真机调节和测试照旧最后公告应用到App
Store那八个证件都以必须的,它是iOS开采的核心申明。

a.开荒证书:开拓证书又分为普通开拓证书和推送证书,要是单独是一般的应用则前者就能够满足,但是尽管开拓推送应用则必须运用推送证书。

b.发表证书:发表证书又有啥不可分为普通宣布证书、推送证书、Pass Type
ID证书、站点宣布证书、VoIP服务证书、苹果支付注脚。相同的,对于供给选择特殊服务的采取则必须选用相应的证书。

行使状态

选用状态

使用标记

App ID,应用程序的绝无仅有标记,对应iOS应用的Bundle Identifier,App
ID在苹果开拓者中心中分成通配应用ID和明明的采取ID,前者一般用来普通应用开辟,贰个ID能够适用于五个不等标记的应用;可是对于利用新闻推送、Passbook、站点公布、iCloud等劳动的利用必须配备分明的选取ID。

类型

类型

器械标识

UDID,用于标记每一台硬件道具的标示符。注意它不是device token,device
token是基于UDID使用2个只有Apple自个儿才知道的算法生成的一组标示符。

音信宗旨

新闻中央

安插简要介绍

Provisioning Profiles,常常又称之为PP文件。将UDID、App
ID、开采证书打包在一起的布局文件,一样分为开荒和通知两类配置文件。

触发receive

触发receive

秘钥

在提请开垦证书时必须求率先付诸一个秘钥请求文件,对于扭转秘钥请求文件的mac,假设要做开荒则只需求下载证书和安插简单介绍就可以支付。不过假诺要想在别的机器上做开辟则必须将注脚中的秘钥导出(导出之后是一个.p1二文本),然后导入别的机器。同时对于类似于推送服务器端应用如若要给APNs发送新闻,一样须求动用.p1贰秘钥文件,并且那么些秘钥文件需若是推送证书导出的附和秘钥。

触发click

触发click

增加补充–文告宗旨

对于广大初学者往往会把iOS中的当地文告、推送文告和iOS公告宗旨的定义弄混。其实二者之间并从未别的涉及,事实上它们都不属于一个框架,前者属于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开辟连串–视图切换”中关系过什么开始展览多视图之间参数字传送递,其实使用自定义公告也能够拓展参数字传送递。经常三个选拔登入后会彰显用户音信,而登6新闻能够经过登入分界面获取。上边就以如此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

运行效果:

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

概述
在大许多活动使用中其余时候都只好有1个应用程序处于活跃状态,借使别的使用此刻爆发…

长途推送

长距离推送

应用在前台

利用在前台

一、普通新闻

一、普通新闻

进入

进入

不触发

不触发

不触发

不触发

二、透传音讯且符合格式

二、透传音讯且符合格式

进入

进入

不触发

不触发

触发

触发

三、透传新闻且不符合格式

3、透传音讯且不适合格式

不进入

不进入

触发

触发

不触发

不触发

使用不在前台

利用不在前台

进程
存活

进程
存活

一、普通音讯

壹、普通新闻

进入

进入

不触发

不触发

不触发

不触发

贰、透传消息且适合格式

2、透传音信且适合格式

进入

进入

不触发

不触发

触发

触发

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

三、透传音信且不相符格式

不进入

不进入

不触发

不触发

不触发

不触发

地方推送

地面推送

应用在前台

采纳在前台

 

 

 

 

进入

进入

不触发

不触发

不触发

不触发

 

 

苹果iOS系统的音信推送:

苹果iOS系统的消息推送:

 

 

 

 

iOS

iOS

推送格局

推送方式

选取状态

运用状态

音讯中央

消息大旨

触发receive

触发receive

触发click

触发click

长途推送
APNs

长距离推送
APNs

选用在前台

行使在前台

澳门葡京,不进入

不进入

触发

触发

不触发

不触发

动用不在前台

使用不在前台

进入

进入

不触发

不触发

触发

触发

地面推送

本地推送

运用在前台

行使在前台

进入

进入

触发

触发

不触发

不触发

 

 

Android:

Android:

触发click事件: 发送透传数据同时格式为行业内部格式。

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

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

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

 

 

iOS:

iOS:

在线:只可以响应receive,但信息中央无消息;

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

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

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

转自:

转自:

相关文章

发表评论

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

*
*
Website