How can I set accessibilityIdentifier to UIAlertController?

前端 未结 4 1633
梦毁少年i
梦毁少年i 2021-02-05 05:56

This is how I simply create UIAlertController and present it on the screen:

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


        
相关标签:
4条回答
  • 2021-02-05 06:24

    From Apple docs...

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

    Making Alert Views Accessible

    Alert views are accessible by default. Accessibility for alert views pertains to the alert title, alert message, and button titles. If VoiceOver is activated, it speaks the word “alert” when an alert is shown, then speaks its title followed by its message if set. As the user taps a button, VoiceOver speaks its title and the word “button.” As the user taps a text field, VoiceOver speaks its value and “text field” or “secure text field.”

    0 讨论(0)
  • 2021-02-05 06:29

    The only way I figured out to do this was to use Apple's private APIs. You call valueForKey on the UIAlertAction object with this super secret key: "__representer" to get whats called a _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"
        })
    

    This has to be done in the completion handler because that that _UIAlertControllerActionView won't exist until the view is presented. On a side note in my project I used these following extensions to make things easier / more readable:

    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
        }
    }
    

    So the above code would be rewritten:

        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()
        })
    

    My first attempt involved trying to navigate the view hierarchy but that became difficult since UIAlertControllerActionView was not a part of the public API. Anyway I'd probably would try to ifdef out the valueForKey("__representer") for builds submitted for the app store or Apple might give you a spanking.

    0 讨论(0)
  • Right now I have a UIAlertAction called addCamera and I'm just doing:

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

    That allows me to tap it in UI Tests as follows:

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

    0 讨论(0)
  • 2021-02-05 06:38

    This is an old thread but someone might use this.

    I was able to set the accessibility identifier like this:

    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)
    

    That way I can access the alert by accessibility identifier and check its contents in accessibility value.

    It is not perfect of course, but it works - at least for my testing using Appium.

    0 讨论(0)
提交回复
热议问题