Upload
ngomien
View
222
Download
0
Embed Size (px)
Citation preview
Escreviminhaprimeiralinhadecódigocom14anosem1999,eela foi em HTML. Daí para CSS e JavaScript foi um pulo. Emseguida, aventurei-me em SSI e PHP, incluindo bancos de dados.Em 2003, inicieimeu curso deCiência daComputação naUSP enadei em águasmais profundas desde então— Java, C e Python.Crescibastanteemprogramaçãoback-end.
Maseusemprefuiapaixonadoporfront-end.
Leiomuito,estudomuito,escrevomuitoeprogramomuito—desde que envolva bastanteHTML,CSS e JavaScript. E, de algumtempo para cá, resolvi focar em mobile. Estudo e falo muito deDesignResponsivoedaWebúnicacomoplataformademocráticaeuniversal. Mas sei que há cenários onde Apps podem ser maisinteressantes,daífalardeCordova.
Já trabalhei em algumas empresas, programando em váriaslinguagens (já até ganhei dinheiro com opensource). Desde 2004,trabalho na Caelum como instrutor e desenvolvedor. Foi ondeminhacarreiradecoloueondemaisaprendi,eaprendotododia.Éondepretendopassaraindamuitosemuitosanos.
Ensinareescreversãoumapaixãodesdeocolégio—lembroda
SOBREMIM
12345578
99
101115
181819192123
Sumário
1AplicaçõesmobilecomCordovaePhoneGap1.1Aplicaçõeshíbridas1.2OCordovaeoPhoneGap1.3CordovanãoéWeb1.4AppouWeb1.5Quandonativo,quandohíbrido?1.6AmortedoCordova1.7Olivroeoprojeto
2AprimeiraversãodaApp2.1OprojetoCenourApp2.2Aprimeirafuncionalidade2.3UmaApphíbridaéumapáginaHTML2.4EfeitosnoHTMLcomCSS
3AdobePhoneGapBuild3.1AdiferençaentreCordovaePhoneGap3.2OqueéoPhoneGapBuild3.3UsandoPhoneGapBuild3.4UmaAppAndroidprontapararodar3.5ConfiguraçõesdoPhoneGapBuild
SumárioCasadoCódigo
252627
28282930
323234353738
404142424345
48484950515255
57
3.6ÍconeeSplashscreen3.7RodandoemmodofixonoAndroid3.8IndoalémcomPhoneGapBuild
4PhoneGapApp4.1PhoneGapDesktopApp4.2UmprojetoPhoneGap4.3PhoneGapDeveloperApp
5UmambienterealparatrabalharcomAppshíbridas5.1PorqueusarsóoPhoneGapnãovaitelevarmuitolonge5.2Umambientelocalparrudo5.3SouusuáriodeWindows,nãotenhoumMac!5.4SouusuáriodeMac,nãotenhoumPC!5.5SouusuárioLinux,oquefaço?
6PreparandoCordovaeAndroid6.1Node.js6.2Cordova6.3JavaSDK6.4AndroidSDK6.5Genymotion
7ComeçandoumaAppnoAndroid7.1PreparaçãodoambienteCordovaeAndroid7.2UsandoCordovapelaprimeiravez7.3Plataformas7.4RodandonoAndroid7.5ExecutandonoaparelhoAndroid7.6Gerandoumapkparadistribuição
8MaterialDesign
CasadoCódigoSumário
57596061636466
69697172757777
78787879808282
84848587919091
8.1OdesigndoGoogle8.2AGarçonapp8.3OMaterialize8.4Itensemabas8.5EfeitosdeondasdoMaterialDesign8.6CustomizaçãodovisualdoMaterialize8.7Topocomtítuloeícones
9ComponentesricosnaApp9.1Anotandoopedido9.2FloatingActionButton9.3Modal9.4Maisajustes9.5TestandonoAndroid9.6EoiOS?
10PreparandooambienteparaiOS10.1Xcode10.2ios-simeios-deploy10.3Adicionandocordova-ios10.4TestandoemumdispositivoiOS10.5Emoutrosprojetos10.6EparadistribuiraApp?
11SuporteaoWindowsPhoneeWindowsPlatform11.1PreparandooAmbienteparaWindowsPhone11.2VisualStudioeEmuladores11.3PlataformaWindowsnoCordova11.4RodandopeloVisualStudio11.5AparelhoWindowsPhone11.6EparadistribuiraApp?
SumárioCasadoCódigo
9393949595969698
101
103103104105105107108
110110111113114116
117117118119120121
12Configuraçõesdoprojeto12.1Estruturadoconfig.xml12.2Metadadosdoprojeto12.3Preferências12.4Preferênciasporplataforma12.5Preferênciasespecíficasdeplataforma12.6Íconeesplashscreen12.7Automatizandogeraçãodosíconesesplashscreens12.8Engines
13PluginsnoCordova13.1MaispodercomCordova13.2PhoneGapBarcodeScanner13.3Lendocódigosdebarras13.4IntegrandonaApp13.5Umaboastatusbar13.6Configurandoastatusbar
14Serviçosremotos14.1AAPIdaCozinhapp14.2AjaxnaApp14.3CORSeSameOriginPolicy14.4PluginCordovaWhitelist14.5Intentsenavegações
15ArquiteturadoCordova15.1OquesãoasWebViews15.2UmaAppCordova15.3WebViewcompoderes15.4EstruturadeumprojetoCordova15.5CordovanãoéWeb
CasadoCódigoSumário
121124126
129129131131133136137139140
141141145149151
154154156159163165
167167169170
15.6CaradeApp,jeitodeApp15.7Boaperformanceéessencial15.8RecursosinteressantesdaAPIdoCordova
16IntroduçãoaoIonic16.1SobreoIonic16.2Novoprojeto16.3ArquiteturadaApp16.4Listadebolos16.5Dadosdinâmicos16.6ServiçoREST16.7Testenodeviceouemulador16.8TestandocomIonicView
17SinglePageAppcomIonic17.1Detalhesdoproduto17.2Finalizandoopedido17.3Interfacemelhorcomnovoscomponentes17.4ConfiguraçõesdoCordova
18Cacheeoffline18.1Estratégiasparadadosoffline18.2Salvandodadosnodispositivo18.3SoluçãoOffline-first18.4Outrasimplementaçõesdeoffline18.5Indoalémnooffline
19Testes,debugecompatibilidade19.1TiposdeWebView19.2UsandoCrosswalknoAndroid19.3UsandoWKWebViewnoiOS9
SumárioCasadoCódigo
171172
174175178
181
19.4DebugnoAndroid19.5DebugnoiOS
20Publicaçãonaslojas20.1PublicaçãodaPlayStore20.2PublicaçãonaAppleStore
21Indoalém
CasadoCódigoSumário
CAPÍTULO1
Aopensaremconstruiraplicativosmobile,éimportantepensarem quais plataformas atacar. Android domina o mundo dossmartphonesnomundoe,principalmente,noBrasil.iOSébastanteusado, ainda mais nas classes sociais mais altas, o que rendeusuários de maior poder aquisitivo. Windows Phone é uma boaterceiraopção,emfrancocrescimento.EháaindaBlackBerry,Tizeneoutros.
Comodesenvolveraplicativosparaessemundomobilediverso?
As plataformas nativamente oferecem a possibilidade de criaraplicativos.UsandooAndroid SDK e a linguagem Java, podemosdesenvolverparaosistemadoGoogle.AAppleofereceferramentasparaiOSepermiteusarObjective-CouSwift.NoWindowsPhone,usamos C# e toda suíte de desenvolvimento Microsoft. Cadaplataforma tem sua combinação de linguagem e, principalmente,APIsespecíficas.
A maior parte das plataformas permite usar C++,essencialmentepensandoemjogos.Porém,asAPIseasbibliotecas,mudambastante.Mesmousandoumalinguagemcomum,émuitodifícilescreveraplicaçõesnativasmultiplataforma.
ÉumproblemaquenãoexistenaWeb.Umapáginawebbemconstruída, usando os padrões, émultiplataforma e suporta todos
APLICAÇÕESMOBILECOMCORDOVAEPHONEGAP
1APLICAÇÕESMOBILECOMCORDOVAEPHONEGAP 1
esses cenários com um só código. HTML, CSS e JavaScript sãolinguagens padronizadas com APIs padronizadas que funcionamemtodo lugar.Mas,nãosãoumaApp.Nãosão instaláveis,nãoseintegramaos recursosavançadosdehardware,nãoexpõe recursosdosSDKsnativos.Muitasvezes,éosuficiente,maseseprecisamosdeumaApp?
A solução mais comum atualmente para construção deaplicativosmultiplataforma é oCordova, que é basicamente umamistura. Ele usa o ponto forte da Web de ter linguagenspadronizadas e um ambiente de execução, o navegador, paraconstruir aplicativos. SãoApps instaláveis que você pode publicarnas lojas, e pode usar recursos nativos da plataforma, mas sãoescritasemHTML,CSSeJavaScript.
ChamamosdeaplicaçõeshíbridasporqueusamaslinguagensdaWebparaconstruiraplicativos.
Só escrever HTML, CSS e JS não é suficiente para ter umaplicativono fim.Então,oqueoCordova fazéproverumacascanativa para o nosso aplicativo responsável por subir um browserquefaráaexecuçãodonossocódigo.OpapeldoCordovaéapenascriaressa janeladenavegadorparanós,e fazeracomunicaçãodasnossas chamadas de código para chamadas nativas quandonecessário.
Essa janela de navegador nativo que vai rodar nossoHTML écomumentechamadadeWebView.SevocêprogramaremJavanoAndroidouObjective-CnoiOS,vaiverqueérelativamentesimplescriaresseWebViewparaexecutarumcódigoHTML.Ochato,claro,é fazer issoparadiversasplataformasecuidardasdiferençasentreelas.
1.1APLICAÇÕESHÍBRIDAS
2 1.1APLICAÇÕESHÍBRIDAS
ÉaíqueentraoCordovaepor issoele é tãoútil.Ele faz todoesse trabalho nativo em diversas plataformas para criar umaWebView e chamar nossoHTML.No fim, ele empacota tudo emumaplicativo-tantoapartenativadechamaroWebViewquantotodoonossocódigoHTML,CSSeJSmultiplataforma.Oresultadofinaléumaplicativoespecíficoparacadaplataformaquevocêpodeinstalareoferecernaslojasoficiais.
Falamos bastante do Cordova, mas onde entra o PhoneGapnessa história? Basicamente, o PhoneGap é uma distribuiçãoproprietáriadoCordova.
OPhoneGapfoicriadoem2009pelaempresaNitobi.Em2011,aAdobecomprouaempresamasdooutodoocódigoparaoprojetoApache.Nascia aí oCordova, umprojeto opensource tocadopelaApache.OPhoneGap passou a ser o nomedo produto daAdobeconstruído ao redor do Cordova. A base é o Cordova, mas comalguns serviços adicionais da Adobe que podem ser interessantesdependendodoprojeto.Veremosmaisaolongodolivro.
O ponto é que, se você quer construir aplicações mobilehíbridas, pode usar o gratuito e opensource Cordova semproblemas. É o que faremos na maior parte do livro. Algumasferramentas do PhoneGap podem ser úteis, então é importanteconhecê-lastambém.Masnãosãoestritamentenecessárias.
O Cordova provê a base para uma aplicação híbrida simples.Todos os recursos adicionais e mais avançados são feitos complugins. Há plugins para quase tudo, alguns oficiais da própriaApache ou Adobe, e outros vários feitos por terceiros. No livro,vamosusarváriospluginsemdiferentesmomentos.
1.2OCORDOVAEOPHONEGAP
1.2OCORDOVAEOPHONEGAP 3
Muito do burburinho que se faz em torno das aplicaçõeshíbridaséquesão"omelhordedoismundos"ou"ajunçãodaWebcomnativo".Eudiscordodessetipodepensamento.
Uma aplicaçãohíbrida éuma aplicaçãonormal, apenas escritaemlinguagenscomunsadesenvolvedoresWeb.NãoéWeb. Issoéimportante: Web não é HTML, CSS e JavaScript. Web é umaplataforma universal e aberta de distribuição e navegação deconteúdo.UsamosHTML5naWeb,masWebnãoéHTML5.
Quando usamosCordova, nosso códigoHTML é empacotadojuntoàcascanativaparasetornarumaaplicaçãonormal.Háquemchametambémdepackagedapps.EessasAppssãomaispróximasdeAppsnativasquedaWeb.
Elas têmasmesmasvantagensedeficiênciasdeAppsnormais:precisam ser geradas para cada plataforma, precisam serdisponibilizadas na loja de cada fabricante, e estão submetidas àsregras de cada plataforma. Não são navegáveis, não estão nainternet,enãotêmURLs.
Porém, estão totalmente integradas ao dispositivo. Podem serinstaladas e ser usadas offline. Podem usar APIs da plataforma eusar recursos de hardware avançados. Podem ser divulgados naslojaseservendidasfacilmenteparaosusuários.
1.3CORDOVANÃOÉWEB
4 1.3CORDOVANÃOÉWEB
PROGRESSIVEWEBAPPS
HámuitadiscussãoealgumaimplementaçãojádeWebAppsinstaláveis com maior integração ao SO (como PushNotifications e ServiceWorkers). Ainda é bastante incipiente,sem suporte universal,mas certamente um caminho bastanteinteressanteparaseobservarnofuturopróximo.
A questão é que Apps eWeb são coisas diferentes. Têm seuspontos fortes e pontos fracos.E a decisãodequal caminho seguirnãoétrivial.Aliás,ébastantepossívelquevocêqueiraeprecisedasduascoisas.
AWebfavoreceadescobertadeconteúdodespretensiosamente:não exige instalação e não exige compromisso do usuário. Aomesmo tempo, asApps geram fidelização com seu público e umaexperiênciamaisintegradaàplataformanativa.
Essa discussão é bastante importante e longa. Em meu outrolivro,AWebMobile, tambémdaeditoraCasadoCódigo, tenho3capítulos sobre Estratégia Mobile, Comparativo App e Web e OcenáriodasPackagedApps.Recomendofortementealeiturasevocêestárefletindosobrequalcaminhoseguir.
Aqui,obviamente,seguiremosocaminhodasApps.Masaindaháumaquestão importante:devo fazer aplicativosnativos, ouumhíbridocomCordova?
1.4APPOUWEB
1.5QUANDONATIVO,QUANDOHÍBRIDO?
1.4APPOUWEB 5
A decisão é puramente técnica. Do ponto de vista do seuusuário,nãohádiferença.Umaplicativohíbridobemconstruídoseintegraàplataformadamesmaformaqueumnativo.Hádiferençasde performance apenas em casos muito específicos que exijamrealmente bastante processamento no dispositivo. Nesses casos,escrevanativo.
Nativo é melhor também em Games 3D complicados, ou emaplicações que precisem de multithreading. Não é recomendadotambém para Apps que precisem ficar em background rodandocertosserviços.Sóoambientenativoconsegue fazer issode formarealmenteeficiente,semmatarabateriadousuário.
Como boa parte das Apps não se encaixa nessas categorias,híbridoésuficiente.Eoquepesaemseufavoréomenorcustodedesenvolvimento.Umúnicocódigoservetodasasplataformas.NãoénecessárioterequipesespecíficasprogramandoJavanoAndroideObjective-CnoiOS,porexemplo.Esseéoprincipalargumento.
Outro cenário é que se você já tem uma equipe comconhecimentosdeHTML,CSSeJS,acurvadeaprendizadoparaohíbridoébempequena.Inclusive,épossívelaproveitarmuitacoisaquejáfoifeitanositeWeb,seforocaso.
Agora,pormaisqueoCordovanosdêacessoamuitosrecursosdaplataforma,éclaroqueumaAppnativaéquemtemrealmentetodas as possibilidades a disposição. Se você estiver em umaempresa grande onde diminuir custo de desenvolvimento não éprioridade, onde há equipes especializadas em cada plataforma,podesermaisinteressanteconstruiraplicativosnativos.
Uma preocupação ao desenvolver com Cordova é que asensaçãodaAppnãoéigualadonativo.Nãousamoscomponentesdaplataforma,massimHTMLeCSSparacriarovisual.Emuitasvezes acabamos com um design comum a várias plataformas,
6 1.5QUANDONATIVO,QUANDOHÍBRIDO?
apenascompequenosajustes.Éclaro,umaoportunidadeparacriarum design único para sua App que extrapole o padrão daplataforma.Massevocêqueralgoqueuseoscomponentesnativos,aíémelhorumaAppnativa.
Pensetambémemestratégiasmistas.Vocêpodecomeçarcomuma App híbrida para cobrir rapidamente o maior número deplataformas,edepois ircriandoversõesespecíficasnativasquandonecessário. O Facebook começou assim, todo emHTML5, e hojetemaplicaçõesnativasemváriasplataformas(alémdeumexcelentesitemobile).
Éestranhofalar,emumlivrosobreCordova,queoCordovavaimorrer.Mas esse é umponto bem interessante quemostra o realpapeldoCordovanomundo.Eopontoéqueeletapaumburacoentre o que os browsers normais podem fazer hoje e o queAppsnativasfazem.
Mas os navegadores têm evoluído e chegado cada vez maispróximos de Apps nativas - vide as novas ProgressiveWeb Apps.Nessesentido,oCordovavaificandocadavezmenosimportante,eumdia talvez seja desnecessário.O próprio criador do PhoneGapdisseissonoiníciodoprojeto.
Enquanto escrevo o livro no começo de 2016, os navegadoresestão começando timidamente a suportar ServiceWorkers e PushNotifications na Web, e alguns experimentando com Web Appsinstaláveis. O Firefox com uma loja onde WebApps podem serpublicadas.OWindows10comamesmaideia.Talvez,nofuturo,ocenárioWebsejasuficienteparamuitostiposdeApps.Atélá,temosoCordovaeoPhoneGap.
1.6AMORTEDOCORDOVA
1.6AMORTEDOCORDOVA 7
O livro é bastante prático. Faremos um projeto mobile real,solucionandováriosproblemascomunsquevocêvaipassarnodiaadia.
Este não é um guia de referência. O conteúdo está todoespalhadono livro.Vamos aprendendomais sobre as ferramentasconformeprecisarmosnonossoprojeto.Sevocêprecisaapenasdeuma lista de comandos ou coisa do tipo, é melhor ver adocumentação oficial. Aqui, nosso foco é evoluir o conhecimentoconformeformosnosaprofundandonoprojeto.
VeremososconceitosdoCordova,aarquiteturadaplataforma,diversos plugins úteis e mais. É importante saber que o livro foiescrito no começo de 2016.OCordova está na versão 5.4. Talvezpequenosajustessejamnecessáriossevocêusaroutrasversões.Mastudo deve funcionar por anos da forma que veremos aqui. E eupretendo atualizar o livro sempre que tivermos mudançasimportantes.ConsulteaeditoraCasadoCódigoparasabersevocêestálendoaúltimaedição.
OsiteoficialdoCordovacommuitomaterialé:
http://cordova.apache.org.
Adocumentaçãooficialdaúltimaversãovocêencontraem:
http://cordova.apache.org/docs/en/latest/index.html.
1.7OLIVROEOPROJETO
8 1.7OLIVROEOPROJETO
CAPÍTULO2
FomoschamadosparaajudaratrazeromundomobileparaaSódeCenoura, uma startupde confeitaria especializada embolosdecenouragourmet.Eles ainda funcionamnabasedomenuclássicoempapeledogarçomanotandopedidosnobloquinho.Oserviçodedeliveryéportelefone,tambémgerandopedidosempapel.
Muitacoisadáerradonessecenário.Semprequehámudançadecardápio,éprecisoimprimirtudodenovo.Apromoçãododianãopode ser colocada no cardápio, uma vez que sempremuda, entãoficaemuma lousanocantodo restaurantequepoucagentevê.Ogarçomanotaopedidoepassaparacozinha,quemuitasvezesnão
APRIMEIRAVERSÃODAAPP
2.1OPROJETOCENOURAPP
2APRIMEIRAVERSÃODAAPP 9
entendealetranopedido.Otelefonedodeliveryviveocupadoeosclientes reclamam que não conseguem acompanhar o status dopedido.
Temosderesolvertodosessesproblemas.EumaAppmobileéasoluçãopensada.DaínascenossoprojetoCenourAppquevamosdesenvolver.
NossaestratégiaserádesenvolveraAppporpartes, resolvendoumproblemaporvez.Sãomuitasaspossibilidadesemuitascoisasparafazer,masvamosadotarumaestratégiadedarpequenospassosejácolocá-losemuso.Aolongodolivro,vamosevoluindoaApp.Masaofimdecadacapítulo,temosumaAppfuncionalquejápodeserusadanapráticanoSódeCenoura.
Nossoprimeiropassoébastantemodesto.Opessoaldaboleriaquer resolver o caso de precisar reimprimir o cardápio a cadasemestrequandoasopçõesepreçosmudam.Queremtambémdarumarmais tecnológicoparaosclienteseoferecero cardápio emumaplicativomobile.
Os donos compraram alguns tablets Android baratos queficarão nasmesas dos clientes. Os cardápios já são desenvolvidospor eles no Photoshop. A diferença é que não queremos maisimprimi-los,esimmostraremumaplicativomobilebonito.
Apesar de todos os tablets da loja hoje serem Android, jáqueremos desenvolver uma App híbrida pensando em outrasplataformas.Seoprojetodercerto, eoSódeCenoura crescer, osdonos pensam em comprar iPads bonitos para os clientes e umgrandetablettouchscreencomWindowsparadeixarnaentradadalojacomodemonstraçãodocardápio.
2.2APRIMEIRAFUNCIONALIDADE
10 2.2APRIMEIRAFUNCIONALIDADE
NossaApphíbridaéapenasumcódigoHTML,CSSeJavaScriptempacotado emumaApp instalável noAndroid. Então, podemoscomeçaradesenvolvernossocódigoHTML.
Essaprimeiraversãoébemsimples.RecebemosdoisPNGscomomenu - frente e verso - usado hoje no restaurante. Nossa Appprecisa mostrar essas imagens e dar uma forma simples denavegaçãoparaousuáriotrocardepágina.
Asimagenscomos2menussão<img>simples.Podemosfazeromenu de troca com radio buttons e seus respectivos labels.UmHTMLsimples:
<html><head><metaname="viewport"content="width=device-width,initial-scale=1.0"><linkrel="stylesheet"href="menu.css"></head><body>
<inputtype="radio"name="opcao"id="opcao-bolos"checked><labelfor="opcao-bolos">Bolos</label>
<inputtype="radio"name="opcao"id="opcao-bebidas"><labelfor="opcao-bebidas">Bebidas</label>
<imgsrc="imagens/menu-bolos.png"id="menu-bolos"class="menu">
<imgsrc="imagens/menu-bebidas.png"id="menu-bebidas"class="menu">
</body></html>
Crie esse conteúdo HTML em um arquivo index.html napastadesuaescolha.
2.3UMAAPPHÍBRIDAÉUMAPÁGINAHTML
2.3UMAAPPHÍBRIDAÉUMAPÁGINAHTML 11
VIEWPORT
Repare que usamos a meta tag viewport como nos sitesmobile e responsivos comuns. Para saber mais sobre ofuncionamentodosviewportsnaWeb, consulte o capítulo10domeulivroAWebMobile.
Usando CSS, é possível exibir apenas a imagem que estiverselecionada utilizando seletores avançados do CSS3. Com apseudoclasse:checked, sabemos qual opção está selecionada. Ecom o seletor de irmão adjacentes ~ , selecionamos a fotocorrespondente.Umaformadefazerissoé:
#opcao-bolos:checked~#menu-bebidas,#opcao-bebidas:checked~#menu-bolos{display:none;}
Comessecódigo,seumacertaopçãoestivermarcada,afotodaoutraopçãoficaráescondida.Hámuitasmaneirasde implementaressa funcionalidade.Essa versão simples comCSSnos é suficienteparaaprimeiraversãodaApp.
Aindapodemosmelhorarbastanteoestilo.Aimagemdomenupodeestouraremcertas telasmenores,entãoqueremosconfigurarsua largura máxima. E vamos esconder os input radio, para usarapenasolabelparaescolhadeopção:
input[type=radio]{display:none;}.menu{width:100%;}
Nosso próximo passo é deixar os labels com cara de botões,
12 2.3UMAAPPHÍBRIDAÉUMAPÁGINAHTML
colocarunsíconesbonitoseacertasoutrascoisasdecorativas:
body{background:#3D1A11;font-family:sans-serif;margin:0;text-align:center;}
label{background:center0.5emno-repeat#563429;background-size:4em;color:white;display:block;font-size:75%;padding:4em01em;text-transform:uppercase;}label[for=opcao-bolos]{background-image:url(imagens/icone-bolos.svg);}label[for=opcao-bebidas]{background-image:url(imagens/icone-bebidas.svg);}:checked+label{background-color:#E4876D;}
Por fim, podemos posicionar os botões embaixo na telafixamenteeladoalado:
label{width:50%;
position:fixed;bottom:0;z-index:1;}label[for=opcao-bolos]{left:0;}label[for=opcao-bebidas]{right:0;}
.menu{margin-bottom:100px;
2.3UMAAPPHÍBRIDAÉUMAPÁGINAHTML 13
}
Escrevendo esse HTML e CSS, junto com os arquivos dasimagens, já teremos um projeto funcionando no browser. Vocêpode abrirnonavegador, diminuir a janela e testar como se fosseumdispositivomóvel. Issoajudamuitonodesenvolvimento.Mas,claro,aindanãoéumaApp.Faremosissonocapítuloseguinte.
Figura2.2:Screenshotdastelasdonossoaplicativo
CÓDIGOCOMPLETODOEXEMPLO
Ocódigocompleto,comtodoHTML,CSSeasimagens,vocêencontranoGitHub:
https://github.com/sergiolopes/cenourapp.
14 2.3UMAAPPHÍBRIDAÉUMAPÁGINAHTML
BUGNOANDROIDVELHO
Versões antigas do WebKit não se davam bem com apseudoclasse:checkedeseletoresadjacentes~.Seforoseucaso, existeumhackque resolve esseproblemaqueeudeixeinofinaldesteCSS:
https://github.com/sergiolopes/cenourapp/blob/master/menu.css#L84-L89.
Maisparaafrente,veremoscomoresolvertodososproblemasdecompatibilidadedoAndroidcomoCrosswalk.
Nosso foco será, claro, construir aplicativos com Cordova ePhoneGap.Nãovou focar tantonaparteHTML/CSSdasApps.Orecado importante é que escrevemos HTML, CSS e JavaScriptnormais,quetododesenvolvedorfront-endestácarecadeescrever.Nãohásegredo.
Neste nosso exemplo mesmo, ainda simples, se quisermosadicionar uns efeitos, é só usar CSS. Por exemplo, fazer umatransição entre as duas telas, escorregando da direita para aesquerda.ComCSSTransitions,issoébemsimples.
Edite a parte das imagens e coloque umnovo div ao redordelas, que será responsável por deslizar quando a transiçãoacontecer:
<divclass="container-menus"><imgsrc="imagens/menu-bolos.png"alt="Nossosbolos"id="menu-bolos"class="menu">
2.4EFEITOSNOHTMLCOMCSS
2.4EFEITOSNOHTMLCOMCSS 15
<imgsrc="imagens/menu-bebidas.png"alt="AsBebidas"id="menu-bebidas"class="menu"></div>
EagoraoCSS.OdeslocamentoemsiéfeitocomCSStransform,fazendo um translateX para deslocar horizontalmente. Avantagemdotransform é que ele é rápido, principalmente emmobile,por ser resolvidonaGPUe ter aceleraçãodehardware.Aanimação é feita com a propriedade transition , ondecontrolamostempoetipodeefeito.
Mais alguns ajustes são necessários.Vamos posicionar fora datela a imagem não selecionada, para depois animá-la para dentroquandoselecionar.Paraevitarumscroll lateral,precisamosdeumoverflow-x:hidden.
html,body{overflow-x:hidden;width:100%;}.container-menus{transform:translateX(0);transition:transform300msease;width:200%;}
.container-menus.menu{float:left;width:50%;}
#opcao-bebidas:checked~.container-menus{transform:translateX(-50%);}
16 2.4EFEITOSNOHTMLCOMCSS
PREFIXOSTRANSFORMETRANSITION
Dependendodonavegador,podesernecessárioaindacolocaralguns prefixos nas propriedades. Todos os modernos nãoprecisam,mastalvezvocêprecisefazercoisascomo:
-webkit-transform:translateX(0);-webkit-transition:-webkit-transform300msease;
Implementeessasduasmudançasevejaoefeitosendoaplicado.E pense em muitos outros efeitos possíveis, como, por exemplo,animar os botões. O ponto aqui é entender que tudo aquilo quefazemoscomHTML,CSSe JavaScriptnaWebpodemos fazernasnossasaplicaçõeshíbridastambém.
2.4EFEITOSNOHTMLCOMCSS 17
Veremosumpoucodecadaumdeles,começandopeloBuild.
Quando começarmos a usar Cordova, você verá que umadificuldadebemgrandeéarrumaroambientededesenvolvimento.Há muita coisa para instalar e configurar. Apesar de sermultiplataforma, a arquitetura do Cordova/PhoneGap exije ageração de uma App nativa no final, aquela casca que abre aWebView.
Isso quer dizer que você precisa dos SDKs nativos de cadaplataformaparausarCordova.VocênãoprecisaconhecerJavanemescrevercódigoAndroid,massequiseruminstalávelAndroid(apk)nofinal,vaiprecisarinstalaroAndroidSDK.AmesmacoisaserveparaoiOS,oWindowsPhoneeasdemaisplataformas.
Entraremos nos detalhes dessas configurações nos capítulosseguintes.AúnicacoisachataéquecomeçarcomCordovaémuitocomplicado.FizemosnossoHTMLeCSSnocapítuloanterioresóqueríamos uma Appzinha para vermos no celular. Nada muitocomplexo,mascomCordova,nãodá.
EntraaíoPhoneGapBuild.EsteéumserviçoclouddaAdobeque tem toda a infraestrutura deAndroid, iOS eWindowsPhoneinstalada para você. Isso quer dizer que você só escreve seuHTML/CSS/JS,manda para a nuvem, e recebe de volta umaAppnativaemcadaplataforma-umapknoAndroid,porexemplo.
OBuild é um serviço pago da Adobe, mas com uma camadagratuita.Sevocê temaassinaturadaCreativeCloud, temacesso jáaoplanomáximodoBuild;senão,custaUS$10pormês.Noplano
3.2OQUEÉOPHONEGAPBUILD
3.3USANDOPHONEGAPBUILD
3.2OQUEÉOPHONEGAPBUILD 19
gratuito,temosquasetodasasvantagensdoplanopago,apenasqueasAppsnãopodemsermuitograndeseestamoslimitamosaapenasumaAppprivada-masinfinitasAppspúblicas.
A formamaissimplesdesubirnossocódigoparaoPhoneGapBuildécriarumarquivoZIPcomtodooHTML,CSS,JSeimagensnecessários. O arquivo raiz precisa ser um index.html. Então,abraapastaondevocêcriouoexercíciodocapítuloanteriorefaçaumZIPcomtodoseuconteúdo.
Sepreferir,ocódigodoprimeiroexemploestánomeuGitHubevocêpodeclicardiretoemDownloadZIP:
https://github.com/sergiolopes/cenourapp.
Agora, vamos subir o ZIP no PhoneGap Build. Para nossostestes, o plano gratuito é suficiente. Entre emhttp://build.phonegap.com e crie uma conta Free. Você deveprecisardeumusuárioAdobeID.
Aoentrarnaprimeiravez,eledeixavocêcriarAppspúblicasapartir de repositórios públicos doGitHub, ouApps privadas comrepositório privado ou upload de ZIP. Vamos usar essa últimaopçãodoZIP.MarqueaabaPrivate,ecliqueemUploada.zipfile.SelecioneoarquivoZIPcomnossoprojeto.
Figura3.1:UploaddezipprivadoparaoBuild
20 3.3USANDOPHONEGAPBUILD
Feito o upload, clique para fazer o build. Ele vai demorar umpouco e logo dará a opção de baixar as Apps finais geradas. Porpadrão,AndroideWindowsPhone.
Figura3.2:Apósobuild
SeclicarnoíconedoAndroid,elevaibaixaroapk,umarquivoinstalável do Android. Ou, ainda mais fácil, escaneie o QRcodediretonoaparelhoparabaixar.Ésóinstalar.
SeuaparelhoprecisaestarabertoparainstalaçãodearquivosdeforadaPlayStore.Sevocênuncafezumainstalaçãoforadaloja,vaiprecisarmarcarumaopção.
Vá nas Configurações e em Segurança. Lá, marque a opçãoPermitirInstalaçãodeFontesdesconhecidas.
3.4 UMA APP ANDROID PRONTA PARARODAR
InstalaçãoemumaparelhoAndroid
3.4UMAAPPANDROIDPRONTAPARARODAR 21
Repare que aAppque subimos ganhouumnome e um íconepadrões.ÉporquesubimosapenasoHTML/CSSsimples.AíoBuildgeraessasconfiguraçõespadrões.
Mas podemos inserir esses e outros parâmetros avançados emumXMLdeconfiguraçãodoPhoneGapBuild.Ébemsimples.Umarquivo config.xml na raiz do projeto, mesmo nível doindex.html.ElesegueaestruturadeXMLdoW3CWidgets.
ParacolocarumnomenaApp,umadescriçãoeinformaçõesdoautor,oarquivoseria:
<?xmlversion="1.0"encoding="UTF-8"?><widgetxmlns="http://www.w3.org/ns/widgets"xmlns:gap="http://phonegap.com/ns/1.0"id="org.sergiolopes.cenourapp"version="1.0.0">
<name>SódeCenoura</name>
<description>MenudorestauranteSódeCenoura.</description>
<authorhref="http://sergiolopes.org"email="[email protected]">SérgioLopes</author></widget>
Repare que usamos as tags <name> , <description> e<author>.Tambémreparequenadeclaraçãoda tag<widget>passamosumidúnico-geralmentebaseadononomedodomínioaocontrário-eaversãodaaplicação.
3.5CONFIGURAÇÕESDOPHONEGAPBUILD
SubindoumanovaversãodaAppparaoBuild
3.5CONFIGURAÇÕESDOPHONEGAPBUILD 23
ComoarquivoXMLcriado,bastarecriaroZIPdaaplicaçãoesubir novamente no Build. Lá na nossa App, deve ter um botãoUpdateCodeondevocêmandaumnovoZIP.
Sepreferir,deixeiessecódigoprontoemumabranchseparadanoGitHub.Delá,vocêpodebaixaroZIPdessaversão:
https://github.com/sergiolopes/cenourapp/tree/build-config.
Alémdas opções básicas doXML, é possível configurar váriaspreferências.Porexemplo,travaraorientaçãocom:
<preferencename="orientation"value="portrait"/>
É uma configuração interessante para nossa App já que oformato do menu foi pensado para ser usado apenas no modoretrato.PodemosaindaindicarquenossaAppdeverodaremmodotelacheia,semabarradestatusnotopo.
<preferencename="fullscreen"value="true"/>
Outra opção simples é configurar as permissões da App. Porpadrão, oBuild gera umaApp que pedemuitas permissões, justopensandoemumaAppcommuitascapacidades.ComonossaAppnãoénadaespecialainda,podemosusar:
Preferências
24 3.5CONFIGURAÇÕESDOPHONEGAPBUILD
<preferencename="permissions"value="none"/>
É interessante para não afugentar o usuário com muitaspermissões.
Pensando emAndroid, podemos ainda restringir a versão dosusuários.OBuild por padrão suporta desde oAndroid 2.1, que émuito velho e tem uma WebView bastante bugada. PodemosrestringirparaAndroid4.1esuperiores,quesãoamaiorianoBrasilhoje.BastausaraversãodoSDK(nocaso,16):
<preferencename="android-minSdkVersion"value="16"/>
ReparequeestamoslidandoapenascomAndroidagora,masoBuild tenta gerar iOS eWindows Phone. Podemos restringir issoparafacilitarepedirapenasobuilddoAndroid:
<gap:platformname="android"/>
Umalistacompletadepreferênciasvocêencontraem:
http://docs.build.phonegap.com/en_US/configuring_preferences.md.html.
REINSTALARAPP
Dependendodasmudanças,oBuildpodegerarumapkqueoAndroidrejeitacomoupdate(porcausadeversões,assinaturae outros motivos). Nesses casos, desinstale a versão antigaprimeiroantesdeinstalaranova.
Duas configurações melhoram bastante a experiência dousuário:umbomíconeparaficarnahomedele,eumabelasplash
3.6ÍCONEESPLASHSCREEN
3.6ÍCONEESPLASHSCREEN 25
screenparaaparecerenquantoaAppcarrega.
O ícone deve ser um arquivo PNG quadrado. É possível fazerdiversostamanhospensandoemplataformase telasdiferentes.Ouapenasumarquivorelativamentegrande,queconfiguramoscom:
<iconsrc="icon.png"/>
AsplashscreenétambémumPNGepodeterváriostamanhos.PensandosóemAndroidporenquanto,umarquivode720x1280ésuficiente.Eleéconfiguradocom:
<gap:splashsrc="splash.png"/>
Deixei um projeto com dois arquivos configurados para vocêusaraqui:
https://github.com/sergiolopes/cenourapp/tree/build-config-completo.
Um recurso importante para aplicativos como esse que vãorodarnorestauranteéderestringiroacessodosusuáriosademaisrecursosdoaparelho.QueremosdeixarnossaApprodandoemtelacheia, e impossibilitar o usuário de sair da App e acessar outrascoisasnoaparelho.
ApartirdoAndroid5,émuitofácil fazer isso.Parahabilitarorecurso, vá nas Configurações do aparelho e selecione o menuSegurança.Láparaofinal,entrenaopçãoFixaçãodetela,emarqueparaativar.VocêaindapodemarcarPedirPINantes de desafixar,um recurso interessante para não deixar o usuário sair daApp senãosouberasenhadoaparelho.
AíabrimosanossaAppnoaparelho.Comelaaberta,aperteobotãoRecentesdabarradenavegaçãodoAndroid,aquelebotãode
3.7RODANDOEMMODOFIXONOANDROID
26 3.7RODANDOEMMODOFIXONOANDROID
CAPÍTULO4
O PhoneGap oferece mais um serviço muito útil para testes,principalmente na fase inicial do projeto, onde queremos verrapidamente um protótipo ou uma aplicação simples. É oPhoneGap Developer App. Usar o Build toda hora durante odesenvolvimentonãoémuitoprático,jáquevocêprecisaregerarereinstalaraaplicaçãoacadamudança.
OPhoneGapDeveloperApp é umaApp que você instala noaparelho e linka com o projeto na sua máquina. Eleautomaticamentepuxaaversãomaisrecentedocódigoeabrecomose fosse a App final. Ou seja, você instala uma vez a App doPhoneGap e pode usá-la para carregar e recarregar o código detodasassuasApps.Facilitamuitoodesenvolvimento.
Antes de abrir o código no celular, precisamos instalar oPhoneGapnocomputador.Háduasformasdefazerisso:vialinhadecomandoecomumaaplicaçãoDesktop.Vamosfazeramaisfácil.
OPhoneGapDesktopAppéumaaplicaçãoDesktopquepermitecriarAppsPhoneGapdeformamuitofácil.Elanãopossuitodasasferramentas,masébemsimplesesuficienteparaoqueprecisamosagora.
Enquanto escrevo, ela ainda é beta e disponível sóparaMac e
PHONEGAPAPP
4.1PHONEGAPDESKTOPAPP
28 4PHONEGAPAPP
Windows.BaixediretonoGitHubeinstale:
https://github.com/phonegap/phonegap-app-desktop/releases.
Abraoprogramaecliqueno+paracriarumnovoprojeto.Dêumapasta,umnomeeumpacotequaisquer.
Repareque,nofinal,elesobeumendereçoqueapareceembaixodajanela-umIPnaporta3000.Anoteesseendereço,poiséoquevamosusarparaconectarosaparelhosmóveis.
Abra a pasta onde você mandou gerar o projeto e veja seuconteúdo. Há muitos arquivos e subpastas lá dentro - hooks , platforms , plugins , www . Quando entrarmos emprofundidade no Cordova, discutiremos em detalhes o papel decadaparte.
Por enquanto, o importante para nós é saber que todonosso
4.2UMPROJETOPHONEGAP
4.2UMPROJETOPHONEGAP 29
código vai dentro da pasta www . Todo nosso HTML, CSS,JavaScript e imagens devem ser colocados lá dentro. Inclusive, seabrir a pasta agora, você verá que o PhoneGap gerou já umindex.html e até certas imagens e estilos de uma App simplespadrão-umHelloWorld.
PeguenossocódigoanteriordomenudoSódeCenouraejoguedentrodapastawwwdestenovoprojetoPhoneGap.Sobrescrevaosarquivosquevieramporpadrãocomosnossos,donossoprojeto.
Próximo passo é instalar a PhoneGap Developer App nodispositivo.HáversõesparaAndroid, iOSeWindowsPhone.Ésóbaixar nas lojas oficiais mesmo. Os links você encontra aqui:http://app.phonegap.com.
Instalada a App, abra e veja que ela pede um endereço. É oendereçoqueaDesktopAppnosdeunopassoanterior,entãoé sódigitar lá e apertar Connect. Ele vai baixar o código da nossamáquinaecarregarnoaparelho.Excelenteparatestarrapidamente!
4.3PHONEGAPDEVELOPERAPP
30 4.3PHONEGAPDEVELOPERAPP
Importante
Oaparelhoeocomputadorprecisamestarnamesmaredeparaseencontrarem.
Outradica: vocêpode tocar a tela com3dedospara voltar ahome,outocarcom4dedosparaforçarumreload.
Porfim,esserecursosobeumserviçodelivereloadtambém.Issosignifica que você pode editar seu código e ele será recarregadoautomaticamentenodispositivo.
4.3PHONEGAPDEVELOPERAPP 31
CAPÍTULO5
Usamos os serviços mais famosos do PhoneGap, o Build e aApp. Eles nos ajudaram a testar rapidamente no dispositivo e aganharprodutividadenesse iníciodanossaApp.Mas eles deixamburacos importantesnodia adia, e é issoqueprecisamosdiscutiraqui.
O PhoneGap App ajuda a visualizar a App, porém ele temlimitações. Você não vê a instalação nem carregamento da App(splash screen); seu código é exibido meio que magicamente. Eletambém não tem suporte a todos os plugins. Eles até tentam esuportammuitospluginsoficiaisdoCordovaePhoneGap,masvocêprovavelmente vai acabar usando algum plugin externo algumahora.
Em Apps avançadas, você também acabará precisandocustomizar alguma coisa nativa, como por exemplo, umaconfiguraçãodo iOSnoXCode.Enãovai conseguir rodar issona
UMAMBIENTEREALPARATRABALHARCOMAPPSHÍBRIDAS
5.1PORQUEUSARSÓOPHONEGAPNÃOVAITELEVARMUITOLONGE
PhoneGapAppnãoétãoútilassim
32 5UMAMBIENTEREALPARATRABALHARCOMAPPSHÍBRIDAS
PhoneGapApp.Naprática,nadasubstituiotestedaaplicaçãorealnoaparelhoenosemuladores.
JáoPhoneGapBuildnosajudouaobterumapkparaAndroidcom relativa facilidade. Seria possível até subir nossas chaves dedesenvolvedor e obter o apk final para subir na Play Store. OsistemaAndroid estámuitobemcoberto, na verdade, oproblemasãoasdemaisplataformas.
OBuild até conseguenos dar um arquivoxap doWindowsPhone,masvocênão consegue instalá-lonoaparelhodiretamentepara testar. O aparelho precisa estar registrado e, para isso, vocêprecisadeumamáquinaWindowscomoSDKdoWindowsPhoneinstalado.Ou seja, se você for ter todoo trabalhode configurar oSDK doWindows, pode muito bem fazer seus builds locais, nãoprecisadoPhoneGapBuild.
No iOS, a situação também é estranha.OBuild não conseguegeraroarquivoiap sevocênãosubiras suaschavespessoaisdedesenvolvedor.Épossívelgeraraschaves,subirnoPhoneGapBuilde aí instalar aAppno seudevicepessoalpara testes.Para isso, ouvocêfazumaassinaturadeDeveloperdaApple(US$99anuais),ouprecisadeumMaccomXCode7instalado.
SevocêjátemoMaccomXCode,vocêconseguegeraraschaveslocalmente, exportá-las e depois importá-las no Phonegap Build.Assim,elegeraráoarquivoiapquevocêpodeinstalarnoaparelhousandoiTunes.Mas,sevocêjátemumMac,podesimplesmentedarumPlaynaAppeelaabrenoaparelho,semprecisardacontapagaparatestar(sódepois,parapublicarnaloja).
OPhoneGapBuildnãosubstituioambientelocal
Evocêvaiprecisardeemuladores
5.1PORQUEUSARSÓOPHONEGAPNÃOVAITELEVARMUITOLONGE 33
VMWarenasuamáquina.Tambémébastantecomplicadoenãopermitido,masháguiasporaí.
4. AlugarumMacnanuvem.Várias empresasoferecemMacnocloudevocêpagaporhoradeuso.Soluçãobembarataefácil.Émais lento, claro, mas é uma opção bastante viável,principalmente se seu objetivo for apenas gerar as chaves dedesenvolvimentoumavezparausarnoPhoneGapBuild.
Jávápensandonissodesdeocomeçodoprojeto.Senão,nofim,você não vai conseguir entregar o projeto no iOS. O melhor écomprar um Mac mesmo. Se você estiver em uma empresa, jásoliciteacompranoiníciodoprojeto.
MinhamáquinapessoaléumMac,então,naverdade,eupassopelopróximoproblema:
Você consegue desenvolverAndroid e iOS sem problemas. SeprecisardeWindowsPhone,temosumproblema.VocêprecisadeumamáquinaWindows, e não um qualquer, uma versão Pro, 64bits,emumhardwarecomprocessadorIntelcomsuporteaHyper-V (a maioria dosMacs modernos tem esse tipo de processador).Comofazerentão?
OPhoneGapBuildpermitebuildaraAppnanuvem.Eleajudabastantesevocêquersópublicar.VocêconseguebuildaresubiroarquivonalojaviaWeb,jáassinado.Mas,paradesenvolver,elenãoajuda. Para rodar o arquivo no aparelho real, você precisa deWindows.ForaquevocêtambémprecisadeWindowspararegistrarseuaparelho,customizarcódigonativoerodaroemulador.
Então, você vai precisar comprarumPCou instalarWindows
5.4SOUUSUÁRIODEMAC,NÃOTENHOUMPC!
5.4SOUUSUÁRIODEMAC,NÃOTENHOUMPC! 37
noseuMac.Háduasformasparafazermosisso.
VocêparticionaseuHDeinstalaoWindowsseparadodoMac.Quandoligaramáquina,vocêpodeescolherbootarnoWindowseusá-lo em toda sua plenitude. Esse tipo de setup é tranquilo,gratuito, rápido e suportado tanto pela Apple quanto pelaMicrosoft.VocêsóprecisacomprarumalicençadoWindowsPro,claro.
O ponto ruim é precisar reiniciar a máquina toda hora paratrocardeWindowsparaMac,evice-versa.
Costuma ser a solução mais usada. Tanto Parallels quantoVMWareFusion rodammuito bem. O essencial é que suportamvirtualizaçãoaninhada,parapoderrodaroemuladordoWindowsPhone.
Ambossãoprodutospagosevocêaindaprecisapagaralicençado Windows também. O VirtualBox é uma solução gratuita devirtualizaçãoe suportarábemquase tudo,menosoemulador. Issoporque ele ainda não consegue rodar a virtualização aninhada daformaqueoWindowsPhoneprecisa.Todooresto-buildar,testarno device, publicar na loja, editar código nativo - funciona noVirtualBox.
Basicamente, você só consegue desenvolver para Android. Sequiser iOS, vai precisar de Mac. Se quiser Windows Phone, vaiprecisar de Windows. Veja as duas seções anteriores, pois você
BootCamp
Virtualização
5.5SOUUSUÁRIOLINUX,OQUEFAÇO?
38 5.5SOUUSUÁRIOLINUX,OQUEFAÇO?
precisarásevirarcomOSXeWindows.
5.5SOUUSUÁRIOLINUX,OQUEFAÇO? 39
CAPÍTULO6
Neste capítulo, vamos preparar o ambiente paradesenvolvimentocomCordovae,aprincípio,comAndroid.ComonossaprimeiraAppsóprecisarodaremAndroid,começaremosporele. É um bom jeito de começar tambémpor sermais simples deconfigurardoqueo iOS e oWindowsPhone.Mais para a frente,veremoscomoadicionaressasoutrasplataformas.
AinstalaçãonoWindowsenoMacépraticamenteidêntica.Nosexemplos, usei Windows 8.1, mas o processo deve ser mais oumenos o mesmo desde o Windows 7 até o 10. No Mac, useiYosemite.
Seprecisardeajuda,recomendofortementeofórumdoGUJemhttp://www.guj.com.br.
INSTALANDONOLINUX
SevocêusaLinux, vocêdeve ser capazde instalar tudodestecapítulo também. O processo depende de qual distribuiçãovocê está usando, então é preciso pesquisar um pouco. Emgeral, porém, a ideia é usar o gerenciador de pacotes da suadistribuiçãoeinstalarascoisas.
PREPARANDOCORDOVAEANDROID
40 6PREPARANDOCORDOVAEANDROID
ABRINDOOPROMPTNOWINDOWS
Vamos usar bastante o terminal para desenvolver cordova.Paraabri-lo,vocêpodeiraomenuIniciar e achara categoriaWindows System, onde há o ícone para oCommandPrompt.OutraopçãoéabrirajaneladeexecuçãocomWin+Redigitarcmd.ChamareideTerminal.
ABRINDOOTERMINALNOMAC
NoMac,vocêachaoTerminal emApplications/Utilities.Ou,sepreferir,procureporTerminalnoSpotlight.
OCordovaéumpacotedoNode.jsquevamosinstalarcomsuaferramentadepacotes,chamadanpm.
NoWindows,fecheeabranovamenteoterminal,edigite:
npm-ginstallcordova
No Mac e no Linux, precisamos do sudo para instalarglobalmente,entãofaça:
sudonpm-ginstallcordova
Devedemorarumpoucopara fazera instalaçãocompletaparanós.
6.2CORDOVA
6.3JAVASDK
42 6.2CORDOVA
PrecisamosdoJavaparausaroAndroidSDK.Sevocênãotemcerteza se possui o Java instalado, abra um terminal e rode ocomando:
javac-version
PrecisamosdoJavanaversão1.8.xousuperior.Parainstalá-lo,acesse:
http://www.oracle.com/technetwork/java/javase/downloads/index.html.
Localize opacote JavaPlatform JDK na versão 8 ou superior(não precisa baixar a versão Netbeans). Baixe e siga a instalaçãopadrãocomNext,Next,Finish.
Ao final, abraumnovo terminal e testenovamente:javac-version.
Apesar de ser um projeto híbrido, o Cordova exige asferramentas nativas instaladas paramontar a App final e testá-la.Por isso, vamos precisar do Android SDK que funciona noWindows,MaceLinux.
EntrenositedoAndroidebaixeoSDKparasuaplataforma:
https://developer.android.com/sdk/index.html#Other.
NoWindows,sigaainstalaçãopadrãocomNext,NexteFinish.Nofinal,temaopçãoStartSDKManager,deixe-amarcada.DeveráabriroSDKManagerdoAndroid.Senão,váaomenuIniciareacheoSDKManager.
JáparaMaceLinux,opacotenadamaiséqueumZIPquevocêpode descompactar onde quiser, como a home do seu usuário ou
6.4ANDROIDSDK
6.4ANDROIDSDK 43
Marque as últimas versões do Build-tools, Platform-tools e doSDKPlatform.CliqueemInstall.Elebaixarábastantecoisaeébemdemoradoparainstalar.
Figura6.1:InstalaçãodasferramentasnoAndroidSDKManager
Figura6.2:OpçõesainstalarnoAndroidSDKManager
OúltimopassoéinstalarumemuladordeAndroid.OSDKtrazemuladoresoficiais,maselessãomuitolentos.UmaferramentaquecresceubastantenomercadoéoGenymotion,quepermiterodaroAndroid direto virtualizado no VirtualBox. E ele é muito mais
6.5GENYMOTION
6.5GENYMOTION 45
rápido.
OGenymotionégratuitoparausopessoalevocêpodebaixá-loem:https://www.genymotion.com/.
CliqueemDownloadeselecioneaversãoFree.Vocêvaiprecisarcriarumaconta,masérápido.
NaversãoWindows,vocêtemaopçãodebaixaroGenymotionjá com VirtualBox embutido (ou só Genymotion caso já tenha oVirtualBoxinstalado).Baixeesigaainstalaçãopadrão.
No Mac e Linux, é necessário instalar o VirtualBoxseparadamente. Entre em http://virtualbox.org, baixe o arquivo esiga a instalação padrão. Você talvez precise reiniciar a máquinaapósainstalaçãodoVirtualBoxparaqueoGenymotionoencontre.
Instalado o Genymotion e o VirtualBox, precisamos baixaremuladoresdeversõesespecíficasdoAndroidquenosinteressam.
AbraoGenymotion. Ele pedirá seuusuário e senha, que vocêcriounoSite.Depois,vocêpodeadicionarnovosemuladores.TesteinstalarumtabletcomAndroid5,porexemplo,ououtraversão.
BaixandoemuladornoGenymotion
46 6.5GENYMOTION
Paratestar,cliqueemStartevejaseoemuladorabreefunciona.
Vocêpodeinstalaroutrosemuladorestambém,emmaisversõesetamanhosdetela.
6.5GENYMOTION 47
O Cordova suporta diversas plataformas - Android, iOS,Windows Phone, Blackberry e mais. Por padrão, não suportanenhuma. Criado o projeto, precisamos adicionar suporte àsplataformasquequeremos.
Antes de adicionarmos o Android, nossa plataforma final,vamosusarumaoutra,maissimplesefácildeusar,emuitoútilparatestes.Éaplataformadopróprionavegador.ComonossoprojetoéumHTML, ele pode ser aberto emumnavegador comum.E issoajudamuitonodesenvolvimento.
Abraumterminaleentrenapastadoprojeto.Então,adicioneaplataformabrowsercom:
cdgarconappcordovaplatformaddbrowser
Assim, podemos executar o projeto que tem aquele HTMLsimplesdeHelloWorldnaplataformabrowser.Ébemsimples:
cordovarunbrowser
Ele vai abrir uma nova instância do Google Chrome comalgumas configurações de segurança alteradas, e mostrará a ApppadrãodoCordova,quetemmaisoumenosessacara:
Agora faça um teste: abra o arquivo index.html na pastawww,eeditealgumafrasedoHTML-porexemplo,o<h1>.Então
7.3PLATAFORMAS
50 7.3PLATAFORMAS
rodecordovarunbrowser novamentepara ver amudançanonavegador.
SeoambienteestiverpropriamenteconfiguradoparaAndroid,executar nesta plataforma é tão simples quanto no browser.Primeiro,adicionamosaplataforma:
cordovaplatformaddandroid
E,pararodar:
cordovarunandroid
Issoprovavelmentedeuumerroparavocê.Elereclamaquenãohá dispositivo Android nenhum. Logo, precisamos de umdispositivoAndroidpara rodar, seja realouemulado.VamosusarosemuladoresGenymotionqueinstalamosantes.
Abra o Genymotion e inicie algum emulador. Depois deiniciado,tentenovamente:
cordovarunandroid
Pronto,agoraaAppdeveexecutarnoemulador.
7.4RODANDONOANDROID
7.4RODANDONOANDROID 51
menupodevariarumpoucodeacordocomofabricante,mastodostêmessaopção.
EsseprocessopermiteocontroledoaparelhoviaUSB.Assim,aoplugarocabonoDesktop,oCordova-viaoAndroidSDK-poderodarnossasAppsdiretonoaparelho,semburocracia.
Primeiro, você precisa que o menu Programador ouDesenvolvedorestejahabilitadonasConfiguraçõesdoAndroid.Eleéopenúltimomenu, logo antesdeSobre, e não vemhabilitadoporpadrão.Parahabilitá-lo,váaomenuSobre e localizeoNúmerodaversão.Toque 7 vezesnomenu e elemostraráumamensagemdequeabriuasopçõesdedesenvolvimento.
VolteàsConfiguraçõesdoAndroid.AgoravocêdeveveraopçãoProgramador.
Figura7.4:OpçãoemumMotoXeemumSamsungGalaxyNote
DepuraçãoUSB
7.5EXECUTANDONOAPARELHOANDROID 53
EntrenessaopçãoehabiliteomenuDepuraçãoUSB.ConecteocaboUSBnoDesktopeeledevepedirparaconfirmarachaveúnicadocomputador(marqueaopçãodesemprepermitir).
NOWINDOWS
NoWindows,naprimeiravezquevocêconectaoaparelhoporUSB, ele faz a instalação dos drivers. Esse processo demoraumpouco,maséimportantíssimo,senãooPCnãoreconheceoaparelho.NoMac,issojánãoénecessário.
Na maioria dos aparelhos, a instalação dos drivers éautomáticaquandoplugamosaprimeiravez.Maspodeserquevocê precise instalar os driversmanualmente casooAndroidSDK não consiga conectar no aparelho. Neste caso, baixe odriverdoseufabricantenestalista:
http://developer.android.com/tools/extras/oem-usb.html.
Tudoconfigurado!ParatercertezadequeocelularestáprontopararodarAppsCordovapelalinhadecomando,digitenoterminaladbdevices e ele deve listar seu aparelho com um código dolado.
Todaessaconfiguraçãoénecessáriaapenasnaprimeiravezemcada aparelho. Feito tudo, basta plugar o cabo USB e rodar noterminal:
cordovarunandroid
VocêdeveveraAppdemodoCordovaabrindonoaparelho:
Finalmenteexecutandonoaparelho
54 7.5EXECUTANDONOAPARELHOANDROID
QuandoacabarmosdedesenvolveraApp,vamosquererinstalá-la nos aparelhos das garçonetes do restaurante, e não vamos ficarconectando viaUSB e rodando linha de comando para isso, paracadaaparelho.
Precisamosgerar uma App Android instalável. No Android,issoéumarquivoapkquepodeserdistribuídoparaaspessoaseinstalado em qualquer aparelho. Quando o Cordova executa nonossoaparelhodetestes,naverdadeelegeraesseapk, instalanoaparelhoeabreaApp.
Podemosgeraroapkcom:
cordovabuildandroid
Ele gera um arquivo na pasta platforms/android/build/outputs/apk/android-debug.apk .
7.6GERANDOUMAPKPARADISTRIBUIÇÃO
7.6GERANDOUMAPKPARADISTRIBUIÇÃO 55
Este pode ser instalado nos aparelhos, mas repare que ele é dedebug,oquesignificaqueeleéabertoparadesenvolvedores,ouseja,nãoéoaplicativofinal.
Podemosgeraroapkfinalcom:
cordovabuildandroid--release
Agora ele gera um platforms/android/build/outputs/apk/android-release-
unsigned.apk.Onomeunsigned significa que não está assinadodigitalmente,oquenãoéimportanteagoraparanós.
Vocêpodemandaressearquivopore-mailparaaspessoas,porexemplo,etodomundopodeinstalarnopróprioaparelho.Aúnicaconfiguração necessária é que o aparelho esteja com a opção deFontesDesconhecidashabilitada(nãoprecisadadepuraçãoUSB).
Esseprocessoéodedistribuiçãointernaparapessoasquevocêcontrola.ParadistribuirviaPlayStoreparaomundotodo,vamosprecisar ainda de mais algumas coisas que veremos mais para afrente.
Para agora, já conseguimos instalar nossa App facilmente emtodososaparelhosdoRestaurante.Opróximopassoéimplementaragarconapp.
56 7.6GERANDOUMAPKPARADISTRIBUIÇÃO
CAPÍTULO8
Precisamos implementar a garconapp , a App que asgarçonetesdoSódeCenoura vãousarpara coletar os pedidosdosclientes. É umaAppde uso interno e com foco inicial apenas emAndroid.VamosusaroMaterialDesignparaisso.
EstecapítuloeopróximomostramcomomontarumaAppemHTML. Não mostram nada novo do Cordova em si, apenasHTML e CSS. Sinta-se à vontade para pulá-los se quiser verapenas Cordova estritamente. No final do próximo capítulo,vocêpodebaixarocódigocompletodoHTML/CSSparausarnosexemplosdeCordovaeseguirolivro.
Junto com o lançamento do Android 5 em 2014, o GoogleanunciouumanovalinguagemvisualparaseussistemaseApps.OMaterial Design é um estilo visual flat, mas que usa efeitos esombras sutis para melhorar a experiência. O Google diz que sebaseounopapelecomoelefuncionanomundoreal.
SevocêusoualgumaAppdoGoogle recentemente, jáviuesseestilo.AmaiorpartedasAppsetodooAndroidforamatualizadosaolongodotempo.AténaWeb.
MATERIALDESIGN
8.1ODESIGNDOGOOGLE
8MATERIALDESIGN 57
O primeiro passo é jogar fora o código que o Cordova gerouparanósnoprojetogarconapp,dentrodapastawww. Entrenapasta,eapagueoindex.htmleassubpastasdecss,jseimg.
Agora baixe o Materialize no site oficial(http://materializecss.com), descompacte o ZIP e copie as pastascss,jsefontparadentrodawwwdonossoprojeto.
BaixetambémojQueryemhttp://jquery.com,poisoMaterializeprecisa dele para os componentes avançados. Jogue o arquivojquery.min.jsnapastajs,dentrodewww.
Precisamos tambémdos ícones oficiais doMaterialDesign doGoogle.Eles oferecemuma icon font pelo serviçoGoogleFonts, oqueémuitofácildeusar,masexigequeousuárioestejaonline.Paranós,seriainteressantebaixarosíconesofflineeembuti-losnaApp.Éumpoucotrabalhoso,poisexigecopiaroCSSqueoGoogleindicaaqui:
http://google.github.io/material-design-icons/#icon-font-for-the-web.
Parafacilitar,deixeijápreparadoosíconeseoCSS,em:
https://github.com/sergiolopes/garconapp/tree/master/www/icons.
Ainda dentro da pasta www , crie um novo arquivoindex.html. Ele deve seguir o esqueletopadrãodeumHTML5comviewportmobile,ejáimportandooCSSeoJSdoMaterialize:
<!DOCTYPEhtml><html>
8.3OMATERIALIZE
Asdependências
60 8.3OMATERIALIZE
<head><metaname="viewport"content="width=device-width,initial-scale=1"><metacharset="utf-8"><title>SódeCenouraGarçom</title><linkrel="stylesheet"href="icons/material.css"><linkrel="stylesheet"href="css/materialize.min.css"></head><body>
<scriptsrc="js/jquery.min.js"></script><scriptsrc="js/materialize.min.js"></script></body></html>
PROJETOINICIAL
Se preferir, deixei esse esqueleto com Materialize, jQuery eMaterialIconsjáprontonoGitHub.ÉsóclicaremDownloadZIPepartirdaí.Ésóentrarem
https://github.com/sergiolopes/garconapp.
NossaAppprecisamostrarumaabacomumalistadeopçõesdeBolos eoutracomBebidas.NoMaterialize, as abas são compostaspor2componentes.Háuma lista (ul) de abas com linksparaoconteúdo de cada aba; e há o conteúdo das abas em si, que nadamaiséqueumdivcomcertoid.
Alistadeabastemclassetabs,ecadaabaéumatab:
<ulclass="tabs"><liclass="tab"><ahref="#bolos">Bolos</a></li><liclass="tab"><ahref="#bebidas">Bebidas</a></li></ul>
8.4ITENSEMABAS
8.4ITENSEMABAS 61
RepareemcomohálinksparaIDscom#bolose#bebidas.PrecisamosdefinirdivscomessesIDsparaseremoconteúdodecada aba.E cada abadeve teruma listade itens, que já criaremoscomaclassecollectioneváriositenscomcollection-item:
<divid="bolos"class="section"><divclass="collection"><aclass="collection-item">SódeCenoura</a><aclass="collection-item">ComNutella</a><aclass="collection-item">DeBrigadeiro</a><aclass="collection-item">Açucarado</a></div></div>
<divid="bebidas"class="section"><divclass="collection"><aclass="collection-item">Espresso</a><aclass="collection-item">Capuccino</a><aclass="collection-item">Mocachino</a></div></div>
TesteesseHTMLnonavegadorevocêteráalgocomo:
Figura8.3:Abascomconteúdoemlistas
Aindanãoestamosnospreocupandocomcoresecustomizaçõesdedesign.
Vocêpodeacrescentarmaisitensnasabas,claro,parabatercom
Maisconteúdonasabas
62 8.4ITENSEMABAS
ocardápiocompletoquetínhamosnaprimeiraAppnocomeçodolivro. Uma dica é criar várias collection e separá-las comsubtítulos separadores (use classe container para deixaralinhado).
Porexemplo,aabadebebidaspoderiaser:
<divid="bebidas"class="section"><h6class="container">Cafés</h6><divclass="collection"><aclass="collection-item">Espresso</a><aclass="collection-item">Capuccino</a><aclass="collection-item">Mocachino</a></div>
<h6class="container">Refrigerantes</h6><divclass="collection"><aclass="collection-item">Soda</a><aclass="collection-item">Guaraná</a><aclass="collection-item">Coca</a></div></div>
Figura8.4:Sugestãodemaisitensnasabas
8.5 EFEITOS DE ONDAS DO MATERIAL
8.5EFEITOSDEONDASDOMATERIALDESIGN 63
UmdosefeitosmaisfamososdoMaterialDesignéorippleeffectou waves effect. Nos itens clicáveis, ele faz um efeito circularanimadoaoclicar/tocar.ComMaterialize,ébemfáciladicionaresseefeito.
Usamosaclassewave-effectnoselementos,eelejápõeumefeito padrão. Você pode mudar também o tipo. Por exemplo,wave-lightfazumaondabrancaemvezdeescura.Vejamaisemhttp://materializecss.com/waves.html.
Podemosadicionarnositensdalista.Porexemplo:
<divclass="collection"><aclass="collection-itemwaves-effect">Soda</a><aclass="collection-itemwaves-effect">Guaraná</a><aclass="collection-itemwaves-effect">Coca</a></div>
As corespadrãodoMaterialize seguemumapalheta inspiradanoMaterialDesign,maselaspodemsertrocadas.HámuitascoresjápredefinidasemclassesCSS:
http://materializecss.com/color.html.
Paradeixarositensdalistaempreto,podemosfazer:
<aclass="collection-itemwaves-effectblack-text">ComNutella</a>
Ostítulosdivisoresdascategoriaspoderiamsermarronscom:
<h6class="containerbrown-text">Sucos</h6>
Asabasqueremoscomumlaranjaetextoembranco.Euescolhiuma variação que envolve duas classes para o laranja, yellow
DESIGN
8.6 CUSTOMIZAÇÃO DO VISUAL DOMATERIALIZE
64 8.6CUSTOMIZAÇÃODOVISUALDOMATERIALIZE
darken-4. E já aproveitamos e colocamos o efeito dewaves nasabastambém.
OHTMLdasabaspodesermodificadopara:
<ulclass="tabsyellowdarken-4"><liclass="tab"><ahref="#bolos"class="white-textwaves-effectwaves-light">Bolos</a></li><liclass="tab"><ahref="#bebidas"class="white-textwaves-effectwaves-light">Bebidas</a></li></ul>
Ao testar, você reparará que, nesta versão do Materialize, aslinhas debaixo das abas não mudam de cor para branco. Vamosprecisar de CSS manual para isso. O bom é que aproveitamos econfiguramosalgumasoutrascoisas.
Crie um arquivo css/estilos.css e referencie no HTMLapósomaterialize.css:
<linkrel="stylesheet"href="css/estilos.css">
Paradeixaralinhadasabasembranco,coloquenoCSS:
.tabs.indicator{background-color:white;}
AproveitetambémemudeofundodaAppparaumcinzaclarobemneutro:
body{background-color:#F2F2F2;
CSSpróprio
8.6CUSTOMIZAÇÃODOVISUALDOMATERIALIZE 65
}
Neste ponto, nossa App já tem uma cara bem bonita ecustomizadaparaaSódeCenoura:
OtopodaAppdeveterumabarradenavegaçãocomotítulodaApp e o ícone domenu.O topo com um título à esquerda e umíconeàdireita,alinhadospelocentro,ficaria:
<divclass="valign-wrapperyellowdarken-4white-text"><h5class="titulo">SódeCenoura</h5>
<div><iclass="material-iconswaves-effectwaves-lightwaves-circle">more_vert</i></div></div>
A classe valign-wrapper alinha o título e o íconeverticalmente no centro. A classe material-icons aplica umíconecomnomemore_vertusandoafonteoficialdoGoogle.
Reparequejácolocamosacordefundoedostextosetambémo
8.7TOPOCOMTÍTULOEÍCONES
66 8.7TOPOCOMTÍTULOEÍCONES
efeitodewavesno ícone.E,aindacomaclassewaves-circle, oefeitoécircular,algocomumemíconessoltosnoMaterialDesign.
Serodaragoranonavegador,quasetudojáfunciona.Sóotítuloainda é meio feio e desalinhado. Por isso, colocamos a classetitulo,queénossa,parapoderestilizarnoCSS.
.titulo{font-size:1.3rem;margin-left:5%;margin-right:auto;}
Aorodarnonavegador,temosagora:
MaisumefeitobastantecomumnasAppséotítuloeabarradenavegação (abas) ficarem fixos no topo. E ainda, com MaterialDesign, terem um efeito de profundidade para pareceremsobrepostosaorestantedoconteúdo.
NoHTML,vamoscriarumdivqueenvolvaabarradotopoeasabas.Voudarumaclassetopo-fixoaeleetambémaclassedoMaterializez-depth-2,queadicionaoefeitodeprofundidade.
<divclass="topo-fixoz-depth-1">
Essedivvaienvolverodivcomclassevalign-wrapper,e
Topofixo
8.7TOPOCOMTÍTULOEÍCONES 67
aulcomclassetabs.
NoCSS,nossotopofixoéummeroposition:fixed:
.topo-fixo{position:fixed;top:0;width:100%;z-index:2;}
Porfim,umajustenosconteúdosdasabasparanãoficaremportrásdotopofixo:
.section{padding-top:125px;}
Testenovamentenonavegador.RepareemcomoumHTMLeumCSSsimples jánostrazemumresultadobembacanacomcaradeApp.
OcódigofinaldosexemplosdestecapítulovocêencontranestabranchnoGitHub:
https://github.com/sergiolopes/garconapp/tree/design.
68 8.7TOPOCOMTÍTULOEÍCONES
CAPÍTULO9
Dando seguimento à App do capítulo anterior, precisamosagora implementar as funcionalidades reais da App. Isso envolveummenudenavegação,umalistadeitensselecionados,umajaneladeconfirmaçãoemais.
Paraessasfuncionalidades,vamosusartambémJavaScript,alémdoHTMLedoCSS.
Temos já uma lista de produtos que o cliente pode pedir.Queremos que a garçonete possa tocar nos itens da lista e iradicionandoelementosnopedido.NoMaterialize,podemoscolocarumcontadordeitenscomaclassebadge.Vejaumexemplo:
<aclass="collection-itemwaves-effectblack-text">Guaraná<spanclass="badgebrown-text">2</span></a>
Ou seja, dentro do collection-item, podemos colocar um badge com o número já adicionado. Mas não podemossimplesmente colocar no HTML como vimos anteriormente,precisamos criar dinamicamente esses elementos e irincrementandoconformeagarçonetetoca.
COMPONENTESRICOSNAAPP
9.1ANOTANDOOPEDIDO
9COMPONENTESRICOSNAAPP 69
VamosusarJavaScriptparaessafuncionalidade.Criaremosumeventodeclicknoscollection-item:
$('.collection').on('click','.collection-item',function(){});
Dentrodoevento,precisamoscriarumspan.badge se aindanãoexistirum.Seriaalgocomo:
var$badge=$('.badge',this);if($badge.length===0){$badge=$('<spanclass="badgebrown-text">0</span>').appendTo(this);}
Reparequecomeçacomvalorzero.Aideiaéirincrementandoessevaloracadaclique,algobemsimples:
$badge.text(parseInt($badge.text())+1);
Ocódigocompletoficariaentão:
$('.collection').on('click','.collection-item',function(){
var$badge=$('.badge',this);if($badge.length===0){$badge=$('<spanclass="badgebrown-text">0</span>').appendTo(this);}
$badge.text(parseInt($badge.text())+1);})
Crie um arquivojs/app.js e coloque esse código anterior.Não se esqueça de importar o arquivo no final da página após osoutrosscripts:
<scriptsrc="js/app.js"></script>
Testeclicarnositensdalistaevejaosnúmerosincrementando.
BadgedinâmicacomjQuery
70 9.1ANOTANDOOPEDIDO
TOAST
UmcomponentelegaldoMaterialDesignéaquelabarraescuradenotificaçãoque aparecequandoumaaçãoacontece. Isso échamado deToast. ComMaterialize, é bem fácil de acionarum,bastachamarMaterialize.toast().
NanossaApp,podemosmostrarumtoastnoeventodeclickquefizemosparamostrarqualprodutofoiadicionado:
varnomeProduto=this.firstChild.textContent;Materialize.toast(nomeProduto+'adicionado',1000);
UmpadrãobastantecomumemAppsMaterialDesign é ousodobotãodeaçãoflutuantenocantodireitoinferior.AmaioriadasAppsdopróprioGoogletemumbotãodesses.
Com Materialize, podemos criar um com a classe fixed-action-btn. O botão em si é um btn-floating e você podecontrolartamanho,wavesecorescomonosoutroselementos:
<divclass="fixed-action-btn">
9.2FLOATINGACTIONBUTTON
9.2FLOATINGACTIONBUTTON 71
<ahref="#confirmacao"id="confirmar"class="btn-floatingbtn-largewaves-effectwaves-lightbrown"><iclass="material-icons">done</i></a></div>
Reparequeolinkapontaparaumaseção#confirmacao, queaindanãotemosnaApp.Aideiaécriarummodaldeconfirmação,eesseseráoIDdomodal.
OMaterialize simplifica bastante o uso demodais nas nossasApps,mas ainda temos de fazer certas configurações. Primeiro, énecessáriorealizaraestruturadomodal.
Estanadamaiséqueumdiv comclassemodal quepossuidoisfilhos:umelementocomclassemodal-contenteoutrocommodal-footer.OimportanteéqueusemosoIDqueobotãoestáreferenciando-confirmacaononossocaso.
<divid="confirmacao"class="modalmodal-fixed-footer"><divclass="modal-content">...</div><divclass="modal-footer">...</div></div>
Para o nosso botão realmente acionar o modal, duasconfigurações são importantes. Primeiro, no link que dispara,precisamosadicionaraclassemodal-trigger.Nonosso caso, éno<a>quepossuiaclassebtn-floating.
Agora é preciso inicializar o plugin dos modais no códigoJavaScript.Acrescentenoarquivojs/app.jsainicialização:
$('.modal-trigger').leanModal();
9.3MODAL
72 9.3MODAL
$('.badge').parent().each(function(){texto+=this.firstChild.textContent+':';texto+=this.lastChild.textContent+',';});
$('#resumo').empty().text(texto);});
O rodapé do modal geralmente possui botões de ação. Ocomum é ter uma confirmação e um de cancelar. Vamos criarambos com <button>, mas de tipos diferentes. Usaremos umbtn-flat para o de cancelar, e um btn normal para o deconfirmar.
Dentrodomodal-footer,insiraos2botões:
<buttonclass="btndeep-orangewaves-effectwaves-lightmodal-close">Pedir</button><buttonclass="btn-flatwaves-effectwaves-redmodal-close">Cancelar</button>
Abarradeações
74 9.3MODAL
Repare que, além das classes de efeitos, colocamos também amodal-close.NoMaterialize, isso faz comque o botão feche omodalaoseracionado.
TesteaAppevejaomodalsendoaberto:
Ao clicar no botãoPedir, faremos uma chamada Ajax para oback-enderegistraremosopedido.Vamosimplementarissoemumcapítulomaisàfrente.Porenquanto,obotãonãofaznada.
Podemos acrescentar pequenos ajustes na aplicação paramelhorarseuuso.Porexemplo,limparumcertoprodutocasosejapedidoerrado.Podemosfazerumeventonoprópriobadgeque,seacionado,deveserremovido.ComjQuery:
$('.collection').on('click','.badge',function(){$(this).remove();returnfalse;})
Outro ponto é se a garçonete quiser apagar o pedido todo.Podemos adicionar um botão Limpar que apaga tudo. Em
9.4MAISAJUSTES
9.4MAISAJUSTES 75
JavaScript, isso é simples. Se ele tiver uma classe acao-limpar,podemosfazer:
$('.acao-limpar').on('click',function(){$('#numero-mesa').val('');$('.badge').remove();});
Mas onde colocar tal ação? Podemos usar o menu de açãosecundáriaquecriamosantes-aqueleíconede3pontinhosnotopo.Osubmenuemsinadamaiséqueumalistadeopçõesdentrodeumelementocomclassedropdown-content.
Crie esse menu chamando nossa ação Limpar logo abaixo doíconemore_vert-noHTML,eraumelemento<i>.
<ulid="submenu"class="dropdown-content"><li><aclass="black-textacao-limpar">Limpar</a></li></ul>
Paraosubmenuseracionado,precisamosmodificaro ícone efalar que ele dispara essedropdown. Isso é feito apenas comdataattributesnatagecomumaclasseespecialdropdown-btn.Altereatagdo<i>paraficar:
<iclass="material-iconswaves-effectwaves-lightwaves-circledropdown-button"data-activates="submenu"data-gutter="5"data-constrainwidth="false">more_vert</i>
Figura9.4:DropdowncomcaradeMaterial
Podemos aplicar nossa acao-limpar ao botão Cancelar domodaltambém.Assim,aoclicar,opedidoéreiniciado.
76 9.4MAISAJUSTES
CÓDIGOFINALDAAPP
Deixei o código todo da App disponível neste branch doGitHub:
https://github.com/sergiolopes/garconapp/tree/js.
Lembre-se de que, a qualquer momento, podemos testar nonosso aparelho Android ou no emulador Genymotion apenasrodando:
cordovarunandroid
Uma das garçonetes do Só de Cenoura comprou um novoiPhone, e queria usar a nossa garconapp no seu novo aparelho.Ainda bem que estamos usando Cordova e HTML! Já estamos ameio caminho andado. No próximo capítulo, veremos comoadicionarsuporteaoiOSnonossoprojeto.
9.5TESTANDONOANDROID
9.6EOIOS?
9.5TESTANDONOANDROID 77
CAPÍTULO10
Comovimosnocapítulo5,vocêvaiprecisarrodaroOSX,sejaemumMacreal,umHackintoshoumesmovirtualizadodealgumamaneira. Neste capítulo, vamos preparar o ambiente para criar,buildar, emular e testar no iOS usandoMac.Assumo que você jáconfigurouoCordovacomNode.js,comovimosnocapítulo6.
VocêvaiprecisardeumaAppleID,masprovavelmentevocêjátemuma,vistoque ela é essencialparausarumMac. Senão, crieem:https://appleid.apple.com.
As ferramentas de desenvolvimento da Apple estão todas noguarda-chuvadoXcode.Então,precisamosinstalá-lo.BaixeoXcodenaMacAppStore,ouem:
https://developer.apple.com/xcode/downloads/.
AinstalaçãoépadrãodoOSX,apenasarrastarparaApplications.EntãoabraoXcodepelaprimeiravezparaeleterminarainstalação.
Ocordova-iosusaduas ferramentasNode.js.O ios-simajudaa
PREPARANDOOAMBIENTEPARAIOS
10.1XCODE
10.2IOS-SIMEIOS-DEPLOY
78 10PREPARANDOOAMBIENTEPARAIOS
lidarcomoemulador,eoios-deploypermiterodaraAppemumdispositivoreal.Vamosinstalarambas.
Noterminal,useonpmparainstalarglobalmente:
sudonpm-ginstallios-simios-deploy
Para conseguirmos testar nosso projeto no emulador,precisamos adicionar o cordova-ios no projeto. Vá ao terminal,entre na pasta do garconapp e adicione a plataforma, comofizemoscomoAndroidantes:
cdgarconappcordovaplatformaddios
Feitoestepasso,conseguimosrodarnoemuladorusando:
cordovaemulateios
Se tudo correu bem, ele deve abrir nossa App no emuladorpadrão:
10.3ADICIONANDOCORDOVA-IOS
10.3ADICIONANDOCORDOVA-IOS 79
Paraverquaisemuladoreshádisponíveis,execute:
cordovaemulateios--list
Você pode escolher um deles na hora de rodar, como porexemplo:
cordovaemulateios--targetiPad-Air
INSTALANDOOUTROSEMULADORES
No Xcode, você pode ir em Preferences, aba Downloads, eescolhermais versõesdo iOSpara baixar o emulador.É bemútilparatestaremversõesmaisantigasdoiOStambém.
Para rodar em um dispositivo real, é um pouco maiscomplicado.OiOSnãodeixarodarAppsemmodoinseguro,entãotodas precisam estar assinadas digitalmente em um processo umtanto quanto chato. É importante saber que até noXcode 6.x eranecessário ter uma conta paga daApple de desenvolvimento parageraras chavesparaassinaraApp.NoXcode7, elepermitegerarchaves de desenvolvimento com uma conta normal, e é o quefaremosaqui.
Quando adicionamos a plataforma iOS no Cordova, ele criouum projeto completo no Xcode. Esse projeto fica emgarconapp/platforms/ios/,eéumarquivocomonomedaAppeextensão.xcodeproj.
Abra esse arquivo. Ele deve abrir o projeto na interface doXcode. Clique no nome do projeto no painel da esquerda paramostrarassuasconfigurações.
10.4TESTANDOEMUMDISPOSITIVOIOS
80 10.4TESTANDOEMUMDISPOSITIVOIOS
Figura10.2:VisãodoprojetopeloXcode
Repare no botão dePlay em cima. Você pode escolher algumdos emuladores e rodar imediatamente. Mas isso não é o quequeremos;queremosrodarnodispositivoreal.Paraisso,precisamosadicionarnossacontanoXcodeecriarumProvisioningProfile.
Nestatelamesmodoprojeto,reparequenomeioháopçõesdoprojeto-comoBundleidentifier,Versionetc.AgoranosinteressaaconfiguraçãoTeam. Se você nunca usou o Xcode antes, ele deveestarvazio.CliquenaopçãoeemAddanAccount.SigaospassosparafazerlogincomseuAppleID.
Adicionadasuaconta,eladeveapareceragoranodropdowndeTeam do projeto. Selecione-o. Ele deve reclamar que falta umprovisioning profile para essa App. Clique no botão Fix que elegeraráoscertificadosparavocê.
10.4TESTANDOEMUMDISPOSITIVOIOS 81
ÉbemimportantequevocêestejausandoumBundleidentifierúnico para seu usuário, se não ele vai acusar um erro. Seprecisarmudar,mexano IDdoconfig.xml doCordova egere novamente o projeto doXcode comcordova prepareios.
Setudodercerto,oseuusuáriodeveaparecercomoTeam,enãodeveternenhumwarningembaixo.
Agora, conecte o dispositivo viaUSB e desbloqueie a tela.Naaba superior do botãoPlay, deve aparecer seu aparelho, além dosemuladores.Selecione-oecliqueemPlayparaexecutar.
AAppé então abertano aparelho real e vocêpode testá-ladeverdade.Quandoacabar,bastaapertarobotãoStopnoXcode.
Feita toda essa configuração, você consegue também executaragorapeloCordovanalinhadecomando.Bastaexecutar:
cordovarunios--device
Todavezquecriarumprojeto iOSequisertestarnoaparelho,você vai precisar seguir esses passos. Abrir o projeto no Xcode,selecionaroTeamegeraroProvisioningprofile.
10.5EMOUTROSPROJETOS
10.6EPARADISTRIBUIRAAPP?
82 10.5EMOUTROSPROJETOS
Repare que, com todo esse processo que vimos aqui,conseguimosinstalaraAppemumdispositivoiOSparatestes.Vocêpode instalar emmais deumaparelho repetindooprocedimento,masnãoéalgomuitoconfortável.
OiOSnãopermiteafacilidadedoAndroiddemandarumaAppparaalguémpore-mailequalquerpessoapoderinstalar.
Para distribuir Apps no iOS para todo mundo, precisamospublicá-las naApp Store. Veremos como fazer isso no fim destelivro.
10.6EPARADISTRIBUIRAAPP? 83
CAPÍTULO11
OCordova suporta a criação de aplicativos para a plataformaWindows de várias formas.A partir doWindows 8 e incluindo oWindows 10, odesenvolvimento é unificado para smartphones,tablets e desktop. Ou seja, com uma única plataforma, podemosatacar toda a família de dispositivos Microsoft. É o cenário queveremosaqui.NoCordova,éoWindowsPlatform.
Como vimos no capítulo 5, você vai precisar rodar umWindows, seja emumamáquina real ou virtualizado.Odetalhe éque,sequiserrodaroemulador,vocêprecisateroWindowsProouEnterprise na versão 64bits. E o processador da sua máquinaprecisa ser um Intel com suporte Hyper-V. A maioria dosprocessadoresmodernossuporta(i5,i7).
SevocêprecisardeumWindows,háumtrialde90diasgratuitodaversãoEnterpriseem:
https://www.microsoft.com/en-us/evalcenter/evaluate-windows-10-enterprise.
SUPORTEAOWINDOWSPHONEEWINDOWSPLATFORM
11.1 PREPARANDO O AMBIENTE PARAWINDOWSPHONE
84 11SUPORTEAOWINDOWSPHONEEWINDOWSPLATFORM
PararodaroemuladordoWindowsPhone,osuporteaHyper-VprecisaestarhabilitadonoseuWindows.
Para isso, vá ao Painel de Controle e entre na categoriaProgramas.Lá, selecioneaopçãoAtivaroudesativar recursosdoWindows(TurnWindowsfeaturesonoroff).
LocalizeocheckboxdoHyper-Vemarqueaopção.Énecessárioreiniciarapósessaconfiguração.
Você vai precisar de toda a plataforma Visual Studio daMicrosoftquejáincluiosemuladoresnecessários.
VocêpodebaixarumaversãogratuitamaissimpleschamadadeVisual Studio Community. É suficiente para nós. Baixe a versão2015em:
https://www.visualstudio.com/products/visual-studio-
HabilitandoHyper-V
11.2VISUALSTUDIOEEMULADORES
11.2VISUALSTUDIOEEMULADORES 85
community-vs.
Rode o instalador e selecione Custom Installation paraselecionarmaiscomponentes.Estamosinteressadosnosemuladoresmobile.MarqueUniversalWindowsAppDevelopment eWindowsPhone8.1.
Façaoprocessodeinstalaçãotodo.Eleébemlongoedemorado,e inclui muitos downloads. No final, você deve ter no seu menuIniciaroVisualStudioeWindowsPhoneTools.
Abra o Visual Studio pela primeira vez e faça login com suacontaMicrosoft.
86 11.2VISUALSTUDIOEEMULADORES
ParaadicionaraplataformaportáveldoWindows8/10,faça:
cordovaplatformaddwindows
O interessante é que o desenvolvimento é portável a ponto devocê conseguir rodar uma App Cordova direto no WindowsDesktop.Bastafazer:
cordovarunwindows
A primeira vez que você rodar esse comando, ele pedirá umasériedeconfirmações.Emumajanela,elevaipedirparacolocarocomputador emModo Desenvolvedor. Em outra, pede para obterlicençasdedesenvolvedor.Ésóseguirasopçõese irconfirmando.Nofim,aAppabrenoDesktopmesmocomoumaAppnormal.
Mas claro que queremos rodar no emulador para simular umaparelhorealcomWindowsPhone.Parafazerisso,execute:
cordovarunwindows----phone
OemuladordoWindowsPhonevaiabrire executaraApp.Aprimeiravezdemoraumpoucoparasubir,masvocêpodedeixá-loabertoesóexecutarocomandodenovopararodarnovamente.
11.3PLATAFORMAWINDOWSNOCORDOVA
11.3PLATAFORMAWINDOWSNOCORDOVA 87
Quandoadicionamosaplataformawindows noCordova, elegeraumprojeto válidodoVisual Studio. Basta entrarnapastadoprojeto e ir em platforms\windows. Lá tem um arquivo comnomedoprojetodotipoVisualStudioSolution (extensão.sln).SóclicareoVisualStudioseráaberto.
Sequiser,podecustomizararquivoseconfiguraçõesespecíficasdoWindows peloVisual Studio, ou rodar o emulador por aí.Notopodajanela,háumbotãodePlayondevocêescolheodestinodaexecução. Pode selecionar um emulador, a máquina local ou umdispositivo.
11.4RODANDOPELOVISUALSTUDIO
88 11.3PLATAFORMAWINDOWSNOCORDOVA
Repare que, na direita, há o Solution Explorer que lista osprojetos da nossa App. E o Cordova gerou um projetoWindowsPhone, outroWindows 10 etc. Você pode clicar em cada projetocom o botão direito e escolher Set as Startup Project para definirqualéopadrão.
Comoestamospreocupadoscommobile,selecioneoprojetodoWindowsPhone.Reparequeomenudedebugmudaparamostrarosemuladoresdisponíveis.
Comovimos,podemosentãoexecutaraApptantopelalinhadecomando com Cordova quanto com Visual Studio. Rodar peloVisual Studio tem a vantagem do modo debug e permitirinspecionaroselementosdaApp,muitoútilparadesenvolvimento.
11.3PLATAFORMAWINDOWSNOCORDOVA 89
Para usar um dispositivo com Windows Phone real, sãonecessárias algumas configurações adicionais, tanto no aparelhoquanto no PC. Eu usei um Lumia 520 comWindows 8.1 para otutorialaseguir.
Oaparelhoprecisa ser registradonaMicrosoftparapermitir ainstalaçãodeAppsdetestes.ComumacontagratuitadaMicrosoft,conseguimos registrar 1 aparelho. Para registrar mais aparelhos epublicarnaloja,vocêprecisarádeumacontapaga.
Quando instalamos o Visual Studio e o SDK do WindowsPhone, veio junto uma ferramenta chamada Windows PhoneDeveloperRegistration.VocêaencontranomenuIniciar.
Conecte o aparelho via USB, desbloqueie a tela, e abra aferramenta. Ele deve identificar seu aparelho e dar a opção deRegister.
11.5APARELHOWINDOWSPHONE
Registraroaparelho(WindowsPhone8.1)
90 11.5APARELHOWINDOWSPHONE
Clique emRegister. Ele vai pedir seu usuárioMicrosoft e logoregistraroaparelho.
Saiba mais em https://msdn.microsoft.com/en-us/library/windows/apps/dn614128.aspx.
SeseucelularjárodaWindows10,nãoéprecisomaisregistrá-lo.VánasConfigurações e emAtualização&Segurança. Lá existeuma opção Para Desenvolvedores, na qual você pode habilitar oModoDesenvolvedor.
Para saber mais, acesse https://msdn.microsoft.com/en-us/library/windows/apps/dn706236.aspx.
Ao abrir o projeto no Visual Studio, como fizemos antes, obotãodePlayláemcimamostraaopçãoDevice.Cliquepararodar.
AlémderodarpeloVisualStudio,vocêpoderodarpelalinhadecomandocomCordovatambém.Bastaexecutar:
cordovarunwindows--device----phone
O que vimos aqui é útil para desenvolvedores testarem suasApps.MassevocêquiserdistribuiraAppparaoutraspessoas,nãoé
DeveloperMode(WindowsMobile10)
RodandopeloVisualStudio
RodandoviaCordova
11.6EPARADISTRIBUIRAAPP?
11.4RODANDOPELOVISUALSTUDIO 91
tãoprático.Omaisprático,claro,épublicarnaWindowsStore.
Umprocesso intermediárioégerarum instalável edistribuí-lonos dispositivos. Não é tão simples quanto o Android, mas pelomenosexisteumapossibilidade(diferentedoiOS).
Primeiro,gereobuildfinaldaApp,umarquivo.appx,com:
cordovabuildwindows--release
Ele vai gerar um arquivo appx na pasta platforms\windows\AppPackages\GarconappTest . Podemosinstalá-lonoaparelhocomoutraferramentaquefoiinstaladajuntocomo SDK, aWindows PhoneApplicationDeployment.Antes,esteja certo de ter destravado o dispositivo como fizemos antes.Assim, abra essa ferramenta, selecioneo arquivo.appx e cliqueemDeploy.
92 11.6EPARADISTRIBUIRAAPP?
CAPÍTULO12
Quando você testar nossa App nos emuladores ou nosdispositivos,veráquenãotemosumíconebonito,nemumasplashscreenenemonomedaApp.Nocapítulo3,discutimosoarquivoconfig.xmlecomoconfigurarváriasdessascoisas.
O Cordova também usa um config.xml , mas ele éligeiramente diferente da versão do PhoneGap. Vamos ver comofazernoCordova.
Primeiro,a localizaçãodoarquivoquemuda.NoCordova,porpadrão,eleficanaraizdoprojeto.Sepreferir,podecolocardentrodewww/comonoPhoneGap,queeletambémsuporta.
Quando geramos o projeto, o Cordova gerou um arquivopadrão cheio de pré-configurações. Vamos aprender a configurarnossoprojetoagora.Entãoapagueoconfig.xmlgerado.
AprópriadeclaraçãodoarquivomudaumpoucoporconterumnamespacedoCordova:
<?xmlversion='1.0'encoding='utf-8'?><widgetid="org.sergiolopes.garconapp"version="0.0.1"xmlns="http://www.w3.org/ns/widgets"
CONFIGURAÇÕESDOPROJETO
12.1ESTRUTURADOCONFIG.XML
12CONFIGURAÇÕESDOPROJETO 93
<contentsrc="minha-app.html"/>
Assim como no PhoneGap, podemos usar várias tags<preference> para habilitar e desligar certos comportamentos.Porexemplo:
<preferencename="Orientation"value="portrait"/><preferencename="Fullscreen"value="true"/>
Conseguimos travar a orientação da App em portrait oulandscape.JáaopçãoFullscreenescondeabarradestatusnotopoedeixaemtelacheia(padrãofalse).
Podemos também mudar a cor de fundo padrão da App.UsamosBackgroundColor que recebeumvalorhexadecimal emRGBA. Cuidado, ele recebemais 2 dígitos que o normal naWebparaindicarocanalAlpha.UseFFparacoresopacas.
<preferencename="BackgroundColor"value="0xF2F2F2FF"/>
OutraspreferênciascontrolammaispequenosdetalhesdaApp.A DisallowOverscroll , por exemplo, impede no iOS e noAndroidqueoscrollestoureos limitesdaApp-porpadrão,vocêvairepararqueeledeixaaAppserscrolladaparaforaedepoisvolta.
<preferencename="DisallowOverscroll"value="true"/>
Vejaoutraspreferênciasglobaisnadocumentação:
https://cordova.apache.org/docs/en/dev/config_ref/index.html
É possívelmudar as preferências tambémpor plataforma. Porexemplo, para deixar a App em tela cheia apenas no Android,faríamos:
12.3PREFERÊNCIAS
12.4PREFERÊNCIASPORPLATAFORMA
12.3PREFERÊNCIAS 95
<platformname="android"><preferencename="Fullscreen"value="true"/></platform>
OuparadesabilitarooverscrollapenasnoiOS:
<platformname="ios"><preferencename="DisallowOverscroll"value="true"/></platform>
Algumaspreferênciassãoespecíficasdeplataformaepermitemconfigurar detalhes bem particulares de cada uma. No iOS, porexemplo,temosaTopActivityIndicator,quepermiteconfiguraracor(white,gray,whiteLarge)daquelespinnerqueaparecenabarradestatusquandoháatividadederede.
Muitas outras preferências podem ser mudadas no iOS. Vejamaisem:
http://cordova.apache.org/docs/en/dev/guide/platforms/ios/config.html
NoAndroid,émesmacoisa;hámaisummontedepreferênciasespecíficas.Porexemplo,podemoscontrolarquantotempoasplashscreen deve aparecer com SplashScreenDelay (o padrão é 3segundos).
VocêpodeconsultarasmuitasoutraspreferênciasconfiguráveisnoAndroidem:
http://cordova.apache.org/docs/en/dev/guide/platforms/android/config.html
12.5 PREFERÊNCIAS ESPECÍFICAS DEPLATAFORMA
12.6ÍCONEESPLASHSCREEN
96 12.5PREFERÊNCIASESPECÍFICASDEPLATAFORMA
OíconedeumaAppémuitoimportante.Eleéusadonahomedousuário,nalojadaplataformaeemváriosoutroslugares.TodaAppprecisadeumícone.Senãoindicamosum,oCordovausaumpadrãodele.
Outro conceito importante emApps é a telade carregamento,chamadadesplashscreen.ÉumaimagemdetelacheiaqueapareceenquantoaAppestácarregando,paraousuárionãoficarcomatelaem branco. Toda App precisa de uma splash screen. E aquitambémoCordovacolocaumapadrãocasonãoespecifiquemos.
Mas como colocarnossopróprio ícone e splash screen?Parecebemsimples.SócriarosarquivosPNGeapontarnoconfig.xml:
<iconsrc="resources/icon.png"/><splashsrc="resources/splash.png"/>
Notequeuseiapastaresources.Podiaserqualqueruma,masesseéumnomebastanteusual.Percebatambémqueessecaminhoérelativoàraizdoprojeto,nãoàpastawww.
Oquepareceum simplesXMLdeduasna linhasnapráticaémuito mais complicado. Como existem muitos aparelhosdiferentes,comtelaseresoluçõesdiferentes,precisamosdearquivosespecíficosparacadatipo.Esãomuitaspossibilidades.
Enquanto escrevo o livro, só para o iOS, precisamos de 16tamanhosdiferentes do ícone. Omenor em 40 x 40 pixels até omaiorem180x180pixels-emais14tamanhosintermediários.NoAndroid, são muitos mais, e é assim também para as outrasplataformas.
Na splash screen, é mesma coisa. Há dezenas de tamanhosdiferentes e, pior, tudo em versão retrato e paisagem (já que oarquivonãoéquadrado).
Sevocêtiverpaciênciaparaexportartodasessasimagens,ainda
12.6ÍCONEESPLASHSCREEN 97
vai precisar configurar o XML. Só os primeiros 5 ícones do iOSficariam:
<iconsrc="resources/ios/[email protected]"width="180"height="180"/><iconsrc="resources/ios/icon-60.png"width="60"height="60"/><iconsrc="resources/ios/[email protected]"width="120"height="120"/><iconsrc="resources/ios/icon-76.png"width="76"height="76"/><iconsrc="resources/ios/[email protected]"width="152"height="152"/>
Está curioso? 180 é para o iPhone 6 Plus, 60 é para o iPhonenormale120oderetina.Aí76paraoiPadnormale152paraoiPadretina.EissosóparaoiOS7emdiante.SequisersuportariOS6eoutros, você precisará de mais um monte. Ou seja, é insanogerenciarosíconesdeumaAppCordovanamão.
Queremos uma ferramenta que, a partir de um arquivoprincipal, gere todos os tamanhos de ícones e splash screensnecessários. E, importantíssimo, gere a configuração noconfig.xml.
ExistemváriosprojetosnoGitHubcomessepropósito.Euvouusar o Ionic para isso.Vamos falarmais do Ionic no livromais àfrente.EleéumframeworkcommuitasferramentaseserviçosúteisparaAppsCordova.Porhora,vamosusarumpequenoserviçoqueeleoferece:ageraçãodosíconesesplashscreens.
OIonicébaseadononode.jsedistribuídovianpm,assimcomoCordova.Precisamosinstalá-loprimeiro.Abraoterminalefaça:
npm-ginstallionic
12.7 AUTOMATIZANDO GERAÇÃO DOSÍCONESESPLASHSCREENS
InstalaçãodoIonic
98 12.7AUTOMATIZANDOGERAÇÃODOSÍCONESESPLASHSCREENS
Lembre-sedequenoMacenoLinux,vocêprecisarádosudonafrentedocomando.
OIonicesperaquevocêcriedoisarquivosnoprojeto:
resources/icon.pngresources/splash.png
Elesserãoabasepararodarageraçãodosdemaistamanhos.Porisso,devemserarquivosbemgrandes,poisserãoredimensionados.
Oicon.png deve ser quadrado e seu desenho deve ocupartoda a área útil.O tamanho recomendado é de 1024 x 1024px oumaior.Nãoadicione efeito algum,pois cadaplataformaaplica seuefeito. As bordas redondas no iOS, por exemplo, são feitas pelaplataforma;oíconedeveserquadrado.
Já osplash.png também deve ser quadrado e bem grande.Recomendo 4096px, mas o desenho é diferente. A ideia é usaralgumailustraçãocentralizadaelongedasbordas.Nofim,oarquivoserácortadoparaencaixaremcadaplataforma.
Eu preparei os 2 arquivos base para o Só de Cenoura, e vocêpodebaixá-losnestapastadoGitHub:
https://github.com/sergiolopes/garconapp/tree/config/resources.
Umavezcriadososdoisarquivosnapastaresources-ecomosnomesicon.pngesplash.png -, basta rodar o Ionic.Bem
Preparandoosarquivos
ExecutandooIonicResources
12.7AUTOMATIZANDOGERAÇÃODOSÍCONESESPLASHSCREENS 99
simples.
Abraumterminal,entrenapastadoprojetoerode:
ionicresources
Elegerarátodososíconesnecessáriosparacadaplataformaqueestivermos usando. E ainda vai atualizar o config.xml
apropriadamente.
Sevocêquiserbaixaroprojetojácomosíconesgeradosetudoconfigurado,deixei-osemumabranchseparadanoGitHub:
https://github.com/sergiolopes/garconapp/tree/iconesgen.
SUPORTEAOWINDOWSPLATFORM
Enquanto escrevo o livro no começo de 2016, o IonicResourcesaindanãosuportaaplataformaWindows,só iOSeAndroid. Então, gerei os arquivos necessários e coloquei oXMLcorrespondentemanualmente.VocêpodebaixarnolinkanteriordoGitHub.
Existem mais algumas opções e configurações possíveis.Consulteadocumentação:
http://ionicframework.com/docs/cli/icon-splashscreen.html.
Umaquepodeserinteressante,dependendodoprojeto,égerarícones diferentes para cada plataforma. Basta criar uma subpastacom o nome da plataforma e o arquivo icon.png (ousplash.png).
MaisIonicResources
100 12.7AUTOMATIZANDOGERAÇÃODOSÍCONESESPLASHSCREENS
resources/android/icon.pngresources/ios/icon.png
Aorodarionicresourcesnovamente,elevaigeraríconesdetodos os tamanhos, mas usando uma base diferente para cadaplataforma.
TodoprojetoCordovapossuidiversaspastas importantes.Nóstrabalhamosbastantecomawww e comoconfig.xml,masháoutrascomoaplatforms,quepossuioscódigoseprojetosnativosdecadaplataformaqueadicionamos.
Essa pasta platforms inclusive é bem grande e é geradaautomaticamente pelo Cordova quando adicionamos algumaplataforma.Podemosatémexernoscódigosnativos,masevitamosisso.Muitagentenãogostademandaressemontedecódigogeradoparaorepositóriodoprojeto,poisficacomsujeirademais.
Uma opção, então, é não commitar essa pasta - adicionar no .gitignore , por exemplo. Mas e quando uma pessoa novaprecisar do projeto, como ela sabe quais plataformas estamosusandoesuportando?
Pararesolverisso,vocêpodeadicionarnoconfig.xml:
<enginename="android"/>
Aengineéumaplataformaemuso.Quandoalguémbaixaroprojeto,aprimeiravezquerodarcordovaprepare,aplataformaindicadaserábaixadaegeradaautomaticamente.
Podemos colocar várias plataformas e até indicar qual versãodeveserusadaexatamente:
<enginename="android"spec="5.0.0"/><enginename="ios"spec="4.0.1"/>
12.8ENGINES
12.8ENGINES 101
Se você já instalou as plataformas como fizemosnos capítulosanteriores,usandonoterminalcordovaplatformaddandroid,ele não gerou esses XMLs. Porém, é fácil colocá-los agora, bastarodar:
cordovaplatformsave
Enaspróximasvezesqueadicionarumaplataformanova,vocêtambémpodefazer:
cordovaplatformaddandroid--save
102 12.8ENGINES
CAPÍTULO13
Odono do SódeCenoura teve uma ideia genial para facilitarainda mais o trabalho das garçonetes que vão usar a App paraanotarpedidos.Emvezdedigitaronúmerodamesaacadapedido,elecoloupequenasetiquetascomqrcodesnasmesas indicandoseunúmero.
Comisso,bastaagarçoneteapontaracâmeraparaoqrcode,eonúmero damesa será preenchido automaticamente.Quer dizer, éissoqueelequer,entãoénossotrabalhoagorafazeraAppescanearqrcodes.
Até o momento, se for pensar bem, nossa App é apenas umHTML, CSS e JS normal. Podia muito bem ser umaWebApp. AúnicacoisaqueoCordovanosdeuatéagorafoioempacotamentonativoeapossibilidadede instalarcomoumaAppnormal.MasoCordovapermitemuitomaisdoqueisso.
A grande vantagem do Cordova é permitir expor recursosnativosdoaparelhoedaplataformaparanossocódigo JavaScript.Isso quer dizer acessar funcionalidades que não estão disponíveisparapáginasWebcomuns,masapenasparaAppsnativas.
Isso é feito com a adição de plugins. Há centenas de pluginsdiferentesnomercado,algunsoficiaisdoCordova,outrosoficiaisda
PLUGINSNOCORDOVA
13.1MAISPODERCOMCORDOVA
13PLUGINSNOCORDOVA 103
Adobe e muitos outros da comunidade. Com eles, conseguimosacessar todos os sensores do aparelho - GPS, giroscópio,acelerômetroetc.-,obterinformaçõesdosistema-níveldebateria,sinalde rede -, integrarcomdadosnativos - comooscontatosdousuário-eacessarhardware-câmera,cartãodememória,bluetoothetc. E muito mais, na verdade. E, claro, existe um plugin paraleituradeqrcodes.
A Adobe tem um plugin para leitura de códigos diversos,incluindo qrcodes, códigos de barra e outros vários. Ele éopensourceevocêencontracódigoedocumentaçãoaqui:
https://github.com/phonegap/phonegap-plugin-barcodescanner.
Como adicionar esse plugin no Cordova? Pela linha decomando,ébemsimples:
cordovapluginaddphonegap-plugin-barcodescanner
Ele vai baixar e instalar o plugin em todas as plataformas queestivermos usando. Você pode até olhar na pasta plugins doprojetoeoveráinstaladolá.
Tambémpodemosindicaressepluginnoconfig.xmleevitarcommitar a pasta plugins no repositório. Basta usar a tagplugins que recebe qual versão queremos ou asteriscos paraindicaraúltima:
<pluginname="phonegap-plugin-barcodescanner"spec="*"/>
Desta forma, a próxima vez que rodarmos o Cordova, ele vaibaixareconfiguraropluginnasplataformasexistentesnoprojeto.
Outra opção é instalar e configurar oXML aomesmo tempo,
13.2PHONEGAPBARCODESCANNER
104 13.2PHONEGAPBARCODESCANNER
com:
cordovapluginaddphonegap-plugin-barcodescanner--save
OpluginofereceumaAPI JavaScriptbastante simplespara lercódigos de barra. Basta chamarcordova.plugins.barcodeScanner.scan e passar um callbackparareceberoresultado.
cordova.plugins.barcodeScanner.scan(function(resultado){alert(resultado.text);});
AsAPIsdoCordovaficampenduradasnesseobjetocordovaglobal,ondesãocarregadosospluginsquevamos instalando.Esseplugin de qrcode em particular tem uma função scan bemsimples.
Mas claroquenãovamos só chamaro código assimepronto.Precisamos colocar um botão na interface e tratar o retorno,inserindoovalornoformulário.
VamosprimeiroadicionarumbotãonanossaAppparadispararo leitor de qrcodes. Crie um novo ícone no topo da App para acâmera.
<iclass="material-iconswaves-effectwaves-lightwaves-circlescan-qrcode">camera</i>
Coloque dentro do div do cabeçalho, logo antes do outroícone <i> que já temos lá. Repare que usamos as classes doMaterializeparaoíconeficarbonito,ecolocamosumaclassenossachamadascan-qrcode.
13.3LENDOCÓDIGOSDEBARRAS
13.4INTEGRANDONAAPP
13.3LENDOCÓDIGOSDEBARRAS 105
Abra o arquivo app.js que tínhamos criado e vamosimplementar a funcionalidade com jQuery. Quando o usuárioacionar o botão do ícone, disparamos o código do barcodeScanner.Apósescanear,pegamosovaloreinserimosnocampodoformulário(#numero-mesa),alémdemostrarumToastsimplesdeconfirmação.
$('.scan-qrcode').on('click',function(){cordova.plugins.barcodeScanner.scan(function(resultado){if(resultado.text){Materialize.toast('Mesa'+resultado.text,2000);$('#numero-mesa').val(resultado.text);}},function(error){Materialize.toast('Erro:'+error,3000,'red-text');});});
Sevocêtestaragora,vairepararquenãofunciona.Elereclamaquenãoencontraoobjetocordova, justoaquelequedeverianosdaracessoaoplugin.Oproblemaéquefaltouimportaroarquivocordova.js,queéquemfazapontecomocódigonativo.
Bastaimportaroscriptnapáginalogoantesdosnossosscripts:
<scriptsrc="cordova.js"></script>
Note, porém, que não temos esse arquivo no projeto. É issomesmo.EssearquivoégeradopeloCordova automaticamentenahoradobuilddaApp.
Observe também que, ao usar um plugin nativo como esse,
106 13.4INTEGRANDONAAPP
precisamos testar em um dispositivo real, para ver ocomportamento funcionando. Se tentarmos abrir o index.htmldireto no navegador, o botão não vai funcionar, já que não hásuporteaoplugin,queénativo.
Entãorodenoseuaparelhoeuseessesqrcodesparatestar:
UmacaracterísticacomumaboasAppsnativasé integrarbemao visual da plataforma em que está rodando. E um pontoimportanteéabarradestatus,aquelabarradotopocomhorário,notificaçõesetc.
Se você abriu nossaApp no iOS e noAndroid, deve ter vistoisso:
NoiOS,astatusbarficaporcimadaApp,quaseatrapalhandooconteúdo da App. No Android, a barra de status é preta e nãoatrapalhaaApp.Masnenhumdessescomportamentoséousualdaplataforma.
13.5UMABOASTATUSBAR
13.5UMABOASTATUSBAR 107
Veja,porexemplo,oGoogleInboxabertonoiOSenoAndroid:
NoiOS,ocomuméterumastatusbardecorsólidanamesmacor do topo da aplicação e, claro, não por cima da App. NoAndroid, o comum é ter uma barra de status em uma corsecundária,umtommaisescurodacordotopodaApp.
Queremos configurar essas características na nossa App. Paraisso,precisamosdeumpluginquelidacomastatusbar.
Instaleopluginpeloterminal.ÉumpluginoficialdoCordova:
cordovapluginaddcordova-plugin-statusbar--save
Esse plugin permite muitas customizações, como cores ecomportamento da status bar. Permite até escrever código paraesconder e mostrar programaticamente. Nosso interesse agora éconfigurar o seu visual, e isso o plugin permite compreferênciasespecíficasnoconfig.xml.
Porexemplo,paraindicarnoiOSqueabarranãodeveficarporcimadaApp,usamosapreferênciaStatusBarOverlaysWebViewcomvalorfalse(opadrãoétrue).Paramudara cor,usamos StatusBarBackgroundColor com o valor de uma cor emhexadecimalcomonaWeb.
A questão é lembrar de que cada plataforma tem suacaracterística.NoiOS,deveseramesmacordotopodaAppe,noAndroid, um tommais escuro. Podemos controlar isso coma tag<platform>quevimosnocapítuloanterior.
13.6CONFIGURANDOASTATUSBAR
108 13.6CONFIGURANDOASTATUSBAR
Aconfiguraçãofinalfica:
<platformname="android"><preferencename="StatusBarBackgroundColor"value="#E86C13"/></platform>
<platformname="ios"><preferencename="StatusBarOverlaysWebView"value="false"/><preferencename="StatusBarBackgroundColor"value="#F57F17"/></platform>
Testenovamenteeteremosagora:
PROJETOFINALDOCAPÍTULO
Sepreferiroprojetodestecapítulocomoqrcodee statusbarestánestabranchnoGitHub:
https://github.com/sergiolopes/garconapp/tree/plugins.
13.6CONFIGURANDOASTATUSBAR 109
CAPÍTULO14
Falta um último detalhe para nossa App poder ser usada nosrestaurantes:efetivamentefinalizaropedido.Fizemosalistagemdeprodutoseaseleçãodositensdopedido,masprecisamosefetivá-lo,enviarparaacozinhapreparar.
OSódeCenourajápossuiumasoluçãoback-endnacozinha.ÉumaaplicaçãoWebquemostraemummonitorgrandequaissãoospedidos empreparo.E essa aplicação temum serviçoREST ondepodemosregistrarnovospedidos.
VamosusaresseserviçonanossaApppararegistrarnosistemadacozinhaospedidosfeitosnasmesas.
A cozinhapp é uma aplicação Web em Node.js e Meteorbastante simples. Possui dois propósitos: mostrar os pedidos emabertoparaoscozinheiroseexporumaAPIRESTpararegistrodenovos pedidos. Vamos observar essas coisas primeiro antes deintegrarnaApp.
Opaineldepedidosabertosestárodandoem:
http://cozinhapp.sergiolopes.org
Abra no seu navegador. É uma lista simples de pedidos -possivelmentevazia,senãohouverpedidosnovosagora.
SERVIÇOSREMOTOS
14.1AAPIDACOZINHAPP
110 14SERVIÇOSREMOTOS
Para registrar os novos pedidos, existe um endpointREST emhttp://cozinhapp.sergiolopes.org/novo-pedido.Eleexigeapassagemde dois argumentos: mesa com o número da mesa que fez opedido,epedidocomotextodopedido.Bemsimples.
Abraoutraabanonavegadoretestechamandonamãomesmo:
http://cozinhapp.sergiolopes.org/novo-pedido?mesa=17&pedido=Bolo+de+Cenoura
Se olhar na lista, seu pedido vai aparecer agora. Você podeinserir outros mais como teste para ver o sistema funcionando.CliqueemFinalizarpararemoveropedidodalista.
COMOFUNCIONAAAPLICAÇÃOWEB
Essa parte do back-end foi escrita em Node.js com Meteor.Nossofoco,claro,énapartemobileeaintegraçãocomanossaAppCordova.Então,vamosusaroserviçopronto.Sequiser,ocódigoestádisponívelem
https://github.com/sergiolopes/cozinhapp.
Umdetalheimportanteéquetemosapenasumback-endparatodos os leitores do livro. Isso quer dizer que seus pedidospodem se misturar a pedidos de outras pessoas. Se preferir,rodesuaprópriainstalaçãoisoladadacozinhapp.
Oqueprecisamos,então,éacionaressaAPIviaAjax.Podemosusar jQuerypara isso.Éumcódigosemsegredo,umsimplesAjaxmesmo.Vejaumexemplo:
14.2AJAXNAAPP
14.2AJAXNAAPP 111
$.ajax({url:'http://cozinhapp.sergiolopes.org/novo-pedido',data:{mesa:$('#numero-mesa').val(),pedido:$('#resumo').text()}});
Estou usando o $.ajax do jQuery que recebe a url e osparâmetros na opção data . Repare que já estou passando osvaloresreaiscombasenosdadosdanossaApp.
Mas é claro que esse código precisa ser disparado apenasquandoobotãoPedirdomodalforacionado.Vamosadicionarumaclasseacao-finalizaraessebotão,quedeveficarmaisoumenosassim:
<buttonclass="btndeep-orangewaves-effectwaves-lightmodal-closeacao-finalizar">Pedir</button>
E,comjQuery,pegamosocliquedobotão:
$('.acao-finalizar').on('click',function(){//códigodoAjaxvaiaquidepois});
Além disso, podemos colocar callbacks de sucesso e erro. Oserviço traz uma mensagem de resposta que vamos mostrar nocomponentetoastdoMaterialize.Nocallbackdesucesso, tambémvamoslimparoscamposparapermitirumnovopedido.
Ocódigocompletoparacolocarmosnoapp.jsé:
$('.acao-finalizar').on('click',function(){$.ajax({url:'http://cozinhapp.sergiolopes.org/novo-pedido',data:{mesa:$('#numero-mesa').val(),pedido:$('#resumo').text()},error:function(erro){Materialize.toast(erro.responseText,3000,'red-text');},success:function(dados){
112 14.2AJAXNAAPP
Materialize.toast(dados,2000);
$('#numero-mesa').val('');$('.badge').remove();}});});
Apesardecorreto, sevocê testaressecódigoagora,elenãovaifuncionar.Temosalgumasrestriçõesdesegurançaqueprecisamosseguir.
Os navegadoresWeb têm uma restrição de segurança famosa,chamadaSameOriginPolicy.Elafazcomquecertosrequests,comoosfeitosviaAjax,sósejampermitidosdentrodomesmodomínio.
Ou seja, se nosso serviço está em cozinhapp.sergiolopes.org , por padrão, o Ajax só vaifuncionar em outras páginas que também estejam emcozinhapp.sergiolopes.org.OquenãoéocasodanossaAppnoCordova.
Nosso HTML no Cordova roda localmente no celular dousuário. Na prática, é como abrir um arquivo local direto nobrowser.EleusaURLsfile://,oquenãobatecomaorigemdoserviço.Então,orequestébloqueado.
Há diversas formas de resolver essa limitação. A soluçãodefinitiva e recomendada é usar CORS (Cross-Origin ResourceSharing).Aimplementaçãoésimpleseenvolveapenasoservidor-obrowserentendeautomaticamente.
Basta, no servidor, colocar um cabeçalho novo da resposta, Access-Control-Allow-Origin , indicando quais outrosdomínios(origens)estãopermitidosparaacessaraqueleserviço.Por
14.3CORSESAMEORIGINPOLICY
14.3CORSESAMEORIGINPOLICY 113
exemplo:
Access-Control-Allow-Origin:http://sodecenoura.com.br
Isso abre o serviço para um outro domínio hipotético:http://sodecenoura.com.br.
OproblemacomCordovaéoquecolocarnessecabeçalho.Nãoexisteumaorigemhttp,umdomínionasAppsCordova.Lembre-se de que elas rodam em file:// . Para resolver, precisamosliberaroCORSparatodoscom:
Access-Control-Allow-Origin:*
Isso liberao acesso a todas asorigens, oque incluinossaAppCordova.Uma ressalva é que isso não significa que seu back-endestá menos seguro. Para segurança, usamos autenticação (comOAuth por exemplo).OCORS só relaxa o nível de acesso para ocliente,oquenessecasonãoéumproblema.
Nos seus serviços, portanto, você vai precisar acrescentar ocabeçalhodoCORSnoback-end.Anossa aplicaçãoNode já estáconfigurada com esse cabeçalho para facilitar. Você pode atéinspecionarnonavegadorevê-loemação.
MasseoCORSjáestavahabilitadononossoback-end,porqueainda não funcionou? O Cordova bloqueia por padrão todas asrequisiçõesexternas.Precisamosliberarexplicitamente.
Existeumpluginchamadocordova-plugin-whitelist, quecontrolaoacessoaURLsexternasnanossaAppCordova.Elevem,inclusive, instalado por padrão quando criamos o projeto. Oupodemosinstalá-locom:
cordovapluginaddcordova-plugin-whitelist--save
14.4PLUGINCORDOVAWHITELIST
114 14.4PLUGINCORDOVAWHITELIST
Comele,podemoslistarnoconfig.xml todasasorigensquequeremos liberar acesso. Para liberar nossa API back-end,colocamos:
<accessorigin="http://cozinhapp.sergiolopes.org"/>
Atagaccess recebeumaorigem.Vocêpodeusar asteriscospara vários subdomínios - por exemplo,http://*.sergiolopes.org.Vocêpodetambémlistarsubpastasapenas, ou até liberar para todas as URLs do mundo colocandoapenas *, o que não é uma boa ideia, a menos que realmenteprecise.
Coloque então essa tagaccess no config.xml, liberandonossoback-end.Depois,testeaAppnoaparelhonovamente.Tudodevefuncionaragora.
ApartirdoiOS9,todasasApps,tantonativasquantohíbridas,sópodemfazerchamadasaserviçosseguroshttps://porpadrão.Isso quer dizer que umAjax para http://, como fizemos, nãofuncionaria.
Umadascoisasqueocordova-ios faz é abrir exceçõesparacadadomínionecessário, relaxandoas configuraçõesde segurançacaso a caso, com base nas configurações dowhitelist. Também épossíveldeixarabertoparatodasasURLs,masnãoérecomendado.
Você pode encontrar essas configurações geradas no arquivoplatforms/ios/Garconete/Resources/Garconete-Info.plist.Lá, procure pela chave NSAppTransportSecurity . Você podecustomizaressearquivotambém.
Sepreferir,existeumaversãoalternativadoserviçousadonestecapítuloquerodaemhttps:https://cozinhapp.meteor.com.
NotasobreiOS9eAppTransportSecuritySettings
14.4PLUGINCORDOVAWHITELIST 115
NossaAppusaapenasowhitelistdechamadasAjax.Entretanto,háoutrasconfiguraçõespossíveiscomesseplugin.Vejamos,sóparaconhecimento.
Como o Cordova roda em um navegador, nada impede quecliquemos emum linkque leveparaoutrapágina.Porpadrão, sópodemosnavegarempáginaslocaisdefile://.Porém,àsvezes,vamosquerernavegarparaoutrasURLs.Liberamosissocom:
<allow-navigationhref="http://sergiolopes.org/*"/>
Também podemos listar quais URLs devem ser tratadas pelosistemaoperacional, e nãopelonavegador.Éo que chamamosdeIntents. Certas URLs especiais podem abrir Apps nativas dosistema, e precisamos liberar quais queremos. Por exemplo,podemosliberarlinksemURLsdotipotel:paraabrirodiscadornativo:
<allow-intenthref="tel:*"/>
Veja mais em https://github.com/apache/cordova-plugin-whitelist.
14.5INTENTSENAVEGAÇÕES
116 14.5INTENTSENAVEGAÇÕES
CAPÍTULO15
JáfizemosbastantecoisacomCordova,eaprendemosváriosdeseusconceitosnapráticaao longododesenvolvimentodoprojeto.Masébomagorapausarmosumpoucoasnovasfuncionalidadeseelaborar um pouco mais como o Cordova realmente funciona.Entendersuaarquitetura,suasvantagenselimitações.
Todas as plataformas móveis oferecem, além do navegadornormaldeinternet,umaespéciedenavegadornativoseminterface,quepodeserusadopelasApps.SãoasWebViews.Pensenelacomoum navegador capaz de executar todo HTML, CSS e JavaScriptnormalmente,massemainterfacedeumnavegador,esembotões,barradeendereço,menusetc.Sóorenderizador.
OobjetivoéqueAppsnativasdaplataformapossamusar essecomponente deWebView para exibir conteúdoHTML em algumponto da App. O Facebook, por exemplo, usa WebView prarenderizar os links clicados em sua App sem abrir o browsercompleto.
PensenaWebViewcomoummotorderenderizaçãodeHTMLplugável. No iOS, ele é baseado no WebKit como o Safari. NoAndroid, é baseado no Chromium a partir da versão 4.4, e no
ARQUITETURADOCORDOVA
15.1OQUESÃOASWEBVIEWS
15ARQUITETURADOCORDOVA 117
WebKit em versões anteriores. No Windows 10, é baseado noEdgeHTML como o Microsoft Edge - e usa o Trident do IE noWindowsPhone8.VamosvermaisdetalhessobreasWebViewsnocapítulo19.
MuitasAppsusamWebViewspara exibirpequenos conteúdosHTMLemseufluxo.Porém,oCordovainovouaorenderizaraAppinteiradentrodeumaWebView.
UmaApp Cordova é umaApp nativa do sistema operacionalque tem apenas uma função: chamar a WebView e carregar oarquivoindex.htmldentrodela.Todaainterfacedousuário,todalógicadaAppseráescritaemHTML,CSSe JSeexecutadadentrodaWebView,assimcomoumaWebApp.
A ideia é tão simplesque, se você conhecerumpouquinhodeAndroideJava,conseguiriafazeressacascasimplesdoCordovaempouquíssimaslinhasdecódigo:
<WebViewxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/webview"/>
WebViewmyWebView=(WebView)findViewById(R.id.webview);myWebView.loadUrl("www/index.html");
Nasoutrasplataformas,ocódigoédiferente,masaideiaémuitoparecidaesimples.
O que oCordova faz é escrever esses códigos nativos de cadaplataforma e empacotar junto com seu código HTML da pastawww.O resultado é umaApp nativa que invoca aWebView ecarregaseuindex.htmldentrodela.
Inclusive, sevocêabrir apastaplatforms dentrodoprojeto
15.2UMAAPPCORDOVA
118 15.2UMAAPPCORDOVA
Cordova,veráocódigonativocompletocuspidopeloCordovaemcadaplataforma.
Uma WebView normal tem a mesma capacidade de umnavegador Web comum. Isso quer dizer que não pode acessarrecursosnativosdaplataforma.OCordovadáumpassoalém.Eleexpõe uma API JavaScript que pode ser chamada daWebView echamarecursosnativos.
Hojecadarecursonativoespecialéencapsuladoemumplugindiferente.Então,sevocêquiser,porexemplo,acessaroscontatosdoaparelho, instaleoplugincordova-plugin-contacts.Esseplugin temtodoocódigonativonecessárioparaacessaroscontatosnativosemJava para Android, Objective-C para iOS etc. E expõe para aWebView o objeto navigator.contacts , onde você podemanipularoscontatosdeformaportável.Porexemplo:
varcontato=navigator.contacts.create({"displayName":"Olga"});
A vantagem é que toda a complexidade nativa estáencapsulada no plugin, e nós escrevemos JavaScript normal napáginasemproblemas.
EssegráficoilustracomoumaAppCordovafunciona:
15.3WEBVIEWCOMPODERES
15.3WEBVIEWCOMPODERES 119
animadas.
Em termos práticos, isso quer dizer que não é uma boa ideiacriar as telas da sua aplicação como arquivos HTML separados,navegandoentresi.OquetemoséumHTMLinicialquecarregaastelassobdemandausandoAjaxecomanimaçõesCSSbonitasentreasnavegações.
IssoéoquechamamosdeSinglePageApplications.UmúnicoHTMLquecarregaaApptodaecuidadetodanavegação.
VocêpodefazerumaSPAsimplescomumpoucodeJavaScripte jQuery, mas, na prática, há frameworks melhores para isso nomercado.Hoje,osmaisfamosossãooAngulareoReact,mastemosaindaEmber,Backboneeoutros.
Melhor aindaquando vocêuneumbom framework SPA comumabibliotecadecomponentesvisuaisbonitos.Eesseéocasodeváriosframeworksquefalamosantes,emespecialoIonic.
O Ionic usa o Angular por baixo e coloca seus componentesricosemcima.Éhojeo frameworkmais famosoparaesse tipodeSPAmobilecomoasquequeremosfazernoCordova.Masháváriosoutros.VamosverumpoucodeIonicnopróximocapítulo.
Se você reparar bem nas duas Apps que fizemos até agora,ambas,apesardesimples,eramsinglepageapplications.UmúnicoHTMLlidavacomtodooconteúdoetodasastelas,semnavegaçãoexterna.
Agarconapp,porexemplo,permitianavegarentreasabas,abriromenu, fazer o pedido, tudo sem atualizar a tela toda.Como erauma App simples, não tínhamos telas secundárias carregadas viaAjax, mas a ideia é a mesma. Em uma App mais complexa, usealgumframeworkJavaScriptdeSPArobusto.
15.6CARADEAPP,JEITODEAPP 123
Além de bom visual e interação com jeito de App, queremosumaboaintegraçãocomosrecursosdaplataforma.Issovaidesdeum bom ícone e uma boa splashscreen até acesso a recursos dehardwareavançados.
Queremos usar as notificações do sistema. Queremos acessarcâmera,acelerômetro,giroscópioeoutrosrecursos.Queremosumastatus bar bonita integrada ao sistema. Queremos acessar oscontatosdoaparelhoemanipulararquivosnocartãodememória.Enfim, tudo o que os diversos plugins do Cordova oferecem.Precisamos apenas usá-los e pensar em boas experiências para ousuário.
Outropontobastanteimportanteéperformance.Hámuitoasefalar sobre isso, quemereceriaum livro sópara esse assunto.Masvamosdiscutiralgunscenáriosimportantes.
TodaAppprecisadeboaperformancepara agradarousuário.Entrtanto, a questão aqui é que o Cordova coloca algunsobstáculosamais ,nos fazendocomeçar jáemdesvantagem.Esenossa App não parece tão rápida quanto as demais Apps doaparelhodousuário,elevaireclamar.
A principal questão é que aWebView é um interpretador deHTML,CSSeJavaScript.Eissoéinerentementemaislentodoquequalquer coisa feita nativamentena plataforma. Isso é um fato.Oqueprecisamosécercaromáximopossívelosgargalosparaterumaperformance aceitável em cada caso. A maioria das Apps nãoprecisadeultraperformance,precisamaiséparecerrápida.
Recursosnativos
15.7BOAPERFORMANCEÉESSENCIAL
124 15.7BOAPERFORMANCEÉESSENCIAL
Um ponto de atenção é a resposta ao toque. Os primeirosnavegadoresmóveisvinhamcomumatrasopropositalnotoquedosbotões da ordem de 300ms. Não parece muito, mas eles causamumademoraperceptívelentreousuárioacionarumbotãoeaaçãoexecutar.Osnavegadores eWebViewsmodernos já retiraram essarestrição,masantigosaindatêm.
A solução mais comum é usar o Fastclick(https://github.com/ftlabs/fastclick). Os frameworks completoscomoIonicjácuidamdissoparavocêtambém,oquepodesermaisumbommotivoparaadotá-los.
Interfacesricascostumamterbelasanimações.Oidealéfazê-lasemCSSusandoaceleração3D. Isso significa transições queusemapenastransformeopacity.Pesquisetambémsobreowill-change.
Outra opção é frameworks JavaScript de animaçõesperformáticas,comooGreensockouVelocity.js.FujadojQueryparaanimações. E, novamente, frameworks completos como Ionic játrazemanimaçõescomunsemcomponentesetransiçõesdetela.
Amaior limitação do JavaScript hoje é que ele roda em umaúnica thread. Isso quer dizer que todo o seu código JS, todos oseventos do usuário e muitas coisas da interface donavegador/WebView são executados em uma única thread demaneiraintercalada.
Basta um código lento para travar tudo. Você já deve ter
Respostaaotoque
Animações
Processamentopesado
15.7BOAPERFORMANCEÉESSENCIAL 125
abertoumapágina com scroll lento, ou clicado emumbotão queteimaemnãoresponder,ouvistoumaanimaçãoquenãorodadeformafluída.Geralmente,essesproblemassãocausadospelathreadúnica do JavaScript estar ocupada executando coisas demais. Opessoalchamaissodejank(http://jankfree.org/).
O recado é evitar código que demorem demais para executar.Mais que uns poucos milissegundo, já é problema. Quebre oscódigosempedaçosmenoresquevocêpodeagendarparaexecutaraospoucoscomsetTimeoutourequestAnimationFrame.
Seprecisarprocessarcoisaspesadas,useWebWorkers,quesãoasolução JavaScript para executar coisas fora da thread principal.Temsuaslimitações,maséoquetemosdisponível.
Uma App empacotada com Cordova já funciona offline porpadrão. TodoHTML, CSS e JS está instalado junto com a App epodeseracessadosemrede.MasboapartedasAppsacessaserviçosexternos via Ajax, por exemplo, o Facebook que precisa pegar asinformaçõesatualizadasdoFeeddeNotícias.
O ideal é construir uma experiência offline-first. Isso significasalvar localmenteosdadosbaixadosdaredeeusá-losnaAppcasonão tenhamos rede.Melhor ainda: usar os dados locais sempre e,casotenharede,buscardadosatualizadosdeformatransparenteembackground.ÉassimqueoFacebookeoutrosfuncionam.Eissodáumaótimasensaçãodeperformanceparaousuário.
Vamosimplementarumaideiaassimnocapítulo18.
Offline-first
15.8 RECURSOS INTERESSANTES DA API DOCORDOVA
126 15.8RECURSOSINTERESSANTESDAAPIDOCORDOVA
OCordovaexpõealgunsrecursosinteressantesparaaWebViewquepodemosacessar via JavaScriptnonosso código. São recursosque permitem interagir melhor com o aparelho e com o próprioambientedaWebView.
O próprio Cordova dispara alguns eventos adicionais noJavaScript emmomentos importantes parauma aplicaçãohíbrida.Omaisfamosodeleséodeviceready,queéchamadoquandoasAPIsdoCordovaestãoprontasparauso.
Às vezes, queremos chamar um recurso do Cordova logo noiníciodaApp,mascomoeletemumcomponentenativo,elepodenãoestardisponívelainda.OdevicereadynosindicaquetudodoCordovafoi inicializado,equepodemoschamarasAPIsepluginssemproblemas.Exemplo:
document.addEventListener("deviceready",function(){//acessaalgumacoisadonavigator.contactsporexemplo});
Outros eventos importantes são do ciclo de vida da App. OeventopauseédisparadoquandoosistemaoperacionalsuspendenossaApp,emgeral,porqueousuárioalternouparaoutraApp.Éum bom momento para suspender qualquer coisa pesada queestejamos processando, ou mesmo parar animações. O eventoresume é disparado quando a App volta à ativa, e aí podemosacionarnovamenteosrecursosqueforampausados.
Podemostambémescutareventosdebotõesnativosdosistemaoperacional, por exemplo, volumedownbutton evolumeupbutton.Nasplataformasquetêmbotãodevoltar,comoAndroid e Windows Phone, podemos escutar o eventobackbuttontambém.
EventosdoCordova
15.8RECURSOSINTERESSANTESDAAPIDOCORDOVA 127
Háalgunsoutroseventos,quevocêpodeconsultarem:
https://cordova.apache.org/docs/en/latest/cordova/events/events.html.
Um recurso simples,mas bempoderoso, são osmerge folders,que permitem customizar códigos específicos para cadaplataforma. 99%do nosso código deve ser portável,mas às vezesqueremosfazeralgoespecífico,comoesconderobotãodebacknoAndroid, já que ele já possui o nativo; mudar a fonte usada noWindowsPhone,ouqualqueroutracoisa.
Imaginequetemosumdetalhes.cssquequeremosquesejadiferenteemcertasplataformas.NoHTML,usamos:
<linkrel="stylesheet"href="css/detalhes.css">
Podemoscriarumarquivowww/css/detalhes.css padrão aserusadoemtodasasplataformas.Masaícriarversõesespecíficasemumanovapastamerges/naraizdoprojeto-aoladodawww-com subpastas com as plataformas interessadas. Por exemplo, noAndroid,seria:merges/android/css/detalhes.css,eassimparaasdemaisplataformas.
NomomentodobuilddaApp,oCordovaverificaosarquivosda pasta merges daquela plataforma, e substitui os arquivoscorrespondentesnawww somentenaquelaplataforma.Épossívelatéterarquivosespecíficosnovosparaapenasumaplataformasemnemaparecernowww,comoumíconedevoltarapenasnoiOSemmerges/ios/img/back.png.
Merges
128 15.8RECURSOSINTERESSANTESDAAPIDOCORDOVA
CAPÍTULO16
ApróximafasedoSódeCenouraélançarumaAppsimplesparadelivery.Osclientesqueremcomprarosdeliciososbolose receberem casa. A nova App deve suportar o máximo de plataformaspossíveis, permitir visualizar o cardápio de entrega e fazer umpedido.
Por ser umaAppmultiplataforma, focada nos clientes, vamosevitarusaroMaterialDesign, que temumapelomaior apenasnoAndroid. Para facilitar, queremos um framework de componentesmobilecomvisualagnósticodeplataforma.E,depreferência,quejáse integre ao Cordova e ao estilo de criação de Apps híbridas.VamosusaroIonicFramework(http://ionicframework.com/).
O Ionicnasceucomoum frameworkdecomponentesvisuaiscom foco emmobile construído em cima do Angular. Isso querdizerentãoqueeleseguetodoomodelodeSinglePageApplicationdoAngular,idealparaAppshíbridas.
Os componentes foram criados com foco em um visualindependentedeplataformaeusabilidadeotimizadaparamobileetouch screens. Existem dezenas de componentes prontos e vocêpodeconsultá-losaqui:
http://ionicframework.com/docs/components/.
INTRODUÇÃOAOIONIC
16.1SOBREOIONIC
16INTRODUÇÃOAOIONIC 129
conceito de single page application em uma App híbrida comCordova.
Vamos iniciar uma nova App para os clientes fazerem seuspedidosdecasa,apedidapp.
SevocênãoinstalouoIonicantes,faça-oagora.Ébemsimples.Noterminal:
npminstall-gionic
Noterminal,usaremosocomandoionicstart comalgunsargumentos.Em--appname, indicamosonomedaApp;em--id, o identificador único do pacote (use um próprio), depois apastaondegerare,porúltimo,o templatebasea serusado(blankindicaumprojetomínimo).
ionicstart--appname"SódeCenouraemCasa"--idorg.sergiolopes.pedidapppedidappblank
Agora entre na pasta pedidapp , e execute o preview doprojeto:
cdpedidappionicserve
O navegador abrirá e veremos um preview simples da App.BastairmosmodificandoaAppagoraeonavegadorseráatualizadoautomaticamente.Nofim,veremoscomoexecutarnodispositivo.
Abra a pasta pedidapp no seu editor e vá se familiarizandocomocódigo.EleéumprojetoCordovacommaiscoisasdoIonic.Denossointeresse,agora,éapastawww.LávocêvaiverumHTML
16.2NOVOPROJETO
16.3ARQUITETURADAAPP
16.2NOVOPROJETO 131
Abra o arquivo js/routes.js e adicione a rota / pararepresentarahome.IndiqueoarquivodotemplateeoController.Ocódigoserá:
angular.module('starter').config(function($stateProvider,$urlRouterProvider){
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home',{url:'/home',templateUrl:'templates/home.html',controller:'HomeController'})
});
ReparequearotaapontaumatemplateUrl comonomedoHTMLasercarregado.Mascarregadoonde?Precisamosindicarnoindex.html onde esses templates vão ser exibidos.Fazemos issocomatag<ion-nav-view>.
Alémdisso,conformeousuárionavega,queremosexibirotítulodapáginanotopo,alémdeummecanismodenavegação(back).NoIonic,sãoastags<ion-nav-bar>e<ion-nav-back-button>.
Abraoindex.htmlesubstituatodoomiolodo<body>por:
<ion-nav-bar><ion-nav-back-button></ion-nav-back-button></ion-nav-bar>
<ion-nav-view></ion-nav-view>
Aproveiteecrieumcontrollervaziotambém,senãoarotanãofunciona.Paraisso,váaoarquivojs/controllers.jsecoloque:
angular.module('starter').controller('HomeController',function($scope){
Aprimeirarota
134 16.4LISTADEBOLOS
});
Podemos colocar qualquer HTML no home.html e ele seráexibido na tela toda assim que a home carregar. Teste se quiser,colocandoum<h1>simplesporexemplodentrodohome.html.
O que queremos é uma lista de bolos com um título bonito.Vamos usar componentes do Ionic para isso. Na documentaçãodeles,vocêencontraalistacompletadecomponentes:
http://ionicframework.com/docs/.
Uma tela com uma lista simples de bolos usando oscomponentesdoIonicficaassim:
<ion-view><ion-nav-title>NossosBolos</ion-nav-title><ion-content><ion-list><ion-item>SódeCenoura</ion-item><ion-item>ComNutella</ion-item><ion-item>ComBrigadeiro</ion-item><ion-item>Açucarado</ion-item></ion-list></ion-content></ion-view>
O<ion-view>representaumanovatela.Astelaspossuemumconteúdo (<ion-content>) que, no caso, é uma lista (<ion-list>)deitens(<ion-item>).
O<ion-nav-title>éumtítuloaserusadoemcadatela.Eleserá usado pelo <ion-nav-bar> que colocamos antes noindex.html. Se não fez ainda, rode essa App e verá uma listasimplescom4opçõesdebolosalémdotítuloBolos.
Umtoquededesign:podemoscolocarabarrade títulonacor
Otemplate
16.4LISTADEBOLOS 135
laranja do Só de Cenoura. Abra o arquivo css/style.css eadicione:
.bar{background:#F77F00;color:white;}.bar.header-item{color:white;}
VocêpodeverocódigoebaixaroZIPnoGitHubem:
https://github.com/sergiolopes/pedidapp/tree/f6e0.
EmvezdecolocarosnomesdosbolosdiretonoHTML,ojeitoAngularédeixarosdadosisoladosemumobjetomodeloeapenasreferenciá-lonoHTML.Comisso,émaisfácilgerenciarosdados-elespodematévirdeumaAPIAjax,porexemplo-,eémais fácilgerenciaroHTML,queficaindependentedosdados.
IssoéoMVC.Aview(HTML)consomeomodel(osdados)equemfazaligaçãoéocontroller.
Dentro do HomeController, criamos uma variável com umarraydeobjetosquerepresentamosnossosprodutos.Aprincípio,
16.5DADOSDINÂMICOS
136 16.5DADOSDINÂMICOS
querocolocarosnomesepreçosdecadabolo.
angular.module('starter').controller('HomeController',function($scope){
$scope.bolos=[{nome:"SódeCenoura",preco:18},{nome:"ComNutella",preco:29},{nome:"DeBrigadeiro",preco:24},{nome:"Açucarado",preco:19}];
});
Expor uma propriedade na variável $scope do Angularsignifica deixar aqueles dados disponíveis na view. Justo o quequeremos.
No HTML, podemos usar o ng-repeat do Angular parapercorrer essa lista de bolos, e exibir os dados usando a notação {{bolo.preco}} . O código da lista acessando os dadosdinamicamentedocontrollerficaassim:
<ion-list><ion-itemng-repeat="boloinbolos"><h2>{{bolo.nome}}</h2><p>apenasR${{bolo.preco}}</p></ion-item></ion-list>
Repare que tiramos os <ion-item> fixos e trocamos porapenas um com ng-repeat. Ele percorre o array de bolos, emontacadaitemmostrandoonomeeoprecodecadabolo.
Testenovamente.
A mudança para dados dinâmicos foi boa, mas queremos opróximopasso.Essesdadosdevemvirdoservidordorestaurante.
16.6SERVIÇOREST
16.6SERVIÇOREST 137
Temos já uma API simples que devolve um JSON com essasinformaçõesem:
http://cozinhapp.sergiolopes.org/produtos.
VamoschamaressaURLusandoalgunsrecursosdoAngular.
O Angular possui uma diretiva bastante útil para chamadasAjax,o$http.ChamarnossaURLébemsimples:
$http.get('http://cozinhapp.sergiolopes.org/produtos')
Eladevolveumapromise que será executadaquandoo serviçoretornar. Podemos, por exemplo, recuperar os dados da respostacom:
$http.get('http://cozinhapp.sergiolopes.org/produtos').then(function(response){returnresponse.data;})
QueremosencapsularessachamadaparaqueoutroslugaresdanossaApppossamteracessoaessesdados.ÉparaissoqueusamososServicesdoAngular.
Noarquivojs/services.js,crieumProdutosServicequepossui apenasummétodolista que encapsula justamente essecódigoquevimosantes:
angular.module('starter').service('ProdutosService',function($http,$q){
varurl='http://cozinhapp.sergiolopes.org/produtos';
return{lista:function(){return$http.get(url).then(function(response){returnresponse.data;});}
Servicee$http
138 16.6SERVIÇOREST
};
});
Agora, queremos trocar no HomeController para usar essenovoserviço.Nojs/controller.js,substituapor:
angular.module('starter').controller('HomeController',function($scope,ProdutosService){ProdutosService.lista().then(function(dados){$scope.bolos=dados;});});
Repare como recebemos o novo ProdutosService comoargumentoeaíchamamosseumétodolista().EledevolveumapromisequeresolvecomosdadosdoserviçoAjaxquecolocamosnoescopoparaconsumodaview.
Teste novamente a App no navegador e veja o serviço sendochamado.
Apesar de usarmos o Ionic diretono browser, ele já vem comtodaestruturadoCordovapreparada.Podemosadicionarumanovaplataformacom:
ionicplatformaddandroid
EdepoisexecutarnoaparelhoAndroidcom:
ionicrunandroid
MesmacoisaparaiOSeasoutrasplataformas.
Reparetambémqueoprojetopossuioconfig.xmlpadrãodoCordova. Você pode modificá-lo à vontade. Por exemplo, paraliberaracessoapenasaURLdonossoserviço,comatag<access>:
<accessorigin="http://cozinhapp.sergiolopes.org"/>
16.7TESTENODEVICEOUEMULADOR
16.7TESTENODEVICEOUEMULADOR 139
E, claro, podemos customizar todo o resto. Colocar o nomecorretoem<name>,inseriro<author>etc.
OcódigofinaldessecapítuloestánoGitHubparavocêbaixar:
https://github.com/sergiolopes/pedidapp/tree/3bbf.
Se você não tiver o ambiente doAndroid ou iOS configuradoparagerarospacotes,podeusaroserviçodoIonicViewparatestarsuasAppsnodispositivo.
ÉumserviçosemelhanteaoPhonegapDeveloperAppquevimosnocapítulo4.Mas,diferentementedoPhonegap,seucódigoficananuvemdo Ionic, o que permite testar emqualquer aparelho e atémandarparaamigos.
A ideia é instalar uma App do Ionic pela própria loja deaplicativos. Aí subimos nosso código no servidor do Ionic e eleexecutaessecódigonaAppdoIonicView.Ébastanteútil.
Opassoapassoé:
1. Crieumacontaemhttps://apps.ionic.io.2. Faça upload da sua App Ionic pelo terminal com ionic
upload.3. Instale a App do Ionic View no seu dispositivo
(http://view.ionic.io/).4. No device, logue no Ionic View, selecione a App e faça
DownloadfilesedepoisViewapp.
É possível também compartilhar a App com outros usuáriospara eles pré-visualizarem com o IonicView. Basta rodar [email protected].
16.8TESTANDOCOMIONICVIEW
140 16.8TESTANDOCOMIONICVIEW
CAPÍTULO17
Vamos continuar a App do capítulo anterior com Ionic. Porenquanto,temosapenasaHome feita.Vamoscriarmaistelas,comnovasrotas,novostemplatesenavegarentreelas.
A ideia é explorar o conceito de Single Page App onde temosapenasumHTMLbase(index.html)eumframeworkJavaScript(Angular)quecarregaasnovastelasdinamicamenteviaAjax.
Queremosque,aoclicaremumbolonaHome,sejaexibidaumatela secundária comosdetalhesdaquelebolo:umadescrição,umafoto bonita e um botão para fazer o pedido. Para criar uma telanova, temos sempreomisto:um templateHTML,umcontroller eumarotaligandoosdois.
Comecemos pela rota. Ao navegar para /bolo , queremosexibir o detalhe do bolo clicado. Mas como saber qual bolo foiclicado? Precisamos passar um parâmetro ou usar uma rotamaisespecífica.Vamosporessecaminho.
Criaremosumarotadinâmicanoformato/bolo/0,/bolo/1
SINGLEPAGEAPPCOMIONIC
17.1DETALHESDOPRODUTO
Arota
17SINGLEPAGEAPPCOMIONIC 141
etc.AideiaépassaroIDdobolonofimdaURL.Paracriaressarotadinâmica, vá ao arquivo js/routes.js e acrescente uma novarotalogoembaixodarotadahome:
.state('detalhe',{url:'/bolo/:boloId',templateUrl:'templates/detalhe.html',controller:'DetalheController'})
Repare na novidade: a url possui um parâmetro dinâmico:boloId . É uma variável que vai receber aquele número quepassaremosnaURL.
Próximo passo é criar o DetalheController nojs/controllers.js.Ele teráopapeldepegaroid dobolo ebuscaroobjetocorrespondentenosdadosdosbolos.
ComAngular,parapegaroparâmetrodefinidonarota,fazemos$stateParams.boloId. Como nosso array está ordenado, bastaacessar a posição correspondente dentro dele. No fim, o novoDetalheControllercompletoserá:
angular.module('starter').controller('DetalheController',function($scope,ProdutosService,$stateParams){
ProdutosService.lista().then(function(dados){$scope.bolo=dados[$stateParams.boloId];});});
Ocontroller expõe o objetobolo para view. Usaremos seusdadosparadesenharatelabonitadedetalhesdobolo.
OHTMLdaviewficanoarquivotemplates/detalhe.html.
Ocontroller
Aview
142 17.1DETALHESDOPRODUTO
Vamos fazerumdesign simples a princípio. Fique à vontadeparaelaborarmais.
Ele mostrará a descrição do bolo, um botão para compra e afoto.Nosso serviço JSON, aliás, já havia devolvido a foto de cadaboloembedadanomeiodosdados.UsamosomecanismodedataURIsparadevolverasfotosdeumasóvez.
Outra abordagem seria indicar apenas a URL de cada foto, eentão baixar a foto nessa nova URL. Optamos pela data URI noserviçoparasimplificar.
Oarquivodetalhe.htmlficará:
<ion-view><ion-nav-title>{{bolo.nome}}</ion-nav-title><ion-content><imgng-src="{{bolo.foto}}"class="detalhe-foto"><pclass="detalhe-descricao">{{bolo.descricao}}</p>
<aclass="buttonbutton-positivebutton-full"href="#">Pediresseboloagora</a></ion-content></ion-view>
ColocamosalgumasclassesnossasnesseHTMLparapodermosfazer um layout simples no CSS. Adicione ao arquivocss/style.css:
.detalhe-foto{max-width:100%;}
.detalhe-descricao{padding:1em;font-size:120%;line-height:1.5;}
Você pode testar agora navegando manualmente para#/bolo/0.
17.1DETALHESDOPRODUTO 143
Nossahomeaindanãolinkaparaapáginadedetalhes.Faremosissoagora,colocandooatributohrefna<ion-item>.
Aproveitemos também para melhorar o design na homeacrescentando uma miniatura da foto. Basta adicionar a classeitem-thumbnail-lefteacrescentara<img>.
Editeoarquivohome.htmle troqueo<ion-item> anteriorporessaversãocomolinkeaimagem:
<ion-itemng-repeat="boloinbolos"href="#/bolo/{{bolo.id}}"class="item-thumbnail-left"><imgng-src="{{bolo.foto}}"style="object-fit:cover"><h2>{{bolo.nome}}</h2><p>apenasR${{bolo.preco}}{{bolo.quantidade}}</p></ion-item>
TesteabriraHomeagoraeclicaremumdosbolos.Anavegaçãoé disparada internamente no Angular, o Ionic faz uma belaanimação.Alémdisso,atéumbotãovoltaréacrescentadonotopo
Linknahome
144 17.1DETALHESDOPRODUTO
daApp-importantenoiOSquenãotembacknativo.
OcódigoatéaquiestánoGitHub:
https://github.com/sergiolopes/pedidapp/tree/da24.
Aúltimatelaquefaremoséadefinalizaçãodopedido,ondeoclientecolocaseusdadosdeentregaefazopedidoefetivamente.
Nesta primeira versão daApp, faremos umpedido simples deapenasumbolo.Nãovamosimplementarumcarrinhodecomprasparasuportarváriosprodutos,porenquanto.Aideiaésimples:nateladedetalhedobolo,eleclicanobotãopedir,navegaparaateladepedido,preencheasinformaçõesdeentregaefinalizaopedido.
Vamoscriaranovateladepedidoentão.
17.2FINALIZANDOOPEDIDO
17.2FINALIZANDOOPEDIDO 145
Como vamos implementar um pedido simples de apenas umproduto, vamos fazer a rota no formato/pedido/:boloId paraindicar qual bolo estamos pedindo, parecida com a anterior dedetalhes.
Acrescenteumanovarotanojs/routes.js:
.state('pedido',{url:'/pedido/:boloId',templateUrl:'templates/pedido.html',controller:'PedidoController'})
Aprincípio,oPedidoControllervaifazerapenasalógicadecarregar qual é o bolo do pedido, igual ao que fizemos no DetalheController . Além disso, ele conterá um objeto$scope.dados para servir demodelo para o preenchimento doformuláriodeentrega.
Adicione o novo controller no final do arquivojs/controllers.js:
angular.module('starter').controller('PedidoController',function($scope,ProdutosService,$stateParams,$http){
ProdutosService.lista().then(function(dados){$scope.bolo=dados[$stateParams.boloId];});
$scope.dados={};});
Atelavaimostrarumresumodopedidocomnomeepreçodo
Arota
Ocontroller
Aview
146 17.2FINALIZANDOOPEDIDO
bolo,eexibir3campos:endereço,telefoneenome.Porfim,teráumbotãoparafinalizaropedido.
Crienoarquivotemplates/pedido.html:
<ion-view><ion-nav-title>Seupedido</ion-nav-title><ion-content><divclass="listlist-inset"><divclass="itemitem-divider">Boloescolhido</div><divclass="item">{{bolo.nome}}porR${{bolo.preco}}</div></div>
<divclass="listlist-inset"><divclass="itemitem-divider">Dadosparaentrega</div>
<labelclass="itemitem-input"><inputtype="text"placeholder="Seunome"ng-model="dados.nome"></label><labelclass="itemitem-input"><inputtype="tel"placeholder="Telefone"ng-model="dados.telefone"></label><labelclass="itemitem-input"><textareaplaceholder="Endereço"ng-model="dados.endereco"></textarea></label>
<buttonclass="buttonbutton-positivebutton-full"ng-click="fecharPedido()">ConfirmarPedido!</button></div></ion-content></ion-view>
Repare que cada um dos <input> possui um ng-modelapontandoparaumapropriedadeespecíficanoobjetodados quecriamosantesnocontroller.
Note tambémqueo<button> que criamos possui um ng-click="fecharPedido()".Aideiaéserummétodonocontrollerquevaifinalizaropedido.Aindanãoofizemos.
17.2FINALIZANDOOPEDIDO 147
O novo método fecharPedido deve ficar dentro do PedidoController . Seu papel é chamar a mesma URL queusamos antes na garconapp para registrar novos pedidos, ahttp://cozinhapp.sergiolopes.org/novo-pedido.
EssaURLagorarecebe2parâmetros:pedido comoprodutoescolhido,einfo comdadosde entrega.Vamosmontar osdoisparâmetrosapartirdosdadosdisponíveisnocontroller.
AcrescentedentrodoPedidoController:
$scope.fecharPedido=function(){$http.get('http://cozinhapp.sergiolopes.org/novo-pedido',{params:{pedido:$scope.bolo.nome,info:$scope.dados.nome+'('+$scope.dados.telefone+')-'+$scope.dados.endereco}});};
Note que estamos usando o $http novamente. Ele precisaestarcomoparâmetronafunçãoquedefineocontroller.
Abra no navegador e teste fazer um novo pedido. Deixe emoutraabaopaineldepedidosabertoparaverseseusdadoschegam:http://cozinhapp.sergiolopes.org/.
ChamadaAjax
148 17.2FINALIZANDOOPEDIDO
OcódigoestánoGitHub:
https://github.com/sergiolopes/pedidapp/tree/472f.
PodemosfazerdiversasmelhoriasemnossaApp.Emparticular,dar um feedbackmelhor para o usuário quando o pedido estiversendoenviado.
Podemosusarumcomponente$ionicLoading paramostrarumspinnerdecarregando:
$ionicLoading.show();
Podemostambémmostrarumpop-updeconfirmaçãoquandoopedidoforregistradousandoo$ionicPopup:
$ionicPopup.alert({title:'Pedidoconfirmado!',
17.3 INTERFACE MELHOR COM NOVOSCOMPONENTES
17.3INTERFACEMELHORCOMNOVOSCOMPONENTES 149
template:'Daquiapoucochega:)'});
Eaténavegardevoltaparahomeapósaconfirmaçãodopedidocom:
$state.go('home');
Juntando tudo isso e ainda fazendoumalert para o caso de oservidordevolvererro,chegamosaestenovofinalizarPedido()maisrobusto:
$scope.fecharPedido=function(){
//mostraospinnerdeloading$ionicLoading.show();
//disparaaAPI$http.get('http://cozinhapp.sergiolopes.org/novo-pedido',{params:{pedido:$scope.bolo.nome,info:$scope.dados.nome-'('+$scope.dados.telefone+')-'-$scope.dados.endereco}}).then(function(){
//casoOK,mostrapop-upconfirmandoe//entãonavegaprahome$ionicPopup.alert({title:'Pedidoconfirmado!',template:'Daquiapoucochega:)'}).then(function(){$state.go('home');});
}).catch(function(erro){
//casodêerromostraalertacomoerro$ionicPopup.alert({title:'Erronopedido!',template:erro.data+'.Ligapragente:011-1406'});
}).finally(function(){//emqualquercaso,removeospinnerdeloading$ionicLoading.hide();
150 17.3INTERFACEMELHORCOMNOVOSCOMPONENTES
});};
Um ponto importante é que, para poder chamar essescomponentes$ionicLoadinge$ionicPopup,alémdo$state,precisamos adicioná-los como parâmetros na definição doPedidoController.Algoassim:
angular.module('starter').controller('PedidoController',function($scope,$stateParams,$http,$state,$ionicPopup,$ionicLoading,ProdutosService){
OcódigoestánoGitHubem:
https://github.com/sergiolopes/pedidapp/tree/acad.
Nossa App está pronta para rodar nos dispositivos reais.Maspodemosfazeralgunsoutrosajustesimportantesqueaprendemos.
17.4CONFIGURAÇÕESDOCORDOVA
ÍconeseSplashScreens
17.4CONFIGURAÇÕESDOCORDOVA 151
Nocapítulo12,vimosaimportânciadoíconeedasplashscreenna App, e a dificuldade em gerar todos os tamanhos de arquivosnecessários.Inclusive,usamosoIonicnaocasiãopararesolverisso.Faremosnovamente.
Baixe os arquivos icon.png e splash.png daqui:https://github.com/sergiolopes/garconapp/tree/config/resources.Coloqueambosemumanovapastaresourcesna raizdonossoprojetopedidapp.
Agoraexecutenoterminal:
ionicresources
ElevaigerartodosostamanhospossíveisnoAndroidenoiOS,alémdeatualizaroconfig.xml.
SepreferirbaixarnoGitHubjácomosarquivosgerados,acesse:
https://github.com/sergiolopes/pedidapp/tree/1061.
Havíamos usado o plugin de StatusBar em uma App anteriorcomCordova.O Ionic já adiciona essepluginporpadrãoquandocriamos o projeto com ele. Então, podemos adicionar noconfig.xmlasconfiguraçõesparacontrolaracordabarracomofizemosantesnocapítulo13:
<platformname="android"><preferencename="StatusBarBackgroundColor"value="#E86C13"/></platform>
<platformname="ios"><preferencename="StatusBarBackgroundColor"value="#F57F17"/></platform>
PodemosaproveitartambémeconfiguraraorientaçãodaApp:
<preferencename="Orientation"value="portrait"/>
StatusBar
152 17.4CONFIGURAÇÕESDOCORDOVA
Lembre-se de que, no fim, um projeto Ionic é um projetoCordova.Então,tudooquevimosantescontinuavalendo.
Oprojetofinaldocapítuloestáem:
https://github.com/sergiolopes/pedidapp/tree/0066.
17.4CONFIGURAÇÕESDOCORDOVA 153
CAPÍTULO18
No quesito suporte a offline, aplicações híbridas têm já umagrande vantagem com relação a Web: todos sua estrutura, seuHTML,CSSeJS,sãobaixadosduranteainstalação.Issoquerdizerque,sefizermosumaAppestáticaquejápossuitudonecessárionocódigo-fonte,elafuncionaofflineautomaticamente.
A grande questão é quando envolvemos dados externos, queexigemchamadasAjax,paraseremobtidos.Comoéocasodanossapedidappquefizemosantes.
Toda a estrutura daApp está disponível offline,mas os dadoscom a lista de produtos a serem vendidos vem do servidor. Se ousuário estiver sem internet ou com o sinal ruim, não conseguiráusaraApp.
A solução para se trabalhar offline é persistir esses dadosdinâmicos localmente no aparelho. A ideia é que, se o usuárioestiver offline, possamos usar os dados locais e oferecer uma boaexperiênciaparaousuário.
Claro que na primeira vez o usuário vai precisar estar onlinepara baixar os dados (assim como ele precisa estar online parainstalar aApp, obviamente).Mas os usos seguintes poderão fazerusodessecachelocal.
CACHEEOFFLINE
18.1ESTRATÉGIASPARADADOSOFFLINE
154 18CACHEEOFFLINE
Um ponto a se considerar é que os dados salvos localmentepodemnãoseraúltimaversãodisponívelnoservidor.Emmuitassituações,issoéaceitável.Masexistemcasosondenãopodemosemhipótese alguma trabalhar com dados velhos. Aí não temos comosuportarusooffline.
No caso das Apps da Só de Cenoura, nenhum dado é crítico.Todos podem ser cacheados localmente e não há problema seestiveremumpoucodesatualizados.
Ainda assim, existem várias formas de trabalhar com offline.Devemosacessarocachelocalapenassearedeestiverindisponível?Devemos sempre devolver o cache local primeiro? Existemvantagens e desvantagens em cada cenário, e depende do caso.Vejamos.
Podemossempre tentaracessar a redeprimeiro. Sóusamosocachesehouveralgumproblema.EntãodisparamosoAjaxe,depoisdeumtemposemresposta,pegamosodadodocacheparausar.Aideia é configurarum timeout para o request para identificar se oAjaxfalhou.
Até existem formasde saber se odispositivo está sem redeounão,massãopoucoúteis.Sóvãodetectarseapessoacolocoumodoaviãoouseestácompletamentesemsinal.Nomundoreal,osinalévariáveledependedaqualidadederecepção.Alémdisso,podeserqueoproblemanão estejano sinaldousuário,mas simnonossoservidor-podetercaído,oupodeestarcomerro.
Vamos preferir a abordagem do timeout então. O problemadisso,claro,éque.nopiorcaso.ousuárioficaumtempoesperandooAjaxdesistir para só aí pegar os dados do cache. É ruimpara asensaçãodeperformance.
Network-firstcomcachedefallback
18.1ESTRATÉGIASPARADADOSOFFLINE 155
Podemosinverteropensamento.Semprepegamosodadolocaldo cache primeiro e já mostramos esse dado para o usuário. SódepoisdisparamosumAjaxembackgroundparaverificarsetemosdadosmaisnovosnoservidor.
A App do Facebook faz exatamente isso. Você abre e vê suatimeline instantaneamente com os dados da última vez quesincronizou, e ela logo começa a pegar os posts mais novos eatualizaatelaeatimelineparavocêautomaticamente.
A vantagem dessa estratégia é que o usuário carrega a Appinstantaneamente.A sensação de performance é ótima. É idealparacasosondeverosdadosantigosprimeironãoétãograve.
Podemos pensar ainda emmais um detalhe: a atualização emAjaxquevaiserdisparadaembackgrounddeveatualizaratelanomomentoqueretornar?OupodemosapenassalvaressesdadosparaapróximavezqueusarmosaApp?Dependedaimportânciadessesdadosatualizadosparaousuário.
O Facebook opta por atualizar a timeline no momento quesincroniza.Maspense,porexemplo,emcomofuncionaoupdatedoChromenoDesktop:elebaixaaversãomaisnovaembackground,mas só atualiza mesmo na próxima vez que você iniciar onavegador.Issoporqueoupdatenãoéabsurdamenteimportanteeparanãoincomodarousuáriocomaatualização.
Nofim,precisamospensaremcadacasoedecidirqualamelhorestratégia.
Antesde implementarmosaestratégiadeofflinepropriamente
Offline-firstcomAjaxparaatualizar
18.2SALVANDODADOSNODISPOSITIVO
156 18.2SALVANDODADOSNODISPOSITIVO
dita, precisamos pensar em como salvar os dados no dispositivo.Existemalgumasopções.
Você pode usar o bom e velho localStorage para salvardados localmente com Cordova. É uma API simples, onde vocêguardachave/valoredepoisrecuperaessesdados.
A vantagem é que funciona em todo tipo de navegador eWebViewmoderno.Adesvantageméqueélimitado.Vocêsópodegravar strings, a API é síncrona, o que pode causar gargalos deperformance, e o volume de dados salvos é limitado (depende donavegador,masédaordemdepoucosmegabytes).
Em muitos casos, como da pedidapp, o localStorage ésuficiente.Parausá-lo,nãoprecisamosdeplugin,apenaschamarnoJavaScript:
localStorage.setItem('chave','valor')varvalor=localStorage.getItem('chave')localStorage.removeItem('chave')
Existe na Web uma API melhorada para storage, que é aIndexedDB. Ela é assíncrona, transacional e suporta todo tipo dedado.Mais robusta que o localStorage, mas um pouco maiscomplicadadeseusar.
A grande desvantagem é que não tem suporte universal. Emparticular, asWebViews clássicas do iOS não suportam. Logo, naprática,nãoémuitoútilemaplicaçõesCordovamultiplataforma.
Épossívelusarumbancodedados localmaisrobustonaWeb
WebStorageAPI
IndexedDB
WebSQL
18.2SALVANDODADOSNODISPOSITIVO 157
com suporte a SQL inclusive.AAPI doWebSQLpermite isso.Oproblemaéqueelafoidescontinuada,entãoseufuturoéincerto.Ocurioso é que, mesmo assim, boa parte dos navegadoresimplementam - a única exceção é Windows Phone / InternetExplorer.
Mesmoassim,aWebSQLnativadonavegador/WebViewtemlimitações de espaço total em uso. Se quiser trabalhar com bancolocal,vejaapróximaopção.
AssoluçõesanterioresdestorageexploravamasdisponíveisnaWeb e nas WebViews por padrão. Mas estamos no Cordova, epodemosusarpluginsparausarrecursosnativos.
Em particular, é bastante comum o uso do banco sqlite nasAppsMobile.Muitasplataformas jádisponibilizamcomopartedosistemaoperacional,inclusive.Bastacriarumbancoeusar.
Podemosusaroplugincordova-sqlite-storageparaisso:
https://github.com/litehelpers/Cordova-sqlite-storage.
ElefuncionaemmuitasplataformaseofereceumaAPIparecidacomaWebSQL.Parausá-lo,precisamosinstalaroplugin:
cordovapluginaddcordova-sqlite-storage--save
UmexemplodecódigoJavaScriptquecriaumatabelaefazumINSERTemumatransaçãoseria:
//abreobancodedadosvardb=window.sqlitePlugin.openDatabase({name:"app.db"});
//iniciatransaçãodb.transaction(function(tx){//criatabelatx.executeSql(
Sqlitecomplugin
158 18.2SALVANDODADOSNODISPOSITIVO
'CREATETABLEProdutos(idintegerprimarykey,nometext)');
//insereumalinhatx.executeSql('INSERTINTOProdutos(nome)VALUES(?)',['BolodeNutella']);});
Vocêpodeconsultaradocumentaçãodopluginparaaprendermaissobreele.
Outraopçãoéoacessodiretoaosarquivosdodispositivo.Issopodeserútilparagravararquivosgrandesoffline,comoumcachedeimagensoumúsicas.
Usamosesteplugin:https://github.com/apache/cordova-plugin-file/.
Pesando todas as possibilidades que discutimos antes, parecefazersentidonapedidappumasoluçãoOffline-first.Vamossempreusaraversãodocache,sedisponível,esódepoisbuscarnaredeodadomais atual. Aindamais: como os dados não são de extremaimportância,aversãoatualizadasóestarádisponívelnapróximavezqueaAppforaberta.
Alémdisso,vamosusarlocalStorageparaguardarosdados,vistoquetemospoucasinformaçõeseesseéojeitomaissimpleseportável existente. Ele é omais limitado e, em algumas situações,pode até ser apagado pelo sistema.Mas como vamos usá-lo paracache,ésuficiente.
Nossa implementação ficará encapsulada naProdutosService,quejáhavíamoscriadonojs/services.js.
Acessoaarquivoslocaiscomplugins
18.3SOLUÇÃOOFFLINE-FIRST
18.3SOLUÇÃOOFFLINE-FIRST 159
A ideia é que todo o restante da App não precisará ser alterado.Agora,aimplementaçãoestáassim:
angular.module('starter').service('ProdutosService',function($http,$q){
varurl='http://cozinhapp.sergiolopes.org/produtos';
return{lista:function(){return$http.get(url).then(function(response){returnresponse.data;});}};
});
Ou seja, cada vez que o método lista() é chamado, nóschamamosumnovoAjaxedevolvemosumapromisequeresolveráquandooAjaxretornar.
Uma primeira coisa que já podemos fazer para melhorar aperformance é isolar a promise fora do lista() para que sejachamadoapenasumavezporexecuçãodaApp.
angular.module('starter').service('ProdutosService',function($http,$q){
varurl='http://cozinhapp.sergiolopes.org/produtos';
varpromise=$http.get(url).then(function(response){returnresponse.data;});
return{lista:function(){returnpromise;}};});
O próximo passo é salvar no localStorage o retorno doserviço.Lembredetransformaroobjetoemstring:
160 18.3SOLUÇÃOOFFLINE-FIRST
varpromise=$http.get(url).then(function(response){varjson=JSON.stringify(response.data);localStorage.setItem('cache',json);returnresponse.data;});
Agoraoqueprecisamoséverificarseexisteumvaloremcacheeusá-loimediatamentenolista().
varcache=localStorage.getItem('cache');
if(cache!=null){promise=$q(function(resolve,reject){resolve(JSON.parse(cache));});}
A API do localStorage é síncrona, mas como o métodolista devolveumapromise, embrulhamoso valordo cache emuma promise que resolve na hora. Assim, ela pode substituir apromisedoAjaxsemquebrarquemestavachamandoolista().
OcódigofinaldoProdutosServiceficaentão:
angular.module('starter').service('ProdutosService',function($http,$q){
varurl='http://cozinhapp.sergiolopes.org/produtos';
//sempredisparaoserviçoprachecardadosmaisrecentesvarpromise=$http.get(url).then(function(response){varjson=JSON.stringify(response.data);localStorage.setItem('cache',json);returnresponse.data;});
//procuranolocalStoragevarcache=localStorage.getItem('cache');if(cache!=null){promise=$q(function(resolve,reject){resolve(JSON.parse(cache));});}
return{lista:function(){
18.3SOLUÇÃOOFFLINE-FIRST 161
returnpromise;}};
});
Éumcódigopeculiar.Vamosrecapitular.
Quandoo service for criado, ele sempre vai disparar umAjaxparapegardadosmaisrecentes,masissoéassíncronoedemorará.Então,logoconsultamosolocalStorageparaversetemosdadoslocais. Se tivermos, disponibilizamos imediatamente esses dados -offlinefirst.
Enquantoisso,algumahoraoAjaxvairetornar,eentãosalvaráosdadosnovosnolocalStorage.Masreparequeessesdadosnãosão usados agora. Optamos por aquela estratégia a la GoogleChrome: os dados novos só vão ser usados na próxima vez queabrirmosaApp.
Éimportantepercebertambémque,casonãoexistamdadosnolocalStorage, apromise doAjax vai ser devolvida.Ou seja, osdadosque serãousados virãodoAjax - e vãodemorarumpoucomais,massónaprimeiravez.
Porfim,valelembrarqueimplementamosumasoluçãosimplespara um problema relativamente simples. Temos apenas umachamadadeAPIeeladevolveapenasumdado.Depropósito,deixeiasimagensemdataURIspara seremsalvas todasdeumavez.Emum projeto maior, talvez você precise usar uma solução maiscomplexa,comogravaroJSONnolocalStorage,masasimagenscomoplugindeacessoaarquivos.
Teste novamente e repare como, a partir da segunda vez, osdados vêm instantaneamente. Offline-first! Você pode desligar a
Testando
162 18.3SOLUÇÃOOFFLINE-FIRST
Interneteosdadosaindaaparecem.
Lembre-se de que ainda estamos chamando o Ajax toda vez,procurandoporatualizações.Comooserviçoéestático,vocênãodeve perceber isso. Então, implementei um truque: passe ?random=1naURLdachamadaqueelemisturaoarraynahoradedevolver (e acrescenta um pouco mais de dados para ficar maisbagunçadotambém).SótrocarnachamadadoAjax:
http://cozinhapp.sergiolopes.org/produtos?random=1
Teste abrindo e fechando a App várias vezes. Repare comotemosdados "novos"acadavez, ede forma instantânea,vindodocacheprimeiro.
Ocódigocompletodesseexemplovocêencontraem:
https://github.com/sergiolopes/pedidapp/tree/84f5.
E se quiséssemos implementar as outras estratégias de offlineque discutimos? Eu gosto bastante da solução que usamos dapedidapp de Offline-first com dados novos apenas na próximaexecução.
Masesetivermosumcenáriodiferente?
Todo o mecanismo de offline-first que fizemos continuavalendo.Precisamosapenasadicionarumaformanovadeavisaroscontrollersqueosdadosnovoschegaram.Hávários jeitosdefazerisso.Eugostodeeventos.
A ideiaéoserviceemitirumeventodeavisoquedadosnovos
18.4OUTRASIMPLEMENTAÇÕESDEOFFLINE
Offline-firstcomdadosnovos
18.4OUTRASIMPLEMENTAÇÕESDEOFFLINE 163
chegarameoscontrollersinteressadosvãoescutaresseevento.ComAngular,ébemfácilfazerisso.
No ProdutosService, quando os dados chegarem no Ajax(dentro do then), nós emitimos um evento global. Para isso,precisamosdo$rootScope, que temummétodo$broadcast,paraenviarqualquerevento:
$rootScope.$broadcast('produtos-atualizados',response.data);
Em todos os controllers interessados nos dados novos, bastaescutar esse evento com $scope.$on e passar o callback a serexecutado.Porexemplo,podemoscolocarnoHomeController:
$scope.$on('produtos-atualizados',function(event,dados){$scope.bolos=dados;});
Teste e veja que os dados do cache são carregados na hora, epoucos instantesdepoisnovosdadosos substituem.Melhor aindaseriamostraralgumindicativovisualparaousuáriodequeosdadosmudaram.
E se precisarmos implementar a solução que vai na redeprimeiroesóemcasodeproblemavainocache?
Primeiro, adicionamos um timeout ao nosso Ajax, porexemplo,5s.Seestourarouderproblemanoservidor,apromisevaifalhar e podemos capturar o erro em um bloco catch, e entãofazeraleituradolocalStorage.Ficariaalgocomo:
varpromise=$http.get(url,{timeout:5000}).then(function(response){varjson=JSON.stringify(response.data);localStorage.setItem('cache',json);returnresponse.data;}).catch(function(){
Network-first
164 18.4OUTRASIMPLEMENTAÇÕESDEOFFLINE
returnJSON.parse(localStorage.getItem('cache'));});
Somente neste cenário dá para melhorar mais coisas, comoatualizarosdadosdetemposemtempos,tentarnovamenteoAjaxsefalharnaprimeiravez,oupensarnoquefazerquandonemredenem cache estão disponíveis. Mas é preciso pensar nos outrospontos da aplicação também, por exemplo, a tela que registra opedido. O que fazer se estivermos sem rede? Faz sentido pedidooffline?Talveznão.Então,essaéumapartedaAppqueprecisaderede e pronto. Talvez seja bom melhorar a comunicação com ousuáriosobreisso.
EmoutrasApps,talvezfaçasentidoenviarosdadosmaistardequando a rede voltar.Opedidodobolonão faz sentido, senãooclientepodeacabarregistrandoumpedidonodiaerrado.
Masumclientedee-mailpodedeixarparaenviarasmensagenspendentesquandoaredevoltar.Bastasalvaramensagempendenteetentarenviarnovamentemaistarde.Noteque,paraimplementarbackgroundsyncdeverdade,comaAppfechada,éprecisofazeremcódigonativo.
Uma melhoria possível na nossa tela de registro do pedido ésalvarosdadosdoclienteparauso futuro.Assim,napróximavezqueelefizerumpedido,jápreenchemososdadospessoaisdele.
Porfim,éimportantecitarque,emcenáriosmaiscomplexos,omaior problema de suporte offline acaba sendo a sincronizaçãoconsistentedosdados.Imagineousuáriocomeçaraeditaralgumacoisa offline e quando a rede volta, descobre que outrousuário jáalterouaqueledado.Comoresolveroconflito?Esseéumproblemabastantecomplexo,quemereceriaquaseum livrosobreoassunto.
18.5INDOALÉMNOOFFLINE
18.5INDOALÉMNOOFFLINE 165
Na prática, existem frameworks para trabalhar com essasincronização.OMeteoréumdeles,porémhávários.
166 18.5INDOALÉMNOOFFLINE
CAPÍTULO19
Boapartedodiaadiadodesenvolvedorétestandoedebugandoseu código. Testar em dispositivos reais é essencial para pegarproblemasdeperformanceedecompatibilidade.
ComoestamosusandoWebViewscomtecnologiasWeb,temosas questões clássicas de portabilidade entre navegadores. Unssuportamcertosrecursoseoutrosnão,masexistemunsdetalhesaínomeioqueprecisamosdiscutir.
NoiOS,asWebViewssãobaseadasnoWebKit,aengineopen-sourceportrásdoSafari.São99%idênticasaoSafari,maspossuemalgumasdiferenças.AtéoiOS7,haviaaWebViewclássicachamadaUIWebView,que tinhadiferençasdeperformancecomrelaçãoaoSafarinormal.
No iOS 8, a Apple lançou uma nova WebView, chamadaWKWebView,alémdemanteraantigaaindadisponível.Anovaébemmelhoremuitomaisrápida,mastinhaunsbugsqueimpediamoCordovadeusá-la,atéoiOS9finalmentecorrigir.
TESTES,DEBUGECOMPATIBILIDADE
19.1TIPOSDEWEBVIEW
AhistóriadoiOS
19TESTES,DEBUGECOMPATIBILIDADE 167
HojeépossíveloptarporqualWebViewusarpelospluginsdoCordova.Porpadrão,aindaéusadaaUIWebView,mesmonoiOS9.
Umponto importanteéqueaWebViewépartedosistemadaApple. Isso quer dizer que só temos atualizações quando háatualizaçõesdoiOScomoumtodo.
OAndroidquandosurgiutinhacomobaseoWebKit também.TantoonavegadorpadrãoquantoaWebViewseguiamoWebKit,mas, geralmente, com muitas diferenças. Para piorar, como osistemaéaberto,muitosfabricantesalteravamocódigodoWebKitemseusdispositivos.
O resultado é um caos de dezenas de versões diferentes doWebKit rodando, e cada uma com seus bugs e diferenças decompatibilidade. Por exemplo, as WebViews da Samsung noAndroid 4.x não tinham suporte a IndexedDB; todos os outrostinham.
No Android 4.4, o Google melhorou o cenário migrando aWebViewdoWebKitparaoChromium,queéabasedoChrome.Muitascoisasmelhoraram,commais suporteemaisperformance.Osfabricantesaindafazemsuasmodificações,masemmenorgrau.
A partir do Android 5.0, melhorou ainda mais. A WebViewpassou a ser um componente independente do sistemaoperacional e ganha atualizações constantes pela Play Store. IssoquerdizerqueoGooglecontrolaaWebViewequeosupdatessãofrequentes, sem depender dos fabricantes atualizarem o sistematodo.
Temos, então, um cenário bastante positivo nos Androidsrecentes: uma WebView muito boa baseada no Chromium com
AhistóriadoAndroid
168 19.1TIPOSDEWEBVIEW
atualização constante. Mas e se nossa App precisa rodar nosdispositivos anteriores ao 4.4?OAndroidWebKit de antigamenteerabemruimepodetrazerváriosproblemasdecompatibilidade.
Para resolver isso, surgiu o projetoCrosswalk com uma ideiabrilhante. Eles implementaram uma WebView baseada noChromium independentedoAndroid emontaramumpluginqueempacota essa WebView junto com sua App Cordova. Isso querdizer que podemos distribuir, junto com a App, uma WebViewmodernaeprevisívelparatodososusuários,semmaisproblemasdecompatibilidade ou dores de cabeça com modificações defabricantes.
O ponto negativo, porém, é que o Crosswalk embute umChromiuminteironasuaApp.SuaAppsaltadealgunsmegabytesde tamanho para várias dezenas de megabytes - só o Crosswalkcostuma adicionar uns 20MB. Isso pode ser ruim para não só otamanho do download, como o uso de memória, já que umChromiuminteirovaiserexecutadoapenasparasuaApp.
Vamos ver como usar o Crosswalk. Cabe a você decidir emquaisprojetosesituaçõesseuusoéjustificável.
O Crosswalk (https://crosswalk-project.org) vai embutir umaWebView completa, baseada no Chromium, junto com sua AppCordova.Usá-lohojeébemsimples,bastaadicionarumplugin.
cordovapluginaddcordova-plugin-crosswalk-webview--save
Parabuildarosapks,execute:
cordovabuildandroid
Repare que ele gera 2 apks diferentes, já que o binário do
19.2USANDOCROSSWALKNOANDROID
19.2USANDOCROSSWALKNOANDROID 169
Chromium muda de acordo com a arquitetura - android-x86-debug.apkeandroid-armv7-debug.apk.Vocêpodeexecutaroprojetocomofizemosantes:
cordovarunandroid
Embutir o Crosswalk é interessante porque acaba com nossosproblemasdecompatibilidade,mas,poroutrolado,acrescentaumpeso a mais na App. Peso esse que pode ser desnecessário nosAndroidmaisrecentesquejásãobaseadosemChromium.
Épossível,então,gerarapksdiferentesparaversõesdiferentesdoAndroid,deformaausaroCrosswalknoAndroid4.x,masusaraWebViewnativanoAndroid5+.Depoisnahoradepublicarnaloja,podemossubiros2apkseindicarqualAndroiddevebaixarqualapk.
Depois de adicionar o plugin do Crosswalk, podemos gerar oapkfinalincluindooCrosswalkcom:
cordovabuild--release
ParagerarooutroAPKparaAndroid5+,precisamosremoveropluginebuildarnovamente,masindicandoqueessaversãoéapenasparaAndroid5+(SDK21):
cordovapluginrmcordova-plugin-crosswalk-webviewcordovabuild--release----minSdkVersion=21
Na prática, você pode criar um script que automatiza essageração - adicionando e removendo o Crosswalk e buildando asversõesdiferentesdoapk.
CrosswalkapenasnosAndroidsvelhos
19.3USANDOWKWEBVIEWNOIOS9
170 19.3USANDOWKWEBVIEWNOIOS9
O Cordova ainda usa a UIWebView, mesmo no iOS 9. Issoporque há algumas pequenas diferenças com relação aWKWebView,enemtodasasAppsvãofuncionardecara.
Mas podemos optar explicitamente pelaWKWebView a partirdo iOS 9, e ter uma performance melhor. Basta usar o plugincordova-plugin-wkwebview-engine.O importanteé tercertezadequeocordova-iosédaversão4ousuperior.Rodecordovaplatformparaconferiraversão.
Instaleoplugincom:
cordovapluginaddcordova-plugin-wkwebview-engine--save
Eagorabastarodar:
cordovarunios
NoiOS9,elevaiusaraWKWebViewe,noiOS8,vaicontinuarusandoaUIWebView.
Como nossa App roda na WebView, é possível fazer debugremoto como se faz em um browser normal: usar o DevTools etodassuasferramentasparadebugaraApp.
NoAndroid,issoépossívelemtodasasWebViewsbaseadasnoChromium.Paradebugaremqualquersistemaoperacional:
1. Nodispositivo,habiliteaDepuraçãoUSBnasconfiguraçõesdedesenvolvedor;
2. PlugueocaboUSBnoaparelhoenoDesktop;3. No Desktop, abra o Google Chrome e navegue para
chrome://inspect;4. SuaWebViewdeveráaparecerlistadaaí.BastaclicaremInspect.
19.4DEBUGNOANDROID
19.4DEBUGNOANDROID 171
ODevToolstoChromeébastantecompletoevocêpodeacessarvários recursos importantes, desde ver erros de JavaScript noConsole, até inspecionaros elementosHTMLe seu estilo, alémdevisualizar as conexões de rede e fazer profilings avançados dememóriaerenderização.
Paramaisinformações,consulteadocumentaçãodoChrome:
https://developers.google.com/web/tools/chrome-devtools/debug/remote-debugging/remote-debugging.
NoiOS,oprocessoésemelhante,masenvolvendooSafari.IssoexigequevocêtenhaumMacadisposição.
1. No aparelho, vá às Configurações > Safari > Avançado. Lá,habiliteaopçãoInspetorWeb.
2. NoDesktop, abra o Safari, vá àsPreferências, abaAvançado emarqueaopçãoMostrarmenuDesenvolvedor.
3. ConecteocaboUSBnoaparelhoenoMac.4. No SafariDesktop, vá aomenuDesenvolvedor e vocêdeve ver
seudispositivolistado.Selecioneapáginaparaabriroinspetor.
Odebugno Safari possuimuitas ferramentas também.ApesardenãosertãocompletoquantoodoChrome,jásupreamaioriadasnecessidades.
19.5DEBUGNOIOS
172 19.5DEBUGNOIOS
DEBUGEMOUTRASPLATAFORMAS
ParadebugarnoWindowsPhone,emumAndroidantigocomWebKit,oumesmoemumiOSsevocênãotiverMac,aúnicaopção é oweinre. Ele é bem ruim, limitado e cheio de bugs,masquebraumgalho.Melhorquenada.
AideiaérodarumservidorlocalnasuamáquinaeacrescentarumscriptespecialnoseuHTML.Saibamaisem:
https://people.apache.org/~pmuellr/weinre-docs/latest/.
19.5DEBUGNOIOS 173
CAPÍTULO20
Depoisdemuitosuor,chegaogloriosomomentofinal:publicarsua nova App nas lojas de aplicativos! Grandemomento, que éacompanhadodealgumascomplicaçõeseburocracias.
Em primeiro lugar, você vai precisar de uma conta dedesenvolvedoremcadaumadasplataformasqueforpublicar,eissoésemprepago.AApplecobra99dólaresanuais,oGooglecobra25dólaresumavez,eaMicrosoft19dólaresanuais.
O processo de gerar o arquivo final para publicação varia emcada plataforma, mas essencialmente significa buildar a aplicaçãocomojáfizemosantescomCordova,edepoisassinardigitalmenteessaApp.
UmpontoimportanteéoIDdaAppquedeveserúnicoenãopode ser mudado depois. Em geral, usamos um nome de pacotegerado a partir do domínio. Nos exemplos do livro, usei org.sergiolopes.garconapp . Use um ID único nos seusprojetos.
DepossedeumaAppassinadaedasuacontadedesenvolvedor,inicia-se o processo de publicação. Existe um trabalho meiomarketeiroaí.Vocêprecisadeumbomnome,umaboadescrição,umbom íconee screenshots reaisda suaAppparamandar junto.Semessascoisas,nenhumalojaaceitapublicar.
Falandoemaceitarapublicação, todasas lojaspossuemalgum
PUBLICAÇÃONASLOJAS
174 20PUBLICAÇÃONASLOJAS
processo de aprovação. Google e Microsoft costumam sertranquilos,comaprovaçãoautomatizadaempoucotempo.
A Apple é conhecidamente a mais chata de todas. Demorasemanasedemandaaavaliaçãopessoaldealgumfuncionáriodelá.Eles rejeitam Apps que não têm "qualidade suficiente", sãoultraconservadores quanto a coisas que competemcomeles e têmmiloutras regras.É importanteconsultaras regrasdaAppleantesdecomeçaradesenvolversuaApp,parasabersesuaideianãotemchancedeserbarradadepois.Mesmoassim,nãohácomoconversarcomeles;vocêaindacorreoriscodeterseutrabalhotodobarradodeúltimahora.
UmavezquealojaaprovasuaApp,elaficadisponívelparaseususuários instalarem. Depois você segue o mesmo processo paraatualizações - gera o pacote final, assina-o e sobe na loja paraaprovação.
Emlinhasgerais,éassimquefunciona.Vejamoscomofazernasprincipaisplataformas,AndroideiOS.
VocêprecisaterumaGoogleAccount.Logadonela,váa:
https://play.google.com/apps/publish/signup/.
Preenchaocadastroepagueataxade$25dólares.Éprecisoumcartãodecréditointernacionalparaisso.
Noterminal,gereoapkfinalcom:
20.1PUBLICAÇÃODAPLAYSTORE
CriaçãodacontadeDeveloper
PreparaçãodaApp
20.1PUBLICAÇÃODAPLAYSTORE 175
cordovabuildandroid--release
Talvez você receba um erro do tipo MissingTranslation .Nesse caso, crie um arquivo platforms/android/build-
extras.gradlecomoconteúdoaseguir,eexportedenovo:
android{lintOptions{disable'MissingTranslation','ExtraTranslation'}}
Oapkserágeradoem:
platforms/android/build/outputs/apk/android-release-unsigned.apk
Sevocênuncapublicounada,vaiprecisardeumpardechavespara assinar sua App digitalmente. Vamos gerar essas chavesprimeiro.
Paraisso,vamosusaroutilitáriokeytoolnoterminal.Eleveioinstalado junto com o Java JDK, então deve estar disponível paravocê.Executeemumúnicocomando:
keytool-genkey-v-keystorechave-android.keystore-aliasalias_name-keyalgRSA-keysize2048-validity10000
Elevaipedirumasenhaparadesbloquearachave.
IMPORTANTÍSSIMO
Guardeessaschavescomsuavida.Vocênãopodeperderessesarquivos; se perder não conseguemais atualizar a App. E secaírem em mão erradas, podem ser usadas para coisasmaliciosasemseunome.
ParaassinaraApp,usamosojarsigner,quetambémveiono
AssinandoaApp
176 20.1PUBLICAÇÃODAPLAYSTORE
JDK.Elerecebeoarquivodachaveeoarquivoapkquegeramosantes.Executeemumúnicocomando:
jarsigner-verbose-sigalgSHA1withRSA-digestalgSHA1-keystorechave-android.keystoreandroid-release-unsigned.apkalias_name
O último passo é rodar o utilitátio zipalign que vem noAndroid SDK. Ele ajeita algumas coisas no arquivo antes dapublicação.
zipalign-v4android-release-unsigned.apkSoDeCenouraFinal.apk
Caso não esteja no seu PATH, o zipalign pode serencontrado na pasta do Android SDK em build-
tools/VERSAO/zipalign.
É possível fazer a exportação e assinatura do apk peloAndroid Studio se você o tiver aberto. A complexidade é amesma,masvocêfazcomumainterfacevisual.
Consulte: http://developer.android.com/intl/pt-br/tools/publishing/app-signing.html#studio.
Feita nossa conta de developer e gerado o apk assinado,podemos iniciar a publicação. Acesse:https://play.google.com/apps/publish/.
CrieumanovaApp,escolhaalíngua,dêumnomeefaçauploaddo APK. Em seguida, vá seguindo as instruções para incluir asoutras informações. Ele pede descrição, screenshots, classificaçãoetária e outros dados. Não coloquei no livro, pois essas opçõesmudam,maséfácildeacompanharpelopassoapassonaStore.
SubindoaAppnaPlayStore
20.1PUBLICAÇÃODAPLAYSTORE 177
No final, o botão Publicar App fica disponível. Então, é sóclicar. Depois de algumas horas, você já deve achar sua App naStore.
Para fazer a publicação, vocêprecisaráda contadeDeveloper,quecusta99dólaresanuais.Paraabrirsuacontadeveloper,acesse:
https://developer.apple.com/programs/enroll/.
Você precisará de um cartão de crédito internacional para opagamento.
PrecisamosregistraroIDdanossaApp.ÉomesmoIDquevocêcolocou no XML do Cordova, por exemplo,org.sergiolopes.teste.Acessecomsuacontadeveloper:
https://developer.apple.com/account/ios/identifiers/.
Lá, crie um novo App ID. No Bundle Identifier, coloque omesmoIDdasuaAppCordova.
OprimeiropassoécriarumCertifiedSigningRequest(CSR).
1. NoMac,abraoaplicativoKeychainAccess.2. VáaomenuKeychainAccess>CertificateAssistant>Requesta
CertificatefromaCertificateAuthority.3. Preenchaseunome,umnomeparaachaveedeixeoCAEmail
embranco.SelecioneaopçãoSavetodisk,efinalizeacriação.
20.2PUBLICAÇÃONAAPPLESTORE
ContadeDeveloper
CriaçãodoAppID
Geraçãodaschaves
178 20.2PUBLICAÇÃONAAPPLESTORE
Agoraprecisamoscriaroscertificadosparaprodução:
1. Acessehttps://developer.apple.com/account/ios/certificate/.2. CrieumnovocertificadodotipoProduction,AppStore.3. FaçauploaddoCSRquegeramosantes.4. Finalizeacriaçãoefaçaodownloaddocertificado.5. AbraoarquivonoMaceadicionenaKeychain.
Agoraprecisamoscriarumprovisioningprofileparaprodução:
1. Acessehttps://developer.apple.com/account/ios/profile/.2. CrieumnovoprofiledotipoDistribution,AppStore.3. SelecioneoAppIDquecriamosantes.4. Emseguida,selecioneocertificadodeproduçãoquecriamosno
passoanterior.5. Dê um nome para o profile e finalize. No final, faça o seu
Download.6. Abraoarquivobaixado.
Oprocesso de exportação, assinatura e envio daAppdeve serfeitopeloXcode,logo,abraoprojetonoXcode.Eleestáem:
platforms/ios/Projeto.xcodeproj
1. AbraoprojetonoXcode.2. No canto esquerdo superior, próximo ao botãoPlay, selecione
GenericiOSDevice.3. VánomenuProduct>Archiveparageraroarquivo.4. Após a geração do pacote, clique em Validate. Selecione o
provisioningprofilequecriamosantes.5. Agora,cliqueemUploadtoAppStoreeselecionenovamenteseu
provisioningprofile.
Opcionalmente, você pode também exportar o arquivo
ExportaçãodaAppassinada
20.2PUBLICAÇÃONAAPPLESTORE 179
localmenteparadepoisfazerouploadnaloja.
BUILDSEMMAC
É possível usar o PhoneGap Build para gerar o pacote finalassinado da sua App para produção. Basta fazer upload docertificado e do provisioning profile, gerar por lá e baixar oarquivoipafinal.
Feitanossacontadedeveloperegeradoarquivofinal,podemosiniciarapublicaçãopeloiTunesConnectem:
https://itunesconnect.apple.com.
CrieumanovaAppe siga as instruções.UseoBundle IDquevocêcriouantes.Vocêvaiprecisarpreenchermuitasinformaçõesesubirscreenshots.Acompanheasinstruções.
VocêpodefazerouploaddoarquivoipaexportadonoXcode.Ou, se fez o upload direto pelo Xcode, seu build já deve estardisponívelnoiTunesConnectparaselecionar.
Nofim,vocêpodeenviarsuaAppparareview,umprocessoquedemora algumas semanas. Aí então sua App estará disponível naloja.
PublicandoaAppnoiTunesConnect
180 20.2PUBLICAÇÃONAAPPLESTORE
usaroIonicPush,quejáresolvealgumasquestões.
O ponto é que, entendida a arquitetura do Cordova, seufuncionamento e suas limitações, agora é questão de apenas irimplementando novas funcionalidades. Boa parte das coisas sãofeitas emHTML,CSS e JavaScript simples, comonaWeb.E paratodas asoutras - comoasnotificações -, existempluginsquevocêpode instalar. Cada plugin tem uma forma de uso própria, bastaconsultaradocumentaçãoindividualmente.
Obrigadopor acompanharo livro. Se você tiverdúvidas,podeme encontrar no fórum da editora Casa do Código, emhttp://forum.casadocodigo.com.br/.
Oquevocêvaicriarcomtudooqueaprendeuaqui?
182 21INDOALÉM