📜 ⬆️ ⬇️

How to make iPhone external buttons work for you

Hello, dear readers Habr!

I've been working as a freelancer for quite some time and sometimes I take a couple of simple projects for $ 100-200 for brain unloading. This time the client asked to use the external volume buttons on the iPhone. The problem was that the built-in API for external buttons in iOS does not exist: until recently, the use of hardware elements of the device, other than system behavior, was prohibited. Therefore, various applications such as Camera + and Camera Pro could not bring such functionality to the user. However, fortunately, in iOS 5, the Apple developers themselves began using a similar approach to the interface: you can now take a photo in the camera's system application by pressing the volume up key.

How to implement a similar behavior of external keys in your application, look under the cut. Sources are attached at the end of the article.
')
A little googling about the problem, you can stumble upon an open solution RBVolumeButtons , which opens the audio session and begins to listen to the change in volume. In my case, this class unpleasantly influenced the work of the camera: by activating a new audio session, we interrupted the camera's audio session. I decided to assemble my bike, approaching the process from a slightly different side; write a separate class NKVolumeButtons, hiding in itself all the necessary functionality.

After a short debriefing, I decided to use the MPMusicPlayer class from the built-in MediaPlayer framework. In this class there are two Siglton music player: one for the application and the second system, common to the entire phone. We will listen to changes in the volume of the music player for our application. To do this, add some code to the initialization method of the NKVolumeButtons object:

Push me!
[[MPMusicPlayerController applicationMusicPlayer] addObserver:self forKeyPath:@"volume" options:NSKeyValueObservingOptionNew context:nil]; 

All according to the canons of KVO : instead of our own bike, we use the good old category inherited from NSObject. Accordingly, we also need an event handler — when the parameter that we listen to changes, we need to somehow accept this information. Feel free to add a method to NKVolumeButtons!

Push me!
 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { //    ,   keyPath  ;  ?   ,    -  volume [self checkVolumeButtons]; } - (void)checkVolumeButtons { // 1 float currentVolume = [[MPMusicPlayerController applicationMusicPlayer] volume]; // 2 if (currentVolume > 0.5) { [self volumeUp]; } else if (currentVolume < 0.5) { [self volumeDown]; } // 3 [[MPMusicPlayerController applicationMusicPlayer] setVolume:0.5]; } 

Let's sort the code in order:

  1. We get the current volume of the application
  2. Check if the volume has increased or decreased
  3. We return the volume to the original value

What is the original value? I explain: if the user came into our application, and the volume is at zero? Then pressing the volume down key will not make sense - nothing will work. Therefore, from the very beginning we need to set the volume at a certain level, from which we will dance. The volume parameter can take values ​​from 0 to 1, so we choose the middle - 0.5. Add the following code to the initialization of the NKVolumeButtons object:

Push me!
 [[MPMusicPlayerController applicationMusicPlayer] setVolume:0.5]; 

Now let's start implementing the volumeUp and volumeDown methods. For convenience, we add two parameters to the NKVolumeButtons class that are accessible from the outside — upBlock and downBlock. Let's take the NKVolumeButtons.h file to the following form:

Push me!
 typedef void (^ButtonBlock)(); #import <Foundation/Foundation.h> @interface NKVolumeButtons : NSObject @property (nonatomic, copy) ButtonBlock upBlock; @property (nonatomic, copy) ButtonBlock downBlock; @end 

Here we simply added the ability to install externally blocks of code, which will be called up when pressing the volume keys, in a convenient key. Do not forget about the synthesis of our parameters. Add the following to the NKVolumeButtons implementation:

Push me!
 @synthesize upBlock = _upBlock; @synthesize downBlock = _downBlock; 

And, of course, calling our blocks at the right time:

Push me!
 - (void)volumeUp { //   ,      if(self.upBlock) { self.upBlock(); } } - (void)volumeDown { //   ,      if(self.downBlock) { self.downBlock(); } } 

And here's another problem! Each time we change the volume, a volume indicator appears on the screen. Well, let's use a ready-made solution, which was already in RBVolumeButtons. That's why he opensource to help each other, right? Add the following code to NKVolumeButtons.m:

Push me!
 //    CGRect frame = CGRectMake(0, -100, 10, 0); UIView *volumeView = [[MPVolumeView alloc] initWithFrame:frame]; [volumeView sizeToFit]; [[[[UIApplication sharedApplication] windows] objectAtIndex:0] addSubview:volumeView]; 

That's all! We only need to add this class to the project, initialize the NKVolumeButtons object and set the necessary code blocks. This simple crutch solves the problem of lack of external keys API.

Thank you for reading to the end! Sources are available on github .
If you suddenly find any inaccuracies or typographical errors, you are welcome to my cozy habrakabinet .

Source: https://habr.com/ru/post/182774/


All Articles