Fazendo o iPhone vibrar

228

Como o iPhone pode ser configurado para vibrar uma vez?

Por exemplo, quando um jogador perde uma vida ou o jogo termina, o iPhone deve vibrar.

sistema
fonte
9
O gesto de agitação é completamente diferente da vibração. Um é iniciado por humanos, um por dispositivo.
Eiko

Respostas:

404

Do " Tutorial do iPhone: melhor maneira de verificar os recursos dos dispositivos iOS ":

Existem duas funções aparentemente semelhantes que usam um parâmetro kSystemSoundID_Vibrate:

1) AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
2) AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

Ambas as funções vibram o iPhone. Porém, quando você usa a primeira função em dispositivos que não suportam vibração, ele emite um sinal sonoro. A segunda função, por outro lado, não faz nada em dispositivos não suportados. Portanto, se você vibrar o dispositivo continuamente, como alerta, o senso comum diz, use a função 2.

Primeiro, adicione a estrutura AudioToolbox AudioToolbox.framework ao seu destino em Fases de construção.

Em seguida, importe este arquivo de cabeçalho:

#import <AudioToolbox/AudioServices.h>
linuxbuild
fonte
3
#import <Cocoa / Cocoa.h> não é necessário.
Raptor
10
Existe uma maneira de reduzir o tempo de vibração para menos de 1 segundo?
George Asda
11
Gostaria de acrescentar que, se a vibração estiver desativada nas Configurações do iOS, o usuário não receberá vibração, mesmo se você usar esses comandos.
Denis Kutlubaev 7/03
7
Em Swift: AudioServicesPlayAlertSound(UInt32(kSystemSoundID_Vibrate))(pelo menos a partir da versão beta 2)
Sam Soffes 18/06
1
AudioServicesPlayAlertSound (kSystemSoundID_Vibrate); Vibarate no iPhone proerly, mas não emite nenhum sinal sonoro no iPad.
Mangesh
45

Swift 2.0+

AudioToolbox agora apresenta a kSystemSoundID_Vibratecomo um SystemSoundIDtipo, de modo que o código é:

import AudioToolbox.AudioServices

AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate)

Em vez de ter que passar pela etapa de elenco extra

(Adereços para @Dov)

Resposta original (Swift 1.x)

E aqui está como você faz isso no Swift (caso você tenha o mesmo problema que eu)

Link contra AudioToolbox.framework(Vá para o seu projeto, selecione seu destino, crie fases, Vincule o Binário às Bibliotecas, adicione a biblioteca)

Depois de concluído:

import AudioToolbox.AudioServices

// Use either of these
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))

A coisa brega é que SystemSoundIDé basicamente um typealias(fantasia rápida typedef) para um UInt32, e o kSystemSoundID_Vibrateé um regular Int. O compilador fornece um erro ao tentar converter de IntparaUInt32 , mas o erro é exibido como "Não é possível converter para SystemSoundID", o que é confuso. Por que a maçã não a transformou em um enum Swift está além de mim.

@ aponomarenko entra em detalhes, minha resposta é apenas para os Swifters por aí.

lata
fonte
Este parece ser fixado em Swift 2 / iOS 9 / Xcode 7. Eu usei AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)e compilado bem
Dov
35

Uma maneira simples de fazer isso é com os Serviços de áudio:

#import <AudioToolbox/AudioToolbox.h> 
...    
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
fsaint
fonte
3
#import <AudioToolbox / AudioToolbox.h> e você precisará adicionar o AudioToolbox.framework às fases de compilação do seu projeto.
Michael Mangold
31

Eu tive um grande problema com isso para dispositivos que tinham a vibração desativada de alguma maneira, mas precisávamos que funcionasse independentemente, porque é fundamental para o funcionamento do aplicativo e, como é apenas um número inteiro para uma chamada de método documentada, ele passará validação. Então, eu tentei alguns sons que estavam fora dos bem documentados aqui: TUNER88 / iOSSystemSoundsLibrary

Tropecei em 1352, que está funcionando independentemente da opção silenciosa ou das configurações do dispositivo (Settings->vibrate on ring, vibrate on silent).

- (void)vibratePhone;
{
     if([[UIDevice currentDevice].model isEqualToString:@"iPhone"])
     {
         AudioServicesPlaySystemSound (1352); //works ALWAYS as of this post
     }
     else
     {
          // Not an iPhone, so doesn't have vibrate
          // play the less annoying tick noise or one of your own
          AudioServicesPlayAlertSound (1105);
     }
}
Joel Teply
fonte
7
É sempre melhor usar aliases nomeados em vez de constantes mágicas, como o kSystemSoundID_Vibrate em vez de 1352. Convido você a atualizar sua resposta.
Nalexn
3
Concordo que o uso dessa mágica 1352 não é o ideal, mas não consigo encontrar outra maneira de forçar uma vibração, mesmo quando o interruptor de vibração está desligado no dispositivo. Este parece ser o único caminho.
marcshilling
4
Eu escrevi um loop com inteiros começando passado as constantes publicados e descobriu que um causou uma vibração
Joel Teply
2
Posso confirmar que o iPhone vibra mesmo que o modo silencioso esteja ativado no iPhone. Ótima resposta!
Vomako 17/05
2
O AudioServicesPlaySystemSound (1352) ainda funciona para iPhones, independentemente da posição do comutador silencioso em janeiro de 2016
JustAnotherCoder
26

Nota importante: Alerta de descontinuação futura.

No iOS 9.0 , a API funciona com a descrição de:

AudioServicesPlaySystemSound(inSystemSoundID: SystemSoundID)
AudioServicesPlayAlertSound(inSystemSoundID: SystemSoundID)

inclui a seguinte nota:

This function will be deprecated in a future release.
Use AudioServicesPlayAlertSoundWithCompletion or  
AudioServicesPlaySystemSoundWithCompletion instead.

O caminho certo a seguir será usar qualquer um destes dois:

AudioServicesPlayAlertSoundWithCompletion(kSystemSoundID_Vibrate, nil)

ou

AudioServicesPlayAlertSoundWithCompletion(kSystemSoundID_Vibrate) {
 //your callback code when the vibration is done (it may not vibrate in iPod, but this callback will be always called)
}

lembrar de import AVFoundation

Hugo Alonso
fonte
está faltando a declaração de importação
Juan Boero
import AudioToolbox.AudioServices
Hugo Alonso
Eu fiz isso sozinho, é apenas com o AVFoundation.
Juan Boero
De qualquer forma, para definir a duração da vibração?
Micro
Você está indo para necessidade de concatenar várias chamadas, use um lapso de tempo entre cada nova chamada
Hugo Alonso
7

Para um iPhone 7/7 Plus ou mais recente, use essas três APIs de feedback tátil.

APIs disponíveis

Para notificações:

let generator = UINotificationFeedbackGenerator()
generator.notificationOccured(style: .error)

Estilos disponíveis são .error, .successe .warning. Cada um tem sua própria sensação distinta.
Dos documentos :

Uma UIFeedbackGeneratorsubclasse concreta que cria hápticos para comunicar sucessos, falhas e avisos.

Para vibrações simples:

let generator = UIImpactFeedbackGenerator(style: .medium)
generator.impactOccured()

Estilos disponíveis são .heavy, .mediume .light. São vibrações simples com graus variados de "dureza".
Dos documentos :

Uma UIFeedbackGeneratorsubclasse de concreto que cria hápticos para simular impactos físicos

Para quando o usuário selecionou um item

let generator = UISelectionFeedbackGenerator()
generator.selectionChanged()

Esse é o menos perceptível de todos os hápticos e, portanto, é o mais adequado para quando os hápticos não devem assumir a experiência do aplicativo.
Dos documentos :

Uma UIFeedbackGeneratorsubclasse concreta que cria hápticos para indicar uma mudança na seleção.

Notas

Vale lembrar algumas coisas ao usar essas APIs.

Nota A

Na verdade, você não cria o háptico. Você solicita que o sistema gere um haptic. O sistema decidirá com base no abaixo:

  • Se há haptics no dispositivo (se ele possui um Taptic Engine nesse caso)
  • Se o aplicativo pode gravar áudio (os haptics não são gerados durante a gravação para evitar interferências indesejadas)
  • Se há haptics está ativado nas configurações do sistema.

Portanto, o sistema ignorará silenciosamente sua solicitação de um háptico, se não for possível. Se isso ocorre devido a um dispositivo não suportado, você pode tentar o seguinte:

func haptic() {
    // Get whether the device can generate haptics or not
    // If feedbackSupportLevel is nil, will assign 0
    let feedbackSupportLevel = UIDevice.current.value(forKey: "_feedbackSupportLevel") as? Int ?? 0

    switch feedbackSupportLevel { 
    case 2:
        // 2 means the device has a Taptic Engine
        // Put Taptic Engine code here, using the APIs explained above

    case 1: 
    // 1 means no Taptic Engine, but will support AudioToolbox
    // AudioToolbox code from the myriad of other answers!

    default: // 0
        // No haptic support
        // Do something else, like a beeping noise or LED flash instead of haptics
    }

Substitua os comentários no switch-case instruções e esse código de geração tátil será portátil para outros dispositivos iOS. Gerará o nível mais alto possível de háptico.

Nota B

  • Devido ao fato de que gerar haptics é uma tarefa em nível de hardware , pode haver latência entre quando você chama o código de geração háptica e quando ele realmente acontece. Por esse motivo, todas as APIs do Taptic Engine têm umprepare() método, para colocá-lo em um estado de prontidão. Usando o exemplo de Game Over: você pode saber que o jogo está prestes a terminar, porque o usuário tem um HP muito baixo ou um monstro perigoso está perto deles.
  • Se você não gerar um háptico em alguns segundos, o Taptic Engine retornará ao estado inativo (para economizar a bateria)


Nesse caso, a preparação do Taptic Engine criaria uma experiência mais responsiva e de maior qualidade.

Por exemplo, digamos que seu aplicativo use um reconhecedor de gestos de panorâmica para alterar a parte do mundo visível. Você deseja gerar um háptico quando o usuário "olhar" em torno de 360 ​​graus. Aqui está como você pode usar prepare():

@IBAction func userChangedViewablePortionOfWorld(_ gesture: UIPanGestureRecogniser!) {

    haptic = UIImpactFeedbackGenerator(style: .heavy)

    switch gesture.state {
        case .began:
            // The user started dragging the screen.
            haptic.prepare()

        case .changed:
            // The user trying to 'look' in another direction
            // Code to change viewable portion of the virtual world

            if virtualWorldViewpointDegreeMiddle = 360.0 { 
                haptic.impactOccured()
            }
        
        default:
            break

} 
Benj
fonte
Apenas lembre-se import UIKit!
Benj
Você não deseja criar uma nova instância hapticdentro deste método. Você não está chamando impactOccuredna mesma instância que chama prepare.
rmaddy
5

E se você estiver usando a estrutura Xamarin (monotouch), basta chamar

SystemSound.Vibrate.PlayAlertSound()
Wheelie
fonte
5

Nas minhas viagens, descobri que, se você tentar qualquer um dos seguintes itens enquanto estiver gravando áudio, o dispositivo não vibrará, mesmo se estiver ativado.

1) AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
2) AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

Meu método foi chamado em um momento específico na medição dos movimentos do dispositivo. Eu tive que parar a gravação e depois reiniciá-la após a vibração.

Parecia assim.

-(void)vibrate {
    [recorder stop];
    AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
    [recorder start];
}

recorder é uma instância do AVRecorder.

Espero que isso ajude outras pessoas que tiveram o mesmo problema antes.

Sebastien Peek
fonte
4

No iOS 10 e em iPhones mais novos, você também pode usar a API háptica. Esse feedback tátil é mais suave que a API AudioToolbox.

Para o seu cenário GAME OVER, um feedback de impacto na interface do usuário pesado deve ser adequado.

UIImpactFeedbackGenerator(style: .heavy).impactOccurred()

Você pode usar os outros estilos de feedback tátil .

samwize
fonte
1

Em Swift:

import AVFoundation
...
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
Eric
fonte
0

No meu caso, eu estava usando o AVCaptureSession. O AudioToolbox estava nas fases de construção do projeto e foi importado, mas ainda não funcionou. Para fazer funcionar, parei a sessão antes da vibração e continuei depois.

#import <AudioToolbox/AudioToolbox.h>
...
@property (nonatomic) AVCaptureSession *session;
...
- (void)vibratePhone;
{
  [self.session stopRunning];
     NSLog(@"vibratePhone %@",@"here");
    if([[UIDevice currentDevice].model isEqualToString:@"iPhone"])
    {
        AudioServicesPlaySystemSound (kSystemSoundID_Vibrate); 
    }
    else
    {
        AudioServicesPlayAlertSound (kSystemSoundID_Vibrate);
    }
  [self.session startRunning];
}
Caner Çakmak
fonte
-5

Você pode usar

1) AudioServicesPlayAlertSound (kSystemSoundID_Vibrate);

para iPhone e alguns iPods mais novos.

2) AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);

para iPads.

swathy krishnan
fonte
3
Os toques do iPod e os iPads não podem vibrar.
DDPWNAGE
1
em um dispositivo sem capacidade de vibração (como o iPod Touch) isso vai fazer nada
Lal Krishna