iOS8.0之后,苹果支持了扩展(Extension)的开发,开发者可以通过系统提供给我们的扩展接入点 (Extension point) 来为系统特定的服务提供某些附加的功能。当时Widget扩展应用不温不火,iOS10之后官方对Widget进行了大幅度的优化,配合3Dtouch Widget逐渐火了起来。本文简单的介绍了Widget的使用。
本地大致按照以下四个步骤介绍widget
1.在宿主工程添加widget target
2.构建UI界面
3.唤醒宿主App
4.与宿主App共享数据
1.在宿主工程添加widget target
打开宿主工程,Flie->New->Target->Today Extension->Next,如下图。
这样创建一个widget target
这个时候需要注意两点
1.在当前的widget target基本配置里面将Deployment Target设置为你要兼容的iOS最低版本。
因为创建出来的时候,这里是默认是iOS最高版本,如果不更改,你自己的手机iOS版本比Deployment Target低的话就会导致运行而不出现widget情况。
2将你需要的图片资源拖入当前的target内
因为widget 与 宿主App是两个不容的进程,资源是不能共享的,如果不推入widget会导致不能加载资源。当然你也可以创建一个xcassets再把图片资源拖入。
2.构建UI界面
系统默认是用storyboard的形式,如果你使用纯代码需要在当前target的info.plist首先将原有NSExtensionMainStoryboard字段删除,添加字段NSExtensionPrincipalClass,value是你所写的controller的名称,一般默认的都是TodayViewController,如下图
如果使用SB那就忽略上面的操作。
iOS10以上支持widget的折叠与展开。
在初始化UI的时候加入下面的代码,告诉系统你的widget是可折叠的样式。
if (@available(iOS 10.0, *)) {
self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
}
重写切换展开及折叠布局时的方法,处理用户点击折叠与展开的操作。
- (void) widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize {
NSLog(@"maxWidth %f maxHeight %f",maxSize.width,maxSize.height);
if (@available(iOS 10.0, *)) {
if (activeDisplayMode == NCWidgetDisplayModeCompact) {
//折叠
self.preferredContentSize = CGSizeMake(maxSize.width, 100);
//处理一些操作
} else {
//展开
self.preferredContentSize = CGSizeMake(maxSize.width, 200);
//处理一些操作
}
} else {
// Fallback on earlier versions
}
}
这里注意加载数据完毕后,渲染UI时一定要在主线程操作。
3.唤醒宿主App
widget 与 宿主App属于两个独立的进程。可以理解为两个不同的App,如果唤醒宿主,可以通过schemes的方式唤醒。
1.在宿主App内设置url schemes
在宿主项目的target->info->URLTypes点击加号增加内容,然后在URL Schemes定义一个Schemes,例如为widgetDemo,如下图
2.处理widget的点击事件
在需要跳转的时候加入以下代码
//点击了内容,要跳转到宿主app
NSURL *URL = [NSURL URLWithString:@"widgetDemo://data=123456"];
[self.extensionContext openURL:URL completionHandler:^(BOOL success) {
if (success) {
NSLog(@"打开成功");
}
}];
4.与宿主App共享数据
1.通过schemes传递参数
如果数据量不大,仅仅是参数的一些传递的话,利用schemes即可,如上面的代码所示widgetDemo://后面的data=123456即是参数,可以携带少量的信息。
2.通过App Groups来共享数据
(1.)去开发者账号Identifiers->App Groups 点击+号增加一个App Groups total.如下图:
(2.)然后去宿主App的appId点击Edit->点击App Groups的Edit,选中刚才创建的App Groups total->Continue.点击如下图
(3.)分别去Xcode中的宿主Targrt 与 widget Target,打开App Groups对刚才创建的App Groups total打钩,无任何错误,证明添加成功,如下图。
当然你也可以忽略前两步直接进行第三步,点击+号分别在宿主Targrt 与 widget Target中增加一个App Groups total,可能会因为格式不对,而无法添加成功。
分别在widget 内添加写入代码,在宿主app内添加读取代码。即可完成App Groups内数据共享
//widget内存入数据
- (void)wirteData:(NSData *)data {
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.widgetdemo.message"];
[userDefaults setObject:data forKey:@"widgetImage"];
BOOL isok = [userDefaults synchronize];
NSLog(@"写入成功?%d",isok);
}
//宿主app内读取数据
- (void)readMessage {
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.widgetdemo.message"];
NSData * date = [userDefaults objectForKey:@"widgetImage"];
_imageView.image = [UIImage imageWithData:date];
}
至此widget的简单使用完成,Demo戳这里,下面有一些注意点:
1.widget与宿主细胞分别是两个不同的进程,相当于是两个不同的app,上架的时候需要创建证书,配置文件等。
2.widget与宿主细胞分别是两个不同的进程,图片等资源不能直接使用宿主app的资源。
3.widget target基本配置里面将Deployment Target设置为你要兼容的iOS最低版本。一定比你真机的iOS系统版本低,否者不能显示出来。