Welkom bij deel III van de reeks Data delen met gebaren. In deel II hebben we ons intermediair serverproces gecreëerd in Ruby on Rails. Dit serverproces zal fungeren als een kanaal tussen twee apparaten die proberen te communiceren met een gebaar dat we een 'dreun' noemen. Wanneer twee apparaten samen worden 'gebumpt', zal de server ze matchen door hun nabijheid tot elkaar te berekenen via GPS-coördinaten en een bijna identieke tijdstempel van wanneer ze de communicatie met de server openden. Nadat deze match is gemaakt, wisselt de server de berichten uit die zijn getypt in de mobiele app, waarbij de communicatie tussen apparaat en apparaat wordt gesimuleerd.
In deel III zullen we onze server-app op het heroku-platform implementeren en daarna onze mobiele app upgraden om ermee te communiceren.
Om te beginnen, zullen we ons thumps-tabelmigratiebestand aanpassen om compatibel te zijn met Postgres. Je vindt dit bestand in de map "db / migrate" en het heeft de naam: TIMESTAMP_create_thumps.rb. De eenvoudigste manier om een heroku-app te implementeren is door gebruik te maken van hun gedeelde databaseservice, die toevallig Postgres is in plaats van MySQL. We gaan de volgende regels vervangen:
t.decimal: lat,: precision => 8,: scale => 8 t.decimal: lng,: precision => 8,: scale => 8
met deze nieuwe regels:
t.decimal: lat,: scale => 8 t.decimal: lng,: scale => 8
Postgres verwerkt grote decimale velden anders dan MySQL, dus dit is een noodzakelijke verandering om ervoor te zorgen dat we de datapuntprecisie krijgen die we nodig hebben in onze breedtegraad- en lengtegraadvelden.
Aangezien dit een Rails 2.3.5-app is, zullen we de oudere heroku-methode gebruiken om edelstenen te installeren door een .gems-bestand te maken in de hoofdmap van ons Rails-project. De meesten van jullie zullen waarschijnlijk gewend zijn om Bundler voor dit soort taken te gebruiken, maar aangezien de geokit-plug-in niet is opgewaardeerd om compatibel te zijn met Rails 3.0, moeten we dingen doen met de oudere Rails 2-conventies.
We voegen eenvoudig het volgende toe aan ons .gems-bestand:
rails -v 2.3.5 pg geokit --version '= 1.5.0'
Hier specificeren we de rails-edelsteen en -versie die we gebruiken voor dit project, evenals de postgres-edelsteen en versie 1.5.0 van de geokit-edelsteen.
Nu kunnen we aan onze inzet beginnen! Laten we beginnen met het creëren van een lokale git repository binnen ons project. Het enige wat we moeten doen is het volgende commando uitvoeren in de hoofdmap van ons Rails-project:
$ git init
Voordat we ons verbinden aan deze repository, moeten we onze app maken op het heroku-platform. Als je je nog niet hebt aangemeld voor een gratis heroku-account, kun je dit doen door je eenvoudig te registreren op https://api.heroku.com/signup. Als u de heroku-edelsteen nog niet op uw systeem hebt geïnstalleerd, kunt u dit doen door de volgende opdracht uit te voeren:
$ sudo gem installeer heroku
Nadat de edelsteen is geïnstalleerd, voert u de volgende opdracht uit vanuit de hoofdmap van het project:
$ heroku maakt --stack bamboo-ree-1.8.7
Hier specificeren we de bamboom-ree stack vanwege het feit dat dit een Rails 2-app is. In het geval dat u zojuist een nieuw account hebt gemaakt, kan het u vragen om uw heroku-accountreferenties. Na invoer worden deze inloggegevens opgeslagen voor toekomstige interacties met de heroku-servers. Als alles goed gaat, zou heroku moeten reageren met zoiets als het volgende:
Gemaakt op http://APPNAME.heroku.com/ | [email protected]: APPNAME.git Git remote heroku toegevoegd
Hier heb ik de eigenlijke toepassingsnaam en het subdomein vervangen door een plaatshouder APPNAME. Neem notitie van dit APPNAME omdat we het later zullen gebruiken. Nu gaan we onze projectbestanden vastleggen in de lokale git-repository die we eerder hebben gemaakt. Het is zo simpel als het uitvoeren van deze twee opdrachten:
$ git add. $ git commit -m "mijn eerste commit"
Zodra het project zich volledig heeft toegewijd aan de lokale git repo, moeten we het naar de externe repository duwen die is gemaakt toen we het heroku create-commando uitvoerden.
$ git push heroku master
Met het heroku-juweeltje kun je externe harkopdrachten uitvoeren op de server met het commando "heroku rake". Om de implementatie te voltooien, moeten we onze databasemigraties uitvoeren die onze thumps-tabel genereren in de heroku-database.
$ heroku rake db: migreren
Proficiat! U hebt onze thump-servertoepassing succesvol geïmplementeerd op het heroku-platform. Nu terug naar de mobiele app!
Laten we ons main.lua-bestand openen in onze Corona-app en de volgende regels toevoegen aan de top:
http = require ("socket.http") ltn12 = require ("ltn12") url = require ("socket.url") require ("Json")
We hebben een aantal bibliotheken nodig die ons in staat stellen om een socket-verbinding te maken met onze server-app. We zullen ook de JSON-ontleedbibliotheek opnemen, zodat we de responsobjecten die de server terugstuurt, kunnen begrijpen.
Weet je nog de APPNAME die is gegeven toen we de heroku-app voor het eerst maakten? Het is tijd om dat nu te gebruiken:
local appname = "APPNAMEHERE"
Deze variabele zal later met anderen worden gecombineerd om onze server-URL voor externe communicatie te genereren.
In Deel I hadden we de app die een waarschuwingsvenster met ons bericht liet zien toen het een "dreun" of een schokbeweging detecteerde. Omdat we dit bericht aan de server moeten doorgeven, verwijderen we de volgende regel uit onze getThump-functie:
local alert = native.showAlert ("Thump!", "Location:"? latitudeText? ","? longitudeText? "\ r \ nMessage:"? textField.text, "OK")
Nu gaan we wat functionaliteit toevoegen aan deze getThump-methode om ons bericht naar de server te sturen. Laten we dit opsplitsen:
local message = textField.text local post = "thump [deviceid] ="? apparaat ID? "& Thump [lat] ="? latitudeText? "& Thump [lng] ="? longitudeText? "& Thump [bericht] ="? bericht lokaal antwoord =
Hier genereren we onze variabelen om naar de server te sturen. De variabele "post" is ingesteld in de indeling van de queryreeks en ons "antwoord" is nu gedeclareerd als een leeg tabelobject.
lokale r, c, h = http.request url = "http: //"? applicatie naam? ".heroku.com / thumps", methode = "POST", headers = ["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, "))
Hier voeren we een HTTP-verzoek van type POST naar onze server uit. We ondermijnen onze appname-variabele als het subdomein voor de URL. De headers zijn standaard voor een typische postoproep. In het veld 'content-length' geeft de lua-syntaxis van het plaatsen van een # vóór de variabele de lengte weer in tekens van die tekenreeks. Omdat we het repons van onze server in een variabele met de naam "response" willen opslaan, decodeert onze laatste regel die variabele als een JSON-object en maakt een lua-tabelobject, zodat we velden binnen het object kunnen openen.
In het geval van een communicatiefout, moeten we de gebruiker erop wijzen dat er iets fout is gegaan. We maken een generieke methode showError () om een waarschuwingsvenster weer te geven aan de gebruiker als dit gebeurt:
lokale functie showError () local alert = native.showAlert ("Error!", "Please try your thump again!", "OK") end
Vanwege het feit dat Rails van nature een enkele thread heeft en omdat met heroku-vrije accounts u slechts één serverproces kunt uitvoeren; Zodra de mobiele app de POST-oproep voltooit om gegevens te verzenden, gaan we onze server pollen en om een antwoordobject vragen. Hoewel dit misschien niet de meest ideale manier is om dit te ontwerpen, kunnen we dit type app uitvoeren met zeer minimale heroku-serverbronnen..
Hier is onze polling-logica hieronder:
if (jsonpost.success == true) then native.setActivityIndicator (true); lokale pogingen = 0 functie retrieveThump (event) als 10 == pogingen dan native.setActivityIndicator (false); timer.cancel (event.source) showError () else local response = lokale r, c, h = http.request url = "http: //"? applicatie naam? ".Heroku.com / dreunen / search? Dreun [DeviceID] ="? apparaat ID? "& Thump [lat] ="? latitudeText? "& Thump [lng] ="? longitudeText, methode = "GET", sink = ltn12.sink.table (response) local jsonget = Json.Decode (table.concat (response, ")) if (jsonget.success == true) then native.setActivityIndicator (false ); timer.cancel (event.source) local alert = native.showAlert ("Thump!", jsonget.message, "OK") eindepogingen = pogingen + 1 timer.performWithDelay (3000, retrievalThump) eindeindtimer. performWithDelay (1000, retrievalThump) else showError () end
Laten we het opsplitsen:
if (jsonpost.success == true) then native.setActivityIndicator (true) ;? else showError () einde
In het geval dat onze "jsonpost" -variabele "success = true" van de server retourneert, zullen we onze ActivityIndicator op het apparaat instellen op waar. Hiermee wordt een native fopspeencomponent gelanceerd die de gebruiker aangeeft dat de app ergens aan werkt. Als we geen "success = true" van de server hebben ontvangen, bellen we onze algemene foutfunctie en geven we het foutwaarschuwingsvak weer.
lokale pogingen = 0 functie retrieveThump (event)? einde timer.performWithDelay (1000, retrievalThump)
In dit geval stellen we een pogingenvariabele buiten het bereik van onze functie in op 0. We zullen dit later gebruiken om een maximum in te stellen voor het aantal verzoeken dat onze pollingfunctie "retrieveThump" kan doen. Corona heeft een ingebouwde timer-klasse waarmee we een functie met een bepaald interval kunnen aanroepen. De timer.performWithDelay-functie heeft een aantal milliseconden en een functie als parameters.
als 10 == pogingen dan native.setActivityIndicator (false); timer.cancel (event.source) showError ()
Eerst zullen we controleren of we deze functie 10 keer hebben uitgevoerd. Als dit het geval is, stoppen we onze ActivityIndicator door deze in te stellen op 'onwaar', annuleren we onze timerfunctie en bellen we onze foutfunctie om de gebruiker te vertellen dat er iets fout is gegaan.
anders lokale respons = lokale r, c, h = http.request url = "http: //"? applicatie naam? ".Heroku.com / dreunen / search? Dreun [DeviceID] ="? apparaat ID? "& Thump [lat] ="? latitudeText? "& Thump [lng] ="? longitudeText, methode = "GET", sink = ltn12.sink.table (response) local jsonget = Json.Decode (table.concat (response, ")) if (jsonget.success == true) then native.setActivityIndicator (false ); timer.cancel (event.source) local alert = native.showAlert ("Thump!", jsonget.message, "OK") einde pogingen = pogingen + 1 timer.performWithDelay (3000, retrievalThump) einde
Als we nog geen 10 pogingen hebben gedaan, gaan we een HTTP-verzoek uitvoeren naar onze server om te zoeken naar onze gematchte 'dreun'. De functie lijkt op de POST-oproep die we eerder hebben gemaakt, alleen geven we de methode GET door in dit geval omdat we proberen te lezen en niet naar de server te schrijven.
Als je je herinnert uit Deel II, hebben we een zoekactie gemaakt in onze Rails-server die onze database doorzoekt voor een overeenkomende dreun op basis van onze GPS-coördinaten en vergelijkbare tijdstempel. We geven deze informatie door aan de server via de querystring in de URL. Net als bij de POST-aanroep analyseren we de retour van de server als een JSON-object en slaan deze op in een lokale lua-tabelvariabele met de naam "jsonget." Als we een succes = waar terug van de server ontvangen, stoppen we onze ActivityIndicator, stoppen we onze uitvoering van de timer en tonen ons bericht in een waarschuwingsvenster. Als dit proces mislukt, zullen we de server simpelweg opnieuw peilen op dezelfde manier voor maximaal 10 pogingen.
En daar heb je het! Deze zelfstudie moet u een goede basis bieden om verschillende soorten apps te maken die gegevens delen via gebaren. Enkele interessante toevoegingen kunnen zijn om te delen via een gelijktijdige schermtip, of om de toepassing uit te breiden om foto's te wisselen die zijn genomen van de camera of de lokale fotobibliotheek van het apparaat. Blije bonzen!