iOS常用

iOS Widget小组件开发(Today Extension)

2020-09-18  本文已影响0人  Singularity_Lee

自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 *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"];
-(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共享
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
上一篇下一篇

猜你喜欢

热点阅读