3

简介

  Today Extension是ios8开始推出的一个重大更新,它与宿主工程是相互独立的,到目前已经有很多app实现了这一功能,但是该功能在ios10系统上才得以真正的发挥。
  extension规定不能直接与它的宿主工程host app进行通讯,也不能共享之间的代码,但是可以通过添加framework共享代码块。
  在ios8、9中today extension没有折叠和展开功能,在这两个系统中只有下拉刷新;然后在ios10系统中,today extension是通过右滑界面而出现的,此时只要实现折叠、展开这两项就能实现该功能。
  同时ios8、ios9与ios10中的toaday extension界面有些区别,iOS10以前的版本中today extension 的背景颜色是黑色带有磨砂效果的;而ios10及以上系统是白色带磨砂的
  Extension可以使用的内存远远低于app可以使用的内存,因此当内存吃紧的时候,会优先杀死extension。所以在开发的过程中应该注意内存的使用
  开发过程中,有些API接口不可用与Extension中,在系统中使用NS_EXTENSION_UNAVAILABLE 标明

创建Today Extension

一、宿主工程

  先创建宿主功能,若在已有的工程上添加today extension可忽略第一步
图片描述

二、创建Extension

  项目--->General---> +

图片描述
图片描述
图片描述

  此时运行工程后,加载extension即可显示Hello World字样是工程原配的

图片描述

三、纯代码开发Extension

  个人比较喜欢纯代码开发,storyboard在多人合作时,容易产生冲突和矛盾。
步骤:

  • 删除Extension中的storyboard以及Info.plist中的NSExtension->NSExtensionMainStoryboard
  • Info.plist中的NSExtension添加NSExtensionPrincipalClass字段,对应的value值TodayViewController

图片描述
图片描述
图片描述

四、与宿主工程产生关联

1.创建证书中的APP Groups

图片描述

2.配置宿主工程的App Groups

图片描述

3.配置Extension中的App Groups

图片描述

  注意:宿主工程中的App Groups必须与Extension中的App Groups保持一致

五、与宿主工程的数据共享

  在extension中可以用NSUserDefaultNSFileManagerNSFileCoordinationCoreDataSqlite等进行数据共享。
  官方建议在iOS8.2以上系统中使用UIDocument来协调共享数据,在ios9以上系统中使用NSFileCoordinator类进行数据共享,但是当应用程序扩展转换到后台时,必须删除NSFilePresenter对象
  首先我们在宿主工程中,存点数据

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSUserDefaults *userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.dyTodayExtension"];
    [userDefault setObject:@"tips" forKey:@"group.dyTodayExtension.tips"];
}
@end

在Extension取出数据显示

#import "TodayViewController.h"
#import <NotificationCenter/NotificationCenter.h>

@interface TodayViewController () <NCWidgetProviding>{
    UILabel *_textLabel;
    UIView *_subView;
}

@end

@implementation TodayViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //设置extension的size
    self.preferredContentSize = CGSizeMake(0, 150);
    
    _subView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 150)];
    _subView.backgroundColor = [UIColor grayColor];
    [self.view addSubview:_subView];
    
    _textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 10, _subView.frame.size.width, 50)];
    _textLabel.numberOfLines = 0;
    _textLabel.textAlignment = NSTextAlignmentCenter;
    _textLabel.backgroundColor = [UIColor brownColor];
    _textLabel.textColor = [UIColor greenColor];
    [_subView addSubview:_textLabel];
    
    NSUserDefaults *userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.DonYau.today"];
    NSString *textStr = [userDefault valueForKey:@"group.DonYau.today.tips"];
    _textLabel.text = textStr;
}

  此时运行工程,可以看到我们在宿主工程保存的数据,在Extension中也可以获取到

图片描述

六、跳转宿主工程

在宿主工程中配置URL Schemes,然后添加点击事件,当我们点击button时,就会跳转到宿主工程

#import "TodayViewController.h"
#import <NotificationCenter/NotificationCenter.h>

@interface TodayViewController () <NCWidgetProviding>{
    UILabel *_textLabel;
    UIView *_subView;
}

@end

@implementation TodayViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //设置extension的size
    self.preferredContentSize = CGSizeMake(0, 150);
    
    _subView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 150)];
    _subView.backgroundColor = [UIColor grayColor];
    [self.view addSubview:_subView];
    
    _textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 10, _subView.frame.size.width, 50)];
    _textLabel.numberOfLines = 0;
    _textLabel.textAlignment = NSTextAlignmentCenter;
    _textLabel.backgroundColor = [UIColor brownColor];
    _textLabel.textColor = [UIColor greenColor];
    [_subView addSubview:_textLabel];
    
    NSUserDefaults *userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.DonYau.today"];
    NSString *textStr = [userDefault valueForKey:@"group.DonYau.today.tips"];
    _textLabel.text = textStr;
    
    UIButton *openApp = [[UIButton alloc] initWithFrame:CGRectMake(0, 60 , _subView.frame.size.width, 30)];
    openApp.backgroundColor = [UIColor blueColor];
    [openApp setTitle:@"打开app" forState:UIControlStateNormal];
    [openApp setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [_subView addSubview:openApp];
    [openApp addTarget:self action:@selector(openApp) forControlEvents:UIControlEventTouchUpInside];

}

- (void)openApp{
    [self.extensionContext openURL:[NSURL URLWithString:@"todayExtension:"] completionHandler:^(BOOL success) {
        
    }];
}

  我们可以在宿主工程中通过AppDelegate的代理方法获取从Extension传过来的数据

-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{

    return YES;
}

七、监控Today Extension的更新

  我们创建好Today Extension时,工程已经自动创建好更新的回调,因此我们可以在该代理方法中监控Today Extension的更新操作

- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler {
- 
    completionHandler(NCUpdateResultNewData);
}

八、Today Extension偏移的控制

  同样Today Extension给我们提供了代理方法,以确定内容的偏移

-(UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets{
    return UIEdgeInsetsZero;
}

九、显示收缩、扩展功能

  当我们需要收缩扩展功能的时候,首先需要确定视图刚开始显示的时候,添加状态的显示。

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    //该处目前只能设置NCWidgetDisplayModeCompact,界面初始显示的时候,只能是收缩状态
    self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeCompact;
}

  当我们在willAppear中设置该属性后,运行工程即可看到收缩、扩展功能按钮
图片描述

然后遵循代理,以便在状态发生变化时,更新界面

-(void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize{
    if (self.extensionContext.widgetActiveDisplayMode == NCWidgetDisplayModeCompact) {
        self.preferredContentSize = CGSizeMake(0, 150);
    }else{
        self.preferredContentSize = CGSizeMake(0, 300);
    }
}

10、Cocoapods库的共用

  在使用Today Extension的过程中,或者我们在extension使用的工具类刚好在宿主工程中也需要使用,这个时候cocoapods就帮上我们的大忙了
  比如需要在宿主工程和Extension中使用AFN框架获取一些网络的数据,这时候我们只需配置Podfile文件即可共享工具类

platform :ios, ‘8.0’
use_frameworks!

def shared_pods
    pod 'AFNetworking', '~> 3.1.0'
end


target 'DYTodayDemo' do
shared_pods

end

target 'DYTodayExtensionDemo' do
shared_pods

end

当执行pod install后,工程的配置如图

图片描述

遇到的问题

  1. 当运行工程的出现error: Embedded binary's bundle identifier is not prefixed with the parent app's bundle identifier的错误时,是因为宿主工程和Extensionbundle identifier不符合规范。
    Extension中的identifier应该是在宿主工程的bundle identifier后面加上后缀,比如
宿主工程 bundle identifier : com.todayDemo.Example
Extension bundle identifier : com.todayDemo.Example.today

推荐文章

App Extension编程指南(iOS8/OS X v10.10)中文版
App Extension Programming Guide


孤盏茗
27 声望3 粉丝