研究 UIActivityViewController

发布于:2014-04-25 09:51阅读数:5903

特定的编程语言,如 Lisp、lo 和 Mathematica 都是同像性的(homoiconic),意味着它们的代码可作为数据原语呈现,也就是说它们自身就可在代码中被操纵。许多其他语言,包括 Objective-C ,就不同了

“”

 
阅读器

本文由@nixzhu翻译至nshipster的《UIActivityViewController
数据与代码的关系一直都让人好奇。
 
特定的编程语言,如 Lisplo和 Mathematica 都是同像性的(homoiconic),意味着它们的代码可作为数据原语呈现,也就是说它们自身就可在代码中被操纵。许多其他语言,包括 Objective-C ,就不同了,在两者之间建立了严格的界限,回避 eval() 和其它潜在的危险的动态指示加载方法。
 
当问题中的数据过大或难以表示为除了字节流之外的任何东西时,那么代码与数据的这种紧张关系就达到了一个新的高度。关于“如何编码、解码以及解释图像、文档和媒体的二进制表示”的问题从最开始的操作系统开始就一直存在着。
 
OS X 的 Core Services 框架与 iOS 的移动 Core Services 框架都提供函数通过通用类型标识符(Universal Type Identifiers,即UTI)来根据文件扩展和MIME类型识别和分类数据类型。UTI提供了可扩展和可继承的分类系统,它能给予开发人员极大的灵活性,即使是处理最奇特的文件类型。例如,一个 Ruby 源代码文件(.rb)被分类为 Ruby 源代码 > 源代码 > 文本 > 内容 > 数据;一个 QuickTime 电影文件(.mov)被分类为视频 > 电影 > 试听内容 > 内容 > 数据;
 
在桌面文件系统抽象里,UTI工作得相当好。然而,在一个移动范式里,文件和目录对于用户来说都被隐藏了,于是这很快就失效了。而且,更重要的是,云服务和社交媒体的兴起已经让远程实体比本地文件具有更重要的地位。因此,UTI和URL之间出现了紧张关系。
 
很明显我们需要其它的某种东西。那 UIActivityViewController 能成为我们拼命追求的解决办法吗?
 
UIActivityViewController ,出现于 iOS 6,在应用里为分享和操作数据提供了一个统一的服务接口。
 
给出一个可操作数据的集合,那一个 UIActivityViewController 实例就可如下创建:
  1. NSString *string = ...;
  2. NSURL *URL = ...;
  3. UIActivityViewController *activityViewController =
  4. [[UIActivityViewController alloc] initWithActivityItems:@[string, URL]
  5. applicationActivities:nil];
  6. [navigationController presentViewController:activityViewController
  7. animated:YES
  8. completion:^{
  9. // ...
  10. }];
 
这将在屏幕的底部呈现如下所示的东西: 
 
默认情况下,UIActivityViewController 将显示所有可用于所提供内容的服务,但我们也可以排除特定的 Activity 类型。
  1. activityViewController.excludedActivityTypes = @[UIActivityTypePostToFacebook];
 
Activity 类型又分为“操作”和“分享”两大类:
UIActivityCategoryAction
1. UIActivityTypePrint
2. UIActivityTypeCopyToPasteboard
3. UIActivityTypeAssignToContact
4. UIActivityTypeSaveToCameraRoll
5. UIActivityTypeAddToReadingList
6. UIActivityTypeAirDrop
 
UIActivityCategoryShare
1. UIActivityTypeMessage
2. UIActivityTypeMail
3. UIActivityTypePostToFacebook
4. UIActivityTypePostToTwitter
5. UIActivityTypePostToFlickr
6. UIActivityTypePostToVimeo
7. UIActivityTypePostToTencentWeibo
8. UIActivityTypePostToWeibo
 
每个 Activity 类型都支持好多种不同的数据类型。例如,一条 Tweet 可能由 NSString 以及一个附加的图像 和/或 URL 所组成。
 
不同的 Activity 类型所支持的数据类型 
 
<UIActivityItemSource> & UIActivityProvider
类似于一个剪贴板条目只在必要时才提供数据,为了避免过多的内存分配或处理时间, Activity 条目可以是自定义类型。
 
<UIActivityItemSource>
获取数据项
1. activityViewControllerPlaceholderItem:
2. activityViewController:itemForActivityType:
 
提供数据项信息
1. activityViewController:subjectForActivityType:
2. activityViewController:dataTypeIdentifierForActivityType:
3. activityViewController:thumbnailImageForActivityType:suggestedSize:
 
一个关于这些方法如何使用的例子是自定义一个消息,其根据是否要分享到 Facebook 或 Twitter 分别定义。
  1. - (id)activityViewController:(UIActivityViewController *)activityViewController
  2. itemForActivityType:(NSString *)activityType
  3. {
  4. if ([activityType isEqualToString:UIActivityTypePostToFacebook]) {
  5. return NSLocalizedString(@"Like this!");
  6. } else if ([activityType isEqualToString:UIActivityTypePostToTwitter]) {
  7. return NSLocalizedString(@"Retweet this!");
  8. } else {
  9. return nil;
  10. }
  11. }
 
创建一个自定义 UIActivity
除了上述系统提供的 Activity ,你也可以自己创建 Activity。
 
作为例子,让我们创建一个自定义 Activity 类型,它能接受一个图片 URL 并使用 mustache.me 为其安上一瞥胡子。 
之前
之后
 
首先,我们为 Activity 类型定义一个反向DNS标识符(reverse-DNS identifier),指定类别为 UIActivityCategoryAction ,然后提供一个本地化的标题和一个合适于iOS版本的图像:
  1. static NSString * const HIPMustachifyActivityType = @"com.nshipster.activity.Mustachify";
  2. #pragma mark - UIActivity
  3. + (UIActivityCategory)activityCategory {
  4. return UIActivityCategoryAction;
  5. }
  6. - (NSString *)activityType {
  7. return HIPMustachifyActivityType;
  8. }
  9. - (NSString *)activityTitle {
  10. return NSLocalizedString(@"Mustachify", nil);
  11. }
  12. - (UIImage *)activityImage {
  13. if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
  14. return [UIImage imageNamed:@"MustachifyUIActivity7"];
  15. } else {
  16. return [UIImage imageNamed:@"MustachifyUIActivity"];
  17. }
  18. }
 
接下来,我们创建一个帮助函数,HIPMatchingURLsInActivityItems,它返回一个由任何所支持类型的图像 URL 组成的数组。
  1. static NSArray * HIPMatchingURLsInActivityItems(NSArray *activityItems) {
  2. return [activityItems filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:
  3. ^BOOL(id item, __unused NSDictionary *bindings) {
  4. if ([item isKindOfClass:[NSURL class]] &&
  5. ![(NSURL *)item isFileURL]) {
  6. return [[(NSURL *)item pathExtension] caseInsensitiveCompare:@"jpg"] == NSOrderedSame ||
  7. [[(NSURL *)item pathExtension] caseInsensitiveCompare:@"png"] == NSOrderedSame;
  8. }
  9. return NO;
  10. }]];
  11. }
 
这个函数用于 -canPerformWithActivityItems: 和 prepareWithActivityItems: 以取得第一个 PNG 或 JPEG 的加了胡子的图像 URL,如果有的话。
  1. - (BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
  2. return [HIPMatchingURLsInActivityItems(activityItems) count] > 0;
  3. }
  4. - (void)prepareWithActivityItems:(NSArray *)activityItems {
  5. static NSString * const HIPMustachifyMeURLFormatString = @"http://mustachify.me/%d?src=%@";
  6. self.imageURL = [NSURL URLWithString:[NSString stringWithFormat:HIPMustachifyMeURLFormatString, self.mustacheType, [HIPMatchingURLsInActivityItems(activityItems) firstObject]]];
  7. }
 
我们的网络服务提供了好几种胡子选项,它们定义在一个 NS_ENUM 中:
  1. typedef NS_ENUM(NSInteger, HIPMustacheType) {
  2. HIPMustacheTypeEnglish,
  3. HIPMustacheTypeHorseshoe,
  4. HIPMustacheTypeImperial,
  5. HIPMustacheTypeChevron,
  6. HIPMustacheTypeNatural,
  7. HIPMustacheTypeHandlebar,
  8. };
 
最终,我们提供一个 UIViewController 来显示图像。在这个例子里,一个简单的 UIWebView 控制器就够了。 
  1. @interface HIPMustachifyWebViewController : UIViewController <UIWebViewDelegate>
  2. @property (readonly, nonatomic, strong) UIWebView *webView;
  3. @end
  4. - (UIViewController *)activityViewController {
  5. HIPMustachifyWebViewController *webViewController = [[HIPMustachifyWebViewController alloc] init];
  6. NSURLRequest *request = [NSURLRequest requestWithURL:self.imageURL];
  7. [webViewController.webView loadRequest:request];
  8. return webViewController;
  9. }
 
要使用我们全新的胡子 Activity,我们简单地将其传递给一个 UIActivityViewController 的初始化函数即可:
  1. HIPMustachifyActivity *mustacheActivity = [[HIPMustachifyActivity alloc] init];
  2. UIActivityViewController *activityViewController =
  3. [[UIActivityViewController alloc] initWithActivityItems:@[imageURL]
  4. applicationActivities:@[mustacheActivity];
 
手动调用操作
现在正是回忆起 “UIActivityViewController 允许用户执行它们选择的操作” 的好时机,但当情况需要时,分享依然可以手动调用。
 
为了完整性,下面就来介绍手动执行这些操作的步骤: 
打开 URL
  1. NSURL *URL = [NSURL URLWithString:@"http://nshipster.com"];
  2. [[UIApplication sharedApplication] openURL:URL];
系统支持的 URL scheme 包括:mailto://、tel://、sms://、and maps://。
 
添加到 Safari 阅读列表
  1. @import SafariServices;
  2. NSURL *URL = [NSURL URLWithString:@"http://nshipster.com/uiactivityviewcontroller"];
  3. [[SSReadingList defaultReadingList] addReadingListItemWithURL:URL
  4. title:@"NSHipster"
  5. previewText:@"..."
  6. error:nil];
 
保存到相册
  1. UIImage *image = ...;
  2. id completionTarget = self;
  3. SEL completionSelector = @selector(didWriteToSavedPhotosAlbum);
  4. void *contextInfo = NULL;
  5. UIImageWriteToSavedPhotosAlbum(image, completionTarget, completionSelector, contextInfo);
 
发送短信
  1. @import MessageUI;
  2. MFMessageComposeViewController *messageComposeViewController = [[MFMessageComposeViewController alloc] init];
  3. messageComposeViewController.delegate = self;
  4. messageComposeViewController.recipients = @[@"mattt@nshipster•com"];
  5. messageComposeViewController.body = @"Lorem ipsum dolor sit amet";
  6. [navigationController presentViewController:messageComposeViewController animated:YES completion:^{
  7. // ...
  8. }];
 
发送邮件
  1. @import MessageUI;
  2. MFMailComposeViewController *mailComposeViewController = [[MFMailComposeViewController alloc] init];
  3. [mailComposeViewController setToRecipients:@[@"mattt@nshipster•com"]];
  4. [mailComposeViewController setSubject:@"Hello"];
  5. [mailComposeViewController setMessageBody:@"Lorem ipsum dolor sit amet"
  6. isHTML:NO];
  7. [navigationController presentViewController:mailComposeViewController animated:YES completion:^{
  8. // ...
  9. }];
 
发送推文
  1. @import Twitter;
  2. TWTweetComposeViewController *tweetComposeViewController =
  3. [[TWTweetComposeViewController alloc] init];
  4. [tweetComposeViewController setInitialText:@"Lorem ipsum dolor sit amet."];
  5. [self.navigationController presentViewController:tweetComposeViewController
  6. animated:YES
  7. completion:^{
  8. //...
  9. }];
 
IntentKit
虽然所有这些都让人影响深刻也很有用,但在与 Android 上的丰富的 Intent 模型对比之下,iOS 的 Activity 范式中还是有一些特殊的缺失。
 
在 Android 上,应用可以注册不同的 Intent,以表面它们可用于地图或作为浏览器,而且能被选择为相关 Activity 的默认应用,例如导航或将某个URL加入书签。
 
虽然 iOS 缺少可扩展的基础架构来支持这些,但一个第三方的库,叫做 IntentKit,由 @lazerwalker (有着f*ingblocksyntax.com 的声誉) 编写,它是一个有趣的关于我们如何缩小差距的例子。 
 
正常情况下,在一开始一个开发者就要做许多工作,例如查询某个特定的应用是否已被安装,以及构造一个 URL 以支持某个特定的 Activity 等。
 
IntentKit 合并了连接到这些最流行的服务(如 Web、地图、邮件、Twitter、Facebook以及Google+这些客户端)的逻辑,而且它的 UI 非常类似 UIActivityViewController。
 
任何想将其应用的分享体验提高一个层次的人都应该研究一下它。
 
还有一个要发出的有力争论是,关于 iOS 平台的长期生存能力取决于如 UIActivityViewController 这样的分享机制。俗话说,“信息需要自由”。而任何阻挡人民联盟的事物终将输给那些不阻挡联盟的事物。
 
公开的 远程视图控制器(remote view controller) API 的未来前景给了我关于iOS上分享的未来希望。虽然对现在来说,我们当然可以做得比 UIActivityViewController 更差。(译者注:是这个意思吗? For now, though, we could certainly do much worse than UIActivityViewController.) 

CocoaChina是全球最大的苹果开发中文社区,官方微信每日定时推送各种精彩的研发教程资源和工具,介绍app推广营销经验,最新企业招聘和外包信息,以及Cocos2d引擎、Cocostudio开发工具包的最新动态及培训信息。关注微信可以第一时间了解最新产品和服务动态,微信在手,天下我有!
 
请搜索微信号“CocoaChina”关注我们!
 

研究 UIActivityViewController的更多相关文章

  1. iOS-微信分享多张图片(UIActivityViewController多图分享和多图分享失败)

    前言 微信分享到朋友圈,可分享的类型有:文字类型.图片类型.音乐类型.视频类型和网页类型,但是我们在做图片分享的时候发现微信给的API只能分享一张图片,达不到一些APP的需求,而产品汪或者Boss想要 ...

  2. IOS6 新特性之UIActivityViewController详解

    新的IOS6增加了一些新特性.因为应用需要,所以在国庆的几天里.研究了一下IOS6的说明文档,然后大概地总结了一下UIActivityViewController的用法与大家分享. 首先 从实际效果入 ...

  3. 闲来无聊,研究一下Web服务器 的源程序

    web服务器是如何工作的 1989年的夏天,蒂姆.博纳斯-李开发了世界上第一个web服务器和web客户机.这个浏览器程序是一个简单的电话号码查询软件.最初的web服务器程序就是一个利用浏览器和web服 ...

  4. SQLSERVER聚集索引与非聚集索引的再次研究(上)

    SQLSERVER聚集索引与非聚集索引的再次研究(上) 上篇主要说聚集索引 下篇的地址:SQLSERVER聚集索引与非聚集索引的再次研究(下) 由于本人还是SQLSERVER菜鸟一枚,加上一些实验的逻 ...

  5. 深入研究Visual studio 2017 RC新特性

    在[Xamarin+Prism开发详解三:Visual studio 2017 RC初体验]中分享了Visual studio 2017RC的大致情况,同时也发现大家对新的Visual Studio很 ...

  6. 【初码干货】使用阿里云对Web开发中的资源文件进行CDN加速的深入研究和实践

    提示:阅读本文需提前了解的相关知识 1.阿里云(https://www.aliyun.com) 2.阿里云CDN(https://www.aliyun.com/product/cdn) 3.阿里云OS ...

  7. 对一致性Hash算法,Java代码实现的深入研究

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

  8. SQLSERVER聚集索引与非聚集索引的再次研究(下)

    SQLSERVER聚集索引与非聚集索引的再次研究(下) 上篇主要说了聚集索引和简单介绍了一下非聚集索引,相信大家一定对聚集索引和非聚集索引开始有一点了解了. 这篇文章只是作为参考,里面的观点不一定正确 ...

  9. 开源Word读写组件DocX 的深入研究和问题总结

    一. 前言 前两天看到了asxinyu大神的[原创]开源Word读写组件DocX介绍与入门,正好我也有类似的自动生成word文档得需求,于是便仔细的研究了这个DocX. 我也把它融入到我的项目当中并进 ...

随机推荐

  1. iOS开发中的Html解析方法

    iOS开发中的Html解析方法 本文作者为大家介绍了在iOS开发中的Html解析方法,并同时提供了Demo代码的下载链接,Demo 解析了某个网站(具体可在代码中查看)的html网页,提取了图片以及标 ...

  2. dos下修复硬盘损坏的文件

    点击开始-->运行-->输入cmd,出现DOS状态对话框.在光标处输入有损坏文件的磁盘盘符后回车(如文件夹在D盘就输入D:然后回车),再输入“CHKDSK”,回车即可看到相关检测信息.“C ...

  3. [SQL注入2]FROM SQL INJECTION TO SHELL: POSTGRESQL EDITION

    FROM SQL INJECTION TO SHELL: POSTGRESQL EDITION 这里先介绍一下POSTGRESQL.这是一款数据库管理系统,与oracle是同类型软件.08年左右的市场 ...

  4. 特征提取(Detect)、特征描述(Descriptor)、特征匹配(Match)的通俗解释

    特征匹配(Feature Match)是计算机视觉中很多应用的基础,比如说图像配准,摄像机跟踪,三维重建,物体识别,人脸识别,所以花一些时间去深入理解这个概念是不为过的.本文希望通过一种通俗易懂的方式 ...

  5. 模仿TMALL搜索,下拉提示 优化 用户keypress停顿200毫秒间隔时,在执行异步取数据操作 通过underscore的函数debounce来实现

  6. 【开源】Hawk-数据抓取工具:简明教程

    1.软件介绍 HAWK是一种数据采集和清洗工具,依据GPL协议开源,能够灵活,有效地采集来自网页,数据库,文件, 并通过可视化地拖拽, 快速地进行生成,过滤,转换等操作.其功能最适合的领域,是爬虫和数 ...

  7. 自定义xcode文件模板

    下面两个路径都可以用于放模板文件 1. /Applications/Xcode.app/Contents/Developer/Library/Xcode/Templates/File Template ...

  8. 合天网安实验室学习笔记----Linux基础

    一.Linux的发展 linux kernel的版本是:2.6.32-279.el6.x86_64,此格式为:主版本.次版本.释出版本-修改版本 次版本为奇数:测试版: 次版本为偶数:稳定版: Lin ...

  9. [置顶] 顿悟JAVA,自己实现Object的Clone的约束关系(上)

    因protected 的理解,顿悟一些JAVA的原理,模拟了Object类的子类为什么在调用clone方法前实现Cloneable接口. 这里不解释 ,上代码先. 运行效果 文件结构 调用类 pack ...

  10. eclipse 添加resources 目录

    java项目需要一些配置,配置放置目录如:/src/main/resources; 如果没有这个文件夹,需要右键项目>new>source folder > Folder name ...