iOS - App Extension 整体总结
一、App Extension的介绍
App Extension可以让你扩展你APP的自定义功能和内容,使用户可以在与其他应用或者系统进行互动的时候去使用它。app extension即为本文所说的extension。extension并不是一个独立的app,它有一个包含在app bundle中的独立bundle,extension的bundle后缀名是.appex。其生命周期也和普通app不同,这些后文将会详述。extension不能单独存在,必须有一个包含它的containing app。扩展(app Extension )是 iOS 8 中引入的一个非常重要的新特性
我们平时看到的Widget、微信和QQ的share等等,都是App Extension,下图是一些例子:
二、 Extension的种类
我们可以在Xcode的File--->New--->Target里面看到不同平台的Extension,包括iOS、watchOS、tvOS、macOS等等。这里主要介绍iOS,主要包括以下几种Extensions:
也可直接参考官方文档
iOS 8 系统有 6 个支持扩展的系统区域,分别是 Today 、 Share 、 Action 、 Photo Editing 、 Storage Provider 、 Custom keyboard 。支持扩展的系统区域也被称为扩展点。
Today Widget
Today扩展 可以快速获取更新或者在通知中心的近日视图中执行一项快速任务。对于赛事比分,股票、天气、快递这类需要实时获取的信息,可以在通知中心的Today 视图中创建一个 Today 扩展实现。 Today 扩展又称为 Widget 。
Share Extension
分享扩展,发布一个共享网站或者与其他应用共享内容,在 iOS 8 之前,用户只有 Facebook,Twitter 等有限的几个分享选项可以选择。在 iOS 8 中,开发者可以创建自定义的分享选项。
Action Extension
动作扩展,在另一个应用程序的上下文中操作或者查看内容, 在所有支持的扩展点中扩展性最强的一个。它可以实现转换另一个 app 上下文中的内容。苹果在 WWDC 大会上演示了一个 Bing 翻译动作扩展,它可以将在 Safari 中选中的文本翻译成不同的语言。
Photo Editing
图片编辑扩展,在照片app中编辑照片或者视频,在 iOS 8 之前,如果你想为你的照片添加一个特殊的滤镜,你需要进入第三方 app 中,这个过程是相当繁琐的。在 iOS 8 中,你可以直接在 Photos 中使用第三方 app ,如 Instagram , VSCO cam 、 Aviary 提供的 Photo Editing 扩展完成对图片的编辑,而无需离开当前的 app 。
Document Provider
Document Provider 让跨多个文件存储服务之间的管理变得更简单。类似 Dropbox 、 Google Drive 等存储提供商通过在 iOS 8 中提供一个 Document Provider 扩展, app 直接可以使用这些扩展检索和存储文件而不再需要创建不必要的拷贝。
Custom Keyboard
键盘扩展,例如第三方的键盘,搜狗输入法,百度输入法等。苹果公司在 2007 年率先推出了触摸屏键盘,但一直没多大改进。在这一方面, Android 则将键盘权限开放给了第三方开发者,所以出现了许多像 Swype , SwiftKey 等优秀的键盘输入法。在 iOS 8 中,苹果终于将键盘权限开发给了第三方开发者,自定义键盘输入法可以让用户在整个系统范围内使用。
以下是iOS 9和之后中新增扩展
1.Audio Unit Extension:音频单元扩展
2.Broadcast UI Extension:广播UI 扩展
3.Broadcast Upload Extension:广播上传扩展
4.Call Directory Extension:呼叫目录扩展
5.Content Blocker Extension:内容拦截器扩展
6.iMessage Extension:消息的扩展
7.Intents Extension:Intents扩展
8.Intents UI Extension:Intents UI扩展
9.Notification Content Extension:通知内容扩展
10.Notification Service Extension:通知服务扩展
11.Shared Links Extension:分享链接扩展
12.Spotlight Index Extension:Spotlight 索引扩展
13.Sticker Pack Extension:贴纸包扩展
三、App Extensions的生命周期
以下是苹果官方提供的图片:
1.用户选择要使用的App extension
2.系统启动App Extension
3.App Extension 代码运行
4.运行完之后系统kill掉App Extension
这就是App Extension的生命周期,举个例子:
一个Share Extension,在图库里面你选择了一张图片,然后点击分享,选择你的Share Extension(第一步),此时系统会启动你的Share Extension(第二步)。然后你将选择的图片分享到指定的程序(例如微信的发送给朋友)(第三步)。接下来分享页面关闭,系统kill掉了Share Extension。
四、App Extension的通信方式
App Extension主要的通信是和他的host app
Host app (如微信) ; App extension (safari里面分享点击出来的微信extension);Containing app (safari)
这个展示的就是正在运行的App Extension、host app和containing app之间的关系。可以看出:Containing App和app Extension并没有直接的沟通。甚至有的时候Containing app可以不运行,而App Extension直接运行。Containing app和Host app没有任何的沟通。
在一个典型的request/response中,系统打开代表host app(图库)的extension(微信分享的share extension),把host app提供的数据(图片和选择的好友)输送到extension的context,然后extension展示界面,提供一些功能任务(例如微信的分享到朋友)。
还有一种是app extension可以直接和他的containing app沟通:
例如Today Widget,可以直接告诉系统打开他的Containing app,只需要调用NSExtensionContext的openURL:CompletionHandler:方法即可。
app extension和containing app可以共同读写一个被称为Shared resources的存储区域,这是通过App Groups实现的。
这里需要注意的是:
但是如果你不怕苹果审核不通过 或者 下架 也可以用以下方法打开:
// UIWebView *webView = [[UIWebView alloc]init];
// webView.hidden = YES;
// NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:@"weixin://"]];
// [webView loadRequest:request];
// [self.view addSubview:webView]; //这个方法已经打不开了 UIResponder* responder = self;
while ((responder = [responder nextResponder]) != nil) {
if ([responder respondsToSelector:@selector(openURL:)] == YES) {
[responder performSelector:@selector(openURL:) withObject:[NSURL URLWithString:[NSString stringWithFormat:@"weixin://"]]];
}
}
stackoverflow 里面有关于 Share Extension to open containing app 相关的解答
五、App Groups 实现数据共享
- TARGETS-->AppExtensionDemo-->Capabilities-->App Groups
- TARGETS-->TodayExtension-->Capabilities-->App Groups
三、extension和containing app数据共享
- (void)saveTextByNSUserDefaults { NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.wangzz"]; [shared setObject:_textField.text forKey:@"wangzz"]; [shared synchronize]; }
- (NSString *)readDataFromNSUserDefaults {
NSUserDefaults *shared = [[NSUserDefaults alloc] initWithSuiteName:@"group.wangzz"]; NSString *value = [shared valueForKey:@"wangzz"]; return value;
}
- (BOOL)saveTextByNSFileManager { NSError *err = nil;
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.wangzz"]; containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/good"]; NSString *value = _textField.text;
BOOL result = [value writeToURL:containerURL atomically:YES encoding:NSUTF8StringEncoding error:&err]; if (!result) { NSLog(@"%@",err);
} else { NSLog(@"save value:%@ success.",value);
} return result; }
- (NSString *)readTextByNSFileManager { NSError *err = nil; NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.wangzz"]; containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/good"]; NSString *value = [NSString stringWithContentsOfURL:containerURL encoding:NSUTF8StringEncoding error:&err]; return value;
}
- (BOOL)copyFrameworkFromMainBundleToAppGroup { NSFileManager *manager = [NSFileManager defaultManager]; NSError *err = nil; NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.wangzz"]; NSString *sorPath = [NSString stringWithFormat:@"%@/Dylib.framework",[[NSBundle mainBundle] bundlePath]]; NSString *desPath = [NSString stringWithFormat:@"%@/Library/Caches/Dylib.framework",containerURL.path]; BOOL removeResult = [manager removeItemAtPath:desPath error:&err]; if (!removeResult) {
NSLog(@"%@",err);
} else {
NSLog(@"remove success.");
} BOOL copyResult = [[NSFileManager defaultManager] copyItemAtPath:sorPath toPath:desPath error:&err]; if (!copyResult) {
NSLog(@"%@",err);
} else {
NSLog(@"copy success.");
} return copyResult; }
- (BOOL)loadFrameworkInAppGroup
{ NSError *err = nil; NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.wangzz"]; NSString *desPath = [NSString stringWithFormat:@"%@/Library/Caches/Dylib.framework",containerURL.path]; NSBundle *bundle = [NSBundle bundleWithPath:desPath]; BOOL result = [bundle loadAndReturnError:&err]; if (result) { Class root = NSClassFromString(@"Person"); if (root) { Person *person = [[root alloc] init]; if (person) { [person run]; } } } else { NSLog(@"%@",err); } return result; }
六、在App Extension中不可以做的事情
一个app extension不能有以下情况:
1.访问sharedApplication对象。因此不能使用任何该对象的防范
2.使用任何标记NS_EXTENSION_UNAVAILABLE宏的API,或者类似的宏,或者不可用framework里面的API,例如HealthKit framework不能用于app extensions
3.iOS设备访问相机或者麦克风(iMessage app可以访问这些资源,只要在Info.plist里面进行配置使用描述即可)
4.运行一个长时间的后台任务(根据不同平台而异)
5.使用AirDrop接收数据
iOS - App Extension 整体总结的更多相关文章
- 关于报错:'sharedApplication' is unavailable: not available on iOS (App Extension) - Use view controller based
最近在看Extension相关知识的时候,自己写了个小demo 发现[UIApplication sharedApplication]这个方法敲不出来了, 总是报错:'sharedApplicatio ...
- iOS9中找不到XXX.dylib 与 is unavailable no availabel on ios (app extension) - use view controller 的解决办法
在 iOS9 中现在找不到 XXX.dylib 了,比如libz.tbd 如果要用到 libz.dylib,可以用下面的办法,来自 Stack Overflow. Go to Build Phase ...
- 揭秘 iOS App Extension 开发 —— Today 篇
转自:http://www.cocoachina.com/ios/20160619/16760.html 本文授权转载,作者:Cyandev(简书) 从 iOS 8 开始,苹果引入了全新的 App E ...
- iOS App Extension入门
转自简书:http://www.jianshu.com/p/8cf08db29356 iOS 10推出了很多新功能,其中有几个高调的变化:通知栏更加实用,电话可以防骚扰,iMessage变得更加有 ...
- iOS Application Extension
链接: iOS App Extension入门 iOS10通知及通知拓展Extension使用详解(附Demo) iOS10 通知extension之 Content Extension
- iOS 在Host App 与 App Extension 之间发送通知
如何从你的一个App发送通知给另一个App? (例:搜狗输入法下载皮肤完成后使用皮肤) 注:搜狗输入法是App.而键盘是Extension 当你为你的App 添加 App Extension时,如果想 ...
- iOS app内存分析套路
iOS app内存分析套路 Xcode下查看app内存使用情况有2中方法: Navigator导航栏中的Debug navigator中的Memory Instruments 一.Debug navi ...
- [摘抄]iOS App icon、启动页、图标规范
以下内容都是我在做App时通过自己的经验和精品的分析得来的,希望会帮助到你.但是有时个别情况也要个别分析,要活学活用. 一. App Icon 在设计iOS App Icon时,设计师不需要切圆角, ...
- App Extension Today
App Extensions 是iOS8新开放的扩展机制,之后不断增加功能.App Extension Programming Guide: Today 不喜欢废话,直接上干货! 一:重要概 ...
随机推荐
- 【转】【Python】python使用urlopen/urlretrieve下载文件时出现403 forbidden的解决方法
第一:urlopen出现403 #!/usr/bin/env python # -*- coding: utf- -*- import urllib url = "http://www.go ...
- php模拟post提交数据,用处很多,可用来网站的采集,登陆等等
1. [代码][PHP]代码 <?php //以程序登陆一个论坛登录为例 function bbslogin($user_login, $password, $host, $port = &qu ...
- Maven Web应用
创建Web应用程序 要创建一个简单的java web应用程序,我们将使用Maven的原型 - web应用插件.因此,让我们打开命令控制台,进入到C: MVN目录并执行以下命令mvn命令. C:MVN& ...
- js中找string中重复项最多的字符个数
// split():字符串中的方法,把字符串转成数组. // sort():数组中的排序方法,按照ACALL码进行排序. // join():数组中的方法,把数组转换为字符串 function de ...
- Logback中文文档(四):Appender
什么是 Appender Appender是负责写记录事件的组件.Appender 必须实现接口"ch.qos.logback.core.Appender".该接口的重要方法总结如 ...
- linux 内存分页
内存是计算机的主存储器.内存为进程开辟出进程空间,让进程在其中保存数据.我将从内存的物理特性出发,深入到内存管理的细节,特别是了解虚拟内存和内存分页的概念. 内存 简单地说,内存就是一个数据货架.内存 ...
- 【玩转Golang】reflect.DeepEqual
如果有两个map,内容都一样,只有顺序不同 m1:=map[,,}; m2:=map[,,}; 我们怎么判断二者是否一致呢? 如果你打算这么写: fmt.Println("m1==m2&qu ...
- 加密算法(扩展知识:Base64编码)
在某些考虑数据安全的场景下,我们常常会用到加密解密.编码解码知识.比如把用户密码保存到数据库上,常用的方式是通过MD5或SHA1不可逆算法进行加密后密文保存. 这里主要介绍三种常用的加密算法: (1) ...
- JavaScript 使用穷举方式实现内容简繁转换
场景: 在Web开发中,有时存在对内容进行简体和繁体互相转换的需求,这时我们可以参考以下做法. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ...
- spring mvc 框架URL接收中文参数的乱码解决方案
后台可能就会出现乱码,具体解决方案如下: 一. 配置tomcat目录下的service.xml文件 tomcat7/conf/server.xml 给该行代码加上 URIEncoding=" ...