Today Extension

2019-05-19  本文已影响0人  黄定师

前言

简单介绍下APP Extension(应用扩展)中的Today Extension的使用方法。下图就是一个TodayExtension示例。


TodayExtension示例.PNG

实现Today Extension

创建Today Extension

创建TodayExtension.png

有两种方式调出以上会话窗口:
1.点击工程 -> TARGETS -> "+" -> 选择Today Extension;
2.点击File -> New -> Target... -> 选择Today Extension。

工程中的Today Extension文件夹结构:


TodayExtension文件夹.png

代码实现

我一般习惯用Masonry布局,所以要删除MainInterface.storyboard,然后修改info.plist中的NSExtension:


NSExtension.png

下面是主要代码:

// TodayViewController.m中的代码
#import "TodayViewController.h"
#import <NotificationCenter/NotificationCenter.h>
#import <Masonry.h>
#import "TodayTableHeaderView.h"

@interface TodayViewController () <NCWidgetProviding,  UITableViewDataSource, UITableViewDelegate>

@property (nonatomic, strong) UITableView *tableView;

@end

@implementation TodayViewController

#pragma mark - life cycle
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    // 将小组件的展现模式设置为可展开
    if (@available(iOS 10.0, *)) {
        self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
    }
    
    [self.view addSubview:self.tableView];
    
    [_tableView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_offset(0);
    }];
}

#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 5;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *identifier = @"cellIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        cell = [[UITableViewCell alloc]initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:identifier];
    }
    
    NSArray *titleArr = @[@"帮助",@"反馈",@"个人信息",@"客服",@"设置"];
    cell.imageView.image = [UIImage imageNamed:titleArr[indexPath.row]];
    cell.textLabel.text = titleArr[indexPath.row];
    
    return cell;
}

#pragma mark - UITableViewDelegate
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    
    UIView *headerView = [[TodayTableHeaderView alloc]init];
    
    return headerView;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *path = [NSString stringWithFormat:@"TodayExtension://%zd",indexPath.row];
    NSURL *url = [NSURL URLWithString:path];
    [self openContainingAPPWithURL:url];
}

- (void)openContainingAPPWithURL:(NSURL *)URL {
    [self.extensionContext openURL:URL completionHandler:nil];
}

#pragma mark - NCWidgetProviding
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize  API_AVAILABLE(ios(10.0)){
    if (activeDisplayMode == NCWidgetDisplayModeExpanded) {
        // 设置展开的新高度
        self.preferredContentSize = CGSizeMake(0, 335.0);
    }else{
        self.preferredContentSize = maxSize;
    }
}

- (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);
}

#pragma mark - lazy load
- (UITableView *)tableView {
    if (!_tableView) {
        _tableView = [[UITableView alloc]init];
        _tableView.dataSource = self;
        _tableView.delegate = self;
    }
    return _tableView;
}

@end

针对上述代码有两点需要说明:

  1. "TodayExtension://"的作用:实现点击Today Extension时,通过openURL的方式主动调起Containing App(包含Today Extension的宿主应用),所以需要在Containing App中添加URL scheme;


    URL scheme.png
  2. 示例中Today Extension的展示内容是固定的,如果要求内容是由宿主应用决定的,那要怎么实现呢?通常做法是通过app group实现,即宿主应用往app group里写入内容,Today Extension去读取并展示。

// TodayTableHeaderView.m中的代码
#import "TodayTableHeaderView.h"
#import <Masonry.h>

@interface TodayTableHeaderView ()

@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UILabel *label;

@end

@implementation TodayTableHeaderView

- (instancetype)init {
    self = [super init];
    if (self) {
        [self addSubview:self.imageView];
        [self addSubview:self.label];

        // 布局子视图
        [self mas_layoutSubviews];
    }
    return self;
}

- (void)mas_layoutSubviews {
    [self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.mas_offset(15.0);
        make.bottom.mas_offset(-15.0);
        make.height.mas_equalTo(80.0);
        make.width.mas_equalTo(70.0);
    }];
    
    [self.label mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(self.imageView);
        make.left.equalTo(self.imageView.mas_right).mas_offset(10.0);
    }];
}

#pragma mark - lazy load
- (UIImageView *)imageView {
    if (!_imageView) {
        _imageView = [[UIImageView alloc]init];
        _imageView.image = [UIImage imageNamed:@"son"];
        _imageView.layer.cornerRadius = 8.0;
        _imageView.layer.masksToBounds = YES;
    }
    return _imageView;
}

- (UILabel *)label {
    if (!_label) {
        _label = [[UILabel alloc]init];
        _label.text = @"Hello World";
    }
    return _label;
}

@end
// 宿主应用的AppDelegate.m中的代码
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    // 处理跳转逻辑
    NSString *absStr = url.absoluteString;
    if ([absStr hasPrefix:@"TodayExtension"]) {
        NSArray *titleArr = @[@"帮助",@"反馈",@"个人信息",@"客服",@"设置"];
        NSInteger index = [[absStr substringFromIndex:absStr.length -1] integerValue];
        HLog(@"用户点击了----%@",titleArr[index]);
    }
    return YES;
}

可能遇到的问题

1.Today Extension展示不出来
解决:检查下是否将Extension的deployment target设置的比宿主应用的deployment target高。如果是的话,将它设置的低于宿主应用。

2.在功能上,宿主应用和Extension是相互独立的,如果Extension想借用宿主应用的代码或者资源,那应该怎么办?
解决:选中要借用的资源,设置Target Membership就好了。

Target Membership.png

3.如果想与宿主应用共享三方框架,如masonry,那应该怎么办?
解决:在podfile里添加一个target,在target里写上你要用的三方框架。

target 'TodayExtension' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!

  # Pods for TodayExtension

pod 'Masonry'

end

参考文献

iOS - App Extension 整体总结
iOS应用扩展(APP Extension)- Today Extension使用
ios TodayExtension 在真机上不显示简单解决方案

上一篇下一篇

猜你喜欢

热点阅读