Preparing Your App to Play Haptics

Set up your app to play haptics.


This article describes the process of setting up your app to play haptics. You'll check for device compatibility, create a haptic engine, and then configure the engine's handler properties.

Check for Device Compatibility

Not all devices support Core Haptics. For example, iPad and iPod touch don’t support haptic feedback, so calls to Core Haptics won’t result in haptics.

Check for haptics compatibility at the app’s launch, in your app delegate:

@property (nonatomic, assign) BOOL supportsHaptics;
// Check if the device supports haptics.
self.supportsHaptics = CHHapticEngine.capabilitiesForHardware.supportsHaptics;

By checking for haptic support early using supportsHaptics, you can set a global Boolean that your view controllers can quickly consult before deciding to play a haptic. If this variable is set to NO, then the app can proceed without even attempting a call to Core Haptics. For an example of conditioning haptic playback on this global Boolean, see Playing a Custom Haptic Pattern from a File.

Based on whether or not the user’s device supports haptics, your app can decide to use a different codepath, with stronger audio or other multimedia alternatives for feedback.

Create a Haptic Engine

The CHHapticEngine is your app’s interface to the haptic device. Use an instance of a haptic engine to perform these key tasks:

• Create players to play those haptic and audio patterns.

• Play haptic patterns directly from a file URL.

• Modulate haptic patterns during playback.

Create this engine early in your app’s life cycle—for example, in your main view controller’s viewDidLoad—and store it in an instance variable or property so it doesn’t go out of scope during playback.

@property (nonatomic, strong) CHHapticEngine* engine;
NSError* error;
_engine = [[CHHapticEngine alloc] initAndReturnError:&error];

Set the Reset Handler to Recover from Failure

Core Haptics calls the reset handler after the media server has recovered from failure. When this occurs, inside the reset handler, your app should do the following:

__weak ViewController* weakViewController = self;
[_engine setResetHandler:^{
    NSLog(@"Engine RESET!");
    // Try restarting the engine again.
    NSError* startupError;
    [weakViewController.engine startAndReturnError:&startupError];
    if (startupError) {
        NSLog(@"ERROR: Engine couldn't restart!");

    // Register any custom resources you had registered, using registerAudioResource.
    // Recreate all haptic pattern players you had created, using createPlayer.

Your app could attempt to restart the engine inside the handler, allowing it to recover on its own. However, as shown in the code listing above, a restart may still fail if the external reason for the reset hasn't subsided.

Receive Notification of Haptic Engine Stoppage Due to Outside Causes

When external factors cause the haptic engine to stop, like audio interruptions from a phone call or because the user has put your app in the background, Core Haptics calls the stoppedHandler. The reason for the stoppage is passed into the handler. Because stopping is a normal part of the life cycle, you need to restart the engine before it can play the next haptic.

As you're testing your app, set the stoppedHandler to debug the precise cause of the engine stoppage, as shown below.

// The stopped handler alerts engine stoppage.
[_engine setStoppedHandler:^(CHHapticEngineStoppedReason reason){
    NSLog(@"Engine STOPPED!");
    switch (reason)
        case CHHapticEngineStoppedReasonAudioSessionInterrupt: {
            NSLog(@"REASON: Audio Session Interrupt");
            // A phone call or notification could have come in, so take note to restart the haptic engine after the call ends. Wait for user-initiated playback.
        case CHHapticEngineStoppedReasonApplicationSuspended: {
            NSLog(@"REASON: Application Suspended");
            // The user could have backgrounded your app, so take note to restart the haptic engine when the app reenters the foreground. Wait for user-initiated playback.
        case CHHapticEngineStoppedReasonIdleTimeout: {
            NSLog(@"REASON: Idle Timeout");
            // The system stopped an idle haptic engine to conserve power, so restart it before your app must play the next haptic pattern.
        case CHHapticEngineStoppedReasonSystemError: {
            NSLog(@"REASON: System Error");
            // The system faulted, so either continue without haptics or terminate the app.

In production, your app can handle each cause in a different way. For example, you could handle the case CHHapticEngineStoppedReasonSystemError by continuing the app without haptics, or by throwing a fatal error to terminate the app.

Define and Play Haptics

Once you've set up your app to play haptics, you can incorporate haptic patterns. See:

See Also


Playing a Single-Tap Haptic Pattern

Create and play a transient haptic pattern from a dictionary literal inline.


An object that manages your app's requests to play haptic patterns.


An object representing a haptic waveform.