6

Uso le notifiche push e memorizza i token dispositivo come presumo che facciano tutti gli altri. In primo luogo li trasformo in una stringa mia app:Collisione di token APNS, archiviata in Postgres

NSString *deviceTokenString = [[[token description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] 
           stringByReplacingOccurrencesOfString:@" " withString:@""]; 

Poi metterle al mio server, dove ActiveRecord li memorizza in una colonna character varying(255):

Device.where(:token => device_token, :username => username).first_or_create!(:model => model) 

ho una convalida che garantisce l'assenza di due gettoni sono gli stessi, che capisco dovrebbe sempre essere il caso:

class Device < ActiveRecord::Base 
    belongs_to :user 
    validates_uniqueness_of :token 
end 

Tuttavia, ho iniziato a vedere la convalida errori di univocità gettone:

ActiveRecord::RecordInvalid: Validation failed: Token has already been taken

interrogazione manuale in psql conferma che un dispositivo sta tentando di registrarsi con un token già nella tabella sotto un altro utente. Questo non dovrebbe essere impossibile? Qualcosa nel modo in cui sto trasformando i token che li troncano? Ho controllato tutti gli esempi di codice che sono riuscito a trovare quando si è verificato il problema e tutti sembrano utilizzare il metodo che ho elencato nel primo esempio di codice.

+0

suona più probabile che sia un bug applicazione in cui uno stato condiviso non è correttamente cancellata. Ma difficilmente sembra impossibile che APNS possa avere stranezze o comportamenti non specificati come "unico nel tempo quindi cicli". Vorrei provare a catturare i dati in arrivo non elaborati e la prossima volta che visualizzi un duplicato, guarda che cosa ha effettivamente inviato il cliente per verificare che sia quello che ti aspetti. –

+0

Non riesco a catturare nulla sul client, ma ho salvato l'input per ogni duplicato e nulla sembra sbagliato. Stanno semplicemente inviando un identificatore che è già stato usato. – kevboh

+0

È ora di parlare con il supporto Apple. Immagino, quindi, e seguo quassù quando (se) ascolterai qualcosa. Non trattenere il respiro. –

risposta

7

Può capitare che un dispositivo tenti di registrarsi con un token già nella tabella con un altro utente se qualcuno si disconnette e quindi accede con un altro account.

vorrei fare le seguenti operazioni sul server per un utente user e una stringa di token token (supponendo che solo un utente può effettuare il login su un solo dispositivo alla volta):

  1. Verificare se v'è un Device per token_string.
  2. Se non v'è alcun dispositivo, crearne uno per token_string e user.
  3. Se è presente un dispositivo e il suo uso non è user, aggiorna il relativo utente user.

In questo modo, le notifiche push verranno inviate per l'ultimo utente che ha effettuato l'accesso sul dispositivo.

Per quanto riguarda il modo di trasformare lo NSData in una stringa esadecimale sul dispositivo, non si deve fare affidamento su -[NSData description]. Meglio farlo a livello di codice (digitato, non testato):

- (NSString *)hexStringForData:(NSData *)data 
{ 
    NSUInteger length = data.length; 
    const char *bytes = data.bytes; 
    NSMutableString *result = [NSMutableString stringWithCapacity:length * 2]; 
    for (int i = 0; i < length; i++) { 
     [result appendFormat:@"%02x", bytes[i] & 0xff]; 
    } 
    return [result copy]; 
} 
1

Scommetto a questo punto, ma prendilo per quello che è, un'ipotesi.

Quando i dispositivi iOS vengono ripristinati da backup o quando vengono "ripristinati" su nuovi dispositivi, ad esempio qualcuno che esegue l'aggiornamento da un iPhone 4 a iPhone 5 o quando qualcuno consegna il proprio iPhone a sua moglie o lo vende su eBay, otterrete dati duplicati/ridondanti/confusionari del dispositivo. L'ho visto sicuramente, ma non specificamente con i token APNS.

Ecco ciò che il APNS docs hanno da dire in proposito:

Richiedendo il dispositivo token e passarlo al fornitore ogni volta che il lancio dell'applicazione, è contribuire a garantire che il provider ha la corrente token per il dispositivo. Se un utente ripristina un backup su un dispositivo o computer diverso da quello creato per il backup (ad esempio, l'utente migra i dati su un nuovo dispositivo o computer), lui o deve avviare l'applicazione almeno una volta per ricevere nuovamente le notifiche . Se l'utente ripristina i dati di backup su un nuovo dispositivo o computer, o reinstalla il sistema operativo, le modifiche del token dispositivo . Inoltre, non mettere mai in cache un token dispositivo e assegnarlo al tuo provider ; ricevi sempre il token dal sistema ogni volta che ne hai bisogno. Se l'applicazione è stata precedentemente registrata, chiamando registerForRemoteNotificationTypes: risultati nel sistema operativo passando immediatamente il token del dispositivo al delegato senza incorrere nel sovraccarico aggiuntivo.

Quindi, non sto guardando il tuo codice, ma sembra probabile che i vostri "Duplica" gettoni abbiano a che fare con una certa combinazione di non registrare ogni volta, una sorta di caching, e il ripristino del dispositivo.

0

È importante capire cosa succede quando un dispositivo si registra. Si invia il server un post su quanto segue:

/passkit/v1/devices/<deviceID>/registrations/<typeID>/<serial#> 

E all'interno del payload JSON è la push_token. Ciò che conta è sia il deviceID e push_token. Per quanto riguarda Apple, si comunica con il dispositivo attraverso il sistema Apple con il push_token e nient'altro.

Quanto al deviceID, è il dispositivo fisico effettivo utilizzato. Il fatto che il dispositivo potrebbe desiderare di registrare più volte è irrilevante, e il codice dovrebbe semplicemente aggiornare il push_token nel vostro DB basato sulla più recente tentativo di registrazione. Questo è tutto.