如何通过 Siri 播放视频?且看优酷技术接入实践

作者 | 阿里文娱高级无线开发工程师 子荀

责编 | 屠敏

随着 iOS 13 的正式发布,SiriKit 开始支持音视频内容播放。例如,用户说“Hey Siri,使用优酷播放《乡村爱情12》”,优酷会自动打开并播放《乡村爱情12》。这是一次新功能的探索和尝试,优酷主客开始相应的技术预研。

这篇文章是对优酷接入 SiriKit 的总结,介绍了整个项目的实施流程和经验教训。随着 iOS 13 的占比越来越高,相信 Siri 的相关功能也会被音视频类的 App 接入。希望我们的心得分享能帮助到大家。

 

SiriKit 概述


SiriKit 将用户对 Siri 的请求分发到对应的 App 中。SiriKit 包含了 Intents和 IntentsUI 框架。它们都是应用程序的拓展,可以拓展 App 的自定义功能和内容。

  • Intents:用户可以发出的请求类型,它被转换为应用程序的操作。类型包含INPlayMediaIntent、INSearchForMessagesIntent、INStartWorkoutIntent 等。

  • IntentsUI:在 Siri 中显示自定义的内容,这个拓展是可选的。

了解完 Intents 和 Intents UI 后,还需要了解 Domains (域)。

  • Domains:将 Intent 分组,只有用户的请求在特定的域中才可以被支持,包含 Messaging、Workouts、Media等。优酷使用的是 Media 域。

注意:SiriKit 会忽略在 MacOS 上运行的 iPad App。

优酷接入 SiriKit的流程

1. 在 Sign & Capabilities 中添加 Siri 权限。

2. 创建 App Extension。因为我们要通过 Siri 直接唤醒优酷,所以创建 Intents Extension 即可,无需创建 Intents UI Extension。

3. 在创建完 App Extension 之后,需要对它进行一些设置:

  • Bundle Identifier:Xcode 自动生成,无需改动;

  • Target:Target 版本设置。笔者的 Xcode 版本为11.2.1 创建的App Extension Target 默认版本为13.2,但是优酷需要从 13.0 开始支持。这个地方一开始没有注意到,导致在 iOS 13.2 以下的系统中无法通过 Siri 唤起优酷;

  • Supported Intents:在 Class Name 中添加类 INPlayMediaIntent 之后会自动出现 Media Categories 选项,该选项包含了 Music、Podcasts、Audiobooks、Radio、General。因为优酷为视频类 App,根据苹果官方的建议选择的类型为 General,即通用类型;

4. 创建完 Siri Extension 之后,会在项目工程中自动生成一个 Siri 分组,默认文件为 IntentHandler.h 和IntentHandler.m。分组为创建的 App Extension 名称。

5. 在IntentHandler.m 处理相关逻辑。这里直接贴上主要代码并对代码做些讲解:

- (void)resolveMediaItemsForPlayMedia:(INPlayMediaIntent *)intent withCompletion:(void (^)(NSArray<INPlayMediaMediaItemResolutionResult *> *resolutionResults))completion
{
    // 描述媒体内容
    INMediaItem *item = [[INMediaItem alloc] initWithIdentifier:@"SiriItem" title:intent.mediaSearch.mediaName type:INMediaItemTypeMovie artwork:nil];
    // 媒体项目类型的解析结果
    INMediaItemResolutionResult *sr = [INMediaItemResolutionResult successWithResolvedMediaItem:item];
    NSMutableArray *mutableArray = [NSMutableArray array];
    INPlayMediaMediaItemResolutionResult *irs = [[INPlayMediaMediaItemResolutionResult alloc] initWithMediaItemResolutionResult:sr];
    [mutableArray addObject:irs];
    completion(mutableArray);
}

- (void)handlePlayMedia:(nonnull INPlayMediaIntent *)intent completion:(nonnull void (^)(INPlayMediaIntentResponse * _Nonnull))completion
{

    NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass([INPlayMediaIntent class])];
    INMediaItem *item = [intent.mediaItems firstObject];
    if (item.title.length > 0) {
        userActivity.userInfo = @{@"title" : item.title, @"source" : @"siri"};
    } else {
        userActivity.userInfo = @{@"title" : @"大明风华", @"source" : @"siri"};
    }
    // media Intent 的回应
    INPlayMediaIntentResponse * re = [[INPlayMediaIntentResponse alloc] initWithCode:INPlayMediaIntentResponseCodeContinueInApp userActivity:userActivity];
    completion(re);
}

从函数resolveMediaItemsForPlayMedia:withCompletion:中可以获得需要需要播放的媒体项目。例如:用户说“使用优酷播放大明风华”,就可以从intent.mediaSearch.mediaName 拿到“大明风华”这四个文字。拿到文字后需要创建一个INMediaItem 类型的对象,该对象描述了对应的媒体内容。接下来通过INMediaItem类型的对象创建 INMediaItemResolutionResult 类型的对象,该对象代表着媒体项目类型的解析结果。

执行完函数resolveMediaItemsForPlayMedia:withCompletion:会执行函数 handlePlayMedia:completion:,该函数的作用是处理媒体请求。因为 Intents 应用程序的生命周期非常短,所以 INPlayMediaIntent 告诉主程序开始媒体播放。这里的媒体播放分为两种:

  • Audio:对于音频内容使用INPlayMediaIntentResponseCodeHandleInApp 进行响应。它会告诉系统在后台启动主程序,在 UIApplicationDelegate 对象上调用方法 application:handleIntent:completionHandler:。应用程序应使用此应用程序委托方法开始音频播放;

  • Video: 对于视频内容使用 INPlayMediaIntentResponseCodeContinueInApp进行响应。它会告诉系统系统在前台启动主程序,在 UIApplicationDelegate 对象上调用方法 application:continueUserActivity:restorationHandler:。应用程序应使用此应用程序委托方法开始视频播放。

在函数handlePlayMedia:completion:里面创建 INPlayMediaIntentResponse 类型对象,它是对 mediaIntent的回应,注意创建该对象的时候需要传入正确的INPlayMediaIntentResponseCode。

至此 Siri Extension 数据的获取已经完成,接下来的任务是将 Siri 获取到的数据转换为对应的媒体资源。


优酷对 SiriKit 传递的信息处理


从流程图中可知对于优酷这种巨型 App 来说 App 内部的信息处理和传递,处理链路非常长,过程比较复杂复杂。

处理流程涉及到了壳程序、一个公共 Bundle、播放页Bundle。

为什么呢?因为优酷业务非常多,代码量巨大,所以将不同的业务拆分成了不同的 Bundle,每条业务线维护自己的 Bundle,每次集成发版本,业务线构建自己的 Bundle,最后通过壳工程将所有业务线的 Framework 集成到一起构建成完整的优酷 App。

Siri Extension 是添加在壳工程里面,而 Siri 的回调在公共 Bundle 里面,搜索、跳转播放的逻辑在播放页 Bundle 里面。

由于壳工程里面主要就是 Siri Extension 的添加,所以这里主要说下公共 Bundle 和播放页 Bundle 这两个 Bundle 的流程。

  • 公共 Bundle 处理:这个 Bundle 非常重要,它链接了壳工程和播放页Bundle。这里主要涉及到两个问题:一是开屏广告的处理。二是不要将过于复杂的业务放在其中;其次为降低跨团队的沟通成本,只在 Bundle 留一个入口,将所有的业务逻辑放到播放页的 Bundle 中去处理。

  • 针对第一点的处理:当 Siri 唤起主包时,有可能是存在广告的,此时不能立即跳转到播放页进行播放,需要等广告结束之后再跳转。这与唤端的逻辑是类似的。

  • 针对第二点处理:通过一个单例类,创建这个单例类的时候将所需要的数据传递进去。并且公共 Bundle 也没有直接依赖播放页的 Bundle,而是通过 NSClassFromString + performSelector 的方式进行调用。

下面是简单的代码示例:

-(BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
{
    // 判断 NSUserActivity 的类型,确认是 Siri Extension 传过来的
    if ([userActivity.activityType isEqualToString:@"INPlayMediaIntent"]) {
        Class siriManagerClass = NSClassFromString(@"YKSiriManager");
        SEL selctor = NSSelectorFromString(@"creatInstanceWithUserActivity:");
        if (siriManagerClass && [siriManagerClass respondsToSelector:selctor]) {
            [siriManagerClass performSelector:selctor withObject:userActivity];
        }
        return YES;
    }
}
  • 播放页 Bundle 处理:这个 bundle 主要是调用搜索 SDK 将剧集名称转化成对的播放视频链接,最后跳转到播放页进行视频播放,主要是搜索参数的拼接和跳转逻辑。

SiriKit 接入后的界面展示:

总结:接入 SiriKit 所踩的坑

目前,优酷 App 已经接入 SiriKit ,已在 App Store 上架。如果你的 App 也希望接入,以下这些防“坑”指南希望能帮到你。

  • 确保 Siri 的 bundle ID 正确;

  • 创建 Siri Extension 注意 target 所支持的版本号,默认是当前 Xcode 所支持的最高版本号;

  • 提交审核时候注意 Siri Extension 的 Support Intents 的class Name 里面只包含 Intent 的类型,不然会报以下错误:

  • 因为涉及到证书和 Profile 的变化一定要提前修改好相关配置。并提示各个业务线进行行相关修改和测试;

  • 有些文字 Siri 无法识别,例如:用优酷播放催眠,在函数handlePlayMedia:completion: 中拿到的 item.title 为 nil 此时需要对这个异常情况进行处理。比如我们可以通过配置平台下发一个剧集名称来处理这种异常。

推荐阅读 

GitHub 移动端正式发布!

GitHub 标星 11000+,阿里开源的微服务组件如何连续 10 年扛住双十一大促?

检测、量化、追踪新冠病毒,基于深度学习的自动CT图像分析有多靠谱?

深度学习“三巨头”、图灵奖得主 Yann LeCun:我没有天赋,所以才追随聪明人

Docker 开发环境的滑坡

来,让我们逐一澄清以太坊 2.0 五大误解

你点的每一个在看,我认真当成了喜欢

发布了1855 篇原创文章 · 获赞 4万+ · 访问量 1674万+

猜你喜欢

转载自blog.csdn.net/csdnnews/article/details/104981110
今日推荐