美文网首页
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简单体验

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