Widget开发步骤
建议先阅读Widget的配置篇,再开始开发,因为开发的过程中需要提前准备一些东西【iOS】Widget开发-配置篇
1. 创建新的Target,选择Today Extension。点击Next后,会生成如下图的几个文件
image image2. 查看新生成的Info.plist
Bundle display name:Widget在通知栏显示的名称
NSExtension
如果你是使用纯代码进行开发,请按照下面进行操作:
(1)请删除NSExtensionMainStoryboard 的键值对和MainInterface.storyboard文件;
(2)请添加NSExtensionPrincipalClass这个key,并将value设置为控制器(如TodayViewController)
3. 准备工作都已经完成,正式进入开发工作
iOS 8
①、iOS8下没有折叠和展开功能,默认的Widget高度为self.preferredContentSize设置的高度。
self.preferredContentSize =CGSizeMake(kScreenW,100);
②、iOS8下所有组件默认右移30单位,可以通过下面的方法修改上下左右的距离
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets {returnUIEdgeInsetsMake(0,0,0,0);}
iOS 10
iOS 10以后,Widget可玩性更高了,有了两种显示模式
NCWidgetDisplayModeCompact, // Fixed height,高度固定,最低高度为110
NCWidgetDisplayModeExpanded, // Variable height,高度可变
// 5s模拟器下:
// NCWidgetDisplayModeCompact模式下:{304, 110}
// NCWidgetDisplayModeExpanded模式下:{304, 528}
// 6s模拟器下:
// NCWidgetDisplayModeCompact模式下:{359, 110}
// NCWidgetDisplayModeExpanded模式下:{359, 616}
设定显示模式,需要在设定Size前设定这个属性!!!
if([[UIDevicecurrentDevice] systemVersion].intValue >=10) {
self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeCompact;
// self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
}
viewDidLoad的代码如下:
- (void)viewDidLoad {
[superviewDidLoad];
if([[UIDevicecurrentDevice] systemVersion].intValue >=10) {
self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeCompact;
}
self.preferredContentSize =CGSizeMake(kScreenW,100);
[selfsetupUI];
}
当显示模式设置为NCWidgetDisplayModeExpanded时,点击折叠和打开时,会触发下面这个方法,在这个方法中可以修改对应状态的高度
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize {
if(activeDisplayMode == NCWidgetDisplayModeCompact) {
self.preferredContentSize =CGSizeMake(maxSize.width,110);
}else{
self.preferredContentSize =CGSizeMake(maxSize.width,200);
}
}
在下面的方法中更新视图
-(void)widgetPerformUpdateWithCompletionHandler:(void(^)(NCUpdateResult))completionHandler {
// NCUpdateResultNewData 新的内容需要重新绘制视图
// NCUpdateResultNoData 部件不需要更新
// NCUpdateResultFailed 更新过程中发生错误
completionHandler(NCUpdateResultNoData);
}
开发中可能会遇上的一些问题
代码共享
目前我见到了四种共享代码的方法:
将代码打包成Framework,然后link到主App和Widget中(推荐)
不怕安装包变大的话,可以考虑将需要的第三方库在主App和Widget中分别复制一份(推荐)
将需要共享的文件按图中进行勾选配置
image通过Pods导入,不太建议通过pod分别向两个Target中导入第三方库,因为很容易发生一些不好处理的问题
数据共享
数据共享有两种常用的方法:
NSUserDefaults,和我们常用的方法一样,不过在创建NSUserDefaults时,需要填写我们之前的GroupID。通过GroupID,我们就可以进行主App和Widget之间的数据共享了。
/// 写入数据
NSString*groupID =@"group.com.aaa.bbb";
NSUserDefaults*ud = [[NSUserDefaultsalloc] initWithSuiteName:groupID];
[ud setObject:@"我是测试的数据"forKey:@"test"];
[ud synchronize];
/// 读取数据
NSString*groupID =@"group.com.aaa.bbb";
NSUserDefaults*ud = [[NSUserDefaultsalloc] initWithSuiteName:groupID];
NSString*value = [ud objectForKey:@"test"];
NSFileManager
/// 写入数据
NSString*groupID =@"group.com.aaa.bbb";
NSError*err =nil;
NSURL*containerURL = [[NSFileManagerdefaultManager] containerURLForSecurityApplicationGroupIdentifier:groupID];
containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/test"];
NSString*value =@"我是测试的数据";
BOOLresult = [value writeToURL:containerURL atomically:YESencoding:NSUTF8StringEncodingerror:&err];
if(result){
NSLog(@"写入成功");
}
/// 读取数据
NSString*groupID =@"group.com.aaa.bbb";
NSError*err =nil;
NSURL*containerURL = [[NSFileManagerdefaultManager] containerURLForSecurityApplicationGroupIdentifier:groupID];
containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/test"];
NSString*value = [NSStringstringWithContentsOfURL:containerURL encoding:NSUTF8StringEncodingerror:&err];
打开App
设置App的URLSchemes,打开APP主要通过URLScheme打开和传递参数值。
设置URLSchemes时,要独特一些,避免与其他App重复
image在Widget中添加点击事件,用于触发打开App的操作和传递参数
NSString*schemeString =@"zhangpeng://actionName?paramName=paramValue";
[self.extensionContext openURL:[NSURLURLWithString:schemeString] completionHandler:^(BOOLsuccess) {
}];
app的appdelegate的代理方法中,截取URL,做响应处理:
// 所有版本的都可以使用
- (BOOL)application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation {
[selfappCallbackWithOpenUrl:url];returnYES;
}
/// iOS 8 以后
- (BOOL)application:(UIApplication*)app openURL:(NSURL*)url options:(NSDictionary *)options {
[selfappCallbackWithOpenUrl:url];
returnYES;
}
/// iOS 7
- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url {
[selfappCallbackWithOpenUrl:url];
returnYES;
}
- (void)appCallbackWithOpenUrl:(NSURL*)url{
NSLog(@"url: %@", url.host);
// 针对url进行不同的操作
}
数据刷新
当widget从屏幕上消失2s左右,再次出现在屏幕中时,都会重新调用viewDidLoad方法。所以每次出现都请求最新数据,进行刷新操作,widget都会闪一下,根据产品需求,可以做一下控制;
- (void)viewDidLoad {
[superviewDidLoad];
}
如果短时间内让Widget频繁地消失显示,那只会执行viewWillAppear方法;
- (void)viewWillAppear:(BOOL)animated {
[superviewWillAppear:animated];
}
网友评论