推送通知/传感器/UIDynamic
一.推送通知
1.推送通知简介
- 什么是推送通知
- 此处的推送通知与NSNotification没有任何关系
- 可以理解为,向用户推送一条信息来通知用户某件事情
- 作用:可以在APP退到后台或者关闭时,继续推送一条消息告诉用户某件事情
- 推送通知的应用场景
- 任务管理类APP,会在任务时间即将到达时,通知做该做的任务
- 即时通讯类APP,即使退到后台,或者关闭APP,也可以收到信息通知告诉用户
- 电商APP,推送消息通知用户最新打折商品等
- 推送通知的分类
- 本地推送通知
- 本地通知,即使在没有网络的情况下,也可以推送通知消息
- 应用场景:确定知道未来某个时间点应该提醒用户什么
- 远程推送通知
- 概念:与本地通知相对,必须在联网情况下才会向用户推送通知消息
- 远程推送服务有成为APNs(Apple Push Notification Service)
- 应用场景1:不确定未来某个时间点应该提醒用户什么,临时性的
- 应用场景2:当APP彻底退出时,也想继续让用户获取一些最新消息
- 使用原则
- 谁能确定通知时间和内容,谁就可以发送
- 开发人员在APP内部通过代码发送->本地通知
- 服务器可以确定通知时间和内容->远程通知
- 推送通知的展现样式
- 在屏幕顶部显示一块横幅(显示具体内容)
- 在屏幕中间弹出一个UIAlertView(显示具体内容)
- 在锁屏界面显示一块横幅(锁屏状态下,显示具体内容)
- 更新APP图标的数字(说明新内容的数量)
- 播放音效(提醒作用)
- 注意:以上样式只能是用户自己设置,开发者无法通过代码控制
2.本地推送通知
- 本地通知的基本使用
- 创建UILocalNotification对象
- 设置一些必要的属性
- 推送通知的触发时间(何时发出推送通知)
- @property(nonatomic,copy) NSDate *fireDate;
- 推送通知的具体内容
- @property(nonatomic,copy) NSString *alertBody;
- 开始推送通知
- 根据fireDate设定的时间进行推送
- [[UIApplication sharedApplication] scheduleLocalNotification];
- 立即推送
- presentLocalNotificationNow:(UILocalNotification *)notification;
- 取消调度本地推送通知
- (void)cancelLocalNotification:(UILocalNotification *)notification;
- (void)cancelAllLocalNotification;
- 获得被调度(定制)的所有本地推送通知
- @property(nonatomic,copy) NSArray *scheduledLocalNotifications;
- 已经发出且过期的推送通知一旦调度结束,会自动从这个数组中移除
- 注意事项
- 在iOS8.0以后,如果要使用本地通知,需要得到用户的许可
- 在didFinishLaunchingWithOptions方法中添加如下代码:
- 设置通知的提示方式(badge图标/sound声音/alert)
- [application registerUserNotificationSettings:settings];
- 额外设置
- 每隔多久重复发一次推送通知
- @property(nonatomic) NSCalendarUnit repeatInterval;
- 点击推送通知打开app时显示的启动图片
- @property(nonatomic,copy) NSString *alertLaunchImage;
- 额外的附加信息
- @property(nonatomic,copy) NSDictionary *userInfo;
- 时区
- @property(nonatomic,copy) NSTimeZone *timeZone;
- 一般设置为[NSTimeZone defaultTimeZone],跟随手机的时区
- 在锁屏时显示的动作标题(完整标题:"滑动来"+alertAction)
- @property(nonatomic,copy) NSString *alertAction;
- 音效文件名
- @property(nonatomic,copy) NSString *soundName;
- app图标数字
- @property(nonatomic) NSInteger applicationIconBadgeNumber;
- 监听用户点击通知
- app处于前台
- 此时不会弹框通知用户通知的到达,但是还是会调用对应的代理方法
- app没有关闭,隐藏在后台
- 此时用户点击通知信息后,会让app进入前台,并会调用AppDelegate的下面方法
- application:didReceiveLocalNotification:
- app已经关闭(进程已死)
- 此时用户点击通知信息后,会启动app,启动完毕会调用AppDelegate的下面方法
- application:didFinishLaunchingWithOptions:
- launchOptions参数通过UIApplicationLaunchOptionsLocalNotificationKey取出本地推送通知对象
- 额外补充:在iOS8之后,可以设置推送通知带操作行为
- 在注册设置时,设置categories:参数UIMutableUserNotification
- identifier:动作标识
- title:动作标题
- activationMode:是前台运行,还是后台运行此动作
- destructive:是否是破坏性动作(只是通过颜色,标识按钮,给用户提示)
- behavior:动作行为(iOS9提供一个文本行为)
- 监听通知操作行为的点击
- application:handleActionWithIdentifier:forLocalNotification:completionHandler:
- application:handleActionWithIdentifier:forLocalNotification:withResponseInfo:completionHandler:
3.远程推送通知
- 远程推送的原理
- 所有苹果设备,在联网状态下,都会与苹果服务器建立一个长连接
- 长连接:
- 优势:服务器可以向客户端发送消息,保证数据的即时性
- 劣势:占用客户端和服务器资源
- 短连接:
- 优势:节省资源,一个会话结束后,立即释放资源
- 劣势:服务器无法主动向客户端发信息
- 苹果设备长连接的作用:
- 时间校准
- 系统升级
- 查找我的iPhone
- 推送通知
- 原理就是借助苹果设备与APNs服务器之间的长连接,借助APNs服务器将消息发送给客户端,与QQ/微信的消息发送机制类似.
- 远程推送通知实现,客户端需要做的事
- 需要真机调试证书,推送测试证书
- 请求苹果获得deviceToken
- 注意:只有真机可以调试推送证书,因为只有真机才具备UDID,才能够生成deviceToken
- 在iOS8之前,请求远程推送通知
- [[UIApplication sharedApplication] registerForRemoteNotificationTypes:nil];
- 在iOS8之后,请求远程推送通知
- UIUserNotificationSettings *notificationSet = [[UIUserNotificationSettings settingsForTypes:nil categories:nil]];
- [[UIApplication sharedApplication] registerForRemoteNotifications];
- 当远程通知注册后,APNs会通过调用这个方法,返回对应的deviceToken
- application:didRegisterForRemoteNotificationWithDeviceToken:
- 得到苹果返回的deviceToken,发送deviceToken给公司的服务器
- 远程推送测试(使用PushMeBaby)
- 编译会出现错误,直接把错误行注释即可
- 需要天街对应的deviceToken
- 需要把推送测试证书改名为aps.cer拖入项目中
- 监听用户对通知的点击
- application:didReceiveRemoteNotification
- application:didReceiveRemoteNotification:fetchCompletionHandler:
- 当前在前台时,或者app在后台/app被彻底退出状态下,点击通知打开app进入前台,都可以执行以下方法
- 执行completionHandler作用
- 系统会估量app消耗的电量,并根据传递的UIBackgroundFetchResult参数记录新数据是否可用
- 调用完成的处理代码时,应用的界面缩略图会自动更新
- 如果想要接收到通知后,不要用户点击通知,就执行以下代码,那么必须有三个要求
- 必须勾选后台模式Remote Notification
- 告诉系统是否有新的内容更新(执行完成代码块)
- 设置发送通知的格式("content-available":"随便传")
- 第三方推送
- 极光推送简介
- 优势
- 减少开发及维护成本
- 应用开发者不需要去开发维护自己的推送服务器与APNs对接
- 集成了JPush iOS SDK后不必自己维护更新deviceToken
- 通过JPush的Web Portal直接推送,也可以调用JPush的HTTP协议API来完成,开发工作量大大减少
- 减少运营成本
- 极光推送支持一次推送,同时向Android/iOS/WinPhone三个平台.支持统一的API与推送界面.
- 极光推送提供标签/别名绑定机制,以及提供了非常细分的用户分群方式,运营起来非常简单,直观.
- 提供应用内消息推送
- 除了使得APNs推送更简单,也另外提供应用内消息推送,这在类似于聊天的场景里很有必要.
- 发送通知流程
- app同时和极光服务器/苹果APNs服务器保持长连接
- 当服务器需要向用户推送消息时,通过极光云,将要推送的消息发送到APNs后,由苹果服务器下发该消息
- 对于应用内消息推送,极光云服务器可以直接与app保持长连接,来及时获取服务器下发的消息
- 集成指导文档
- 具体集成步骤以及使用方法
- 配置证书(开发环境/生产环境下的推送P12证书)
- 创建应用,上传待集成,发布的应用所使用的AppID的APNs证书
- 在"iOS开发证书"选项中,选择导出的APNs Development iOS证书的.p12文件
- 开发证书密码,需要与到处p12证书时设置的一致
- 在"iOS生产证书"选项中,选择到处的Apple Push Service证书的.p12文件
- 获取AppKey,集成过程中需要把该值配置到项目中
- Bundle ID为上传的证书的BundleID,请确定与Xcode项目中info.plist中的Bundle Identifier一致
- 下载SDK并集成到项目中
- 解压SDK包,将解压后的lib子文件夹添加到工程目录中
- 根据文档,添加必要的框架
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
// Required
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];
}
// Required
//如需兼容旧版本的方式,请依旧使用[JPUSHService setupWithOption:launchOptions]方式初始化和同时使用pushConfig.plist文件声明appKey等配置内容。
[JPUSHService setupWithOption:launchOptions appKey:appKey channel:channel apsForProduction:isProduction];
return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// Required
[JPUSHService registerDeviceToken:deviceToken];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// Required,For systems with less than or equal to iOS6
[JPUSHService handleRemoteNotification:userInfo];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// IOS 7 Support Required
[JPUSHService handleRemoteNotification:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
//Optional
NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}
iOS10推送通知适配
- iOS10推送新增了UserNotifications.framwork,使用起来其实很简单
- iOS10之前,点击通知栏,执行的回调方法
- application:didReceiveRemoteNotification:
- application:didReceiveRemoteNotification:fetchCompletionHandler:
- iOS10推送通知
- 在前台的时候回调(userNotificationCenter:willPresentNotification:withCompletionHandler:)
- 在后台进入的时候回调(userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:)
- 使用步骤:
- 导入头文件UserNotification/UserNotification.h
- 在application:didFinishLaunchingWithOptions:中判断系统版本号,并注册通知(iOS8之前/iOS8-iOS9/iOS10三中情况下,注册通知的方式不一样)
- 在对应的回调方法中,获取通知数据
- 对于本地通知没有变化,依然回调(application:didReceiveLocalNotification:)
二.传感器
1.传感器简介
- 简介:传感器是一种感应/检测装置,目前已经广泛应用于智能手机上
- 作用:用户感应/检测设备周边的信息,不同类型的传感器,检测的信息也不一样
- 使用场景:
- 地图app中,判断手机的朝向
- 在光线较暗的条件下,自动降低屏幕亮度
- 打电话时,人脸贴近iPhone屏幕时,屏幕会自动锁屏
- iPhone内置的传感器
- 运动传感器/加速度传感器/加速计(Motion/Accelerometer Sensor)
- 最早出现在iOS设备上的传感器之一
- 加速计用于检测设备在X/Y/Z轴上的加速度(哪个方向有力的作用)
- 应用场景:加速度计可以用于检测设备的摇晃/摇一摇/计步器
- 环境光传感器(Ambient Light Sensor)
- 是iOS/Mac设备中最为古老的传感器成员
- 它能够让用户在使用的时候,眼镜更为舒适
- 距离传感器(Proximity Sensor)
- 磁力计传感器(Magnetometer Sensor)
- 感应地球磁场,获得方向信息,使位置服务数据更精确
- 用于电子罗盘和导航应用
- iPad的Smart Cover盒盖睡眠操作就是基于磁力计传感器
- 内部温度传感器(Internal Temperature Sensor)
- 从iPad一代开始,iOS设备就加入了内部温度传感器,用于检测内部组件温度,当温度超过系统设定的阈值时,就会警告用户.
- 湿度传感器(Moisture Sensor)
- 湿度传感器和其他微电子的传感器不同,是一个简单的物理传感器
- 简单来说,湿度传感器就是一张遇水变红的试纸
- Apple的维修人员就是通过检测试纸是否变红,来判断设备是否进水(设备进水不在保修范围之内)
- 陀螺仪(Gyroscope)
- 陀螺仪是随着iPhone4的上市首次出现在iOS设备上的传感器
- 陀螺仪可以用于检测设备的握持方式
- 陀螺仪的原理是检测设备在X/Y/Z轴上所旋转的角度
- 应用场景:
- 陀螺仪在赛车类游戏中有重大作用
- 模拟汽车驾驶时方向盘螺旋的动作,使得这类游戏的操控体验更为真实
2.常用传感器的实现
- 距离传感器
- 作用:检测是否有物体靠近设备
- 应用场景:微信中的语音消息,如果把设备靠近耳边会启动听筒播放,如果离开,会启动扩音器播放
- 使用步骤
- 开启距离感应功能
- [UIdevice currentDevice].proximityMonitoringEnalbe = YES;
- 监听距离感应的通知
- 通知名称:UIDeviceProximityStateDidChangeNotification
- 实现监听方法
- 在监听方法中,需要判断是否开启了距离感应功能,再决定是否执行相应的代码
- 加速度计(iOS4以前)
- 原理:检测设备在X/Y/Z轴上的加速度(哪个方向有力的作用,哪个方向运动了)
- 根据加速度数值,可以判断出各个方向上的作用力度
- 在iOS4以前,使用UIAccelerometer,用法非常简单(到了iOS5就已经过期),swift无法使用
- 获得单例对象
- UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
- 设置代理
- accelerometer.delegate = self;
- 设置采样间隔(1秒钟采样30次)
- accelerometer.updateInterval = 1.0/30.0;
- 实现代理方法
- accelerometer:didAccelerate
- 加速度计(iOS4之后)
- 从iOS4开始使用CoreMotion.framework
- 使用变化
- 随着iPhone4的推出,加速度计全面升级,并引入了陀螺仪
- 与Motion(运动)相关的编程成为重头戏
- 苹果特地在iOS4中增加了专门处理Motion的框架-CoreMotion.framework
- CoreMotion不仅能够提供实时的加速度值和旋转速度值,更重要的是,苹果在其中继承了很多重要的算法
- CoreMotion获取数据的两种方式
- push:实时采集所有数据(采集频率高)
- 优点:从不缺失采样,适用于数据采集app
- 缺点:Increased overhead/Often best to drop samples
- pull:在有需要的时候,再主动去采集数据
- 优点:更加高效/需要的代码更少,蛇用于大多数app和游戏类app
- 缺点:由于是在需要的时候主动采集,可能需要添加额外的定时器
- CoreMotion的使用步骤
- push
- 创建运动管理者对象
- CMMotionManager *mgr = [[CMMotionManager alloc] init];
- 判断加速度计是否可用(最好判断)
- if(mgr.isAccelerometerAvailable)
- 设置采样间隔(1秒钟采样30次)
- mgr.accelerometerUpdateInterval = 1.0/30.0
- 开始采样(采样到数据就会调用handler,handler会在queue中执行)
- startAccelerometerUpdatesToQueue:withHandler:
- pull
- 创建运动管理者对象
- CMMotionManager *mgr = [[CMMotionManager alloc] init];
- 判断加速度计是否可用(最好判断)
- if(mgr.isAccelerometerAvailable)
- 开始采用
- startAccelerometerUpdates
- 在需要的时候采集加速度数据
- CMAcceleration acc = mgr.accelerometerData.acceleration;
- 摇一摇
- 方法1:通过分析加速度数据来判断是否进行了摇一摇操作(复杂)
- 方法2:iOS自带的Shake监控API(简单)
- 实现3个摇一摇监听方法
- 检测到摇动:motionBegan:withEvent:
- 摇动取消(被中断):motionCancelled:withEvent:
- 摇动结束:motionEnded:withEvent:
- 计步器
- 功能作用:判断走了多少步/判断爬了多少楼层
- 实现步骤:
- CMStepCounter(iOS8之前)
- 判断计步器是否可用
- [CMPedometer isStepCountingAvailable];
- 创建计步器对象
- CMPedometer *stepCounter = [[CMPedometer alloc] init];
- 开始计步
- [stepCounter startPedometerUpdatesFromDate:nil withHandler:nil];
三.UIDynamic
1.物理引擎UIDynamic简介
- 什么是UIDynamic?
- UIDynamic是从iOS7开始引入的一种新技术,隶属于UIKit框架
- 可以认为是一种物理引擎,能模拟和仿真现实生活中的物理现象(重力/弹性碰撞等现象)
- 物理引擎的价值
- 广泛用于游戏开发,经典成功案例是"愤怒的小鸟"
- 让开发人员可以在原理物理学公式的情况下,实现炫酷的物理方针效果
- 提高了游戏开发效率,产生更多优秀好玩的物理仿真游戏
2.UIDynamic的使用步骤
- 使用步骤
- 创建一个物理仿真器(顺便设置仿真范围)
- 创建相应的物理仿真行为(顺便添加物理仿真元素)
- 将物理仿真行为添加到物理仿真器中,开始仿真
- 三大概念
- 物理仿真元素(Dynamic Item)
- 谁要进行物理仿真
- 注意:不是任何对象都能做物理仿真元素/不是任何对象都能进行物理仿真
- 哪些对象才能做物理仿真元素
- 任何遵守了UIDynamicItem协议的对象
- UIView默认已经遵守了UIDynamicItem协议,因此任何UI控件都能做物理仿真
- UICollectionViewLayoutAttributes类也默认遵守了UIDynamicItem协议
- 物理仿真行为(Dynamic Behavior)
- 执行怎样的物理仿真效果?怎样的动画效果?
- UIDynamic提供了以下几种物理仿真行为
- UIGravityBehavior:重力行为
- UICollisionBehavior:碰撞行为
- UISnapBehavior:捕捉行为
- UIPushBehavior:推动行为
- 物理仿真行为须知
- 上述所有物理仿真行为都继承自UIDynamicBehavior
- 所有的UIDynamicBehavior都可以独立进行
- 组合使用多种行为时,可以实现一些比较复杂的效果
- 物理仿真器(Dynamic Animator)
- 让物理仿真元素执行具体的物理仿真行为
- 物理仿真器须知
- 他可以让物理仿真元素执行物理仿真行为
- 它是UIDynamicAnimator类型的对象
- UIDynamicAnimator的初始化
- (instancetype)initWithReferenceView:(UIView *)view;
- view参数:是一个参照视图,表示物理仿真的范围
- UIDynamicAnimator的常见方法
- 添加1个物理仿真行为(addBehavior:)
- 移除1个物理仿真行为(removeBehavior:)
- 移除之前添加过的所有物理仿真行为(removeAllBehavior)
- UIDynamicAnimator的常见属性
- 参照视图
- @property(nonatomic,readonly) UIView *referenceView;
- 添加到物理仿真器中的所有物理仿真行为
- @property(nonatomic,readonly,copy) NSArray *behaviors;
- 是否正在进行物理仿真
- @property(nonatomic,readonly,getter=isRunning) BOOL running;
- 代理对象(能监听物理仿真器的仿真过程,比如开始和结束)
- @property (nonatomic,assign) id delegate;
3.常用行为演练
- 使用技巧:根据仿真元素创建仿真行为,添加到仿真器即可执行该方法
- 重力行为(UIGravityAnimator)
- 简介:给定重力方向/加速度,让物体朝着重力方向掉落
- 初始化:initWithItems:(参数中存放着物理仿真元素)
- 常见方法:添加1个物理仿真元素(addItem)
- 常见属性:
- 添加到重力行为中的所有物理仿真元素:NSArray *items;
- 重力方向(二维向量):CGVector gravityDirection;
- 重力方向(是一个角度,以x轴正方向为0°,顺时针为正,逆时针为负):CGFloat angle;
- 量级(用来控制加速度,1.0代表加速度是1000点/秒的平方):CGFloat magnitude;
- 演练步骤:
- 创建物理仿真器
- _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
- 根据仿真元素创建重力仿真行为
- UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[self.boxView]];
- 设置重力角度
- gravityBehavior.angle = M_PI*0.5;
- 设置量级
- gravityBehavior.magnitude = 1;
- 添加仿真行为到仿真器,开始仿真
- [self.animator addBehavior:gravityBehavior];
- 碰撞行为(UICollisionAnimator)
- 简介:可以让物体之间实现碰撞效果,可以通过添加便捷(boundary),让物理碰撞局限在某个空间中
- 边界相关的方法
- addBoundaryWithIdentifier:forPath:
- addBoundaryWithIdentifier:fromPoint:toPoint:
- boundaryWithIdentifier:
- removeBoundaryWithIdentifier:
- NSArray *boundaryIdentifiers;
- removeAllBoundaries;
- 常见用法
- 是否以参照视图的bounds为边界
- BOOL translatesReferenceBoundsIntoBoundary;
- 设置参照视图的bounds为边界,并设置内边框
- setTranslatesReferenceBoundsIntoBoundaryWithInsets:
- 碰撞模式(分为3中,元素碰撞/边界碰撞/全体碰撞)
- UICollisionBehaviorMode collisionMode;
- 只碰撞物体,不碰撞边界(UICollisionBehaviorModeItems=1<<0)
- 只碰撞边界,不碰撞物体(UICollisionBehaviorModeBoundaries=1<<1)
- 边界和物体都碰撞(UICollisionBehaviorModeEverything=NSUIntegerMax)
- 演练步骤
- 创建物理仿真器
- 根据仿真元素创建碰撞仿真行为
- 设置是否以参照视图的bounds为边界
- 设置碰撞模式
- 添加仿真行为到仿真器,开始仿真
- 捕捉行为(UISnapAnimator)
- 简介:可以让物体迅速冲到某个位置(捕捉位置),捕捉到位置之后会带有一定的震动
- 初始化:initWithItem:snapToPoint:
- 常见属性:CGFloat damping;(用于减幅/减震,取值范围0.0~1.0,值越大,震动幅度越小)
- 使用注意:如果要进行连续的捕捉行为,需要先把前面的捕捉行为熊物理仿真器中移除
- 演练步骤
- 创建物理仿真器
- 注意:如果想多次执行捕捉行为,需要在捕捉之前移除前面添加的捕捉行为
- 创建捕捉行为
- 设置振幅
- 添加仿真行为到仿真器,开始仿真
- 推动行为(UIPushAnimator)
- 简介:可以向某个方向,推动某个物体
- 初始化:initWithItems:mode:
- UIPushBehaviorMode
- UIPushBehaviorModeContinuous:持续,一直推
- UIPushBehaviorModeInstantaneous:不持续,推一下就放开
- 常见属性:CGVector pushDirection;(推送方向,是一个向量,其坐标系与屏幕坐标系一致)
- 演练步骤:
- 创建物理仿真器
- 根据仿真元素创建推动仿真行为
- 设置推动方向
- 添加仿真行为到仿真器,开始仿真