LuizTools 2.0

Desde 2010 codificando minhas ideias!

Império dos Apps - Resenha

Resenha do livro Império dos Apps, de Chad Mureta.

Recentemente estive na Livraria Cultura em Porto Alegre para tirar o atraso de leitura que já me perseguia algum tempo. Como rato de livraria que sou, minha lista de livros para ler estava ficando grande demais e resolvi comprar alguns. Não queria um livro de programação (que aliás nunca comprei nenhum) mas queria um livro que falasse sobre desenvolvimento de apps de um modo geral. Foi quando encontrei o Império dos Apps, de Chad Mureta.

Ganhe dinheiro, aproveite a vida e deixe a tecnologia trabalhar por você

Esse é o lema do livro, logo abaixo do grande título sobre a capa cheia de ícones simbolizando apps. O livro relata a grande virada na vida do autor, que quase morreu em um acidente de carro e teve seu braço e confiança mutilados. Chad decidiu que aproveitaria melhor a sua "nova chance" e acabou conhecendo por acaso o mercado de apps graças à uma revista emprestada. Com U$1500 emprestados ele investiu no desenvolvimento de seu primeiro app e deu início à sua empresa chamada Empire Apps, daí o nome do livro.

Discípulo do Tim Ferriss

Em outro post de resenha aqui do blog comento do excelente Trabalhe 4 Horas por Semana, de Timothy Ferriss. Enquanto lia O Império dos Apps notei muita semelhança no discurso de Chad e lá pelas tantas descobri o motivo: Chad leu o livro de Tim e é uma das poucas pessoas que já ouvi falar que realmente aplicaram o método dele de microaposentadorias, infoprodutos e tudo mais. Chad não chega ao extremo de terceirizar todas suas tarefas, mantendo uma equipe focada em desenvolver seus aplicativos em sua própria empresa, mas pegou o que há de melhor no método de Trabalhar 4 Horas por Semana e aplicou em seu negócio de apps, hoje um enorme sucesso com mais de 46 aplicativos no portfólio e mais de 50 milhões de downloads na App Store.

Técnica e muita Prática

O livro de Mureta é muito prático e cheio de exemplos. Ele cita os números que obteve, as pesquisas que realizou e os apps que pagou para desenvolvedores contratados por ele desenvolvessem. Sim, Chad não é um desenvolvedor, ele era um corretor de imóveis antes de entrar neste mercado e mesmo que você seja um, ele não aconselha que desenvolva seus próprios apps. O motivo? Como CEO de uma empresa de apps (que ele chama de appreendedor) o seu foco deve ser gerir o negócio, contratar as pessoas certas e fazer o marketing dos apps. A estratégia como um todo, e não a operação. E isso faz todo sentido.

Mesmo que não queira construir um império dos apps assim como o autor, muitas das técnicas abordadas no livro são extremamente úteis como pesquisa de mercado, o ciclo construir-medir-aprender assim como no Lean Startup (que já mencionei em outro post), a análise da concorrência, modelos de negócio para apps e muito mais. É uma leitura recomendadíssima para startupeiros do ramo de apps, na minha opinião.

Sem milagres

Ao contrário do que muitos podem pensar, Chad não força a barra dizendo que todos podem ficar ricos da noite pro dia criando um app mágico. O slogan do livro é apenas marketing e seu conteúdo deixa claro que criar uma empresa de apps sustentável e duradoura requer muito foco e disciplina. É preciso lançar muitos apps para construir uma cadeia de valor que gere uma renda constante capaz de manter uma empresa, sem contar que muitos dos apps irão fracassar como o próprio autor experimentou mais de uma vez. Chad não enconraja ninguém a tentar criar o próximo Angry Birds, mas sim em aproveitar as tendências do mercado e criar os apps que as pessoas estão buscando para, obviamente, lucrar com eles. Esse posicionamento pragmático foi o que mais me chamou a atenção no livro e me fez dar mais valor aos ensinamentos de um empreendedor de sucesso que hoje lidera algumas empresas bem sucedidas deste mercado. 

Ou seria melhor dizer, appreedendor? ;)

Acessando banco de dados remoto com Android

Passo-a-passo de como acessar bancos de dados remotos com Android, com técnica baseada em API.

Este tutorial estava há tempos para ser escrito e na verdade é muito mais simples do que a maioria dos desenvolvedores pensam. Programadores Java em geral estão acostumados a utilizar o framework JDBC para realizar conexões aos seus bancos de dados favoritos como MySQL e SQL Server, diretamente. Entretanto, o Android não oferece suporte nativo à conexões remotas em SGBDs e este tipo de conexão deve ser realizado através de uma API.

A API

Como o intuito deste post não é ensinar como criar uma API, que neste exemplo nada mais é do que um webservice, usaremos uma API pronta. O site http://freegeoip.net oferece uma API aberta e gratuita para descobrir a geolocalização de um dispositivo com base em seu endereço IP. Ou seja, você informa o IP e a API deles retorna um JSON, CSV ou XML com os dados de localização, quando encontrados.

Você pode testar a API fazendo chamadas a http://freegeoip.net/formato/seu_ip onde 'formato' deve ser substituído por json, csv ou xml e 'seu_ip' deve ser substituído pelo IP que deseja consultar, ou nada, para consultar a localização do seu IP atual. Neste exemplo usaremos a URL http://freegeoip.net/json/8.8.8.8 que é o IP do servidor de DNS do Google, na Califórnia.

Mas o que isso tem a ver com acesso a bancos de dados remotos, você deve estar se perguntando. O FreeGeoIP nada mais é do que uma base de dados remota onde seus desenvolvedores criaram um webservice REST para consulta de dados a a partir de qualquer plataforma, ou seja, eles permitem através da API que qualquer um possa acessar seu banco de dados, e é exatamente isso que um desenvolvedor Android necessita fazer para integrar de maneira prática e eficiente um banco de dados remoto ao seu app.

O APP

O primeiro passo é abrir nossa ferramenta, o Android Studio. Outras ferramentas possíveis incluem o ADT Bundle e o NetBeans com suporte à Android. Mande criar um novo projeto do tipo Android Application e lhe dê o nome de LocationApp. A versão de Android fica ao seu gosto, enquanto eu utilizei a versão 4.0 em meus testes, oferecendo compatibilidade com toda a família IceCream Sandwich e posteriores, incluindo o Android Kit Kat (4.4).

Crie uma Blank Activity chamada LocationActivity que herdará da Activity base e que criará ao mesmo tempo o arquivo de layout activity_location.xml na pasta de layouts. Crie seu layout de maneira bem simples, usandos widgets padrões do Android SDK como TextViews, EditText e Button, como mostra o trecho de código abaixo (devido a problemas em meu plugin, está tudo em minúsculo):



    
    

    
    

    

    
    

    
    

    
    

    
    


O layout pretendido é esse:


Com o layout criado, é hora de começar a programar nossa Activity, fazendo o binding de cada widget com variáveis de mesmo tipo, como mostra o trecho de código abaixo que fica no evento onCreate da Activity.

    EditText txtIP;
    TextView lblCountry, lblRegion, lblCity;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_location);

        //permite conexão com a Internet na Thread principal
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);

        //carrega os controles da interface para objetos
        txtIP = (EditText)findViewById(R.id.txtIP);
        lblCountry = (TextView)findViewById(R.id.lblCountry);
        lblRegion = (TextView)findViewById(R.id.lblRegion);
        lblCity = (TextView)findViewById(R.id.lblCity);
    }

O próximo passo é criar uma classe para consumir a API do FreeGeoIP.net, que chamamos de ClienteGeoIP, além de uma classe para representar o objeto Localizacao do nosso app, que possui as referidas informações que queremos exibir na tela. A classe ClienteGeoIP conecta-se na API usando um cliente HTTP e convertendo o retorno para o formato JSON, usando as bibliotecas nativas do Android.

Primeiro a classe Localizacao.java:

public class Localizacao {
    private String country;
    private String region;
    private String city;

    public Localizacao(String country, String region, String city){
        this.country = country;
        this.region = region;
        this.city = city;
    }

    public String getCountry(){ return this.country; }
    public String getRegion(){ return this.region; }
    public String getCity(){ return this.city; }
}

Agora a classe ClienteGeoIP e seu único método que consome a API:

import org.apache.http.client.*;
import org.apache.http.client.methods.*;
import org.apache.http.impl.client.*;
import org.json.*;

import java.io.IOException;

public class ClienteGeoIP {

    public static Localizacao retornarLocalizacaoPorIp(String ip) throws IOException, JSONException {
        HttpClient client = new DefaultHttpClient();
        HttpGet getMethod=new HttpGet("http://freegeoip.net/json/" + ip);
        ResponseHandler responseHandler = new BasicResponseHandler();
        String responseBody = client.execute(getMethod, responseHandler);

        JSONObject obj = new JSONObject(responseBody);
        String pais = obj.get("country_name").toString();
        String estado = obj.get("region_name").toString();
        String cidade = obj.get("city").toString();
        return new Localizacao(pais, estado, cidade);
    }
}

Com o método de retornar localização criado, devemos definir o método do evento OnClick do botão de carregar a  localização da nossa LocationActivity (note que existe uma chamada a um evento carregarLocalizacao no XML do Button). Esse método deve ser declarado na LocationActivity, logo abaixo do evento onCreate:

public void carregarLocalizacao(View view){
        try {
            Localizacao localizacao = ClienteGeoIP.retornarLocalizacaoPorIp(txtIP.getText().toString());
            lblRegion.setText("Estado: " + localizacao.getRegion());
            lblCity.setText("Cidade: " + localizacao.getCity());
            lblCountry.setText("País: " + localizacao.getCountry());
        }
        catch(Exception ex){
            Toast.makeText(getBaseContext(), ex.getMessage(), Toast.LENGTH_LONG).show();
        }
    }

Não esqueçamos que uma vez que vamos conectar à Internet precisamos informar essa permissão no AndroidManifest.xml, conforme mostrado abaixo.




    
        
            
                
                
            
        
    

    

Testando nosso app em um AVD conseguimos ver que ele funciona perfeitamente e com isso encerramos mais este breve tutorial. Um abraço.


Download do APK: GeoLocalizacao.apk (56,4KB)

Download do Código-Fonte: GeoLocalizacao.7z (175,3KB)

Tudo sobre o arquivo build.settings do Corona SDK

Saiba tudo sobre Corona SDK com o único livro em Português sobre este incrível framework, com quase

Saiba tudo sobre Corona SDK com o único livro em Português sobre este incrível framework, com quase 500 páginas. Saiba mais!

Alguns desenvolvedores, especialmente aqueles novos com Corona ou com desenvolvimento de apps em geral, têm problemas com as configurações e parâmetros que são necessários para compilar com sucesso um app para testar e eventualmente, lançar no mercado. Em Corona, estas configurações são ditadas através do arquivo build.settings, mas inspecionar um build.settings complexo pode ser intimidador. Entretanto, se você entende tables Lua e mentalmente separar este arquivo em seções, você irá entender melhor este elemento crucial do projeto.

Overview

Essencialmente, o arquivo build.settings contém informações que determinam quais recursos devem ocorrer em tempo de compilação. Estes são divididos em 5 áreas primárias:

  • Orientation - controla as orientações de tela suportadas;
  • iOS Settings - características especiais do iOS
  • Android Settings - características para Android
  • Plugins - carrega vários plugins que um app pode precisar acessar
  • Excluded Files - Exclui certos arquivos das suas compilações de app.

Isto tudo começa com uma simples table Lua chamada settings:


Desta forma, esta table pode conter vários pares de chave-valor para cada uma das cinco seções, e cada uma destas tables pode ter vários pares chave-valor aninhados, muitos dos quais exploraremos neste tutorial.

Declaração Chave-Valor

Estas seções chave-valor podem ser definidas de uma de três maneiras, ou uma combinação de todas três, dependendo da sua preferência ou, e alguns casos, o nome da chave sendo definida.

1. Propriedades da Table


2. Array Associativo


Note que este método é exigido quando sua chave contém caracteres especiais como um traço. Por exemplo, se você precisa definir uma chave como hokey-pokey, você precisará especificar ela como settings["hokey-pokey"] e não como settings.hokey-pokey que é considerado inválido em Lua. Isto será muito importante quando definirmos os plugins.

3. Estrutura de Tables Aninhadas


Observações Adicionais

Todos os três formatos são perfeitamente válidos, mas o formato padrão mostrado em nossos exemplos e documentação é o formato table aninhada.

Cada uma destas seções chave-valor é opcional. Se você está compilando somente para iOS, você não precisa incluir a table android. Da mesma forme, se estiver compilando para Android, você não precisa incluir a table iphone. Se você não usa quaisquer plugins, você pode omitir a table plugins. E, embora você não precise de uma table orientation, você deve fornecer uma em praticamente todo app para definir as orientações permitidas ao app.

A ordem destas seções não é importante, desde que inclua-as corretamente como pares de chave-valor.

A table Orientation

A seção orientation é a mais fácil das cinco - ela meramente define qual orientação é a padrão para o app, e quais outras orientações são permitidas se o usuário girar o telefone.


Existem duas chaves para esta table: default e supported. O valor default é uma string que determina a orientação na qual o app irá começar. Strings válidas incluem:

  • "portrait"
  • "portraitUpsideDown"
  • "landscapeLeft"
  • "landscapeRight"

O valor supported é uma table indexada (sem chaves) que pode conter quaisquer das quatro opções listadas acima, separada por vírgulas. Note que esta table deve incluir o mesmo valor que você definiu como default, em adição a quaisquer outras orientações que você deseja suportar. No exemplo acima, o app irá carregar em "landscapeRight", mas também permite trocar para a orientação "landscapeLeft", visando fornecer uma melhor experiência aos usuários.

A table iphone

A table iphone contém todas as configurações necessárias para compilar para dispositivos iOS. Note o seguinte:

Esta table deve ser digitada como iphone (tudo em minúscula) mesmo que o dispositivo seja normalmente chamado de "iPhone" - este é um problema comum para novos usuários, então certifique-se de digitar corretamente.

A table iphone cobre todos os dispositivos iOS incluindo iPhone, iPad e iPod Touch, então você só precisa desta seção para compilar para todos eles.

A sub-table plist

A table iphone sempre contém outra table aninhada chamada plist. Esta é uma table cujos valores são copiados dentro do dicionários plist do projeto XCode. Logo, se você precisa incluir itens nessa lista, adicione-os aqui.

As chaves dentro da table plist são as mesmas do XCode, mas os valores são orientados ao Lua. Por exemplo, em XCode existe um par chave-valor chamado UIApplicationExitsOnSuspend que aceita valores booleanos do XCode como YES e NO. Entretanto, Lua usa true ou false, logo, para definir esta preferência para um app Corona, sua table iphone deve incluir isto:


A maioria das tables iphone incluirão mais do que isto, e alguns desenvolvedores comumente copiam esta table de build.settings existentes sem entender seu conteúdo. Considere o seguinte exemplo:


Esta table pode parecer complexa, mas vamos dar uma olhada e explorar os vários elementos:

  • CFBundleIconFile - esta String declara o nome base do seu ícone do app. Este valor pode ser geralmente "Icon.png" (note que é case-sensitive com I maiúsculo).
  • CFBundleIconFiles - esta é uma table indexada (sem chaves) que diz ao iOS quais arquivos de ícone devem ser usados nos vários dispositivos. Para uma experiência de usuário melhor, você deve incluir todas estas opções, e deve criar todos os arquivos de ícones associados nos tamanhos apropriados.
  • UIApplicationExitsOnSuspend - este valor boolean instrui o IOS que o app não deve terminar quando é suspenso. Este valor deve ser false na maioria das vezes.
  • FacebookAppID - para implementar a funcionalidade do Facebook, você precisará incluir este par chave-valor. Seu valor único pode ser obtido no painel de desenvolvedor do Facebook.
  • CFBundleURLTypes - este é um array indexado de chaves-valores que descrevem os esquemas de URL suportados pelo app (consulte a documentação da Apple para maiores detalhes). Por causa desta estrutura, esta table começa com uma sub-table sem chaves adicional. No exemplo acima, relacionamos um esquema de URL para o Facebok.

Outros Elementos

Este tutorial não pode discutir cada elementos que possa existir na table iphone, então consulte a documentação oficial do Corona e da Apple para maiores informações.

A table android

O Android é razoavelmente simples na maioria dos casos - tipicamente é somente uma lista de permissões e características. Note que você deve incluir uma table usesPermission dentro da table Android que é uma lista de permissões que você quer conceder ao app. No exemplo seguinte, permitimos ao app Corona acesso à Internet.


Uma versão um pouco mais complexa pode incluir uma table usesFeatures que diz ao Android Marketplace quais capacidades de hardware o app precisa ou não precisa.


Outros Elementos

Este tutorial não pode discutir cada elemento que pode existir na table android, para isso consulte a documentação oficial do Corona e a documentação do Google, na parte de permissions e features.

A table plugins

A seção final a ser discutida é a table que suporta os plugins do Corona SDK. Um exemplo básico que habilita o plugin AdMob se pareceria com isso:


Note que o nome da chave para est plugin (CoronaProvider.ads.admob) inclui pontuação. Devido a isto, você deve usar colchetes e aspas ao definir esta chave. Mesmo que o nome do plugin não inclua pontuação, este método fornece um nível de consistência:


Neste exemplo mostramos um aspecto importante de incluri plugins: a sub-table supportedPlatforms. Se você usar um plugin que é específico de uma plataforma, você pode usar a chave supportedPlatforms para instruir os servidores de build do Corona a somente incluírem o plugin na plataforma específica.

Porque Facebook é considerado "platform specific" no contexto de plugins? A funcionalidade do Facebook é, na verdade, disponível para iOS e Android, mas desde algum tempo que o Facebook para iOS foi removido do core do Corona e agora é implementado via plugin. Se você está usando uma versão mais recente do Corona e está compilando para iOS, você deve incluir a chave acima ["facebook"] na sua table plugins, juntamente com a sub-table supportedPlatforms.

Precauções Importantes

1. Copiando e Colando Blocos de Código

Comumente, desenvolvedores copiam e colam exemplo de código a documentação do Corona. Tudo bem, mas você deve estar atento a manter a organização de todas tables dentro do build.settings. Não copie simplesmente os exemplos mostrados acima e se copiar tome cuidado em não colar as sub-tables nas seções errradas, como colar um bloco plugin dentro de uma table iphone.

2. Indentação Apropriada

Realmente ajuda indentar seu código. A maioria dos editores de código modernos manipulam a indentação do código automaticamente, e é ainda mais importante indentar o código do build.settings porque ele será normalmente uma miríade de tables e sub-tables. Com a indentação apropriada, será mais fácil de manter seus elementos organizados e legíveis.

Conclusão

O build.settings pode ser bem complexo, mas no fundo, nada mais é do que tables Lua aninhadas com seus pares de chave-valor, e quanto mais confortável você estiver com esses aspectos, mais fácil será construir um build sem falhas para todas plataformas.

Saiba tudo sobre Corona SDK com o único livro em Português sobre este incrível framework, com quase 500 páginas. Saiba mais!