应用只能间接的和设备上的其他应用进行通信。你可以使用AirDrop来与其他应用共享文件和数据。你也可以定义一个自定义URL方案,以便应用能使用URL向其他应用发送信息。
注意:你还可以使用UIDocumentInteractionController对象或文档拾取器来在应用间发送文件。关于添加对文件交互控制器的支持的信息,参见Document Interaction Programming Topics for iOS。关于使用文档拾取器打开文件的信息,参见Document Picker Programming Guide。
支持AirDrop
AirDrop让你可以和附近的设备共享照片、文档、URLs、以及其他类型的数据。AirDrop利用点对点网络来查找附近的设备并与它们连接。
发送文件和数据到其他应用
为了使用AirDrop发送文件和数据,使用UIActivityViewController对象从使用中的用户界面显示一个活动表。当创建这个视图控制器的时候,指定你想要共享的数据对象。这个视图控制器仅显示支持指定数据的活动。对于AirDrop,你可以指定图片、字符串、URLs、以及集中其他类型的数据。你还可以传递采用UIActivityItemSource协议的自定义对象。
为了显示活动视图控制器,你可以使用类似代码清单6-1的代码来实现。这个活动视图控制器自动使用特定对象的类型来决定什么活动显示在活动表。你不必明确指定AirDrop的活动。但是,你可以使用视图控制器的excludedActivityTypes属性来防止显示特定类型表单。当在iPad上显示一个活动视图控制器,你必须使用popover。
代码清单6-1 在iPhone上显示一个活动表单
- (void)displayActivityControllerWithDataObject:(id)obj {
UIActivityViewController* vc = [[UIActivityViewController alloc]
initWithActivityItems:@[obj] applicationActivities:nil];
[self presentViewController:vc animated:YES completion:nil];
}
更多关于使用活动视图控制器的信息,参见UIActivityViewController Class Reference。有关活动以及它所支持的数据类型的完整列表,参见UIActivity Class Reference。
接收发送到应用的文件和数据
想要使用AirDrop接收发送到应用的文件,需要做如下操作:
- 在Xcode中,声明对应用能够打开的文档类型支的持。
- 在应用的委托中,实现application:openURL:sourceApplication:annotation:方法,使用这个方法来接收被其他应用发送来的数据。
Xcode项目的Info选项卡包含一个Document Types部分,它用于指定应用支持的文档类型。至少,你必须指定文档类型的名称,以及一个或多个表示数据类型的UTI。例如,想要声明支持PNG文件,你将把public.png设置为UTI字符串。iOS使用特定的UTI来确定应用是否有资格打开给定的文档。
在把符合条件的文档转移到应用的容器之后,iOS启动应用(如有必要)并调用应用委托的application:openURL:sourceApplication:annotation:方法。如果应用在前台,你将使用这个方法来打开这个文件,并显示给用户。如果应用在后台,你只需要确定该文件在那里,以便你以后打开它。因为文件通过AirDrop传输是使用数据保护加密的,所以除非设备解锁否则你无法打开文件。
应用可以读取和删除它接收到的文件,但是它不可以对文件进行修改。如果你计划修改文件,你必须先把它从当前位置移出去。建议删除后续文件的原始版本
使用URL方案(Schema)实现应用间通信
URL方案让你可以通过你定义的协议来实现应用间的通信。想要与实现这个方案的应用进行通信,你必须常见恰当格式的URL并请求系统打开它。为了实现支持自定义方案,你必须声明支持这个方案,并处理使用该方案传入的URL
注意:苹果为 http, mailto, tel, 以及 sms 等URL方案提供内建支持。它还支持针对Maps、YouTube、以及iPod应用的基于http的URL。这些方案的处理器时固定的不能修改。如果你的URL类型包含与苹果定义的相同的方案,苹果提供的应用会代替你的应用启动。关于苹果支持的方案的信息,参见Apple URL Scheme Reference。
发送URL到其他应用
当你向发送数据到一个实现了自定义URL方案的应用,创建一个合适格式的URL,并调用该应用对象的openURL:方法。openURL:方法使用注册的方案启动该应用,并把你的URL传递给它。此时,控制权传递给了新应用。
以下代码片段说明一个应用如何能够请求另一个应用的服务(这个例子中的“todolist”是假定的应用注册的自定义方案):
NSURL *myURL = [NSURL URLWithString:@"todolist://www.acme.com?Quarterly%20Report#200806231300"];
[[UIApplication sharedApplication] openURL:myURL];
如果你的应用定义了一个自定义的URL方案,它应该实现该方案的处理器,如同Implementing Custom URL Schemes中描述的那样。更多关于系统支持的URL方案的信息,参见Apple URL Scheme Reference。
实现在定义URL方案
如果你的应用接收特定格式的URL,你应该利用系统注册合适的URL方案。应用经常使用自定义的URL方案来向其他应用提供服务。例如,Maps应用支持显示特定地图位置的URL。
注册自定义URL方案
想要给应用注册一个URL类型,请在应用的Info.plist文件中包含 CFBundleURLTypes键。 CFBundleURLTypes键包含一个字典数组,每个字典都定义了一个应用支持的URL方案。表6-1描述了每个字典包含的键和值。
表6-1 CFBundleURLTypes属性的键和值
键 | 值 |
---|---|
CFBundleURLName | 包含URL抽象名字的字符串。想要确保唯一性,建议使用反向DNS风格的标识符,例如com.acme.myscheme。 你指定的字符串也用于应用的InfoPlist.strings文件中的键。这个键的值是人可读的方案名。 |
CFBundleURLSchemes | 一个包含URL方案名的字符串数组—— 例如http, mailto, tel, 和 sms. |
注意:如果多个第三方应用被注册用来处理同一个URL方案,则目前还没有确定哪个应用将被分配给该方案。
拥有自己自定义URL方案的应用,必须能够处理传入的URL。所有URLs都会在启动时或者应用在后台运行时被传递给应用委托。为了处理传入的URL,你的委托应该实现下面两个方法:
- 使用application:willFinishLaunchingWithOptions:和application:didFinishLaunchingWithOptions:方法来取回关于URL的信息,并决定是否打开它。如果两个方法都返回NO,应用的URL处理代码不会被调用。
- 使用application:openURL:sourceApplication:annotation:方法打开文件。
如果当URL请求到达时应用没有在运行,它将启动并进入前台,以便能够打开URL。application:willFinishLaunchingWithOptions: 或 application:didFinishLaunchingWithOptions:方法的实现可以从选项字典中取回URL,并确定应用是否可以它开它。如果能,返回YES,让application:openURL:sourceApplication:annotation: (或 application:handleOpenURL:)方法处理URL的打开。(如果你两个方法都实现了,那么两个都要返回YES。)图6-1显示了请求打开URL的应用的启动顺序。
图6-1 启动应用来打开一个URL
如果当URL请求到达的时候应用在后台运行或是被挂起,它会进入前台并打开URL。此后不久,系统会调用委托的application:openURL:sourceApplication:annotation方法来检查URL并打开它。图6-2战士了应用进入前台代开URL的过程。
图6-2 唤醒后台应用来打开URL
注意:支持自定义URL方案的应用在启动应用来处理URL的时候,能指定不同的启动图片来显示。更多关于如何指定这些启动图片的信息,参见Displaying a Custom Launch Image When a URL is Opened。
所有被传递到应用的URL都是以NSURL对象的形式存在的。你可以定义自己的URL格式,但是NSURL类符合 RFC 1808规范,因此支持大多数URL格式约定。具体来说,这个类包括了一系列方法,它们返回URL的各个部分,包括用户、密码、查询、片段、以及参数字符串等。你自定义方案的“协议”能使用URL的这些部分来传达个钟信息。
在代码清单6-2中展示了application:openURL:sourceApplication:annotation:方法的实现,把传入URL的特定信息传递给应用。这个委托提取这些信息(在本例中是to-do任务类型以及任务到期时间),并创建应用的模型对象。这个例子嘉定用户使用的是格里高利日历。如果应用支持非格里高利日历,你需要设计你的URL方案,并准备好处理代码中的其他日历的类型。
代码清单6-2 基于自定义方案处理URL请求
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
if ([[url scheme] isEqualToString:@"todolist"]) {
ToDoItem *item = [[ToDoItem alloc] init];
NSString *taskName = [url query];
if (!taskName || ![self isValidTaskString:taskName]) { // must have a task name
return NO;
}
taskName = [taskName stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
item.toDoTask = taskName;
NSString *dateString = [url fragment];
if (!dateString || [dateString isEqualToString:@"today"]) {
item.dateDue = [NSDate date];
} else {
if (![self isValidDateString:dateString]) {
return NO;
}
// format: yyyymmddhhmm (24-hour clock)
NSString *curStr = [dateString substringWithRange:NSMakeRange(0, 4)];
NSInteger yeardigit = [curStr integerValue];
curStr = [dateString substringWithRange:NSMakeRange(4, 2)];
NSInteger monthdigit = [curStr integerValue];
curStr = [dateString substringWithRange:NSMakeRange(6, 2)];
NSInteger daydigit = [curStr integerValue];
curStr = [dateString substringWithRange:NSMakeRange(8, 2)];
NSInteger hourdigit = [curStr integerValue];
curStr = [dateString substringWithRange:NSMakeRange(10, 2)];
NSInteger minutedigit = [curStr integerValue];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setYear:yeardigit];
[dateComps setMonth:monthdigit];
[dateComps setDay:daydigit];
[dateComps setHour:hourdigit];
[dateComps setMinute:minutedigit];
NSCalendar *calendar = [s[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
if (!itemDate) {
return NO;
}
item.dateDue = itemDate;
}
[(NSMutableArray *)self.list addObject:item];
return YES;
}
return NO;
}
一定要验证从URL传入到应用的输入;查看 Secure Coding Guide中的Validating Input and Interprocess Communication ,来查找如何避免与URL处理相关的问题。想要学习关于苹果定义的URL方案,参见Apple URL Scheme Reference。
当URL被打开的时候显示自定义启动图片
应用支持自定义URL方案能给每个方案提供各自的自定义启动图片。当系统启动应用来处理URL的时候,并灭有相关的快照可用,它显示的是你指定的启动图片。想要指定启动图片,提供用下面的命名约定来命名的PNG格式的图片。
在这个命名约定中,basename表示基础图像名,这个图像名是在Info.plist文件中的由UILaunchImageFile键指定的。如果你不指定一个自定义的基础名字,系统会使用字符串Default。<url_scheme>部分是你的URL方案名。要想为myapp的URL方案指定一个通用的启动图片,你应该在应用程序束当中包含一个名字为Default-myapp@2x.png的图片文件。(@2x修饰符表示该图像用于Retina显示屏。如果你的应用也支持标准分辨率的显示器,你应该还要提供Default-myapp.png图像。)
关于你能包含在启动图片名字中的其他修饰符的信息,参见Information Property List Key Reference中UILaunchImageFile键的描述。