программа доступа к кнопкам громкости iPhone - PullRequest
21 голосов
/ 21 апреля 2009

Есть ли способ подписаться на кнопки громкости нажатия на события?

Ответы [ 5 ]

21 голосов
/ 21 апреля 2009

После недавних отказов от Apple

Не используйте это. Apple теперь использует какой-то патч, который сразу отклонил бы ваше приложение, если бы он использовал какой-либо из частных API-интерфейсов - хотя следует заметить, что некоторые приложения в App Store уже используют его и все еще там!

Единственный способ сделать это сейчас - подготовить AVAudioPlayer для воспроизведения, но не для воспроизведения ([player prepareToPlay]). Это похоже на настройку громкости приложения в соответствии с клавишами-переключателями.

В настоящее время нет другого способа справиться с этим.

ПОЖАЛУЙСТА, ПРОЧИТАЙТЕ ВЫШЕ ПРИМЕЧАНИЕ

Да, использовать MPVolumeView

MPVolumeView *volume = [[[MPVolumeView alloc] initWithFrame:CGRectMake(18.0, 340.0, 284.0, 23.0)] autorelease];
  [[self view] addSubview:volume];

  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) 
                                        name:@"AVSystemController_SystemVolumeDidChangeNotification" 
                                        object:nil];    
  for (UIView *view in [volume subviews]){
    if ([[[view class] description] isEqualToString:@"MPVolumeSlider"]) {
      volumeViewSlider = view;  //volumeViewSlider is a UIView * object
    }
  }
  [volumeViewSlider _updateVolumeFromAVSystemController];

-(IBAction)volumeChanged:(id)sender{
  [volumeViewSlider _updateVolumeFromAVSystemController];
}

Это даст вам ползунок (аналогичный тому, который используется в ipod), значение которого будет изменяться в зависимости от громкости телефона

Вы получите предупреждение во время компиляции, что представление может не реагировать на _updateVolumeFromAVSystemControl, а просто игнорировать его.

17 голосов
/ 26 июня 2010

Если вы просто хотите получать уведомления, я думаю, что это так:

Пожалуйста, исправьте меня, если я ошибаюсь, но я не верю, что здесь используется какой-либо внутренний API.

[[NSNotificationCenter defaultCenter] addObserver:self
        selector:@selector(volumeChanged:) 
        name:@"AVSystemController_SystemVolumeDidChangeNotification" 
        object:nil];

Подробности этого события здесь: http://www.cocoadev.com/index.pl?AVSystemController

Другие ответы здесь, похоже, основаны на этом хаке: http://blog.stormyprods.com/2008/09/proper-usage-of-mpvolumeview-class.html, который был обходным путем для исправленной ошибки.

Но я почти уверен, что если вам нужно только GET уведомление, а не SET системный том, вы можете просто использовать центр уведомлений, как и любой другой событие !!

Имейте в виду: поскольку Apple добавила в камеру действие увеличения громкости, это уведомление отправлено , а не , в то время как отображается UIImagePickerController.

1 голос
/ 21 мая 2016

Самый простой и наиболее функционально полный способ сделать это, который я нашел при изучении всех источников, упомянутых выше и в других темах: JPSVolumeButtonHandler (Я не участвую, кроме как являюсь пользователем. Но спасибо много ответственным людям!)

РЕДАКТИРОВАТЬ: Выпуск 1.0.2 пришел с некоторыми значительными изменениями / улучшениями. Я оставлю свой предыдущий ответ на 1.0.1 ниже сгиба.

Я поместил пример класса-обертки, который вы можете развернуть как есть или использовать, чтобы, надеюсь, правильно использовать JPSVolumeButtonHandler в отдельном отдельном репозитории Github .

Вот как предполагается использовать обертку (я добавлю это в хранилище, как только доберусь до нее):

  1. Синглтон-класс имеет два флага: isInUse и isOn. isInUse предназначен для установки в каких-то общих настройках приложения и вообще включает и выключает поддержку кнопок. Таким образом, независимо от каких-либо других значений в классе, если это false, ничего не произойдет, когда пользователь нажимает кнопку громкости, а реализация максимально старается поддерживать чистоту и не влиять на уровень громкости системы без необходимости. (Прочтите проблему, упомянутую в README, чтобы узнать, что может произойти при первом включении поддержки кнопок.) Значение isOn должно быть true точно на время, необходимое для кнопки. Вы можете включать и выключать его независимо от текущего значения isInUse.

  2. В каком бы режиме вы ни инициировали действие, которое должно происходить при нажатии кнопки громкости, установите действие следующим образом:

    PhysicalButton.shared.action = {/ * сделать что-то * /}

Действие имеет тип () -> Void. Пока вы не инициализируете действие, ничего не сломается. Просто ничего не случится. Эта защитная функциональность была важна для меня, поскольку представление, использующее поддержку кнопок громкости, будет создано только после настройки поддержки кнопок.

Чтобы увидеть вещи в действии, вы можете скачать приложение , которым я пользуюсь очень быстро и бесплатно. Настройки управляют «поддержкой физических кнопок» в целом. Основной вид секундомера - это тот, который фактически включает обработку кнопок при входе в вид и выключается при выходе из него. Если вы найдете время, вы также найдете важную заметку в меню «Настройки»> «Руководство пользователя»> «Опция: поддержка физических кнопок»:

В исключительных случаях приложение может не получить возможности правильно выключить управление громкостью за пределами окна секундомера ...

Я добавлю полную заметку в Github README.md. Не стесняйтесь адаптировать и повторно использовать его, если это уместно в вашем случае.

Обстоятельства на самом деле не настолько исключительны, и я не до конца понял, что случилось. Когда пользователь убивает приложение (или вы просто останавливаете его изнутри XCode), когда кнопки громкости включены, поддержка физических кнопок может быть неправильно удалена из ОС. Таким образом, вы можете получить два внутренних экземпляра обработчика, только один из которых вы можете контролировать. Таким образом, каждое нажатие кнопки приводит к двум или даже большему количеству вызовов процедуры действий. В моей оболочке есть некоторый защитный код, чтобы предотвратить слишком быстрый вызов кнопки. Но это только частичное решение. Исправление должно идти в базовый обработчик, который, к сожалению, я все еще слишком мало понимаю, чтобы попытаться исправить все самостоятельно.


СТАРЫЙ, ДЛЯ 1.0.1:

В частности, мой интерес был к решению Swift. Код находится в Objective-C. Чтобы сохранить кому-то какое-то исследование, это все, что я делал, используя Cocoapods (для таких чайников, как я):

  1. Добавить pod 'JPSVolumeButtonHandler' в подфайл
  2. Выполнить pod install в командной строке
  3. Добавить #import <JPSVolumeButtonHandler.h> в файл заголовка моста
  4. Настройка обратных вызовов для кнопок увеличения и уменьшения громкости, например:

    let volumeButtonHandler = JPSVolumeButtonHandler(
        upBlock: {
            log.debug("Volume up button pressed...")
            // Do something when the volume up button is pressed...
        }, downBlock: {
            log.debug("Volume down button pressed...")
            // Do something else for volume down...
        })
    

Вот и все. Остальное необязательно.


В моем случае я хотел включить наложение физических нажатий кнопок виртуальными экранными кнопками только для выбранных видов, при этом стараясь максимально блокировать обычные функции кнопок (чтобы пользователь мог запускать музыку в фон и настроить его громкость в остальной части приложения просто отлично). Я закончил в основном синглтон-классом следующим образом:

class OptionalButtonHandler {

  static var sharedInstance: OptionalButtonHandler?

  private var volumeButtonHandler: JPSVolumeButtonHandler? = nil
  private let action: () -> ()

  var enabled: Bool {
    set {
        if !enabled && newValue {
            // Switching from disabled to enabled...
            assert(volumeButtonHandler == nil, "No leftover volume button handlers")
            volumeButtonHandler = JPSVolumeButtonHandler(upBlock: {
                log.debug("Volume up button pressed...")
                self.action()
                }, downBlock: {
                    log.debug("Volume down button pressed...")
                    self.action()
            })
        } else if enabled && !newValue {
            log.debug("Disabling physical button...")
            // The other way around: Switching from enabled to disabled...
            volumeButtonHandler = nil
        }
    }
    get { return (volumeButtonHandler != nil) }
  }

  /// For one-time initialization of this otherwise singleton class.
  static func initSharedInstance(action: () -> ()) {
      sharedInstance = OptionalButtonHandler(action: action)
  }

  private init(action: () -> ()) {
      self.action = action
  }
}

Здесь есть только одно общее действие для кнопок увеличения и уменьшения громкости. initSharedInstance() был необходим, потому что мое действие включало ссылки на элемент пользовательского интерфейса (представление), который будет установлен только в некоторой пользовательской точке после запуска приложения.

Разовая настройка:

OptionalButtonHandler.initSharedInstance({
    // ...some UI action
})

Включить / отключить выборочно просто так:

OptionalButtonHandler.sharedInstance!.enabled = true  // (false)

(Обратите внимание, что моя логика кода гарантирует, что .enabled никогда не был доступен до initSharedInstance().)

Я использую Xcode 7.3 и iOS 9.3.2 на (обязательном!) Тестовом устройстве.

Будем рады узнать, как Apple чувствует себя перегруженной своими драгоценными кнопками громкости. По крайней мере, мое приложение должно быть минимально инвазивным, а использование кнопок действительно имеет смысл. Это не приложение для камеры, но в аналогичных приложениях раньше использовались кнопки физической громкости (даже не очень приятно).

1 голос
/ 14 июля 2015

Хорошо,

Итак, я видел ваши решения и точно не знаю, собирается ли Apple отклонить или принять, используя AVSystemController_SystemVolumeDidChangeNotification. Но у меня есть работа вокруг.

Используйте UISlider из MPVolumeView для регистрации любых изменений громкости на оборудовании iPhone, подобном этому

MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectZero];

for (UIView *view in [volumeView subviews]) {
    if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
        self.volume_slider = (UISlider*)view;
        break;
    }
}
[volumeView sizeToFit];
#THIS IS THE MAIN LINE. ADD YOUR CALLBACK TARGET HERE
[self.volume_slider addTarget:self action:@selector(volumeListener:) forControlEvents:UIControlEventValueChanged];
[self addSubview:volumeView];
[volumeView setAlpha:0.0f];

-(void)volumeListener:(NSNotification*)notification {
     #UPDATE YOUR UI ACCORDING OR DO WHATEVER YOU WANNA DO.
     #YOU CAN ALSO GET THE SOUND STEP VALUE HERE FROM NOTIFICATION.
}

Дайте мне знать, если это кому-нибудь поможет.

1 голос
/ 22 апреля 2009

Если вы хотите окунуться в частный API, у меня есть патч для Wolf3d , который добавляет именно ту функциональность, которую вы ищете. Он использует закрытый класс AVSystemController и некоторые скрытые методы для UIApplication

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...