【问题标题】:Custom Intent Handler Not Called - iOS claims IntentHandlerMethodForIntent not Implemented未调用自定义 Intent 处理程序 - iOS 声明 IntentHandlerMethodForIntent 未实现
【发布时间】:2022-01-07 14:58:56
【问题描述】:

自定义 Intent 的 Objective-C 实现中的 IntentHandler 无法接收来自语音激活快捷方式的呼叫。当使用 Siri 调用捐赠的交互时,我观察到我在控制台应用程序中收到以下错误,声称意图的意图处理程序方法未实现:

-[INIntentDeliverer _invokeIntentHandlerMethodForIntent:intentHandler:parameterNamed:keyForSelectors:executionHandler:unimplementedHandler:] _invokeIntentHandlerMethodForIntent sirikit.intent.voice_commands.RunVoiceCommandIntent


-[WFRVCIntentHandler stateMachineForIntent:] Created state machine <WFRVCStateMachine: 0x102e23970 state=WaitingForServer phase=Unknown> for intent with identifier 8A87FC68-329D-49FF-B534-B0A5821854CA


-[INIntentDeliverer _invokeIntentHandlerMethodForIntent:intentHandler:parameterNamed:keyForSelectors:executionHandler:unimplementedHandler:] _invokeIntentHandlerMethodForIntent sirikit.intent.voice_commands.RunVoiceCommandIntent

此错误与尝试使用语音命令触发自定义意图导致 iOS 调用我的 appDelegate,特别是 application:continueUserActivity:restorationHandler: 的事实一致。根据文档,只有在未处理意图且必须由主应用程序处理时才应调用 restoreHandler。

由于 Objective-C 实现的文档很少,我无法弄清楚我缺少什么。我试图将 Siri Shortcuts 的示例 SoupChef 应用程序实现映射到我的实现。我无法弄清楚我哪里出错了。这是我的实现(对不起所有细节,但我希望你能看到一些错误):

首先,我实现了两个额外的目标;一个共享框架和一个意图扩展。我还实现了一个意图定义文件。

这是我的目标的图像:

W_P_r是主app,W_P_rKit是共享框架,PartsListManagerIntents是Intents Extension。

接下来,这是我的 Intents 定义文件和它所属的目标成员:

我还为 main 目标和 PartsListIntentManager 目标添加了一个应用组到 add 的功能部分。我在主要目标中添加了 Siri 功能。

所有这些都会自动创建一些代码,包括默认的 IntentHandler.m 和 PartsListManagerIntents 目标中的 info.plist。我已将 info.plist 更新如下:

这是自动生成的 IntentHandler(我已对其进行修改以记录活动并调用驻留在 W_P_rKit 共享框架中的特定意图处理程序:

#import "IntentHandler.h"
#import <Intents/Intents.h>
#import <W_P_rKit/W_P_rKit.h>
#import "CreatePartsListIntentHandler.h"
#import "P__tHandler.h"
#import <os/log.h>

@interface IntentHandler () /* <CreatePartsListIntentHandling, P__tHandling> */

@end


@implementation IntentHandler

- (id)handlerForIntent:(INIntent *)intent {

    os_log_with_type(OS_LOG_DEFAULT, OS_LOG_TYPE_DEBUG, "handlerForIntent: Reached IntentHandler.");

    if ([intent.identifier isEqualToString:@"P__rIntent"]) {
        NSLog(@"P__rIntent");
        return [[P__rIntentHandler alloc] init];
    }
    else if ([intent.identifier isEqualToString:@"CreatePartsListIntent"]) {
        NSLog(@"CreatePartsListIntent");
        os_log_with_type(OS_LOG_DEFAULT, OS_LOG_TYPE_DEBUG, "handlerForIntent: IntentHandler Received CreatePartsListIntent.");
        return [[CreatePartsListIntentHandler alloc] init];
    
    }
    return self;
}

请注意,CreatePartsListIntentHandler 是一个实现 CreatePartsListIntentHandling 协议(IntentHandler 的解析、确认和处理方法)的类。

下面是应该触发 iOS 调用 IntentHandler 的相关实现:

在我的应用程序中,当用户填写新项目的名称时,我拨打电话以捐赠互动,如下所示:

CreatePartsListIntent *data = [[CreatePartsListIntent alloc] init];
data.projectName = [projectPlistName copy];
data.quantity = [NSNumber numberWithInteger : currentProjectQuantity];
[[W_P_rDonationManager sharedInstance] donateCreatePartsListIntent : data];

对 donateCreatePartsListIntent 的调用执行以下操作:

data.suggestedInvocationPhrase = @"Create Parts List";
INInteraction* interaction = [[INInteraction alloc] initWithIntent:data response:nil];
[interaction donateInteractionWithCompletion:^(NSError * _Nullable error) { ... }

一旦用户创建了空的部件列表(强制进行上述交互捐赠),视图控制器 将显示一个“添加 Siri 快捷方式”按钮。自动点击按钮 调用如下方法创建快捷方式:

-(void) addCreatePartsListShortcutWasTapped {
    CreatePartsListIntent *intentWithData = [[WoodPickerDonationManager sharedInstance] prepareCreatePartsListIntent :
                                         @"" withNumberOfAssemblies : 1];
    INShortcut *shortcut = [[INShortcut alloc] initWithIntent:intentWithData];
    INUIAddVoiceShortcutViewController *addSiri = [[INUIAddVoiceShortcutViewController alloc] initWithShortcut:shortcut];
    addSiri.delegate = self;    
    [self presentViewController:addSiri animated:YES completion: nil];
}

对 prepareCreatePartsListIntent 的调用执行以下操作:

-(CreatePartsListIntent *) prepareCreatePartsListIntent : (NSString *) partsListName withNumberOfAssemblies : (NSInteger) quantity {

    CreatePartsListIntent *intentWithData = [[CreatePartsListIntent alloc] init];

    intentWithData.projectName = partsListName;
    intentWithData.quantity = [NSNumber numberWithInteger: quantity];
    intentWithData.suggestedInvocationPhrase = @"Create Parts List";

    return intentWithData;
}

这确实会创建一个快捷方式应用程序中可见的快捷方式。单击快捷方式或说出调用短语将带您 直接到应用委托的 application:userActivity:restorationHandler。但它不调用 IntentHandler。

为什么我的 IntentHandler 没有被调用?为什么iOS会发送错误消息_invokeIntentHandlerMethodForIntent:intentHandler:parameterNamed:keyForSelectors:executionHandler:unimplementedHandler:?

实际上我已经为此苦苦挣扎了好几个星期。任何帮助或提示都会很有帮助。

【问题讨论】:

  • 我在构建实现​​时记录了很多内容。也许这会有所帮助? pqvst.com/2018/09/21/…
  • @pqvst 是的,这是一篇很好的文章,这就是我联系你的原因。我想知道你在那篇文章中所说的一件事。您能否详细说明您在编写时遇到的问题: 3)将 Intents 定义文件添加到您的 Intents 扩展目标。注意:我尝试将意图定义文件移动到主应用程序和意图扩展都可以访问的共享 Cocoa Touch 框架,但这似乎不起作用。因此,我建议将意图定义文件保留在主应用程序目标中,并将意图目标添加到目标成员资格设置中。
  • Tbh,我不记得了,因为它已经有几年了,但我想如果 Intents 定义文件不在主应用程序中,我会遇到编译错误。总的来说,我记得有很多问题。一般来说,我发现删除所有保存的快捷方式、重新安装应用程序以及从头开始在很多情况下都有帮助。
  • 当您接到application:continueUserActivity:restorationHandler: 的电话时,activity.interaction.intent 是否已填充?
  • @davidgyoung 在 Xcode 控制台中,interaction.intent 参数自动完成(即显示该参数存在。但是当我尝试打印此内容时,出现以下错误:错误::1:14: 在'NSUserActivity *' userActivity.interaction.intent 类型的对象上找不到属性'interaction'。你认为为什么会这样?如果我打印 userActivity.activityType,它会打印我的意图“CreatePartsListIntent”,所以它知道我的意图。

标签: objective-c sirishortcuts intents-extension inshortcut


【解决方案1】:

检查所有目标(Siri Intent 目标、IntentUI 目标等)的 XCode 构建设置是否都在部署信息下指定了相同的最低 iOS 版本,如下所示:

如果 Intent 目标指定的最低 iOS 版本高于您用于测试的设备,则 IntentHandler 将永远不会被调用,而是会调用主目标中的 AppDelegate 方法。就我而言,一旦我将部署信息更改为较低的 iOS 版本,IntentHandler 立即开始被调用,并且不再调用 AppDelegate 方法。

感谢 Ondřej Korol 的这个想法:https://stackoverflow.com/a/59500997/1461050

在为旧 iOS 版本修改旧项目时尤其可能发生此问题,因为当您在 XCode 中创建新目标时,即使它与主目标的 DeploymentInfo 不匹配,它也会将 DeploymentInfo 默认为 XCode 的默认值。不幸的是,这是导致 SiriKit 开发非常脆弱的众多问题之一。一件小事错了,整个事情就默默地失败了!

【讨论】:

  • 我曾希望这可能解决了我的问题。虽然我的目标都具有相同的最低 iOS 版本,但我的 PROJECT iOS 部署目标却不同。所以我将所有内容都更新到了 14.5 版。不幸的是,这并没有解决问题。感谢您尝试帮助我。
  • 我注意到的一件事是,当我尝试在自动生成的 IntentHandler 中放置断点时,断点会出现轮廓,如果将鼠标悬停在它上面,它会说:Xcode 不会作为这个断点暂停,因为尚未解决。解决它需要: - 编译器为列断点的表达式生成一个位置。 - 没有这样的位置是有效的。 - 编译断点处的行。 - 编译器生成未剥离的调试信息(检查构建设置)。 - 加载断点的库。这是个问题吗?
  • 要正确解析 IntentHandlers 中的断点,您无法从 Xcode 运行您的主目标,您必须运行您的 App Intent Extension 目标,此时 Xcode 会提示您输入配套应用运行它,然后选择您的主应用程序。见这里:stackoverflow.com/questions/38093871/…
【解决方案2】:

我怀疑您的 .intentdefinition 文件的 Target Membership 选择过于严格。我相信您应该将所有三个目标都设置为“Public Intent Classes”(屏幕截图显示其中两个目标为“No Generated Classes”。

我不确定这是问题的原因,但值得尝试查看问题或控制台日志消息是否消失。

我会注意到,我在混合 Objective C / Swift 项目时遇到了与您相同的症状。 AppDelegate 在 Objective C 中,而大多数其他代码在 Swift 中。我还看到 AppDelegate 方法被调用,但意图处理程序没有。尽管在我的情况下,我将所有目标都设置为“公共意图类”,并且控制台没有显示您描述的相同日志行。我怀疑如果您进行上述更改,它可能会使这些日志行消失而不解决核心问题——如果是这样,这表明这些日志行是一个红鲱鱼。

关于我的案例的一些其他说明可能与您的案例相似或不同:(1) 我正在使用带有“旧版构建系统”的旧 Xcode 项目,我最近尝试在其中添加 Siri 支持。 (2) 我正在使用 Xcode 13.1 构建,但在较旧的 iOS 12.4.6 设备上进行测试,因为这是我们用户的最低操作系统版本。我还没有尝试过更新的 iOS 版本。

编辑:请参阅我的其他答案以解决我的问题。我在旧版 iOS 12.4.6 设备上使用 Xcode 13.1 上的旧版构建系统进行了这项工作。

【讨论】:

    猜你喜欢
    • 2019-03-05
    • 2018-09-16
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    • 2013-12-26
    • 2019-10-03
    • 2020-03-11
    • 2017-10-19
    相关资源
    最近更新 更多