iOS开发之widget实现

作者: 不多满 | 来源:发表于2016-06-21 18:20 被阅读16886次

前言

iOS extension的出现,方便了用户查看应用的服务,比如用户可以在Today的widgets中查看应用的简略信息,然后点击进入相关的应用界面。
暂且不表网络上现有的widget文章,本篇文章主要说明本人具体实现widget的步骤,希望能够帮助到需要实现widget的同行朋友。


图1 Today的widget展示----以支付宝为例说明

文章将依次从以下几个问题着手,进行详细说明:
1、如何为现有的工程添加widget;
2、如何绘制UI;
3、如何调起app;
4、如何与host app共享数据。

添加Today Extension

图2 添加today的target

   如图,为现有的工程添加Today Extension,命名这里不赘述了,大家都懂的。


图3 添加today之后的工程目录

    这是添加Today Extension之后的工程目录。
    到这里,为现有的工程添加Today Extension算是完成了,运行程序就可以看到类似图1的简单的效果了,很简单哈。

绘制UI

与网上发表文章的童鞋们一样,我也是个代码控(装B一下),习惯用纯代码来绘制Today的UI。


图4 删除默认创建的MainInterface并修改Info.plist

    这里,删除默认创建的MainInterface.storyboard,并按图4所示修改Info.plist文件。(当然,习惯使用storyboard的童鞋可以略过,直接操作storyboard即可)

图5 设置widget展示视图的大小

    首先,设置widget展示视图的大小。关于widget的背景色,以及具体展示的内容大家按需绘制,这里暂且不表。

图6 设置widget视图距离左侧边界距离为0

    运行程序后,会发现一个问题:绘制的内容与左侧边界有一定距离(约30px)。如何解决这个问题呢,如图6所示,TodayViewController遵守的NCWidgetProviding协议给出了解决方案。

调起app

因为extension和containing app是两个完全独立的进程,所以它们之间不能直接通信(不能像应用内部点击按钮,跳转到指定页面)。为了实现widget调起app,这里通过openURL的方式来启动containing app。
- (void)openURLContainingAPP{ //通过extensionContext借助host app调起app [self.extensionContext openURL:[NSURL URLWithString:@"appextension://xxx"] completionHandler:^(BOOL success) { NSLog(@"open url result:%d",success); }]; }

数据共享

图7 添加App Groups

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

1 通过NSUserDefaults共享数据

保存数据
- (void)saveDataByNSUserDefaults{ NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.c om.xxx"]; [shared setObject:@"asdfasdf" forKey:@"widget"]; [shared synchronize]; }
读取数据
- (NSString *)readDataFromNSUserDefaults{ NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.c om.xxx"]; NSString *value = [shared valueForKey:@"widget"]; return value; }

2 通过NSFileManager共享数据

保存数据
- (BOOL)saveDataByNSFileManager{ NSError *err = nil; NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecuri tyApplicationGroupIdentifier:@"group.com.xxx"]; containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/ widget"]; NSString *value = @"asdfasdfasf"; BOOL result = [value writeToURL:containerURL atomically:YES encoding:NSUTF8StringEncoding error:&err]; if (!result) { NSLog(@"%@",err); } else { NSLog(@"save value:%@ success.",value); } return result; }
读取数据
- (NSString *)readDataByNSFileManager{ NSError *err = nil; NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecuri tyApplicationGroupIdentifier:@"group.com.xxx"]; containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/ widget"]; NSString *value = [NSString stringWithContentsOfURL:containerURL encoding: NSUTF8StringEncoding error:&err]; return value; }
    到这里,在Today中添加应用的widget就完成了,从Today中可以浏览预设的快捷服务,在文章iOS 10 Today Widget中接着说iOS 10的适配问题。

-- ending

相关文章

网友评论

  • 北暖37:楼主你好,如果我彻底杀死程序,点击按钮的话,这个方式试运行的[self.extensionContext openURL:url completionHandler:^(BOOL success) {}],但是就是没有进入到应用内,也没有崩溃,但是如果应用只是进入后台是可以通过点击widget上的按钮进入程序 的,请问这个是什么原因,我不是很理解
  • 旭哥哥:另外给其他同学补充一下第一个界面是怎么出来的。
    点击项目中蓝色的工程文件->PROJECT,TARGETS左下角的加号
  • 旭哥哥:命名大家都懂。。。 我不懂
  • hhuua:你好,在开发的时候遇到了在widget中找不到在工程中已经导入的Masonry,是不是需要在widget中再次用pods导入?
    hhuua:@糯米姐姐 需要开发人员注册weiget的证书,widget和主程序相当于两个程序,独立开发,可以共用资源。做好之后就可以在下拉的编辑里添加了。
    糯米姐姐:不是程序员,所以问一个笨拙的问题,只需要在现在程序代码中添加好就能在“更多WIDGET”中找到自己的程序了么
    不多满:@hhuua 是的,不过widget一般不会太复杂,可以自己写一下自适应布局。
  • 情来情去情随缘:有俩问题请教下:
    一 跳转app,那个URL的string就是@“app名://”这样吗?
    二 widget运行后打开app,app退到后台,滑动到widget,widget会重新走viewDidLoad,但是之前的一些线程还在运行...这个怎么破,打开app的时候widget会走一些什么代理方法吗?如果有的话就好办了。
  • wokenshin:Hi 博主,有两个问题 我在纯代码中 修改的widget的size属性,然后运行后并没有任何变化,始终都是一个size。这个好像修改不了吧。还有意个问题就是文中设置距离左边边距的方法 在程序中并没有触发。
  • 9666ccbb8560:楼主,有个问题,请问Library/Caches/Widget这样可以保存成功,为什么Library/Caches/Widget/WidgetData这样就不成功呢?
  • 一路向北客:添加之后打包APP 需要修改证书?
    不多满:@一路向北客 没有证书,你也没法打包的吧
    一路向北客:@三月米果 我之前打包正常,添加widget之后不能打包了,不知道要怎么修改证书。 还有数据共享这块能交流下吗
    不多满:@一路向北客 发布到appstore需要
  • 厚脸皮小强打不死的小强:按照楼主的步骤,删除默认创建的MainInterface.storyboard,修改info.plist,结果运行不出来.不删除,按照默认创建的方式就能出来
    不多满:@厚脸皮小强打不死的小强 两种方式都可以实现。删除后运行不出来,是不是因为你删除了之后,没有在todayviewcontroller中添加UI、处理逻辑啊。
  • super_chao:跳转的URL是怎么定义的啊
    不多满:@super_chao 这个就看你的主app的对于openurl的处理逻辑了,完全是自定义的
  • 写代码的小农民:博主,怎么能3DTouch的时候不触发Widget,我看支付宝使用3DTouch的时候就关闭了Widget。求指教!!!
    玩赖是小狗:那个是因为他widget的版本比你手机版本高 没显示吧
  • ifelseboyxx:博主,我想问下,如果我的app 里面写了一套 UI ,然后 widget的UI 一摸一样的,怎么能共用这一套UI 呢? 还是只能重新写?
    wokenshin:用纯代码来实现 共同的UI放在父类
    清晨日暮:@_littleboy试试framework
  • soulDxl:您好,博主,请问下//通过extensionContext借助host app调起app
    [self.extensionContext openURL:[NSURL URLWithString:@"appextension://xxx"] 这个xxx是在哪设置的呢
    陌上北辰:@soul1993 如果要跳转到AppB里的某一个页面呢
    soulDxl:@陌上北辰 例如跳转到AppB,这样写,AppB:// ,后面的//双斜杠不能省略。[self.extensionContext openURL:[NSURL URLWithString:@"AppB://"] completionHandler:^(BOOL success) {
    }];
    陌上北辰:@soul1993 你解决了么,我也想这个问题
  • zero000:您好,我想问下widget的高度有限制吗
    被风吹过的印记:@zero000 有。的,最低110。
  • Python数据分析实战:不通过本地保存的形式,可以共享对象数组么?

本文标题:iOS开发之widget实现

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