iOS 应用扩展 - Today Extension

需求

作出下图效果(上半部分)

同花顺

首先我们知道这是一种Today Extension,上图是通过3DTouch触按弹出的,我们也可以在今日通知栏里添加看到。

最终的效果如下:

效果图

创建步骤

1、创建Today Extension

2、实现扩展和宿主App之间共享数据

3、使用宿主App中的资源

4、扩展中打开宿主App

5、补充:读取xib文件、扩展中支持三方框架、参数传递、扩展Widget高度、上架注意事项

创建Today Extension

首先,我们选中项目文件,选择 xcode ->Editor ->Add Target,如下图,选中Today Extension项,然后点击Next,命名(本文中为MyTodayWidget),在弹出框中选择Activate,激活这个scheme。

创建

激活之后,项目中就会多出一个 TodayWidget 的扩展,新增的文件夹中的MainInterface.storyboard 和 TodayViewController 这个类就是我们要在通知中心显示的界面的控制器。storyborad,里面已经有一个默认的界面,其中只包含了一个label,显示“Hello World”。

新增的文件

TodayWidget扩展都是以宿主App前缀开始的。

我们先运行项目,再运行应用扩展。

运行应用扩展

这样,我门可以在系统的今日通知中心看到如下样式

今日扩展

上述就完成了Today Extension的创建。

当然你可以将扩展中的 plist 中的 displayname 更换为宿主应用名称,在TodayViewController完成项目需要的UI。

共享数据

在 Today Extension 开发中,避免不了要和宿主App之间共享数据,比如,笔者的项目中需要使用项目中的域名、三方平台请求头部、服务器数据地址等等;

扩展与宿主App之间共享数据有两种方式:

  • 通过NSUserDefaults
  • 通过一个扩展与App都可以访问的共享容器,来存放文件,数据(Core Data, Sqlite等都可以存放在这个共享的容器中)

首先,我们需要创建一个 app group,如下图,选中项目的Target -> Capabilities -> App Groups,打开,如果你以前创建过group,会自动列出来。选择+号,填入group的名称(记下这个名称,因为这个是扩展和宿主之间共享数据的标志符)

group

创建完成之后,选择扩展的Target -> Capabilities -> App Groups,打开,选择我们刚才所创建的group。

⚠️: 如果出现了错误,应该是名称不可用,换一个重试

也可以登录开发中选中《App Group》创建

创建App Group

在扩展和宿主App打开group之后,项目中会多出两个文件,如下图

新增的环境

完成上述之后,我们利用刚刚的标志符来存取共享的数据

// 存储数据
[[[NSUserDefaults alloc] initWithSuiteName:@"group.com.LOLITA.appExtension"] setValue:myNote forKey:@"myShareData"];
// 取出数据
NSArray *myData = [[[NSUserDefaults alloc] initWithSuiteName:@"group.com.LOLITA.appExtension"] valueForKey:@"myShareData"];

这样我们可以在扩展和宿主App之间存取共享的数据了。

补充:

如果需要存储更多的数据,可以通过文件或者数据库(Core Data, Sqlite等)。这个时候共享数据的方法就是要创建一个共享的文件夹。

NSURL *groupURL = [[NSFileManager defaultManager]  containerURLForSecurityApplicationGroupIdentifier: @"group.com.LOLITA.appExtension"];

通过上面的方法,扩展和App就都可以访问这个共享的文件夹了,将数据库,文件等存储在这个文件夹中,也同样的达到数据共享的目的。

使用宿主App中的文件

在扩展中,总是避免不了想要使用宿主项目中的文件,例如cell样式,数据处理工具等等,重写一份当然是可以的,但不是我们想要的结果。

我们可以将需要用的文件也供用给扩展,步骤如下

打开.m文件,选中下图按钮

共享文件

这样我们就可以在扩展中使用该文件了

⚠️:在选择的文件中,如果包含了其他文件,一样是需要添加到扩展中的

扩展中打开宿主App

既然扩展作为了宿主App消息的展示栏,肯定应用的入口了,那么我们怎么让扩展和App之间进行消息传递呢?例如,我们需要打开某条消息的详情,或者是某个功能模块。

我们知道,我们打开别的应用是需要设置URL Types,然后通过URL Schemes来打开应用的,同样的,扩展也可以看成是其他应用,这样,我们势必也要为自己的App设置一个URL Types。

首页我们设置一个URL Types

设置URL Types

当我们想通过openURL来打开应用时,却发现报错了

openURL

这是因为扩展不是一个完整的程序,所以它并没没有 sharedApplication 这个对象。

所以Apple给每个UIViewController加了一个 extensionContext 属性,在我们的宿主App中,这个属性是nil,而在扩展中,我们就可以通过extensionContext来执行跳转。

我们在点击事件中添加如下代码。

[self.extensionContext openURL:[NSURL URLWithString:@"AppExtension://add"] completionHandler:nil];

既然有跳转,肯定涉及到传处理了,我们在AppDelegate里处理消息。

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    // 可以先回到应用首页,在跳转
    if ([url.absoluteString hasPrefix:@"AppExtension"]) {
        if ([url.absoluteString hasSuffix:@"add"]) {
            // do something
        }
        else if ([url.absoluteString containsString:@"detail"]){
            // do something
        }
    }
    return YES;
}

补充

读取xib文件、扩展中支持三方框架、参数传递、扩展Widget高度、上架注意事项等**

  • 读取xib文件

如果cell样式是xib,并出现读取错误问题,可以使用下面代码尝试。

NSBundle *bundle = [NSBundle bundleForClass:[TodayItemView class]];
NSArray *cells = [bundle loadNibNamed:@"TodayItemView" owner:nil options:nil];
TodayItemView *itemView = cells.firstObject;
  • 扩展中支持三方框架

如果扩展中使用到三方框架,则在Podfile中添加下面代码,并且update

target :'MyTodayWidget' do
    platform :ios, '8.0'
    pod 'AFNetworking', '~> 3.1.0'
end
  • 参数传递

如果需要传递多个参数,可以参考下面代码尝试

NSString *urlString = [NSString stringWithFormat:@"AppExtension://markCode=%@&code=%@&yesclose=%@&stockName=%@",market_stockCode,stockCode,preclose_px,[stockName stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];
[self.extensionContext openURL:[NSURL URLWithString:urlString] completionHandler:nil];

⚠️:url中不能出现中文,需要进行UTF-8转换,上面例子中,我将中文名称进行了转换,你也可以将urlString整体进行转换。

  • url解析(接上面c)

如果url解析有问题,可以参考下面代码尝试

// 将url转为http形式
NSString *tmpUrlString = [url.absoluteString stringByReplacingOccurrencesOfString:@"AppExtension://" withString:@"http://xxx?"];
NSURLComponents *components = [NSURLComponents componentsWithString:tmpUrlString];
NSArray* queryItems = components.queryItems;
NSMutableDictionary* queryItemDict = [NSMutableDictionary dictionary];
// 将value和name转换为字典
for (NSURLQueryItem* item in queryItems) {
    [queryItemDict setObject:item.value forKey:item.name];
}
  • 扩展Widget高度

系统默认的高度为110,如果想要在通知中心扩展高度,可以使用下面代码尝试。

- (void)viewDidLoad {
    [super viewDidLoad];
    // 将小部件展现模型设置为可展开
    self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
}

在代理方法中设置高度。

- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize {
    if (activeDisplayMode == NCWidgetDisplayModeExpanded) {
        // 设置展开的新高度
        self.preferredContentSize = CGSizeMake(0, NewHeight);
    }else{
        self.preferredContentSize = maxSize;
    }
}

⚠️:使用3DTouch唤出的弹窗依旧是110,上面代码只是改变了通知中心的高度

  • 上架注意事项

如果出现打包,或上架失败,可以尝试下面步骤。

  1. 扩展和target中的应用包都选自动管理签名和证书
签名
证书
  1. 项目中配置正确的证书
项目配置证书
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容

  • 最近在做一个记事类的App,其中有一个想实现的功能就是希望能够在通知中心查看自己的一些记事内容。正好也是之前写了一...
    水哥阅读 8,095评论 8 56
  • iOS8.0加入了扩展,iOS10苹果又增加了很多扩展。在今后,程序中会集成越来越多的扩展功能。 今天主要来模仿1...
    fou7阅读 12,396评论 7 47
  • 在生活中,我曾经尝试坚持锻炼身体,明明知道这样对自己是有益的,但往往坚持不下去。当看到身边有的人,明明有好的选择,...
    可可儿妈阅读 232评论 0 0
  • 也许 用完后 你就不会在想我 可是 这并不能 阻止我 去装饰你的美 请原谅我 太容易变形 水向我冲来 我就现出原形...
    萤火虫最美阅读 237评论 1 4
  • 我一直认为,具有远见是一件太困难的事情。远见,是一种尽可能接近未来的推理能力,它的基础是:洞察力、判断力、学习力。...
    王炳炜阅读 167评论 0 0