美文网首页
Widget简单体验

Widget简单体验

作者: 翻炒吧蛋滚饭 | 来源:发表于2016-12-28 12:39 被阅读244次

前言

对于一款应用来说,想要获得更多关注,想要更频繁的出现在用户的视野中,推送、widget都是必不可少的,推送在实际开发中,是很常见的,那我们就来玩一玩不常见的widget吧!

创建一个TodayExtension

新创建一个项目,创建完成后,再在项目中新加入一个target。target选Today Extension。


新建target
选择todayExtension

  当然TodayExtension作为一个单独的target,也是需要证书的,为了demo方便,我们就直接自动管理了。


需要证书
  创建成功后,你会发现,新的target里面多了一个controller,这个controller就是我们所能看到的widget,而且他继承自UIViewController,所以我们可以正常的像开发其他功能一样来做widegt,不过widget是有内存限制的,请尽量做些简单的功能。
  观察iOS10的widget你会发现,他有两种状态,分别是折叠、展开。
展开折叠

  我们在TodayViewController加入折叠的支持。首先在viewWillAppear中加入折叠的代码。当然折叠特性是iOS10新加入的,需要做下版本区分,防止非iOS10设备崩溃。

- (void)viewWillAppear:(BOOL)animated {
    // 设置widget的状态为展开
    self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
}

然后有个协议方法需要实现,协议为:


协议

  方法为:

- (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);
    }
}

该方法,指定折叠和展开两个状态下的widget大小。现在再运行,你就可以正常添加我们制作的widget到通知中心了。

调起主程序

通过上面的步骤,你就可以正常的创建任何你想做的widget插件了。但我们最关心的不是widget该怎么做,因为它作为一个UIViewController,以我们的开发经验想创造出各种页面,都是没问题的。
  我们最关心的是,如何通过widget,将用户引导到我们的APP中,也就是应用跳转。以支付宝为例,对支付宝进行3D Touch操作,你会发现,它的快捷widget有四个可跳转到APP内部各个功能的按钮。


支付宝的widget

  那么这是怎么实现的呢?实际上iOS8开始引入的Extension,相对于母体APP,都是独立的,Extension管理自己的数据,母体APP管理自己的数据。那如何调起母体APP呢?其实很简单,正如我们自己的APP调起其他APP一样,比如微信、支付宝、微博等,那就是利用URL Scheme。
  我们先为我们的母体APP加入一个URL Scheme。


为母体APP添加URL Scheme
  widget中想调起母体APP,直接使用下面的OpenUrl就搞定了。
- (void)openApp {
    NSURL *url = [NSURL URLWithString:@"todayDemo://"];
    [self.extensionContext openURL:url completionHandler:nil];
}

这里有一个需要注意的点就是,widget作为一个Extension,是不存在Application的概念的,所以不能用传统的[UIApplication sharedApplication]的方式来进行openUrl操作。使用self.extensionContext,即可获取当前Extension上下文,也就是我们的widget。
  母体APP需要在AppDelegate中的openUrl方法中拦截到widget的openUrl。我们看看获取到的url(下面的方法在iOS10舍弃了,但还是可以用的):

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    
    UIAlertView *av = [[UIAlertView alloc] initWithTitle:[url absoluteString] message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:nil, nil];
    [av show];
    
    return YES;
}

运行项目,点击widget后调起母体APP的效果为:


接收到的url

  跟我们openUrl时填写的url一模一样。这样我们就可以在这个url后面拼接上各种参数,告诉母体APP跳转到哪个页面了。大致样式是这样的:

todayDemo://?params=gotoSomeView

跟一般的get请求的网址类似,可以拼接各种参数进去,在母体APP获取到url时,直接[url query]就能获取到"?"后面的所有参数。

与母体APP组成APP Group

我们的主要目的还是想widget和母体APP共享数据,在很多笔记APP中,widget和母体APP是共享笔记的,那我们就要用到APP Group了。我们先在母体APP中创建一个APP Group:


创建Group

  创建完成后,再来到我们的Extension的target下。你会发现APP Group下多了之前我们在母体添加的Group,将它勾选上,则我们的Extension就和母体APP组成了APP Group。


Paste_Image.png
  这个时候,两个程序,就可以共享一些数据了。我们以NSUserDefault为例,在母体中保存一个字段,然后在Extension中读取这个字段,识别到后,将widget的颜色变成红色。
  首先在母体APP的ViewController中获取APP Group的UserDefault,并存储一个字段。
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 创建一个UserDefault
    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.MyTodayGroup"];
    
    // 存储一个颜色
    [userDefaults setObject:@"redColor" forKey:@"color"];
    
    // 同步
    [userDefaults synchronize];
}

这里需要注意的是,我们平时项目中用的都是[NSUserDefaults standardUserDefaults],但这个UserDefault实际上是无法跟Extension互通的,我们需要找到APP Group所对应的UserDefault,注意initWithSuiteName后面接的名字,一定是我们之前创建的APP Group的名字。
  然后我们来到widget中的controller,还记得之前我们遵守的协议吗,里面还有一个方法,就是更新widget的一个方法。方法中completionHandler之前的代码,就是我们正常的逻辑操作,匹配到字段后,将背景色替换为红色,然后completionHandler(NCUpdateResultNewData)这句,则是告诉widget我们处理完了,做了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

    // 拿到主程序的NSUserDefault
    NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.MyTodayGroup"];
    
    NSString *color = [userDefaults objectForKey:@"color"];
    if ([color isEqualToString:@"redColor"]) {
        self.view.backgroundColor = [UIColor redColor];
    }
    
    completionHandler(NCUpdateResultNewData);
}

先运行母体APP,再运行widget,看下效果:


效果

总结

以上的包括widget的UI、调起母体APP、与母体APP数据互通这些特性组合在一起,便可满足我们正常的开发需求了。所以还等什么呢,快为你的APP加入widget特性吧!

相关文章

  • Widget简单体验

    前言 对于一款应用来说,想要获得更多关注,想要更频繁的出现在用户的视野中,推送、widget都是必不可少的,推送在...

  • SwiftUI-Widget 使用及避坑指南

    iOS Widget简单介绍( 只介绍iOS 14 以后Widget相关内容): Widget 是 iOS 14 ...

  • 简单的Widget

    Widget就是iPhone左滑展示出来的小窗口,我理解为——自家app的又一个入口,哈哈。比如下图中的天气。 其...

  • 关于Flutter一个Widget的生命周期

    先给结果,在看代码。 简单易懂。 flutter widget的布局信息是存在父widget里面的 结果 flut...

  • 图形用户接口(GUI)

    创建GUI很简单,大体分为4步: 创建frame 创建widget 将widget加到frame上 将整个页面显示...

  • L总(1)

    “这个是啥东西?”我问道。 “嗨,这不简单。就是一个widget呗。”他回答。 “widget?”我奇怪无比。 “...

  • Flutter 101: 何为 Flutter Elements

    小菜前段时间简单了解了一下 Widget 的相关知识,其中 Widget 是 immutable 不可变的,而 W...

  • Flutter 102: 何为 Flutter RenderOb

    小菜前段时间简单了解了一下 Widget 和 Element,其中 Widget 主要是存放渲染内容以及布局信息等...

  • 关于Flutter的Tips

    占用大量空间的Widget,必须包装在Expanded widget中。 一旦拆分好布局,最简单的就是采取自下而上...

  • Flutter 完整的生命周期(State状态管理)

    一.Widget 树 界面布局之后,会出现布局层级 不论简单还是复杂布局都会有布局的嵌套层级 Widget树的展现...

网友评论

      本文标题:Widget简单体验

      本文链接:https://www.haomeiwen.com/subject/apruyttx.html