如何将accessibilityIdentifier 设置为UIAlertController?

Posted

技术标签:

【中文标题】如何将accessibilityIdentifier 设置为UIAlertController?【英文标题】:How can I set accessibilityIdentifier to UIAlertController? 【发布时间】:2016-06-30 08:10:05 【问题描述】:

这就是我简单地创建UIAlertController 并将其呈现在屏幕上的方式:

private class func showAlertWithTitle(title: String, message: String) 

    let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
    //alert.accessibilityLabel = "my string here"      //doesnt work
    let action = UIAlertAction(title: "OK", style: .Default)  action in
        alert.dismissViewControllerAnimated(true, completion: nil)
    

    alert.addAction(action)
    UIStoryboard.topViewController()?.presentViewController(alert, animated: true, completion: nil)

这就是我在 UITests 下访问它的方式:

emailAlert = app.alerts["First Name"] //for title "First Name"

但我想在那里设置自定义标识符并通过firstName 访问它,如下所示:

emailAlert = app.alerts["firstName"]

有可能吗?

【问题讨论】:

【参考方案1】:

这是一个旧线程,但有人可能会使用它。

我能够像这样设置可访问性标识符:

let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.view.accessibilityIdentifier = "custom_alert"
alert.view.accessibilityValue = "\(title)-\(message)"

alert.addAction(
    UIAlertAction(
        title: "ALERT_BUTTON_OK".localized,
        style: .default,
        handler: handler
    )
)

present(alert, animated: true)

这样我可以通过可访问性标识符访问警报并在可访问性值中检查其内容。

当然它并不完美,但它确实有效——至少对于我使用 Appium 进行的测试而言。

【讨论】:

我一直在寻找一种为警报提供特定标识符的方法。这是我一直在寻找的答案。谢谢!哦,它在 Swift 4 中运行良好。 你写的是你检查它的内容,但是你如何检查按钮的文本呢?它没有可访问性 ID。【参考方案2】:

我想出的唯一方法是使用 Apple 的私有 API。您使用此超级密钥在 UIAlertAction 对象上调用 valueForKey"__representer" 以获取所谓的 _UIAlertControllerActionView

    let alertView = UIAlertController(title: "This is Alert!", message: "This is a message!", preferredStyle: .Alert)
    let okAction = UIAlertAction(title: "OK", style: .Default, handler: nil)

    alertView.addAction(okAction)

    self.presentViewController(alertView, animated: true, completion: 
        let alertButton = action.valueForKey("__representer")
        let view = alertButton as? UIView
        view?.accessibilityIdentifier = "okAction_AID"
    )

这必须在完成处理程序中完成,因为 _UIAlertControllerActionView 在视图出现之前不会存在。在我的项目中,我使用了以下这些扩展来使事情变得更容易/更具可读性:

extension UIAlertController 
    func applyAccessibilityIdentifiers()
    
        for action in actions
        
            let label = action.valueForKey("__representer")
            let view = label as? UIView
            view?.accessibilityIdentifier = action.getAcAccessibilityIdentifier()
        

    



extension UIAlertAction

    private struct AssociatedKeys 
        static var AccessabilityIdentifier = "nsh_AccesabilityIdentifier"
    

    func setAccessibilityIdentifier(accessabilityIdentifier: String)
    
        objc_setAssociatedObject(self, &AssociatedKeys.AccessabilityIdentifier, accessabilityIdentifier, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
    

    func getAcAccessibilityIdentifier() -> String?
    
        return objc_getAssociatedObject(self, &AssociatedKeys.AccessabilityIdentifier) as? String
    

所以上面的代码会被重写:

    let alertView = UIAlertController(title: NSLocalizedString("NMN_LOGINPAGECONTROLLER_ERROR_TITLE", comment: ""), message: message as String, preferredStyle:.Alert)
    let okAction = UIAlertAction(title: NSLocalizedString("NMN_OK", comment: ""), style: .Default, handler: nil)
    okAction.setAccessibilityIdentifier(InvalidLoginAlertView_AID)


    alertView.addAction(okAction)


    self.presentViewController(alertView, animated: true, completion: 
        alertView.applyAccessibilityIdentifiers()
    )

我的第一次尝试涉及尝试导航视图层次结构,但这变得很困难,因为UIAlertControllerActionView 不是公共 API 的一部分。无论如何,我可能会尝试将 valueForKey("__representer") 排除在为应用商店提交的构建中,否则 Apple 可能会打你一顿。

【讨论】:

这行得通。我刚刚向 Apple 提出了一个错误,希望如果我们中的许多人抱怨他们会有所作为。 知道如何设置标题和消息的可访问性标识符吗? 抱歉,我不确定。只需为自动化目的设置可访问性标识符,因此无需访问标题或消息。 感谢@AnthonyOlds!它对我有用。但我有一个问题,你为什么使用“__representer”?有相关文档吗? 我认为这些键是无证的,但我了解到这个特定的键可以从这个堆栈溢出问题中接受的答案中工作:***.com/questions/26460706/…【参考方案3】:

现在我有一个名为addCameraUIAlertAction,我只是在做:

addCamera.accessibilityLabel = "camera-autocomplete-action-photo"

这允许我在 UI 测试中点击它,如下所示:

app.sheets.buttons["camera-autocomplete-action-photo"].firstMatch.tap()

【讨论】:

这对那些真正需要辅助功能帮助的人非常无益。 您不能使用“编程命名”标签进行测试,因为它们是由启用了可访问性的用户读取的,而是使用可访问性标识符。【参考方案4】:

来自 Apple 文档...

https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/UIKitUICatalog/UIAlertView.html

使警报视图可访问

默认情况下可以访问警报视图。 警报视图的可访问性与警报标题、警报消息和按钮标题有关。如果 VoiceOver 已激活,它会在显示警报时说出“警报”一词,然后说出其标题,如果已设置,则说出其消息。当用户点击一个按钮时,VoiceOver 会说出它的标题和“按钮”这个词。当用户点击文本字段时,VoiceOver 会说出其值和“文本字段”或“安全文本字段”。

【讨论】:

这里根本没有提到如何设置可访问性标识符。 不,它没有,但这是 Apple 推荐的访问警报的方式。 这很糟糕,尤其是如果过程中涉及本地化。 该文本谈到让用户可以访问警报,这与使用accessibilityIdentifier 访问它们以进行UI 测试仅略有关系。除名称相似性外,accessibilityIdentifier 与其他可访问性* 项目没有真正的关系;用户根本不使用它。 这里说的是UIAlertViews而不是UIAlertController,和问题无关

以上是关于如何将accessibilityIdentifier 设置为UIAlertController?的主要内容,如果未能解决你的问题,请参考以下文章

UITests:如何通过带有谓词的accessibilityIdentifier 找到UIBarButtonItem?

如何在 UITests Target 中使用accessibilityIdentifier 查找UIView

如何在 XCode 5 Interface Builder 中设置accessibilityLabel 或accessibilityIdentifier?

在 UIAutomation 中使用accessibilityIdentifier 获取UIElement

在 UIAutomation 的自定义表格部分标题视图上设置 accessibilityIdentifier

SwiftUI:仅在 iOS 14+ 上使用“accessibilityIdentifier”