Latest 0.8.0
Homepage https://github.com/chrs1885/Capable
License MIT
Platforms ios 10.0, osx 10.12, tvos 10.0, watchos 4.0
Frameworks Foundation
Authors

Capable


Awesome
Build Status
Platforms
Carthage compatible
Cocoapods compatible
SPM
Documentation
codecov
Twitter

Have you ever thought about adopting accessibility features within you apps to gain your user base instead of spending a lot of time implementing features no-one really ever asked for?

Most of us did, however there has never been an easy way to tell if anyone benefits from that. Adjusting layouts to be usable for people with low vision can be quite complex in some situations and tracking the user’s accessibility settings adds a lot of boilerplate code to your app.

What if there was a simple way to figure out if there’s a real need to support accessibility right now. Or even better, which disability exists most across your user base.

Check out the Example.xcworkspace to get a quick overview.

Features

Installation

There are currently four different ways to integrate Capable into your apps.

CocoaPods

use_frameworks!

target 'MyApp' do
  pod 'Capable'
end

Carthage

github "chrs1885/Capable"

Swift Package Manager (macOS)

dependencies: [
    .package(url: "https://github.com/chrs1885/Capable.git", from: "0.8.0")
]

Manually

Simply drop Capable.xcodeproj into your project. Also make sure to add
Capable.framework to your app’s embedded frameworks found in the General tab of your main project.

Usage

Register for (specific) accessibility settings

Firstly, you need to import the Capable framework in your class by adding the following import statement:

import Capable

There are two different ways to initialize the framework instance. You can either set it up to consider all accessibility features

let capable = Capable()

or by passing in only specific feature names

let capable = Capable(withFeatures: [.largerText, .boldText, .shakeToUndo])

You can find a list of all accessibility features available on each platform in the accessibility feature overview section.

Get accessibility status

If you are interested in a specific accessibility feature, you can retrieve its current status as follows:

let capable = Capable()
let isVoiceOverEnabled: Bool = capable.isFeatureEnable(feature: .voiceOver)

To get a dictionary of all features, that the Capable instance has been initialized with you can use:

let capable = Capable()
let statusMap = capable.statusMap

This will return each feature name (key) along with its current value as described in the accessibility feature overview section.

Handicaps – grouped accessibility features

You can also group accessibility features to represent a specific handicap:

// Define a set of features that represent a handicap
let features: [CapableFeature] = [.voiceOver, .speakScreen, .speakSelection]

// Use the Handicap object to group them
let blindness = Handicap(with: features, name: "Blindness", enabledIf: .allFeaturesEnabled)

// Initialize the framework instance by providing the Handicap
let capable = Capable(withHandicaps: [blindness])

The value of the name parameter will be used inside the statusMap provided by the Capable framework instance. Based on the value of enabledIf, you can specify if all features need to be set to enabled in order to set the Handicap to enabled as well.

As accessibility feature, the Handicap type works great with notifications.

Send accessibility status

The statusMap object is compatible with most analytic SDK APIs. Here’s a quick example of how to send your data along with user properties or custom events.

func sendMetrics() {
    let statusMap = self.capable.statusMap
    let eventName = "Capable features received"

    // App Center
    MSAnalytics.trackEvent(eventName, withProperties: statusMap)

    // Firebase
    Analytics.logEvent(eventName, parameters: statusMap)

    // Fabric
    Answers.logCustomEvent(withName: eventName, customAttributes: statusMap)
}

Listen for settings changes

After initialization, notifications for all features that have been registered can be retrieved. To react to changes, you need to add your class as an observer as follows:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(self.featureStatusChanged),
    name: .CapableFeatureStatusDidChange,
    object: nil)

Inside your featureStatusChanged you can parse the specific feature and value:

@objc private func featureStatusChanged(notification: NSNotification) {
    if let featureStatus = notification.object as? FeatureStatus {
        let feature = featureStatus.feature
        let currentValue = featureStatus.statusString
    }
}

If your framework instance has been set up with Handicaps instead, you can use the CapableHandicapStatusDidChange notification:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(self.handicapStatusChanged),
    name: .CapableHandicapStatusDidChange,
    object: nil)

Once the notification has been sent, you can parse the Handicapand its current status as follows:

@objc private func handicapStatusChanged(notification: NSNotification) {
    if let handicapStatus = notification.object as? HandicapStatus {
        let handicap = handicapStatus.handicap
        let currentValue = handicapStatus.statusString
    }
}

Please note that when using notifications with Handicaps on macOS or watchOS, you might not get notified about all changes since not all accessibility features do support notifications, yet.

Dynamic Type with custom fonts (Capable UIFont extension)

Supporting Dynamic Type along with different OS versions such as iOS 10 and iOS 11 (watchOS 3 and watchOS 4) can be a huge pain, since both versions provide different APIs.

Capable easily auto scales system fonts as well as your custom fonts by providing one line of code:

let myLabel = UILabel(frame: frame)

// Scalable custom font
let myCustomFont = UIFont(name: "Custom Font Name", size: defaultFontSize)!
myLabel.font = UIFont.scaledFont(for: myCustomFont)

// or
myLabel.font = UIFont.scaledFont(name: "Custom Font Name", size: defaultFontSize)

// Scalable system font
myLabel.font = UIFont.scaledSystemFont(ofSize: defaultFontSize)

// Scalable italic system font
myLabel.font = UIFont.scaledItalicSystemFont(ofSize: defaultFontSize)

// Scalable bold system font
myLabel.font = UIFont.scaledBoldSystemFont(ofSize: defaultFontSize)

While these extension APIs are available on tvOS as well, setting the font size in the system settings is not supported on this platforms.

Logging with OSLog

The Capable framework provides a logging mechanism that lets you keep track of what’s going on under the hood. You’ll get information regarding your current setup, warnings about anything that might cause issues further on, and errors that will lead to misbehavior.

By default, all messages will be logged automatically by using Apple’s Unified Logging System. However, it also integrates with your specific logging environment by providing a custom closure that will be called instead. For example, you may want to send all errors coming from the Capable framework to your analytics service:

// Send error messages to your data backend
Capable.onLog = { message, logType in
    if logType == OSLogType.error {
        sendLog("Capable Framework: (message)")
    }
}

Furthermore, you can specify the minimum log level that should be considered when logging messages:

// Configure logger to only log warnings and errors (.default, .error, and .fault)
Capable.minLogType = OSLogType.default

Here’s a list of the supported log types, their order, and what kind of messages they are used for:

OSLogType Usage
.debug Verbose logging *
.info Information regarding the framework setup and status changes
.default Warnings that may lead to unwanted behavior
.error Errors caused by the framework
.fault Errors caused by the framework due to system issues *

* Currently not being used by the framework when logging messages.

Accessibility feature overview

The following table contains all features that are available AND settable on each platform.

iOS macOS tvOS watchOS
.assistiveTouch :white_check_mark:
.boldText :white_check_mark: :white_check_mark:  :white_check_mark:*
.closedCaptioning :white_check_mark: :white_check_mark:
.darkerSystemColors :white_check_mark:
.differentiateWithoutColor :white_check_mark:
.fullKeyboardAccess  :white_check_mark:*
.grayscale :white_check_mark: :white_check_mark:
.guidedAccess :white_check_mark:
.increaseContrast :white_check_mark:
.invertColors :white_check_mark: :white_check_mark: :white_check_mark:
.largerText :white_check_mark:  :white_check_mark:*
.monoAudio :white_check_mark: :white_check_mark:
.reduceMotion :white_check_mark: :white_check_mark: :white_check_mark: :white_check_mark:
.reduceTransparency :white_check_mark: :white_check_mark: :white_check_mark:
.shakeToUndo :white_check_mark:
.speakScreen :white_check_mark:
.speakSelection :white_check_mark:
.switchControl :white_check_mark: :white_check_mark: :white_check_mark:
.voiceOver :white_check_mark: :white_check_mark: :white_check_mark: :white_check_mark:

* Feature status can be read but notifications are not available.

While most features can only have a status set to enabled or disabled, the .largerText feature offers the font scale set by the user:

iOS

  • XS
  • S
  • M (default)
  • L
  • XL
  • XXL
  • XXXL
  • Accessibility M
  • Accessibility L
  • Accessibility XL
  • Accessibility XXL
  • Accessibility XXXL
  • Unknown

watchOS

  • XS
  • S (default watch with 38mm)
  • L (default watch with 42mm)
  • XL
  • XXL
  • XXXL
  • Unknown

Resources

Contributions

We’d love to see you contributing to this project by proposing or adding features, reporting bugs, or spreading the word. Please have a quick look at our contribution gudelines.

License

Capable is available under the MIT license. See the LICENSE file for more info.

Latest podspec

{
    "name": "Capable",
    "version": "0.8.0",
    "summary": "Keep track of accessibility settings and enable users with disabilities to use your iOS, tvOS, and watchOS app.",
    "description": "Capable lets you easily keep track of accessibility settings used by your app users. Send this info along with user properties and find out about where to improve accessibility within your app. Capable also comes with additional features that will help you to solve common accessibility problems.",
    "homepage": "https://github.com/chrs1885/Capable",
    "license": {
        "type": "MIT",
        "file": "LICENSE"
    },
    "authors": {
        "Christoph Wendt": "[email protected]"
    },
    "source": {
        "git": "https://github.com/chrs1885/Capable.git",
        "tag": "0.8.0"
    },
    "documentation_url": "http://htmlpreview.github.io/?https://github.com/chrs1885/Capable/blob/0.8.0/Documentation/index.html",
    "swift_version": "4.2",
    "source_files": "Source/**/*.swift",
    "frameworks": "Foundation",
    "watchos": {
        "frameworks": "WatchKit"
    },
    "tvos": {
        "frameworks": "UIKit"
    },
    "ios": {
        "frameworks": "UIKit"
    },
    "osx": {
        "frameworks": "AppKit"
    },
    "platforms": {
        "ios": "10.0",
        "osx": "10.12",
        "tvos": "10.0",
        "watchos": "4.0"
    }
}

Pin It on Pinterest

Share This