iOS - Widget 小部件

简介: 1、WidgetiOS extension 的出现,方便了用户查看应用的服务,比如用户可以在 Today 的 widgets 中查看应用的简略信息,然后点击进入相关的应用界面。2、添加 Widget添加 Widget 流程1、添加 Today Extension2、绘制 UI3、调起 app4 、数据共享2.

1、Widget

  • iOS extension 的出现,方便了用户查看应用的服务,比如用户可以在 Today 的 widgets 中查看应用的简略信息,然后点击进入相关的应用界面。

    Widget1Widget2

2、添加 Widget

  • 添加 Widget 流程

    • 1、添加 Today Extension
    • 2、绘制 UI
    • 3、调起 app
    • 4 、数据共享

2.1 添加 Today Extension

  • 在 Xcode菜单 => File => New => Target.. => 中选择 Today Extension

    Widget3

    Widget4

    Widget5

2.2 绘制 UI

  • 创建 Today Extension 时会默认创建 MainInterface.storyboard,可以在里面绘制显示的 Widget 内容,也可以使用代码绘制 UI。

    Widget6

  • 设置 Widget 展示视图的大小。关于 Widget 的背景色,以及具体展示的内容大家按需绘制。

        - (void)viewDidLoad {
            [super viewDidLoad];
    
            // 设置 Widget 展示视图的大小
            self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 100);
    
            self.view.backgroundColor = [UIColor yellowColor];
        }
  • 在 iOS8 - iOS9 中运行程序后,会发现一个问题:绘制的内容与左侧边界有一定距离(约 30px)。如何解决这个问题呢,NCWidgetProviding 协议给出了解决方案。iOS10 中不存在这个问题。

        // 实现 NCWidgetProviding 协议方法
        - (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets {
            return UIEdgeInsetsMake(0, 0, 0, 0);
        }

2.3 调起 app

  

  • 因为 extension 和 containing app 是两个完全独立的进程,所以它们之间不能直接通信(不能像应用内部点击按钮,跳转到指定页面)。为了实现 Widget 调起 app,这里通过 openURL 的方式来启动 containing app。

  • 在 containing app 中设置 URL Schemes

    Widget9

  • 在 extension 的 ViewController 中添加如下代码。

        // 通过 extensionContext 借助 host app 调起 app
    
        // TodayWidget 为在 containing app 中设置的 URL Schemes
        [self.extensionContext openURL:[NSURL URLWithString:@"TodayWidget://"] completionHandler:^(BOOL success) {
    
            NSLog(@"open url result:%d", success);
        }];

2.4 数据共享

  • 通过 App Groups 提供的同一 group 内 app 共同读写区域,可以用 NSUserDefaults 和 NSFileManager 两种方式实现 extension 和 containing app 之间的数据共享。

    Widget7

    Widget8

  • 1) 通过 NSUserDefaults 共享数据

    • 保存数据

          - (void)saveDataByNSUserDefaults {
      
              NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.qianqianstudio.freeInHouse"];
              [shared setObject:@"asdfasdf" forKey:@"widget"]; 
              [shared synchronize];
          }
    • 读取数据

          - (NSString *)readDataFromNSUserDefaults { 
      
              NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.qianqianstudio.freeInHouse"]; 
              NSString *value = [shared valueForKey:@"widget"]; 
              return value;
          }
  • 2) 通过 NSFileManager 共享数据

    • 保存数据

          - (BOOL)saveDataByNSFileManager {
      
              NSError * error = nil;
      
              NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.qianqianstudio.freeInHouse"]; 
              containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/widget"]; 
              NSString *value = @"asdfasdfasf"; 
              BOOL result = [value writeToURL:containerURL atomically:YES encoding:NSUTF8StringEncoding error:&error];
      
              if (!result) { 
                  NSLog(@"%@", error); 
              } else { 
                  NSLog(@"save value:%@ success.", value); 
              } 
      
              return result;
          }
    • 读取数据

          - (NSString *)readDataByNSFileManager {
      
              NSError *error = nil;
      
              NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.qianqianstudio.freeInHouse"];
              containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/widget"];
              NSString *value = [NSString stringWithContentsOfURL:containerURL encoding:NSUTF8StringEncoding error:& error];
      
              return value;
          }

3、设置 Widget

  • 1、Widget 中展开、折叠

    • iOS10 在 NSExtensionContext 中,新添了 widgetLargestAvailableDisplayMode 属性,来确认当前 Widget 是展开还是折叠状态。所以,先在 viewWillAppear 中设置 Widget 的 mode 为展开。

          - (void)viewWillAppear:(BOOL)animated {
              [super viewWillAppear:animated];
      
              self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
          }
    • 然后,就是展开和折叠的处理了。在 NCWidgetProviding 协议中,新添了这个方法 widgetActiveDisplayModeDidChange。

          - (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize {
      
              if (activeDisplayMode == NCWidgetDisplayModeCompact) {
                  self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 110);
              } else {
                  self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 300);
              }
          }
  • 2、启动 app 后,第一次显示的是折叠,而不是展开 ?

    • 这个问题,归咎于 preferredContentSize 的设置,确认 Widget 的 mode 之前,不要设置这个值。在 widgetActiveDisplayModeDidChange 中设置展开或折叠状态下 Widget 的高度,iOS10 环境下在这里设置高度也就足够了。
  • 3、为什么有时展开或折叠 "失灵" 了,没有对应的展开或折叠呢 ?

    • 这个问题的前提,肯定是你展开、折叠对应的 Widget 高度不一样,只是看到了右上角按钮内容改变,但高度却没有变。
    • 这个问题的原因在于,点击展开、折叠按钮修改了 Widget 的 mode 之后,却没有设置对应的高度 preferredContentSize。怎么办呢?mode 改变后,设置对应状态下的高度即可。

4、真机调试 Widget

  • 真机调试 Widget,牵扯到配置 group。首先我们的宿主 app id 为 com.qianqianstudio.TodayWidget, Today widget 插件的 bundle id 为 com.qianqianstudio.TodayWidget.Widget 这里我们需要注意,widget 的 bundle id 必须以宿主 bundle id 作为前缀。然后它俩之间建立的 group id 为 group.qianqianstudio.freeInHouse(可以取任意名)。

  • 开发者证书配置

    • Identifiers => App Groups 里添加一个 app group id 为:group.qianqianstudio.freeInHouse

      Widget10

    • 创建 app id。创建的时候选择 Explict App ID,App Services 里面勾选上 App Groups

      Widget11

    • 主 app

      Widget12

    • widget

      Widget13

    • 配置 provisioning profile(这里不再赘述 certificate 的生成步骤,添加 device 等),此时因为选择了勾选了 App Groups 这个 service 的 app id,所以可以看到 enabled services 那里有此项。

      Widget14

目录
相关文章
|
Android开发 Swift iOS开发
iOS14新特性探索之二:App Widget小组件应用(一)
iOS14新特性探索之二:App Widget小组件应用
497 0
iOS14新特性探索之二:App Widget小组件应用(一)
|
存储 Swift iOS开发
iOS14新特性探索之二:App Widget小组件应用(二)
iOS14新特性探索之二:App Widget小组件应用
565 0
iOS14新特性探索之二:App Widget小组件应用(二)
|
机器学习/深度学习 安全 搜索推荐
盒马 app iOS 14 Widget 实践
# Widget 简介 Widget 是 iOS 14 重磅推出的新功能,使得用户可以在主屏幕添加小组件,快速浏览 app 提供的重要信息。它的设计与旧版本 macOS 的 Widget 一脉相承,甚至连添加的动画也是去掉了拟物化的水波纹效果。 ![Untitled_design__79_.png](https://intranetproxy.alipay.com/skylark/lark/0
2490 0
|
机器学习/深度学习 搜索推荐 API
如何进行 iOS Widget 开发?
iOS 14 重磅推出了新功能 Widget,可以在主屏上展示一些关键信息,如日程、待办事项、设备电量等。Widget 的设计定位是什么?有哪些限制?如何进行 Widget 开发?本文基于一个小游戏——盒马小镇的 Widget 开发,分享在登录授权、数据更新、界面渲染以及审核上的实践经验。
4438 0
如何进行 iOS Widget 开发?
|
iOS开发
【iOS开发】发布 Widget App 注意事项
在被 App Store Review 拒绝了一次之后,我的一款 Today Widget App 上线了,把过程中遇到的坑分享出来。 1. 主 App 中要有内容 第一次提交 App 时,只是在 Widget 中添加了内容,主 App 中仅有教用户如何添加插件的几张图片做教程,被拒绝上架了。
1056 0
|
6天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
1月前
|
Java Android开发 Swift
安卓与iOS开发对比:平台选择对项目成功的影响
【10月更文挑战第4天】在移动应用开发的世界中,选择合适的平台是至关重要的。本文将深入探讨安卓和iOS两大主流平台的开发环境、用户基础、市场份额和开发成本等方面的差异,并分析这些差异如何影响项目的最终成果。通过比较这两个平台的优势与挑战,开发者可以更好地决定哪个平台更适合他们的项目需求。
114 1
|
13天前
|
安全 数据处理 Swift
深入探索iOS开发中的Swift语言特性
本文旨在为开发者提供对Swift语言在iOS平台开发的深度理解,涵盖从基础语法到高级特性的全面分析。通过具体案例和代码示例,揭示Swift如何简化编程过程、提高代码效率,并促进iOS应用的创新。文章不仅适合初学者作为入门指南,也适合有经验的开发者深化对Swift语言的认识。
35 9
|
10天前
|
设计模式 Swift iOS开发
探索iOS开发:从基础到高级,打造你的第一款App
【10月更文挑战第40天】在这个数字时代,掌握移动应用开发已成为许多技术爱好者的梦想。本文将带你走进iOS开发的世界,从最基础的概念出发,逐步深入到高级功能实现,最终指导你完成自己的第一款App。无论你是编程新手还是有志于扩展技能的开发者,这篇文章都将为你提供一条清晰的学习路径。让我们一起开始这段旅程吧!
|
13天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。