美文网首页
Today Extension

Today Extension

作者: 黄定师 | 来源:发表于2019-05-19 12:45 被阅读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 在真机上不显示简单解决方案

    相关文章

      网友评论

          本文标题:Today Extension

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