Подтвердить что ты не робот

Программный доступ к кнопкам громкости iPhone

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

4b9b3361

Ответ 1

После недавних отказов от 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, но просто игнорируйте его.

Ответ 2

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

Пожалуйста, исправьте меня, если я ошибаюсь, но я не верю, что это использует какой-либо внутренний 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 уведомление, а не установка системного тома, вы можете просто использовать центр уведомлений, как с любым другим событием!

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

Ответ 3

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

Ответ 4

Хорошо,

Итак, я видел ваши решения и точно не знаю, собирается ли 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.
}

Сообщите мне, поможет ли это кому-либо.

Ответ 5

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

EDIT: версия 1.0.2 появилась с некоторыми существенными изменениями/улучшениями. Я оставлю свой предыдущий ответ за 1.0.1 ниже складки.

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

Здесь, как предполагается, будет использоваться оболочка (я добавлю это в репозиторий, как только я получу):

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

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

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

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

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

В исключительных обстоятельствах приложение может не получить клавиша регулировки громкости, выходящая за пределы экрана "Секундомер"...

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

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


OLD, FOR 1.0.1:

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

  • Добавить pod 'JPSVolumeButtonHandler' в podfile
  • Запустите pod install в командной строке
  • Добавить #import <JPSVolumeButtonHandler.h> в файл заголовка моста
  • Настройте обратные вызовы кнопок увеличения и уменьшения громкости следующим образом:

    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...
        })
    

Что это. Остальное необязательно.


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

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 почувствует перегрузку своих драгоценных кнопок громкости. По крайней мере, мое приложение обязательно будет минимально инвазивным, и использование кнопки действительно имеет смысл. Это не приложение для камеры, но в сопоставимых приложениях ранее использовались кнопки физического уровня (менее хорошо).