Condivisione dei dati con i gesti corrispondenza Thump

Benvenuti alla parte III della serie Condivisione dei dati con i gesti. Nella parte II, abbiamo creato il nostro processo di server intermedio in Ruby on Rails. Questo processo server fungerà da canale tra due dispositivi che stanno tentando di comunicare con un gesto che chiamiamo "thump". Quando due dispositivi sono "thump" -ed insieme, il server li abbina calcolando la loro vicinanza l'uno all'altro tramite le coordinate GPS e un timestamp quasi identico di quando hanno aperto la comunicazione con il server. Una volta che questa corrispondenza è stata effettuata, il server scambierà i messaggi digitati nell'app mobile, simulando la comunicazione da dispositivo a dispositivo.

Nella parte III, implementeremo la nostra app server sulla piattaforma heroku e quindi aggiorneremo la nostra app mobile per comunicare con essa.

Per iniziare, modificheremo il nostro file di migrazione della tabella dei bozzi per renderlo compatibile con Postgres. Puoi trovare questo file nella directory "db / migrate" e verrà chiamato qualcosa come: TIMESTAMP_create_thumps.rb. Il modo più semplice per implementare un'app di heroku è utilizzare il loro servizio di database condiviso, che è Postgres invece di MySQL. Stiamo andando a sostituire le seguenti linee:

 t.decimal: lat,: precision => 8,: scale => 8 t.decimal: lng,: precision => 8,: scale => 8

con queste nuove linee:

 t.decimal: lat,: scale => 8 t.decimal: lng,: scale => 8

Postgres gestisce i grandi campi decimali in modo diverso rispetto a MySQL, quindi questa è una modifica necessaria per garantire che otteniamo la precisione dei punti dati di cui abbiamo bisogno nei nostri campi di latitudine e longitudine.

Poiché si tratta di un'app Rails 2.3.5, utilizzeremo il vecchio metodo heroku per l'installazione di gemme creando un file .gems nella radice del nostro progetto Rails. La maggior parte di voi sarà probabilmente abituata a usare Bundler per questo tipo di attività, tuttavia dal momento che il plugin geokit non è stato aggiornato per essere compatibile con Rails 3.0, dobbiamo fare le cose con le vecchie convenzioni di Rails 2.

Semplicemente aggiungiamo quanto segue al nostro file .gems:

 rails -v 2.3.5 pg geokit --version '= 1.5.0'

Qui specifichiamo la gemma rails e la versione che stiamo usando per questo progetto, così come la gemma postgres e la versione 1.5.0 della gemma geokit.

Ora possiamo iniziare il nostro spiegamento! Iniziamo creando un repository git locale all'interno del nostro progetto. Tutto quello che dobbiamo fare è eseguire il seguente comando nella directory principale del nostro progetto Rails:

 $ git init

Prima di impegnarsi in questo repository, è necessario creare la nostra app sulla piattaforma heroku. Se non ti sei ancora registrato per un account gratuito di heroku, fallo semplicemente registrandoti su https://api.heroku.com/signup. Se non hai ancora installato il gem di heroku sul tuo sistema, puoi farlo eseguendo il seguente comando:

 $ sudo gem installa heroku

Una volta installata la gemma, eseguire il seguente comando dalla directory root del progetto:

 $ heroku crea --stack bamboo-ree-1.8.7

Qui stiamo specificando lo stack bamboom-ree perché questa è un'app Rails 2. Nel caso in cui tu abbia appena creato un nuovo account, potrebbe chiederti le credenziali dell'account Heroku. Una volta inserite, queste credenziali verranno archiviate per future interazioni con i server di heroku. Se tutto va bene, heroku dovrebbe rispondere con qualcosa del tipo:

 Creato http://APPNAME.heroku.com/ | [email protected]: APPNAME.git Aggiunto heroku remoto Git

Qui ho sostituito il nome e il sottodominio dell'applicazione con un segnaposto chiamato APPNAME. Prendi nota di questo APPNAME poiché lo useremo in seguito. Ora trasferiremo i file di progetto nel repository git locale creato in precedenza. È semplice come eseguire questi due comandi:

 $ git add. $ git commit -m "il mio primo commit"

Una volta che il progetto è stato completamente impegnato sul repository git locale, è necessario inserirlo nel repository remoto che è stato creato quando è stato eseguito il comando heroku create.

 $ git push heroku master

La gemma di heroku ti permette di eseguire comandi di rake remoti sul server con il comando "heroku rake". Per completare la distribuzione, dobbiamo eseguire le nostre migrazioni di database che genereranno la nostra tabella di thumps nel database heroku.

 $ heroku rake db: migrate

Congratulazioni! Hai implementato con successo la nostra applicazione server thump sulla piattaforma heroku. Ora torna all'app mobile!

Apriamo il nostro file main.lua nella nostra app Corona e aggiungiamo le seguenti righe in alto:

 http = require ("socket.http") ltn12 = require ("ltn12") url = require ("socket.url") require ("Json")

Abbiamo bisogno di richiedere alcune librerie che ci permetteranno di creare una connessione socket alla nostra app server. Includeremo anche la libreria di analisi JSON in modo che possiamo comprendere gli oggetti di risposta che il server invierà.

Ricorda l'APPNAME che è stato dato quando abbiamo creato l'app heroku per la prima volta? È ora di usarlo adesso:

 appname locale = "APPNAMEHERE"

Questa variabile verrà combinata in seguito con altre per generare l'URL del nostro server per le comunicazioni esterne.

Nella Parte I, avevamo l'app che mostrava una finestra di avviso con il nostro messaggio quando ha rilevato un gesto di "colpo" o scossa. Poiché dobbiamo comunicare questo messaggio al server, rimuoveremo la seguente riga dalla nostra funzione getThump:

 alert locale = native.showAlert ("Thump!", "Posizione:"? latitudeText? ","? longitudeText? "\ r \ nMessaggio:"? textField.text, "OK")

Ora aggiungeremo alcune funzionalità a questo metodo getThump per inviare il nostro messaggio al server. Rompiamo questo:

 messaggio locale = textField.text local post = "thump [deviceid] ="? ID del dispositivo? "& Tonfo [lat] ="? latitudeText? "& Tonfo [lng] ="? longitudeText? "& Tonfo [messaggio] ="? risposta locale del messaggio = 

Qui stiamo generando le nostre variabili da inviare al server. La variabile "post" è impostata nel formato stringa di query e la nostra "risposta" è dichiarata come oggetto tabella vuota per ora.

 local r, c, h = http.request url = "http: //"? nome dell'applicazione? ".heroku.com / thump", method = "POST", header = ["content-length"] = #post, ["Content-Type"] = "application / x-www-form-urlencoded", source = ltn12.source.string (post), sink = ltn12.sink.table (response) local jsonpost = Json.Decode (table.concat (response, "))

Qui stiamo eseguendo una richiesta HTTP di tipo POST sul nostro server. Stiamo sottotitolando nella nostra variabile appname come sottodominio per l'url. Le intestazioni sono standard per una tipica post call. Nel campo "lunghezza del contenuto", la sintassi lua di mettere un # davanti alla variabile produrrà la lunghezza in caratteri di quella stringa. Dal momento che vogliamo archiviare la risposta del nostro server in una variabile chiamata "risposta", la nostra ultima riga decodificherà quella variabile come un oggetto JSON e creerà un oggetto di tabella lua in modo che possiamo accedere ai campi al suo interno.

In caso di errore di comunicazione, dobbiamo avvisare l'utente che qualcosa è andato storto. Creeremo un metodo showError () generico per visualizzare una finestra di avviso per l'utente se ciò si verifica:

 funzione locale showError () alert locale = native.showAlert ("Errore!", "Per favore prova di nuovo il tuo thump!", "OK") fine

A causa del fatto che Rails è single threaded per natura e dato che gli account gratuiti di heroku consentono di eseguire solo un singolo processo del server; una volta che l'app mobile completa la chiamata POST per inviare i dati, interrogeremo il nostro server, chiedendo un oggetto risposta. Anche se questo potrebbe non essere il modo più ideale per progettare questo, ci permette di eseguire questo tipo di app con risorse del server heroku minime.

Ecco la nostra logica di polling sotto:

 if (jsonpost.success == true) then native.setActivityIndicator (true); tentativi locali = 0 funzione retrieveThump (evento) se 10 == tentativi then native.setActivityIndicator (false); timer.cancel (event.source) showError () else response locale =  local r, c, h = http.request url = "http: //"? nome dell'applicazione? ".Heroku.com / tonfi / ricerca? Tonfo [deviceid] ="? ID del dispositivo? "& Tonfo [lat] ="? latitudeText? "& Tonfo [lng] ="? longitudeText, method = "GET", sink = ltn12.sink.table (response) jsonget locale = Json.Decode (table.concat (response, ")) if (jsonget.success == true) then native.setActivityIndicator (false ); timer.cancel (event.source) alert locale = native.showAlert ("Thump!", jsonget.message, "OK") tentativi finali = tentativi + 1 timer.performWithDelay (3000, retrieveThump) timer di fine. performWithDelay (1000, retrieveThump) else showError () end

Scopriamolo:

 if (jsonpost.success == true) then native.setActivityIndicator (true) ;? else fine ShowError ()

Nel caso in cui la nostra variabile "jsonpost" restituisca "success = true" dal server, imposteremo il nostro ActivityIndicator sul dispositivo su true. Questo avvia un componente pacifier nativo che segnala all'utente che l'app sta lavorando su qualcosa. Se non avessimo ricevuto un "successo = true" dal server, chiameremo la nostra funzione di errore generico e mostreremo la casella di segnalazione degli errori.

 tentativi locali = 0 funzione retrieveThump (evento)? end timer.performWithDelay (1000, retrieveThump)

In questo caso stiamo impostando una variabile di tentativi al di fuori dell'ambito della nostra funzione su 0. La useremo più avanti per mettere un limite al numero di richieste che la nostra funzione di polling "retrieveThump" può effettuare. Corona ha una classe temporizzatore integrata che ci consente di chiamare una funzione in un intervallo di tempo. La funzione timer.performWithDelay richiede un numero di millisecondi e una funzione come parametri.

 se 10 == tentativi allora native.setActivityIndicator (false); timer.cancel (event.source) showError ()

Innanzitutto, controlleremo se abbiamo eseguito questa funzione 10 volte. In tal caso, interrompiamo il nostro ActivityIndicator impostandolo su false, annulla la nostra funzione timer e quindi chiama la nostra funzione di errore per segnalare all'utente che qualcosa è andato storto.

 else local response =  local r, c, h = http.request url = "http: //"? nome dell'applicazione? ".Heroku.com / tonfi / ricerca? Tonfo [deviceid] ="? ID del dispositivo? "& Tonfo [lat] ="? latitudeText? "& Tonfo [lng] ="? longitudeText, method = "GET", sink = ltn12.sink.table (response) jsonget locale = Json.Decode (table.concat (response, ")) if (jsonget.success == true) then native.setActivityIndicator (false timer.cancel (event.source) alert locale = native.showAlert ("Thump!", jsonget.message, "OK") end attempt = attempt + 1 timer.performWithDelay (3000, retrieveThump) end

Se non abbiamo ancora raggiunto 10 tentativi, eseguiremo una richiesta HTTP sul nostro server per cercare il nostro "thump" corrispondente. La funzione è simile alla chiamata POST che abbiamo fatto in precedenza, solo in questo caso stiamo passando il metodo GET perché stiamo cercando di leggere e non scrivere sul server.

Se ti ricordi dalla Parte II, abbiamo creato un'azione di ricerca nel nostro server Rails che cerca nel nostro database un thump corrispondente in base alle nostre coordinate GPS e al timestamp simile. Passiamo queste informazioni al server tramite la stringa di query nell'URL. Simile alla chiamata POST, stiamo analizzando il ritorno dal server come un oggetto JSON e memorizzandolo in una variabile di tabella lua locale chiamata "jsonget". Se riceviamo un successo = true back dal server, interromperemo il nostro ActivityIndicator, interromperà l'esecuzione del timer e mostreremo il nostro messaggio in una casella di avviso. Se questo processo fallisce, eseguiremo semplicemente il polling del server nello stesso modo per un massimo di 10 tentativi.

E il gioco è fatto! Questo tutorial dovrebbe darti una buona base per creare diversi tipi di app che condividono i dati tramite gesti. Alcune aggiunte interessanti potrebbero essere condivise tramite un tocco di schermo simultaneo o estendere l'applicazione per scambiare immagini prelevate dalla fotocamera o dalla libreria fotografica locale del dispositivo. Colpo felice!