讲述之前首先看下demo效果图:

基本的展开收起、本App本体交互

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

毒物 && Keep

ESPN

PCalc

Musixmatch

Fantastical 2

Carrot Weather

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 标识符

这个写好之后,再去扩展的target做相同的操作,标识符一定要一样!!

切换 target 的方法在这里
  • 报错信息:[_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效果图
  • iOS8下所有组件默认右移30pt

六、其他注意点

  1. 当程序内存不足时,苹果优先会杀死扩展,因此需要注意内存的管理。

  2. 在配置team是账号需要一致(免费账号不行,需要付费的账号),上传包的时候一定注意选择 Product -> Archive -> 选择 distribution 模式!

  3. 3D touch 对应的也有Widget!?答案是 YES!,只要设置了3D touch,Widget的第一栏就会自动显示

Extension 证书配置指南
官网说明
一直很心仪的app --> Things 关于widget的介绍
几个精致的 Widget app
在模拟器上进行3D touch 测试

再次附上 demo Github 地址,欢迎star

从0到1思考与实现iOS-Widget相关推荐

  1. Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮...

    Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮 前言 之前写过屏蔽系统导航栏功能的文章,具体可看Android6.0 源码修改之屏蔽导航栏虚拟按键(Home和RecentAPP) ...

  2. 苹果关闭iOS 16和16.0.1验证通道,升级iOS 16.0.2后无法降级这2版本

    今日消息,现在苹果官方已经关闭了iOS 16.0和16.0.1的验证通道,意味着升级到iOS 16.0.2的用户将无法降级到这两个版本. 苹果于9月23日向iPhone用户推送了iOS 16.0.2正 ...

  3. 连麦张小龙:谈微信 8.0 背后的思考

    所有的思考都不是心血来潮,所有的选择也并非随心所欲. 时隔两年,微信终于在它十周年之际发布了最新的 8.0 版本.涉及表情.状态等一些功能的迭代,引发了不少讨论.1 月 22 日晚间,在视频号直播间里 ...

  4. 大型企业云化2.0的深度思考与展望

    伴随着IT新技术的发展,像虚拟化.云计算和大数据对大家来说已经不再陌生了.在企业里面进行云化实施的时候,各种新技术在优势显现的同时,随之而来的问题也比较多.上了云之后,有时候我们没有感觉到轻松反而更累 ...

  5. android 8.0 iso6,微信8.0.6更新了什么?IOS系统微信8.0.6版本更新详情一览[多图]

    微信8.0.6更新了什么?近日,IOS系统中的微信最新版本8.0.6已经正式更新,很多用户不清楚此次的新版本具体更新了什么,接下来小编就为大家带来IOS系统微信8.0.6版本的更新详情一览吧. 微信8 ...

  6. 苹果微信更新不了最新版本_微信更新7.0版本,为何优先给iOS用户体验?这是在歧视安卓?...

    不知道大家有没有留意过,微信每次更新版本,都会优先上线iOS版本,而安卓版本一般要落后一两周的时间,近期新推出的7.0.0版本也是iOS版本优先上线. 虽然更新是早晚的事,但是每次都让iOS用户优先体 ...

  7. 微服务平台建设之微服务2.0技术选型思考

    前言 前事不忘后事之师,本篇博客是在拜读和学习了杨波的<微服务架构技术栈选型手册>后结合自己的整理和思考. https://www.infoq.cn/article/micro-servi ...

  8. ✈️从0到1打造直播 App(iOS /Android直播流程介绍整理 <mark>)

    概要 分享内容: 互联网内容载体变迁历程,文字--图片/声音--视频--VR/AR----..从直播1.0秀场时代(YY),2.0游戏直播(斗鱼.虎牙.熊猫)到如今全民直播3.0泛生活娱乐时代(映客. ...

  9. 工业4.0的小小思考

    工业4.0 在机械电子行业如何开展? 现场管理的应用mes, 现在整的一个项目是 结合移动互联网,利用手机来完成现场管理的联络功能,提高沟通效率. 另外,再积累准确的现场跟踪记录,积累数据,作为日后的 ...

最新文章

  1. showdialog 尝试读取或写入受保护的内存_TreadMarks: 基于工作站网络的共享内存计算...
  2. GNS3模拟ATM的简单配置
  3. 关于JavaScript语句后面的分号
  4. 经验分享:布线测试关键步骤有哪些 ?
  5. 3.7 su命令 3.8 sudo命令 3.9 限制root远程登录
  6. 精讲23种设计模式-策略模式~聚合短信服务和聚合支付服务
  7. Android 轮播图从 0 到 1
  8. 随机森林matlab实现
  9. 计算机辅助药物量子力学,计算机辅助药物设计(完整版).doc
  10. web-登陆界面html-数据库
  11. WPF/WinForm 如何生成单文件的EXE
  12. React使用iconfont阿里巴巴矢量图库
  13. 携程mysql架构_携程数据库高可用架构实践
  14. ResNet残差网络——Deep Residual Learning for image recongnition
  15. 众里寻它千百度,原来它在...MSDN处
  16. php实现支付宝二维码支付
  17. 联想笔记本进入pe_联想小新笔记本怎么进入bios设置U盘启动
  18. unity3D 中各英文翻译
  19. 百度地图集成(一):百度地图简单实现
  20. 中柏平板u盘启动_中柏平板设置u盘启动图文教程

热门文章

  1. 15-11-23:system指令
  2. Spring.net使用说明
  3. FWFT FIFO读操作注意
  4. C# GDAL 学习一
  5. 『网站升级』PHPWind8.0至8.3升级过程及问题种种回顾录
  6. 【C++】 保存内容到文件工具
  7. PHP安装扩展mcrypt以及相关依赖项 【PHP安装PECL扩展的方法】
  8. PHP也玩并发,巧用curl 并发减少后端访问时间
  9. PHP内核中的哈希表结构
  10. 绑定CPU逻辑核心的利器——taskset