MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Objective-C中的Spotlight搜索与Siri集成

2022-09-131.4k 阅读

一、Spotlight 搜索基础

在 iOS 应用开发中,Spotlight 搜索为用户提供了一种便捷的方式,能够在设备上快速查找应用内的内容。Objective - C 作为 iOS 开发的传统语言,对 Spotlight 搜索有着良好的支持。

1.1 创建索引

为了让应用内容能够被 Spotlight 搜索到,首先需要创建索引。在 Objective - C 中,可以使用 CSSearchableIndex 类来完成这一操作。以下是创建索引的基本步骤:

  1. 导入框架:首先要导入 CoreSpotlight 框架,因为 CSSearchableIndex 类在该框架中。
#import <CoreSpotlight/CoreSpotlight.h>
  1. 获取索引实例:通过 defaultSearchableIndex 类方法获取 CSSearchableIndex 的单例实例。
CSSearchableIndex *searchableIndex = [CSSearchableIndex defaultSearchableIndex];
  1. 定义搜索项:创建 CSSearchableItemAttributeSet 对象,用于描述要索引的内容属性。例如,如果要索引一篇文章,可能会设置文章标题、摘要、作者等属性。
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeText];
attributeSet.title = @"示例文章标题";
attributeSet.contentDescription = @"这是一篇示例文章的摘要";
attributeSet.keywords = @[@"文章", @"示例"];

这里的 itemContentType 是用于指定内容类型的统一类型标识符(UTI)。常见的 UTI 如 kUTTypeText 表示文本,kUTTypeImage 表示图片等。

  1. 创建搜索项:使用 CSSearchableItem 类创建具体的搜索项,将 CSSearchableItemAttributeSet 对象传入。
CSSearchableItem *searchableItem = [[CSSearchableItem alloc] initWithUniqueIdentifier:@"article1" domainIdentifier:@"com.example.app" attributeSet:attributeSet];

uniqueIdentifier 是该项的唯一标识符,domainIdentifier 一般设置为应用的 bundle ID,用于标识应用域。

  1. 添加搜索项到索引:最后将搜索项添加到索引中。
[searchableIndex indexSearchableItems:@[searchableItem] completionHandler:^(NSError * _Nullable error) {
    if (error) {
        NSLog(@"索引添加失败: %@", error);
    } else {
        NSLog(@"索引添加成功");
    }
}];

在实际应用中,可能会有多个搜索项,只需将多个 CSSearchableItem 对象放入数组中传入 indexSearchableItems:completionHandler: 方法即可。

1.2 处理搜索结果

当用户在 Spotlight 中搜索应用相关内容并点击结果时,应用需要能够正确处理并展示对应的内容。在应用的 AppDelegate 中,可以通过实现 application:continueUserActivity:restorationHandler: 方法来处理搜索结果。

  1. 判断活动类型:首先要判断 userActivity 的类型是否为 CSSearchableItemActionType,这表示该活动是由 Spotlight 搜索结果触发的。
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
    if ([userActivity.activityType isEqualToString:CSSearchableItemActionType]) {
        // 处理搜索结果
    }
    return YES;
}
  1. 获取搜索项标识符:从 userActivity 中获取搜索项的唯一标识符。
NSString *uniqueIdentifier = userActivity.userInfo[CSSearchableItemActivityIdentifier];
  1. 根据标识符加载内容:应用根据这个唯一标识符,从数据存储中加载对应的内容,并展示给用户。例如,如果是文章,可能会跳转到文章详情页面。
// 假设这里有一个方法根据标识符加载文章
Article *article = [Article loadArticleWithUniqueIdentifier:uniqueIdentifier];
if (article) {
    ArticleViewController *articleVC = [[ArticleViewController alloc] initWithArticle:article];
    UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
    [navController pushViewController:articleVC animated:YES];
}

二、Siri 集成基础

Siri 作为 iOS 设备上的智能语音助手,为应用提供了语音交互的能力。Objective - C 开发者可以通过 SiriKit 框架来实现应用与 Siri 的集成。

2.1 创建 Intents 扩展

要让应用支持 Siri 交互,首先需要创建一个 Intents 扩展。

  1. 创建新目标:在 Xcode 中,选择项目导航器中的项目,点击“File” -> “New” -> “Target”。在弹出的窗口中,选择“Intents Extension”,然后点击“Next”。按照提示设置扩展的名称、组织标识符等信息,最后点击“Finish”。

  2. 配置 Intents:在 Intents 扩展的 IntentsDefinitionFile.intentdefinition 文件中,定义应用支持的意图(Intent)。例如,如果应用是一个待办事项应用,可以定义“添加待办事项”、“完成待办事项”等意图。

  3. 实现 Intent 处理逻辑:在 Intents 扩展的 IntentHandler.m 文件中,实现定义的意图处理逻辑。以“添加待办事项”意图为例,假设意图名为 AddTodoIntent

#import "IntentHandler.h"
#import "AddTodoIntent.h"

@interface IntentHandler () <AddTodoIntentHandling>
@end

@implementation IntentHandler

- (id <AddTodoIntentHandling>)handlerForAddTodoIntent:(AddTodoIntent *)intent {
    return self;
}

- (void)handleAddTodoIntent:(AddTodoIntent *)intent completion:(void (^)(AddTodoIntentResponse *response))completion {
    // 解析意图参数
    NSString *todoTitle = intent.todoTitle;
    // 调用应用逻辑添加待办事项
    BOOL success = [TodoManager addTodoWithTitle:todoTitle];
    if (success) {
        AddTodoIntentResponse *response = [[AddTodoIntentResponse alloc] initWithCode:AddTodoIntentResponseCodeSuccess userActivity:nil];
        response.title = @"待办事项已添加";
        completion(response);
    } else {
        AddTodoIntentResponse *response = [[AddTodoIntentResponse alloc] initWithCode:AddTodoIntentResponseCodeFailure userActivity:nil];
        response.title = @"添加待办事项失败";
        completion(response);
    }
}

@end

这里的 TodoManager 是一个假设的用于管理待办事项的类,addTodoWithTitle: 方法负责实际的添加逻辑。

2.2 配置应用以支持 Siri

在主应用中,还需要进行一些配置以支持 Siri。

  1. 添加权限:在应用的 Info.plist 文件中,添加 NSPhotoLibraryUsageDescription(如果应用需要访问相册等)、NSMicrophoneUsageDescription(如果应用需要使用麦克风)等权限描述,以确保 Siri 集成时权限合规。

  2. 关联 Intents 扩展:在主应用的 Info.plist 文件中,添加 NSExtensionAttributes 字典,并在其中设置 IntentsSupported 数组,列出应用支持的意图。例如:

<key>NSExtensionAttributes</key>
<dict>
    <key>IntentsSupported</key>
    <array>
        <string>AddTodoIntent</string>
    </array>
</dict>
  1. 测试 Siri 集成:在设备上安装应用及其 Intents 扩展后,可以通过长按 Home 键(或使用 iPhone X 及后续机型的侧边按钮)唤起 Siri,并说出与定义的意图相关的语音指令,如“在[应用名称]中添加待办事项[具体事项]”,测试应用与 Siri 的集成是否正常。

三、Objective - C 中 Spotlight 搜索与 Siri 集成的结合

将 Spotlight 搜索与 Siri 集成结合,可以为用户提供更加无缝的搜索和交互体验。

3.1 利用 Siri 触发 Spotlight 搜索相关操作

假设应用中已经通过 Spotlight 索引了一些内容,并且通过 Siri 可以触发与这些内容相关的操作。例如,用户可以通过 Siri 搜索应用内的文章,并直接跳转到文章详情页面。

  1. 修改 Intents 定义:在 Intents 扩展的 IntentsDefinitionFile.intentdefinition 文件中,定义一个新的意图,比如 SearchArticleIntent,用于搜索文章。为该意图添加参数,如文章关键词。

  2. 实现意图处理逻辑:在 IntentHandler.m 文件中实现 SearchArticleIntent 的处理逻辑。

#import "IntentHandler.h"
#import "SearchArticleIntent.h"

@interface IntentHandler () <SearchArticleIntentHandling>
@end

@implementation IntentHandler

- (id <SearchArticleIntentHandling>)handlerForSearchArticleIntent:(SearchArticleIntent *)intent {
    return self;
}

- (void)handleSearchArticleIntent:(SearchArticleIntent *)intent completion:(void (^)(SearchArticleIntentResponse *response))completion {
    NSString *keyword = intent.keyword;
    // 模拟根据关键词搜索文章的逻辑,这里假设返回一个文章标识符数组
    NSArray<NSString *> *articleIdentifiers = [ArticleSearcher searchArticlesWithKeyword:keyword];
    if (articleIdentifiers.count > 0) {
        // 这里简单取第一个文章标识符作为示例
        NSString *articleIdentifier = articleIdentifiers[0];
        CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeText];
        attributeSet.title = @"搜索到的文章标题";
        attributeSet.contentDescription = @"搜索到的文章摘要";
        CSSearchableItem *searchableItem = [[CSSearchableItem alloc] initWithUniqueIdentifier:articleIdentifier domainIdentifier:@"com.example.app" attributeSet:attributeSet];
        [CSSearchableIndex.defaultSearchableIndex indexSearchableItems:@[searchableItem] completionHandler:^(NSError * _Nullable error) {
            if (error) {
                SearchArticleIntentResponse *response = [[SearchArticleIntentResponse alloc] initWithCode:SearchArticleIntentResponseCodeFailure userActivity:nil];
                response.title = @"搜索失败";
                completion(response);
            } else {
                // 模拟跳转到文章详情的操作,这里返回成功响应
                SearchArticleIntentResponse *response = [[SearchArticleIntentResponse alloc] initWithCode:SearchArticleIntentResponseCodeSuccess userActivity:nil];
                response.title = @"搜索成功,即将跳转到文章";
                completion(response);
            }
        }];
    } else {
        SearchArticleIntentResponse *response = [[SearchArticleIntentResponse alloc] initWithCode:SearchArticleIntentResponseCodeFailure userActivity:nil];
        response.title = @"未找到相关文章";
        completion(response);
    }
}

@end

这里的 ArticleSearcher 是一个假设的用于搜索文章的类,searchArticlesWithKeyword: 方法根据关键词搜索文章并返回文章标识符数组。

  1. 在主应用中处理结果:当用户通过 Siri 触发 SearchArticleIntent 并成功搜索到文章后,在主应用的 application:continueUserActivity:restorationHandler: 方法中处理搜索结果,跳转到文章详情页面,与处理 Spotlight 搜索结果类似。
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
    if ([userActivity.activityType isEqualToString:CSSearchableItemActionType]) {
        NSString *uniqueIdentifier = userActivity.userInfo[CSSearchableItemActivityIdentifier];
        Article *article = [Article loadArticleWithUniqueIdentifier:uniqueIdentifier];
        if (article) {
            ArticleViewController *articleVC = [[ArticleViewController alloc] initWithArticle:article];
            UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
            [navController pushViewController:articleVC animated:YES];
        }
    }
    return YES;
}

3.2 使用 Spotlight 搜索引导 Siri 交互

反过来,也可以利用 Spotlight 搜索的结果来引导用户进行 Siri 交互。例如,在 Spotlight 搜索结果中显示一些提示,告知用户可以通过 Siri 执行与该结果相关的进一步操作。

  1. 自定义搜索结果展示:在创建 CSSearchableItemAttributeSet 对象时,可以添加自定义属性来显示提示信息。
CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeText];
attributeSet.title = @"示例文章标题";
attributeSet.contentDescription = @"这是一篇示例文章的摘要";
attributeSet.keywords = @[@"文章", @"示例"];
attributeSet.userInfo = @{@"siriHint": @"通过 Siri 朗读这篇文章"};
  1. 在搜索结果视图中展示提示:当应用处理 Spotlight 搜索结果并展示给用户时,从 CSSearchableItemAttributeSetuserInfo 中取出 siriHint 信息,并在界面上合适的位置展示给用户,引导用户通过 Siri 执行“朗读文章”等操作。在实际实现中,可能需要根据应用的界面布局,在搜索结果的单元格或详情页面等位置添加相应的提示标签。

四、优化与注意事项

在实现 Objective - C 中的 Spotlight 搜索与 Siri 集成时,有一些优化点和注意事项需要关注。

4.1 性能优化

  1. 索引优化:避免在主线程上进行大规模的索引操作,因为索引过程可能会比较耗时。可以使用 dispatch_async 将索引操作放到后台队列中执行。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    CSSearchableIndex *searchableIndex = [CSSearchableIndex defaultSearchableIndex];
    CSSearchableItemAttributeSet *attributeSet = [[CSSearchableItemAttributeSet alloc] initWithItemContentType:(NSString *)kUTTypeText];
    attributeSet.title = @"示例文章标题";
    attributeSet.contentDescription = @"这是一篇示例文章的摘要";
    attributeSet.keywords = @[@"文章", @"示例"];
    CSSearchableItem *searchableItem = [[CSSearchableItem alloc] initWithUniqueIdentifier:@"article1" domainIdentifier:@"com.example.app" attributeSet:attributeSet];
    [searchableIndex indexSearchableItems:@[searchableItem] completionHandler:^(NSError * _Nullable error) {
        if (error) {
            NSLog(@"索引添加失败: %@", error);
        } else {
            NSLog(@"索引添加成功");
        }
    }];
});
  1. Siri 意图处理优化:在处理 Siri 意图时,尽量减少复杂的计算和网络请求。如果需要进行网络请求,可以使用异步请求,并在请求完成后返回合适的响应给 Siri。例如,使用 NSURLSession 进行异步网络请求:
- (void)handleSomeIntent:(SomeIntent *)intent completion:(void (^)(SomeIntentResponse *response))completion {
    NSURL *url = [NSURL URLWithString:@"http://example.com/api/someapi"];
    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error) {
            SomeIntentResponse *response = [[SomeIntentResponse alloc] initWithCode:SomeIntentResponseCodeFailure userActivity:nil];
            response.title = @"请求失败";
            dispatch_async(dispatch_get_main_queue(), ^{
                completion(response);
            });
        } else {
            // 解析数据并处理
            // 返回成功响应
            SomeIntentResponse *response = [[SomeIntentResponse alloc] initWithCode:SomeIntentResponseCodeSuccess userActivity:nil];
            response.title = @"操作成功";
            dispatch_async(dispatch_get_main_queue(), ^{
                completion(response);
            });
        }
    }];
    [task resume];
}

4.2 兼容性与更新

  1. iOS 版本兼容性:确保应用支持的 iOS 版本能够正常使用 Spotlight 搜索和 Siri 集成功能。随着 iOS 版本的更新,可能会有新的特性和 API 变化,需要及时关注并适配。例如,在较新的 iOS 版本中,SiriKit 可能会有新的意图类型或增强的功能。
  2. 应用更新:当应用更新时,需要考虑对 Spotlight 搜索索引和 Siri 集成的影响。如果应用的数据结构或功能发生变化,可能需要更新索引内容和意图处理逻辑。可以在应用更新时,添加相应的迁移逻辑,如更新或重建 Spotlight 搜索索引。

4.3 用户体验优化

  1. 搜索结果相关性:确保 Spotlight 搜索结果与用户输入的关键词高度相关。这需要在创建索引时,合理设置关键词、标题和摘要等属性。同时,可以使用一些机器学习或自然语言处理技术(如果适用)来提高搜索的准确性。
  2. Siri 交互友好性:在 Siri 意图处理过程中,返回给用户的响应信息应该清晰、简洁且友好。避免使用过于技术化或难以理解的语言。例如,在处理“添加待办事项”意图时,如果添加成功,返回的响应可以是“已为您成功添加待办事项,快去看看吧!”而不是简单的“成功”。

通过以上对 Objective - C 中 Spotlight 搜索与 Siri 集成的深入探讨,开发者可以为应用添加强大的搜索和语音交互功能,提升用户体验,使应用在众多 iOS 应用中脱颖而出。在实际开发过程中,需要根据应用的具体需求和业务逻辑,灵活运用这些技术,并不断优化和完善。