从0到1思考与实现iOS-Widget
讲述之前首先看下demo效果图:


然后再展示几个效果不错的 Widget app






demo 地址在此!欢迎star

一、Widget总览
- Widget 是 iOS8 推出第一版,在iOS 10 进行大幅度的优化
- Widget可以让用户更快地访问到其感兴趣的内容,官方的说法是用来呈现功能比较简单的,交互性不强的东西,在不打扰或者中断用户使用当前应用的前提下完成自己的功能点.对于这个说法,国内的开发者表示呵呵,因为几乎所有的 Widget都绑定了对应的点击事件
二、Widget代码实现
因为 Widget 属于单独的进程,因此需要再新建一个target:File -> New ->target
初次构建 UI 时,运行 Widget 后会发现,Widget左侧距离屏幕左侧始终有一段距离,导致效果不佳,可以通过下面的代理方法消除间距
// 取消widget默认的inset,让应用靠左
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets {return UIEdgeInsetsZero;
}
- Widget 的收起、展开 则是通过这个代理方法:
/**activeDisplayMode有以下两种NCWidgetDisplayModeCompact, // 收起模式NCWidgetDisplayModeExpanded, // 展开模式*/
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize {if(activeDisplayMode == NCWidgetDisplayModeCompact) {// 尺寸只设置高度即可,因为宽度是固定的,设置了也不会有效果self.preferredContentSize = CGSizeMake(0, 110);} else {self.preferredContentSize = CGSizeMake(0, 310);}
}
在设置 UI 的过程中,若想使用本体 Target 中的类:
在对应类的 Target Membership 勾选 Widget 即可如果想使用Pod 管理的第三方库,那么只需要以下三步就可以愉快地玩耍了(比如我想使用 Masonry 布局)
1、 在podfile文件中
2、 按照如图所示配置configurations
3、 最后分别配置两个 Target 的 link Binanry当然有些第三方包含 source 文件的可能还需要别的操作,最简单粗暴的方式就是-->拖进去!
使用图片也是必不可少,然而 imageNamed: 和 imageWithContentsOfFile: 两种方式加载都不行,即使设置了文件的 target 为 Widget Extension,后来在其target 内部建立一个 .xcassets 文件即可加载图片
然而在 Widget Extension 里面新建类又出现了如下报错
- 造成这个的原因是新建的时候默认是 C header,而且没有指向对应的target,按照下图所示修改一下type,选一下target,再次编译就木有问题了

- 如果需要网络请求,记住在 Extension 的plist文件中添加App Transport Security Settings 属性
- 在开发过程中,那么怎么一直有个“Hello World”显示,最后看了一下原来是 Storyboard 加载,去 Storyboard 文件删除对应 label 即可
- 如果你的项目中要求纯代码
- 删除 Storyboard 文件和plist 对应键值对
- 添加 NSExtensionPrincipalClass 字段并设置为 TodayViewController
三、与 App 本体交互
与本体 app 进行交互之前,要明白的一个概念是:Widget 与 app 本身 是两个target,appId 也是独立的,因此 Widget 与本体 app 是通过 app group 进行交互
1、设置群组关系
在 本体 App 的 target > Capabilities添加 container 标识符


- 报错信息:[_NCWidgetExtensionContext openURL:completionHandler:]_block_invoke failed: Error Domain=NSOSStatusErrorDomain Code=-50 "(null) 如果报这个错说明 urlScheme有问题,没有标准对应,比如下划线识别等
2、设置 scheme 进行交互
- 设置 app 的 scheme 标识符在plist 文件内添加以下键值对
- 然后!就可以在 Widget 对应的点击事件里面
// 扫一扫按钮的点击事件
- (void)scanBtnTapped:(UIButton *)sender {[self.extensionContext openURL:[NSURL URLWithString:@"wpfWidgetTest://action=richScan"] completionHandler:^(BOOL success) {NSLog(@"scanBtnTapped open url result:%d",success);}];
}
- 在 app 本体的 AppDelegate 方法里面
// 处理 Widget 相关事件
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {NSString* prefix = @"wpfWidgetTest://action=";NSString *urlString = [url absoluteString];if ([urlString rangeOfString:prefix].location != NSNotFound) {NSString *action = [urlString substringFromIndex:prefix.length];if ([action isEqualToString:@"richScan"]) {// 进入到扫一扫页面[self.rootVC transferToRichScanVC];} else if ([action isEqualToString:@"web"]) {// 进入到 web 活动页[self.rootVC transferToWebVCWithUrlString:@"webTest"];} }return YES;
}
- 数据共享:widget项目必然经常要和主项目共享数据,可以通过NSUserDefault,注意和平时用有些不同,创建UserDefault的时候,要指定groupid。上代码:
// widget项目里取数据
+ (NSString*)widgetStringForKey:(NSString*)defaultName {NSUserDefaults*shared = [[NSUserDefaultsalloc] initWithSuiteName:@"group.com.widgetTest"];return[shared stringForKey:defaultName];
}// 主项目里存数据
+ (void)widgetSetObject:(id)value forKey:(NSString*)defaultName {NSUserDefaults*shared = [[NSUserDefaultsalloc] initWithSuiteName:@"group.com.widgetTest"];[shared setObject:value forKey:defaultName];[shared synchronize];
}#warning 涉及到大量数据交互也可以使用 NSFileManager 进行数据共享
在demo中,实现了从Widget入口 点击未读消息后,下次不再展示该未读消息项

四、关于刷新时机
- Widget 自身的更新机制,是进入到 Widget 页面后(iOS 10 左滑,之前是下拉),先执行 viewDidLoad 方法,然后是 viewWillAppear 方法,但是经测验,Widget 页面在屏幕消失超过两秒后(手机没有停留在 Widget 页面 或者 停留在别的app 的Widget页面,自己的没显示)
- 由于以上特性,更新代码最好写在 viewWillAppear 方法里面,对于更新时效性特别强的,比如天气类 app,这种最好就是 在该方法里面添加一个 NSTimer 定时进行刷新,在 viewWillDisAppear 方法中 进行 取消NSTimer invalidate定时更新即可
- 知乎、得到 app的 Widget,只要走 viewDidLoad 方法就会闪一下(如下图),因为每次Widget加载请求的数据后会进行替换造成的。这里可以做个缓存优化,判断如果请求来的数据和当前数据内容一致,那么就不进行刷新列表操作不信你看
五、关于 iOS8 适配
- iOS8、9是老式的下拉刷新,并没有折叠和展开功能,默认的Widget高度为self.preferredContentSize设置的高度
- iOS8 默认的背景是黑色磨砂效果,iOS10默认的背景色是白色磨砂效果。因此在控件颜色上做下适配

- iOS8下所有组件默认右移30pt
六、其他注意点
当程序内存不足时,苹果优先会杀死扩展,因此需要注意内存的管理。
在配置team是账号需要一致(免费账号不行,需要付费的账号),上传包的时候一定注意选择 Product -> Archive -> 选择 distribution 模式!
3D touch 对应的也有Widget!?答案是 YES!,只要设置了3D touch,Widget的第一栏就会自动显示
Extension 证书配置指南
官网说明
一直很心仪的app --> Things 关于widget的介绍
几个精致的 Widget app
在模拟器上进行3D touch 测试

再次附上 demo Github 地址,欢迎star
相关文章:
Android Studio 初体验
Google在I/O2013大会上发布了Android新的开发工具Android Studio,趁周末时间做了一下尝试。有需要的可以在http://developer.android.com/sdk/installing/studio.html下载,当前版本是V0.1。官方解释:Android Studio is anew Android developm…

JAVA面试题(2)
1 String 与 new 的不同 使用“”赋值不一定每次都创建一个新的字符串,而是从“字符串实例池”中查找字符串。使用“new”进行赋值,则每次都创建一个新的字符串。 2 String与StringBuffer String类是不可变类,字符串一旦初始化后,…

限制HTTP数据包发送Referer
一般点击一个A标签的时候都会发送 Referer 什么是 Referer? 就是你点击A标签 Referer的信息告诉服务端你从哪里点击出来的 可在HTML上加 <meta name"referrer" content"no-referrer">这样就不发送Referer头了
TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议
把这三个协议放到一起学习是因为这三个协议处于同一层,ARP协议用来找到目标主机的Ethernet网卡Mac地址,IP则承载要发送的消息。数据链路层可以从ARP得到数据的传送信息,而从IP得到要传输的数据信息。 1.IP协议 IP协议是TCP/IP协议的核心&…

数据结构与算法分析(C++版)(第二版)
查看书籍详细信息: 数据结构与算法分析(C版)(第二版) 内容简介 本书采用程序员最爱用的面向对象C语言来描述数据结构和算法,并把数据结构原理和算法分析技术有机地结合在一起,系统介绍了各种…

nginx反向代理原理讲解
一 、概述 反向代理(Reverse Proxy)方式是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器;并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务…

cojs 简单的数位DP 题解报告
首先这道题真的是个数位DP 我们考虑所有的限制: 首先第六个限制和第二个限制是重复的,保留第二个限制即可 第五个限制在转移中可以判断,不用放在状态里 对于第一个限制,我们可以增加一维表示余数即可 对于第四个限制也是同理 对于…

iOS ERROR ITMS - 打包上传报错整理
作者 Silence_广 关注 2017.03.24 11:12 字数 706 阅读 45评论 1喜欢 12ERROR ITMS-90034 ERROR ITMS-90034这个问题就是你的包里面的证书和开发者中心的证书不一样所以提交的时候回报错. 如果试过网上很多的解决方法之后(诸如重新制作证书,删调过期证书…

照片墙瀑布流加载与阻止加载
网上大部分主流的瀑布流应用基本都是由后端在提供图片地址的同时提供图片宽高,这样,前端不必等待图片渲染完成,可以根据图片的宽高先把装载图片的容器或父节点先放上页面,完成基础性的布局,再让图片以渐变或其他方式逐…

利用Nginx实现简易负载均衡
基本思路如下: 比如我们有三个服务器: 其中: 130.251是反向代理转发服务器 130.251和130.238分别是负载服务器 Mysql服务器没有标出来, 为方便区分,我们先把1号负载的首页写成111111111 2号负载的首页写成222222 然后我们现在控制130.251, 把nginx配置文…

两行代码搞定iOS自定义HUD风格动画弹窗(支持选择记录) - SKChoosePopView的使用和实现思路
作者 ShevaKuilin 关注 2017.03.25 18:28* 字数 2014 阅读 270评论 0喜欢 23さらい屋五葉原文地址----> MyBlog HUD风格的选项弹窗是我们在日常开发中经常会碰到的一类需求,通常因为项目周期等因素,很少会专门抽出时间来对此类弹窗进行专门的定制开发…

yii2框架随笔29
今天我们来看UrlRule.php <?php /*** link http://www.yiiframework.com/* copyright Copyright (c) 2008 Yii Software LLC* license http://www.yiiframework.com/license/*/ namespace yii\web; use Yii; use yii\base\Object; use yii\base\InvalidConfigException; /*…

八种简易健康减肥瘦身法
①原地跑,紧实大腿肌肉;②上楼梯,瘦小腿、大腿、臀;③步行,瘦腿、腰;④瑜珈,瘦全身;⑤跳舞,瘦全身;⑥跳绳,瘦大腿、小腿;⑦晨操&#…

LaZagne检测windows本地存储的密码
LaZagne项目是用于检索存储在本地计算机上的大量密码的开源应用程序。 每个软件使用不同的技术(明文,API,自定义算法,数据库等)存储其密码。 该工具的开发是为了找到最常用的软件的密码。 下载到windows机器࿰…

通知提示SCPromptView
作者 陈小翰 关注 2017.03.24 18:01 字数 138 阅读 62评论 0喜欢 1SCPromptView SCPromptView : 显示在顶部的提示控件 你的star是我最大的动力 effect.gif安装 手动安装 下载源码,将SCPromptView文件夹拖进项目 CocoaPod pod SCPromptView 使用 SCPromptView 的用…

4566: [Haoi2016]找相同字符 SAM
折腾了好久。不过收获还是很多的。第一次自己去画SAM所建出来fail树。深入体会了这棵树的神奇性质。 当然,我最终靠着自己A掉了。(这是我第一次推SAM的性质(以前都是抄别人的,感觉自己好可耻),不过感觉好像…

NYOJ-232 How to eat more Banana
How to eat more Banana 时间限制:1000 ms | 内存限制:65535 KB难度:4描述A group of researchers are designing an experiment to test the IQ of a monkey. They will hang a banana at the roof of a building, and at the mean time, …

UIView Animation
作者 嘿o大远 关注 2017.03.23 17:02* 字数 402 阅读 47评论 1喜欢 3今天总结一下UIView动画就是 UiView动画是基于高层API封装进行封装的,对UIView的属性进行修改时候所产生的动画. 基本动画 下面两种方法是最常用的两种. (void)animateWithDuration:(NSTimeInterval)duratio…

[转]Ext Grid控件的配置与方法
http://www.blogjava.net/wangdetian168/archive/2011/04/12/348651.html 1、Ext.grid.GridPanel 主要配置项: store:表格的数据集 columns:表格列模式的配置数组,可自动创建ColumnModel列模式 autoExpandColumn:自动充…
永久设置SecureCRT的背景色和文字颜色方案
对于默认的连接颜色感觉不舒服,一通乱搞,总结出这些。 一、对于临时设置,可以如下操作: 首先options -- session - appearance 此处可以设置临时的窗口背景,字体颜色,大小等等,为什么说是临时&a…

利用Procdump+Mimikatz获取Windows帐户密码
0x01 前言: 前段时间拿下一个网站的shell,很幸运的是直接就是System权限,结果发现执行添加用户命令并不能成功回显 看了下系统进程,原来是开启了360的主动防御,奈何也不会做免杀,上传exp运行就被杀&#x…

一个逻辑清晰的购物车模型
效果图 2017-03-25 18.28.23.gifGitHub: https://github.com/lll1024/JVShopcart 说明 这是一个具备常规功能并方便改造的购物车模型 一共包含五个模块: JVShopcartViewController: 购物车控制器 负责协调Model和View 只有100多行代码JVShopcartFormat: 负责网络请求…

Nginx基本配置、性能优化指南
转载自:http://www.chinaz.com/web/2015/0424/401323.shtml 大多数的Nginx安装指南告诉你如下基础知识——通过apt-get,或yum安装,修改这里或那里的几行配置,好了,你已经有了一个Web服务器了!而且ÿ…

关于批量修改AD域用户的脚本
最近几天帮人弄了个脚本,是修改域用户属性的脚本,今天看到徐火军写的 关于批量修改用户属性 脚本,觉得有必要把我的成果分享给大家。什么都不说了,上脚本: Dim oFSO, oTF, iDim sLineDim sLoginName 用户批量文件Const…

Python multiprocess 多进程模块
转发:http://www.langzi.fun/Python multiprocess 多进程模块.html 需要注意的是,如果使用多线程,用法一定要加上if __name____main__:(Python中的multiprocess提供了Process类,实现进程相关的功能。但是它基于fork机制ÿ…

PHP正则数组
<?php //正则表达式//斜杠代表定界符 /^$///$str "好厉害18653378660了hi请勿嫁得好15165339515安徽dah矮冬瓜 拍行业大概啊好广东也欺负偶怕哈";//$reg "/(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}/";//echo preg_repl…

iOS Socket Client 通讯
iOS Socket Client 通讯 阅读 239收藏 192017-03-29原文链接:https://github.com/guangzhouxia/JTSocketiOS Socket Client 通讯(偏流程和代码展示),具体原理可以在网上搜索到很多,就不多做追叙复制了。。。 —— 由广…
api工程IOS学习:在IOS开发中使用GoogleMaps SDK
今天一直在学习api工程之类的问题,今天正好有机会和大家分享一下. 官方文档地址:https://developers.google.com/maps/documentation/ios/start#getting_the_google_maps_sdk_for_ios 一、申请一个收费的API KEY 要应用GoogleMaps SDK,必须要为你的应用申…

Python多进程与进程锁的基本使用
Python的multiprocessing模块提供了多种进程间通信的方式,如Queue、Pipe等。 Queue是multiprocessing提供的一个模块,它的数据结构就是"FIFO——first in first out"的队列,常用的方法有:put(object)入队;g…