返回

爱情故事

Widget开发指南

作者:admin 浏览数: 2019-03-09

目前负责的App新增了Widget功能,之后在组内分享中分享了下Widget的开发经验。基于之前的PPT提炼出了这篇文章。本篇文章只讲基于Widget关于iOS10+ 之后的知识点。

Widget是iOS8以后Apple推出的一项功能,并且在iOS10后进行了大幅的优化。

在主屏幕和锁定屏幕上向右滑动来访问Widget,也可以在对应的App图标上面使用3D Touch按压访问相应的Widget。


Widget设计规范和要求

Widget是一个单独的进程,和主App独立,但是支持数据共享。在设计和开发Widget时候要注意以下几点设计规范:

  • 设计一个友好的交互体验

Widget用来执行非常简单的任务,尽可能提供点击一次就能完成的任务,Widget不支持窗口滚动,不支持键盘输入(其实是可以做到键盘输入的 具体办法见后面)
详见《App Extension Programming Guide》


  • 要快速显示内容

    内容要尽量从本地加载,依赖网络的内容要在本地做缓存,以免长时间等待。确保每次出现都有内容

  • 提供充足的边距和填充

    避免将内容扩展到Widegt边缘。每行最多显示4个按钮或图标

  • 适应屏幕
    iOS10以后,Widget支持折叠和展开。折叠状态下默认高度为110且不可更改。展开高度不超过一个屏幕的高度。(官方文档说最低高度为2.5个默认行高 44*3.5=110)官方推荐使用AutoLayout布局。
    横屏时候宽度还是默认屏幕宽度。不会拉伸

  • 不要自定义背景色

    系统自带模糊的背景色,尽量不要改(当然只是建议咯)。不要用照片做背景,会和壁纸冲突。


    部分App设计了皮肤功能
  • 注意字体颜色、取一个好名字、一个App可以有多个Widget

    字体颜色尽量是深色或者深灰色(然而用白色的最多)。如果一个App存在多个Widget,要命名清晰。Widget的名字里面,英文字母系统会自动转换成大写

    Logo会自动使用主App的icon

  • 适当的时候让用户跳转到主App来做更多的事

    Widget尽量只给用户提供简单的功能(规范而已。。),不要在Widget中出现“打开App”等按钮。点击Widget icon后会自动吊起主App。和主App交互使用URLScheme方法。后面会讲到。

  • 很短的生命周期、要注意内存问题

    离开屏幕2s+就会被销毁,后面会讲到

建立Widget Target

选择主工程,在Project设置界面下方点击加号,新建Today Extension



系统会自动生成TodayViewController和storyBoard。不要忘记在Target设置里面设置基本信息,版本号和主App保持一致,否则上传iTunes Connect会有警告邮件

也要注意选择Deployment Target。Xcode10默认是iOS12

和Widget共享代码

  • 支持pod导入三方库,在podfile中新增Widget的target


Xcode10 后,如果在Build Phases中运行Script。执行pod可能报错。解决办法见
《#iOS知识小集# Xcode10 pod install 报错》

  • 主工程代码共享
    在需要共享的类的.m文件中的Target Membership中勾选Widget所在的Target


Widget代码实现

NCWidgetProviding协议

Widget工程建立后会自动生成TodayViewController。
会遵循NCWidgetProviding协议
iOS10以后这个协议只有两个方法

- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult result))completionHandler;
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize NS_AVAILABLE_IOS(10_0);

其中widgetPerformUpdateWithCompletionHandler 默认返回NCUpdateResultNewData

- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler {
    // Perform any setup necessary in order to update the view.
    
    // If an error is encountered, use NCUpdateResultFailed
    // If there's no update required, use NCUpdateResultNoData
    // If there's an update, use NCUpdateResultNewData

    completionHandler(NCUpdateResultNewData);
}

这个可以忽略掉,直接返回NCUpdateResultNewData就好了
iOS10以后支持折叠和展开功能,折叠状态下默认高度为110且不可更改。展开高度不超过一个屏幕的高度。(官方文档说最低高度为2.5个默认行高 44*3.5=110)

在ViewDidLoaded方法中设置是否开启折叠功能

//NCWidgetDisplayModeCompact 收起模式
//NCWidgetDisplayModeExpanded  展开模式
     
self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize {
    
    if (activeDisplayMode == NCWidgetDisplayModeCompact) {
        self.preferredContentSize = CGSizeMake(maxSize.width, 110);
    } else {
        self.preferredContentSize = CGSizeMake(maxSize.width, 200);
    }
}

使用纯代码

示例工程会默认使用StoryBoard,如果想使用纯代码。进行以下步骤

  1. 删除MainInterface.storyboard文件和NSExtensionMainStoryboard键值对


2.添加NSExtensionPrincipalClass为key ,value为TodayViewController


图片管理

Widget可以使用Asset Catalog管理图片,命名为Assets,和主工程使用方式一致
[图片上传失败...(image-63b41f-1548926798999)]

代码调试

在Widget工程更新代码后,可以运行主工程,然后添加Widget。就可以看到最新的效果展示。
如果想断点调试,要选择Widget Target


和主工程共享数据

Widget和主工程是完全独立的两个工程,两个独立的进程。所以数据共享是通过App Groups进行的。

App Groups需要去开发者中心去创建。ID必须以group开头。后面一般跟公司名称。


建立完成后回到主工程,打开App Groups开关,就能刷新出刚刚创建的Groups,打钩远中

然后把Widget Target 也打开App Groups,选中同一个Groups

App Groups可以通过NSUserDefaults和NSFileManager共享数据

  • NSUserDefaults
//主工程中存
NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.YouDao.xxxx"];
[shared setObject:_targetLanguage.abb forKey:@"UD_TargetLanguage_Widget_key"];
[shared synchronize];


//Widget 中取
[[NSUserDefaults alloc] initWithSuiteName:@"group.YouDao.xxxx"] objectForKey:@"UD_TargetLanguage_Widget_key"];
  • NSFileManager
//存
NSString *groupID = @"group.YouDao.xxxx";
NSError *err = nil;
NSURL *fileUrl = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:groupID];
fileUrl = [fileUrl URLByAppendingPathComponent:@"Library/Caches/test"];
NSString *value = @"test";
BOOL result = [value writeToURL:fileUrl atomically:YES encoding:NSUTF8StringEncoding error:te>

App Gropu是跨App的,只要在同一个开发中账号。不同的App使用同一个Gropu ID都是可以共享数据的。在Shared目录下还有AppGroup目录。里面有各个Group ID的文件夹。其中通过NSUserDefault共享的数据在Library/Prefrences下。是一个plist文件。

Widget吊起主工程

Widget吊起主App通过URLSchemes

  1. 为主App设置URLSchemes


2.Widget添加交互

[self.extensionContext openURL:[NSURL URLWithString:@"YDUDictionary://action=CameraTranslate"] completionHandler:^(BOOL success) {
                NSLog(@"open url result:%d",success);
            }];

3.主App中处理Scheme.在AppDelegate中实现application:openURL:options:

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionaryte>

Widget离开屏幕2s以上,就会被销毁回收掉。每次离开前系统会做快照处理。下次进来先加载快照。
离开超过2s以上,下次进入就会调用ViewDidLoad,然后是viewWillAppear
离开不超过2s 下次进入会调用viewWillAppear

所以为了交互体验,最好是记录用户上次的使用状态,下次加载时候进行还原操作。

当内存不足时候,系统会优先kill掉Widget。所以要注意内存问题,不要进行需要大量内存的操作。
网络请求如果需要频繁刷新。可以在viewWillAppear方法中启用一个Timer,在Timer中请求接口数据。在viewWillDisAppear中取消定时器。

如何在Widget中使用键盘

Apple官方文档说Widget是不支持键盘输入的。如果在TodayViewController中新建一个输入框。点击是没有反应的。但是我们可以用另外一种办法绕过去。效果如下图。

做法就是做一个假的输入框,让用户点击。点击后present一个ViewController,在这个Controller新建UITextView或者UITextField就可以获取焦点,出现键盘啦

相关文章

  • Widget开发指南

    目前负责的App新增了Widget功能,之后在组内分享中分享了下Widget的开发经验。基于之前的PPT提炼出了这...

  • Terraform 开发指南

    本文主要向大家展示如何为阿里云 Terraform Provider贡献自己的力量,帮助开发者和志同道合的朋友尽快...

  • Connector开发指南

    本篇文章描述了开发人员如何为Kafka Connect编写新的connector。 核心概念与API Con...

  • IAP开发指南

    IAP流程 介绍 这里介绍的IAP使用服务器模式: 调用服务器接口创建一个商品的订单 请求Apple的商品列表 选...

  • Redis开发指南

    Redis介绍 Redis是内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 优势是: 支持多种类型...

  • 《Nodejs开发指南》

    Node.js是一个让javascript可以运行在服务器端的平台,是一个为数据密集型(data-intensiv...

  • Gradle插件开发指南

    作为Android开发者,你可能见过无数个apply plugin:plugin_name,plugin_name...

  • Spark Streaming 开发指南

    原文地址:Spark Streaming Programming Guide 概述 Spark Streaming...

  • 大数据开发指南

    package 数据开发/大数据开发/hadoop开发架构: public class(终极目标): class ...

  • GraphQL服务开发指南

    2015年7月,Facebook 发GraphQL布并开源了GraphQL,GraphQL作为负责前后端交互的协议...

网友评论

    • iOS随笔
      相关文章
      精选图文
      作者的其他文章