Are there APIs for custom vibrations in iOS?
After serval hours' digging in the Contact App, I have figured out how it works.
ABNewPersonViewControlle invoke some class in ToneLibrary framework to do this.
The call stack looks like this:
0 CoreFoundation 0x3359a1d4 CFGetTypeID + 0
1 CoreFoundation 0x33596396 __CFPropertyListIsValidAux + 46
2 CoreFoundation 0x33517090 CFPropertyListCreateData + 124
3 AudioToolbox 0x38ac255a AudioServicesPlaySystemSoundWithVibration + 158
5 ToneLibrary 0x35a7811a -[TLVibrationRecorderView vibrationComponentDidStartForVibrationRecorderTouchSurface:] + 38
6 ToneLibrary 0x35a772b2 -[TLVibrationRecorderTouchSurface touchesBegan:withEvent:] + 342
7 UIKit 0x3610f526 -[UIWindow _sendTouchesForEvent:] + 314
8 UIKit 0x360fc804 -[UIApplication sendEvent:] + 376
After search "AudioServicesPlaySystemSoundWithVibration" on the web , I found nothing.
So I decide to look into it myself. It's a private function in AudioToolbox framework.
the declaration of the function is like
void AudioServicesPlaySystemSoundWithVibration(SystemSoundID inSystemSoundID,id arg,NSDictionary* vibratePattern)
"inSystemSoundID" is SystemSoundID .just like "AudioServicesPlaySystemSound", pass "kSystemSoundID_Vibrate".
"arg" is not important, pass nil to it , everything will still work fine.
"vibratePattern" is a pointer of "NSDictionary", the Contact App pass into
{
Intensity = 1;
OffDuration = 1;
OnDuration = 10;
} for recording user input.
But only call this function will make a vibration never stop. So I have to found some function to stop it.
The answer is "AudioServicesStopSystemSound". It's also a private function in AudioToolbox framework.
the declaration of the function is like
void AudioServicesStopSystemSound(SystemSoundID inSystemSoundID)
I guess the Contact App use AudioServicesPlaySystemSoundWithVibration in touchesBegan method, and AudioServicesStopSystemSound in touchEnd method to reach this effect.
TLVibrationController will manager a vibrate pattern object to record the process you input.
At last it generate a dictionary to pass into AudioServicesPlaySystemSoundWithVibration to replay the whole process like below:
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
NSMutableArray* arr = [NSMutableArray array ];
[arr addObject:[NSNumber numberWithBool:YES]]; //vibrate for 2000ms
[arr addObject:[NSNumber numberWithInt:2000]];
[arr addObject:[NSNumber numberWithBool:NO]]; //stop for 1000ms
[arr addObject:[NSNumber numberWithInt:1000]];
[arr addObject:[NSNumber numberWithBool:YES]]; //vibrate for 1000ms
[arr addObject:[NSNumber numberWithInt:1000]];
[arr addObject:[NSNumber numberWithBool:NO]]; //stop for 500ms
[arr addObject:[NSNumber numberWithInt:500]];
[dict setObject:arr forKey:@"VibePattern"];
[dict setObject:[NSNumber numberWithInt:1] forKey:@"Intensity"];
AudioServicesPlaySystemSoundWithVibration(4095,nil,dict);
So if you want a custom vibrations in iOS. Use AudioServicesPlaySystemSoundWithVibration and AudioServicesStopSystemSound.
How to make iPhone vibrate using Swift?
Short example:
import UIKit
import AudioToolbox
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
}
}
load onto your phone and it will vibrate. You can put it in a function or IBAction as you wish.
Code Update:
AudioServicesPlayAlertSoundWithCompletion(SystemSoundID(kSystemSoundID_Vibrate)) { }
As apple code docs written:
This function will be deprecated in a future release. Use
AudioServicesPlaySystemSoundWithCompletion instead.
NOTE: If vibrate doesn't work. check vibrate is enable in sounds and haptics settings
Intensity of custom iPhone vibration
Change the numberWithInt
call into numberWithFloat
, and change the intensity so it's between 0 and 1. I thought it was weird when they used an int
rather than a float
.
Edit: Here's a copy/paste that should work for your code to invoke custom vibration:
#pragma mark - Custom vibration methods
-(void)invokeCustomVibrationWithStartStopTimes:(NSArray*)startStopTimes andIntensity:(float)intensity {
BOOL startOrStop = YES;
NSMutableArray* arr = [@[] mutableCopy];
double time = 0;
for (NSNumber *x in stopStartTimes) {
[arr addObject:x]
startOrStop = !startOrStop;
[arr addObject:@(startOrStop)];
time = [x doubleValue] / 1000.0;
}
AudioServicesPlaySystemSoundWithVibration(4095,nil,{@"VibePattern":arr,@"Intensity":@(intensity)})
[self performSelector:@selector(stop) withObject:nil afterDelay:time];
}
-(void)stop {
AudioServicesStopSystemSound(4095); // stop buzzing the phone
}
For startStopTimes
, it should alternate between times started and times stopped. Passing in this array:
@[@(2000), @(1000), @(1000), @(500)]
Will do what the example code did. In this case, it will start for 2000 ms, stop for 1000 ms, start for 1000 ms, and stop for 500 ms.
stop
is called to stop the sound. The way I have it set up, it stops sounds after the total amount of time sent in.
You may have noticed I've been using array/number literals rather than using [NSArray arrayWithObjects: ... , nil];
or [NSNumber numberWith...];
. This makes your code a lot shorter. Also, I marked the beginning with a #pragma mark
. Use that to organize it better. Hope it helps!
iOS - local notification - custom vibration or vibrate for longer duration
You cannot change the duration of vibration,or make it,for example,vibrate several times(untill you don't make several notifications).
Only way to make custom vibration is to do it from the app, while it is running, no other way for you.
Related Topics
Close UIdatepicker After Selection When Style Is .Compact
How to Define a Variable in a Swift If Statement
How to Solve This Error: Thread 1: Exc_Resource Resource_Type_Memory (Limit=650 Mb, Unused=0X0)
Uidatepicker Show Only Sunday's Date Only
Horizontal Scrolling in Spritekit (Vs. a Viewcontroller)
How to Return Subscript in Constant Time
Extra Argument Userinfo in Call
Swiftui: UIimage (Qrcode) Does Not Load After Calling Function
Need Clarification of Type Casting Operator in Swift
Audiokit - Temporary File Size Is Too Big
How to Get .Adjustsfontsizetofitwidth to Function Properly
Swift: Binary Operator '==' Cannot Be Applied to Operands of Type "Protocol"
Sizing a UIpickerview Inside a UIalertview
Difference Between @Propertydelegate and @Propertywrapper
Swift: Urlsession.Shared.Datatask Says Status Code 304 = 200
How to a Convert a Dictionary Slice to a Dictionary in Swift