Continuity Features - Handoff
Create by Joker 2020/05/27
连续互通,是 Apple 设备生态系统中的一个重要特性。
借助“连续互通”,在设备之间实现无缝衔接。无需拿起 iPhone,便可拨打和接听电话。使用 iPad 扩展 Mac 的工作空间。佩戴 Apple Watch 时,自动解锁您的 Mac。另外,还可以将 iPhone 或 iPad 中的图像、视频和文本拷贝并粘贴到附近的 Mac,反之亦然。
Handoff(官方翻译为接力)就是其中一种。
借助接力,您可以在一台设备上开始工作,再切换到附近的另一台设备上继续工作,非常的方便。
怎么用?
不是很重要的内容,可以选择性跳过这一部分。
设置接力的基本要求
接力兼容任何满足“连续互通”系统要求的 Mac、iPhone、iPad、iPod touch 或 Apple Watch。当设备位于彼此附近并且进行了如下设置时,接力便可有效工作:
- 每台设备均已使用同一 Apple ID 登录 iCloud。
- 要查看 Apple Watch 上所用的 Apple ID,可在 iPhone 上打开 Apple Watch 应用,再前往“通用”>“Apple ID”。
- 所有设备均已开启蓝牙。
- 所有设备均已开启 Wi-Fi。
- 所有设备均已打开接力。
打开接力的方法
- 在 Mac 上:选取苹果 () 菜单 >“系统偏好设置”,然后点按“通用”。选择“允许在这台 Mac 和 iCloud 设备之间使用‘接力’”。
- 在 iPhone、iPad 或 iPod touch 上:前往“设置”>“通用”>“接力”,然后打开“接力”。
- 在 Apple Watch 上:在 iPhone 上的 Apple Watch 应用中,轻点“通用”,然后打开“启用接力”。
- Apple Watch 支持从 Watch 到 iPhone 进行接力,或者从 Watch 到运行 OS X Yosemite 或更高版本的 Mac 进行接力。
- 在您打开接力后,“通用剪贴板”也将打开。
使用接力的方法
打开一个支持接力的应用。
支持接力的应用包括“邮件”、“地图”、Safari 浏览器、“提醒事项”、“日历”、“通讯录”、Pages 文稿、Numbers 表格、Keynote 讲演,以及许多第三方应用。
使用该应用开始一项任务,例如撰写电子邮件或文稿。
然后在另一台设备上继续完成任务:
如果要切换到 Mac,请点按“程序坞”上该应用的图标
如果您要切换到 iPhone、iPad 或 iPod touch,请像切换应用时那样打开应用切换器,然后轻点屏幕底部的应用横幅。
编码
配置 activity
Handoff 的逻辑是基于用户 activity 这个概念的,负责处理 activity 的类叫做 NSUserActivity。每个 activity 都需要一个用来在不同设备和应用之间唯一标识一个特定 activity 的 activity type。一般建议采用反转域名风格的简单字符串。
所以,编写支持 Handoff 应用是,首先就需要考虑定义你的 activity type,通过 activity type 应该即可判断那种 activity 可以被共享以及在其他设备上接着进行。
为了让应用知道所有可以被接力的 activity type,Info.plist文件中必须加入一个包含所有 activity type 的列表。
在info.plist中添加一个新的项:键名为NSUserActivityTypes,数据类型为Array,然后填入你所支持的 activity type。如下:
提交 activity
使应用程序中的用户activity可以被接力。
创建 activity
在应用中实现 handoff 功能时,首先需要创建一个新的用户 activity。即创建一个NSUserActivity 对象,然后对这个对象进行配置。
需要提及的是,iOS 中 handoff功能是基于 UIKit 框架的。从 8.0 版本开始,UIResponder 类新增了一个叫做 userActivity 的属性用来封装为响应对象(responder,如视图控制器)定义的用户 activity,以及一些其他的方法。
故而,即使是不声明相关属性,也可以访问self.userActivity,另外也不要声明一个叫做userActivity的同名属性。
// create user activity
self.userActivity = [[NSUserActivity alloc] initWithActivityType:@"com.apple.handoffdemoe.openweb"];
[self.userActivity becomeCurrent];
通过上面代码,可以看到,初始化的时候,我们指明了对应的 activity type。确保 activity 初始化时使用的字符串和 plist 文件中添加的字符串匹配。
最后,也是必须的一步,- becomeCurrent;将这个 activity 可以被接力。
更新 activity
在上一步中,我们只是简单地创建了一个 activity,但是并没有数据传递。这样子并没有什么实际意义。
self.userActivity.webpageURL = [NSURL URLWithString:@"https://www.apple.com"];
// [self.userActivity addUserInfoEntriesFromDictionary:@{@"title":@"apple web", @"from":@"handoffdemo"}];
[self updateUserActivityState:self.userActivity];
如上图,我们对这个 activity 进行一些简单的配置。
如配置webpageURL。
webpageURL : When no suitable application is installed on a resuming device and the webpageURL is set, the user activity will instead be continued in a web browser by loading this resource.
即当接力的设备上没有安装合适的应用,并且设置了webpageURL,则该用户 activity 将在默认的浏览器中继续进行
或者配置一些自定义数据 - addUserInfoEntriesFromDictionary:
最后,通过 - updateUserActivityState:方法更新 activity。
停止 activity
在相关位置(如,视图控制器退出之前)停止 activity
[self.userActivity invalidate];
继续 activity
使应用程序可以接力来自另一个设备的用户 activity
在 appDelegate 中 实现如下方法:
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
if ([userActivity.activityType isEqualToString:@"com.apple.handoffdemoe.openweb"]) {
// write you code
NSURL *url = userActivity.webpageURL;
[WebController openWebWithURL:url];
} else if ([userActivity.activityType isEqualToString:@"com.apple.handoffdemoe.dootherthing"]) {
// write you code
}
return YES;
}
以及其他选择性的委托方法:
- (void)application:(UIApplication *)application didUpdateUserActivity:(NSUserActivity *)userActivity {
NSLog(@"activity type: %@", userActivity.activityType);
}
- (void)application:(UIApplication *)application didFailToContinueUserActivityWithType:(nonnull NSString *)userActivityType error:(nonnull NSError *)error {
NSLog(@"activity type: %@ \nerror: %@", userActivityType, error);
}