iOS Widget小组件开发(Today Extension)

·  阅读 784

自iOS8之后,苹果支持了扩展(Extension)的开发,开发者可以通过系统提供给我们的扩展接入点 (Extension point) 来为系统特定的服务提供某些附加的功能。

所谓Widget,就是我们熟知的小组件,这是独立于应用之外的又一个新小应用,但是和主应用之间又有着一定的关系。

本文介绍的是iOS14系统以下的widget组件,也就是Todat Extension iOS14系统以上widget请见: iOS14 Widget(Widget Extension)小组件开发

widget实现

1.创建添加Todat Extension

File -> New -> Target -> Todat Extension 创建路径.jpg

2.添加widget的URL Schemes

由于extension 和主app 是两个完全独立的进程,所以它们之间不能直接相互跳转。为了实现 Widget 调起 APP,这里通过 openURL 的方式来启动 主app。

主APP中 Target -> Info-> URL Types -> + urlscheme.png

调用方式 widget中点击跳转事件添加如下代码

[self.extensionContext openURL:[NSURL URLWithString:@"NowWidget://"] completionHandler:nil];
复制代码

主APP的AppDelegate中接收

-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
    if ([url.scheme isEqualToString:@"NowWidget"]){
        //执行跳转后的操作
    }
    return YES;
}
复制代码

3.数据共享

由于widget跟APP间相互独立,如果想用相同的数据则需要两者间数据共享,创建 App Group 主APP中 Target -> Signing & Capability -> +Capability -> 添加 App Group APPGroups创建.png

ps:网上说的还需创建申请 APPID 但在开启自动管理 Automatically manage signing的情况下xcode会自动给你创建相关联的APPID

两者间的数据共享主要通过NSFileManagerNSUserDefaults两种形式。

  • 通过NSUserDefaults共享数据
//存数据
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.imoblife.now"];
[userDefaults setObject:@"content" forKey:@"widget"];
[userDefaults synchronize];

//取数据
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.imoblife.now"];
NSString *content = [userDefaults objectForKey:@"widget"];
复制代码
  • 通过NSFileManager共享数据
-(BOOL)saveDataByNSFileManager:(NSData *)data
{
    NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.imoblife.now"];
    containerURL = [containerURL URLByAppendingPathComponent:@"widget"];
    BOOL result = [data writeToURL:containerURL atomically:YES];
    return result;
}

-(NSData *)readDataByNSFileManager
{
    NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.imoblife.now"];
    containerURL = [containerURL URLByAppendingPathComponent:@"widget"];
    NSData *value = [NSData dataWithContentsOfURL:containerURL];
    return value;
}
复制代码

4.开启折叠及尺寸规定

不需要折叠功能忽略此步骤

- (void)viewDidLoad {
    [super viewDidLoad];
    //添加折叠效果
    self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
}
//折叠及非折叠样式更改
-(void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize {
    /**
     iOS10以后,重新规定了Today Extension的size。宽度是固定(例如在iPhone6上是359),所以无法改变;但是高度方面,提供了两种模式:
     
     NCWidgetDisplayModeCompact:固定高度,则为110
     
     NCWidgetDisplayModeExpanded:可以变化的高度,区间为110~616
     */
    if (activeDisplayMode == NCWidgetDisplayModeCompact) {
        self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width-16, 110);
    } else {
        self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width-16, 250);
    }
}

//此方法主要执行刷新操作
- (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
    
    completionHandler(NCUpdateResultNewData);
}

复制代码

5.文件共享及pods共享

  • 文件共享

文件共享.png 勾选共享widget选项即可

  • pods共享

正常使用下widget中无法使用pods导入的第三方SDK如Masonry等,会造成布局等极其不便,因此需要共享pods,在Podfile中需要另设置并重新install

source 'https://github.com/CocoaPods/Specs.git'

platform :ios, '9.0'
inhibit_all_warnings!

#共享Masonry
def share_pods
    pod 'HandyJSON'
end

target "targetName" do
    pod 'AFNetworking'
    share_pods
end

target "widgetTargetName" do
    share_pods
end
复制代码

完成后即可使用pods中的第三方SDK了

  • #import <Masonry.h>
  • #import <SDWebImage/UIImageView+WebCache.h>
  • #import <SDWebImageDownloader.h>
  • #import <SDImageCache.h>
  • #import <AFNetworking.h>...

Pods第三方SDK使用错误提示 如果在pods导入共享第三方库,或者使用[UIApplication sharedApplication]方法报错如下时

not available on iOS (App Extension) - Use view controller based solutions where appropriate instead.

则需要在pods Target里面,选中出错的SDK并点击buildSettings 搜索Require 然后把Require Only App-Extension-Safe API 然后把YES改为**NO**即可 修正路径说明.png ps:工程项目里也可按照这个方法去排查原因


在调试widget功能时不要忘记将Device变更为widget项目 🤦‍♀️🤦‍♀️🤦‍♀️ 调整device.png

分类:
iOS
标签:
分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改