美文网首页iOS常用
iOS Widget小组件开发(Today Extension)

iOS Widget小组件开发(Today Extension)

作者: Singularity_Lee | 来源:发表于2020-09-18 15:01 被阅读0次

    自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 Widget小组件开发(Today Extension)

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