This section explains the specifics of using Nice Vibrations on iOS or Android.

Introduction

When using NiceVibrations, most of the time, you’ll just interact with the MMVibrationManager class. It’s been designed as an interface that calls platform specific methods based on context, so you don’t have to deal with platform detection all the time. That said, all the gamepad rumble, Android and iOS specific methods are exposed in their respective classes, and you can check out the API documentation to learn more about them. This page describes mostly initialization specifics.

Android specific methods

Initialization

For Android to support vibrations you’ll need to have the following line in your Android manifest :

<uses-permission android:name="android.permission.VIBRATE" />

Haptics

When targeting Android specifically with Nice Vibrations, there’s mostly only one method you have to deal with : AndroidVibrate(). It comes in different flavours, allowing you to do different things :

  • AndroidVibrate(long milliseconds) : will trigger a vibration of the specified duration (in milliseconds)
  • AndroidVibrate(long milliseconds, int amplitude) : will trigger a vibration of the specified duration (in milliseconds) and amplitude. The amplitude is a strength value that goes from 0 (light) to 255 (heavy)
  • AndroidVibrate(long[] pattern, int repeat) : will trigger a vibration based on the specified pattern.
  • AndroidVibrate(long[] pattern, int[] amplitudes, int repeat ) : will trigger a vibration based on the specified pattern and amplitude.

Here are some use examples :

MMVibrationManager.AndroidVibrate(150);
MMVibrationManager.AndroidVibrate(100, 255);
MMVibrationManager.AndroidVibrate(new long[] { 0, 20, 40, 100 }, -1);
MMVibrationManager.AndroidVibrate(new long[] { 0, 20, 40, 100 }, new int[] { 0, 255, 0, 100 }, -1);

Patterns can get tricky to work with, so here’s how it goes : the first value in the array will indicate the initial delay before the vibration starts. Then, it’s a succession of durations for which you want the vibration to be on or off. So for example the following :

MMVibrationManager.AndroidVibrate(new long[] { 0, 20, 40, 100 }, -1);

would cause an Android device to vibrate instantly for 20ms, then wait for 40ms, and vibrate again for 100ms. And you could add amplitude to that too :

MMVibrationManager.AndroidVibrate(new long[] { 0, 20, 40, 100 }, new int[] { 0, 255, 0, 100 }, -1);

would cause an Android device to vibrate instantly and heavily for 20ms, then wait for 40ms, and vibrate more lightly again for 100ms. Oh and the -1 at the end is there to prevent repeat.

Please also note that due to Android’s hardware and API limitations that prevent from playing multiple haptics at once, only control point based AHAP files are supported.

iOS specific methods

On “old” iOS, ideally you’ll want to initialize your haptics at the start of your scene, and release them when they’re not needed anymore. This is done through the iOSInitializeHaptics and iOSReleaseHaptics methods. You’re strongly encouraged to do so. If you don’t, they’ll be automatically initialized for you the first time you call for a vibration, but note that this may generate a slight delay or cause other issues down the line depending on your context.

Here’s how you initialize the haptic engine (ideally in Awake() in every scene) :

MMNViOS.iOSInitializeHaptics ();

And here’s how you release it when you don’t need vibrations anymore (ideally just before exiting your scene):

MMNViOS.iOSReleaseHaptics ();

On more recent iOS, this is done for you automatically.

On most iOS dedicated methods triggering Core Haptics, you’ll find an optional Threaded parameter. When set to true, this forces the haptics call to run on a separate thread (separate from main). This can help avoid freezes, at the cost of sometimes (very slightly) delayed haptics.

For example, this is how you trigger a 0.5 intensity, 0.25 sharpness transient haptic using multithreading (ignoring Android and gamepad parameters for convenience):

MMVibrationManager.TransientHaptic(true, 0.5f, 0.25f, false, 0f, 0f, false, false, 0f, 0f, -1, this, true);

And this is how you trigger a multithreaded continuous haptic with 0.5 intensity and 0.25 sharpness, for 3s :

MMVibrationManager.ContinuousHaptic(0.5f, 0.25f, 3f, HapticTypes.None, this, false, -1, true);

Also good to know : iOS forbids haptics when the microphone is recording. Not the most common use case, but maybe will save someone a headache :)

[OLD VERSIONS ONLY] Building for iOS on Nice Vibrations v3.9 or before

Nice Vibrations uses a post processor (MMNVBuildPostProcessor) to ease the pain of setting up XCode to work with haptics, setting up permissions, paths, and frameworks for you. You can of course decide to not use the post processor (simply removing it from the project, or commenting it will do the trick) and modify these in XCode like you would for any project. If the paths don’t work for you, you can change them in the PostProcessor itself, the file described below, or in XCode directly.

Additionally, you’ll find a MMNVPathDefinition file in NiceVibrations/Common/Resources/ that you can edit to link two classes used in the build :

  • the header, UnitySwift-Bridging-Header.h typically found at NiceVibrations/Common/Plugins/iOS/Swift
  • the module, module.modulemap, typically found in the same folder
  • ForceAlwaysEmbedSwiftStandardLibraries : whether or not the post processing build should force ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES to true, on the framework or the main target. It’s usually not needed, but it’s solved build errors for some people

You’ll want to always make sure that “Symlink Unity Libraries” is unchecked (set to false). That’s a setting in your Build Settings window. Turning it to true would prevent Unity from copying the library to the device. It’s cool for quick tests, not cool if you expect your device to vibrate. Starting with v3.8, the console will show an error if that’s the case. If you really want to build with symlinks and not have that error pop up, edit the post processor class to remove that check.

If you’re using SDKs like Facebook, or Firebase, that modify the “normal” build process, usually forcing you to use CocoaPods, or if you’ve implemented your own build pipeline, you may have to set things manually. You’ll know soon enough if you’re in such a case, as you’ll get an error like “Invalid SWIFT_VERSION could not parse version component from ‘0 5’“.

If that’s the case, you’ll likely have to go to XCode, select your project and/or targets in the left panel, and in Build Settings, force Swift Language Version to 5 (or 5.1), and set Enable Bitcode to No.

You may also have to set ForceAlwaysEmbedSwiftStandardLibraries for Main Target on the MMNVPathDefinition file, and may have to manually move both the UnitySwift-Bridging-Header.h and MMNViOSCoreHapticsInterface files to Libraries/NiceVibrations/Common/Plugins/iOS/Swift in your XCode project. Of course if that’s the case, you’ll likely want to consider automating these tasks in your build pipeline. You’ll also want to avoid spaces in your paths.

A few people have reported getting “disallowed file Frameworks” issues. While not related directly to Nice Vibrations, here’s a link that explains how to solve it. It’s easy to solve, it all comes down to deleting a Framework folder. Others have reported that they managed to fix it in XCode by navigating to the Workspace entry in Build Settings, and setting the toggle to Yes, then setting it to No again (or vice versa). Yay XCode!

On some versions of Unity, it’s possible that bindings will break. If that happens, you’ll need to set them again manually. To do so, search for the MMNVPathDefinition scriptable object in your project, select it, and in its inspector, set its Header to UnitySwift-Bridging-Header, and its ModuleMap to module.

Gamepad specific methods

You can of course trigger all sorts of gamepad rumble vibrations via the MMVibrationManager class, but if you want to target the gamepad specifically, you’ll want to do it via the MMNVRumble class. The only thing to know about it is that in most cases you’ll need to pass a monobehaviour to its methods, which will be used to run coroutines on. In most situations, you can just pass it this.

For example, this is how you make it rumble with full force for 2 seconds :

MMNVRumble.Rumble(1f, 1f, 2f, this);

In addition to that, Nice Vibrations lets you specify what gamepad to target when rumbling, using an optional additional parameter on all methods.

For example, this will rumble what Unity considers to be the “current” gamepad :

MMVibrationManager.Haptic(HapticTypes.Warning, false, true, this);

Which is good until you have more than one gamepad, in which case it becomes less predictable. But you can add an extra parameter to specify the index of the gamepad you want to target (0 is the first gamepad, 1 is the second, 2 is the third, etc) :

// triggers a rumble on the 3rd gamepad
MMVibrationManager.Haptic(HapticTypes.Warning, false, true, this, 2);

Note that for gamepad access you’ll need to install Unity’s new Input System package via the Package Manager.