SentryCar – Sistema de rastreamento e bloqueio veicular

Olá,

Recentemente desenvolvi todo um sistema de rastreamento e bloqueio de veículos, chamado de SentryCar.

O projeto consiste em uma aplicação mobile ou web que pode ser acessada por um cliente/usuário para rastrear um ou vários veículos, monitorar sua localização e velocidade, além de bloquear e desbloquear o carro, cortando a fonte de combustível quando ele atinge 20Km/H ou menos.

O sistema é dividido em 6 partes:

  • Apps (iOS e Android).
  • Web (mesmo sistema acessado pelos apps e pagamento da mensalidade).
  • Servidor (servidor desenvolvido em Go para receber conexões TCP/IP dos rastreadores e coletar os dados necessários).
  • Banco de dados MySql.
  • Rastreadores importados do AliExpress e interpretação do protocolo definido pelo fabricante.
  • API que permite qualquer device via HTTP/TCP enviar sua posição, desde que esteja cadastrado no sistema. Tanto os aplicativos, como o sistema web e o rastreador, utilizam a mesma API.

 

Eu precisei fazer uns vídeos para que a Apple aprovasse meu app, então fiz alguns vídeos demos e coloquei em minha conta do Youtube:

  • https://www.youtube.com/watch?v=pKCQLeSOvdg
  • https://www.youtube.com/watch?v=0RsqSgQETRc

 

URL para demonstração:

  • http://sentrycar.prsolucoes.com

 

Caso alguém precise desenvolver algo do tipo, podemos fazer uma parceria.

 

Obrigado e até o próximo post pessoal.

Limpando os dados do Docker em sua máquina (containers e imagens)

Olá,

Quem utiliza Docker no dia-a-dia sabe que ele deixa muitos lixos na máquina em que está rodando, principalmente se você fica criando containers de teste como eu.

Quando você sai do container o Docker não apaga eles automaticamente, o que vai enchendo o disco e você acaba recebendo o erro: No space left on device.

Como eu passo por isso sempre, resolvi fazer uma sequência de comandos para copiar e colar no terminal, a fim de que o ambiente fique limpo denovo.

docker rm -v $(docker ps -a -q -f status=exited)
docker rmi $(docker images -f "dangling=true" -q)
docker volume rm $(docker volume ls -qf dangling=true)

 

Espero ter ajudado com este artigo.

Obrigado e até o próximo post pessoal.

 

Usando o auto-update do Fastlane

Olá pessoal,

Recentemente tivemos um necessidade de fazer com que o Fastlane (ferramenta para deploy contínuo – http://fastlane.io/) fizesse a atualização de suas dependências automaticamente, isso inclui todos esses caras:

cert, credentials_manager, deliver, fastlane, fastlane_core, frameit, gym, match, pem, pilot, produce, scan, screengrab, sigh, snapshot, spaceship, supply

Toda vez que vamos usar o Fastlane para subir as aplicações tem atualizações novas de suas dependências e que muitas das vezes gera algum erro no envio e não conseguimos subir os aplicativos até que atualizemos manualmente as dependências necessárias com o comando “gem update …” e depois começamos o processo novamente de deploy.

Isso é bem chato, então a primeira coisa que pensei foi em adicionar o “gem update” em nossa ferramenta de integração contínua, GoCI (http://github.com/prsolucoes/goci), antes de fazer as chamadas ao Fastlane.

A segunda opção era buscar na documentação para saber se existe alguma coisa pronta para este problema, e foi ai que achei o comando “update_fastlane”. Após olhar a documentação e realizar alguns testes, resolvi escrever o passo-a-passo para implementar isso. Vamos à prática:

  1. Adicione no início do seu arquivo Fastfile, antes de qualquer coisa, esta linha:

    update_fastlane

  2. Adicione as seguintes linhas ao seu arquivo “.bash_profile” ou “.bashrc”, que fica na pasta do seu usuário, ex (nano ~/.bash_profile):

    export GEM_HOME=~/.gems
    export GEM_SPEC_CACHE=$GEM_HOME/specs
    export PATH=$PATH:~/.gems/bin

  3. Execute o arquivo modificado com o comando “source”, ex:

    source ~/.bash_profile

  4. Atualize o rubygems e o gem:

    gem install rubygems-update
    sudo gem update –system

  5. Instale suas gems novamente, as que você usa. No meu caso era o fastlane e cocoapods, então fiz assim:

    gem install cocoapods fastlane –no-ri –no-rdoc

Com tudo isso feito, você já preparou o seu ambiente e atualizou tudo o que é necessário para que o auto-update do fastlane funcione. Agora basta você executar suas tarefas do fastlane que ele vai executar o auto-update antes de tudo.

Obs: Nós definimos uma novo diretório para as “gems” do ruby porque sem isso o fastlane irá reclamar que a pasta de “gems” é do usuário root (sendo necessário fazer um sudo + comand) e não sua.

 

Espero ter ajudado com este artigo.

Obrigado e até o próximo post pessoal.

Instalando drivers não assinados (unsigned) no Mac/OSX

Olá,

Recentemente precisamos instalar o driver de um adaptador de Rede Ethernet RJ45 no Mac (Plugable USB 3.0 to 10/100/1000 Gigabit Ethernet LAN Network Adapte – Chiptset LAN7500) e o adaptador não ligava e não funcionava de jeito algum.

Porém ao tentar carregar o driver via terminal aparecia a mensagem:

/System/Library/Extensions/LAN7500.kext failed to load – (libkern/kext) not loadable (reason unspecified); check the system/kernel logs for errors or try kextutil(8).

O problema está na verdade não com o driver, mas com o sistema que é o Sierra. Parece que depois de alguma versão El Captain ou Yosemite a Apple passou a aplicar um sistema de segurança nos drivers que só pode ser desabilitado em modo de recuperação.

Então para fazer o driver funcionar e verificar se você possui o mesmo problema, faça o seguinte:

sudo kextload /System/Library/Extensions/LAN7500.kext

Substitua “LAN7500.kext” pelo nome do seu driver. Se ao executar você receber a mensagem abaixo, então você está com o mesmo problema:

/System/Library/Extensions/LAN7500.kext failed to load – (libkern/kext) not loadable (reason unspecified); check the system/kernel logs for errors or try kextutil(8).

Agora reinicie seu Mac segurando as teclas CMD + R. O sistema iniciará em modo de recuperação. Acesse o menu “Utilitários > Terminal” e digite:

csrutil disable

Ele vai informar que você precisa reiniciar, então digite agora:

reboot

Ao reiniciar seu Mac, o driver já será carregado e tudo funcionará.

 

Adaptador rede Mac OSX

 

Espero ter ajudado com este artigo.

Obrigado e até o próximo post pessoal.

Golang – GoDiffExporter – Exporte seus DIFFs com este utilitário

Olá,

Recentemente precisei compartilhar o resultado de um DIFF (git diff) para uma outra pessoa fazer a conferência e com isso eu precisava passar o acesso ao bitbucket e o link do commit específico para a conferência.

Isso me gerava um certo trabalho que eu não gostaria de ter toda vez que precisasse fazer isso, foi ai que pensei então no GoDiffExporter, um exportador em PDF de um arquivo DIFF qualquer.

Basicamente o parser do DIFF é feito e depois eu itero nas diferenças e crio o PDF, usando a lib GoFPDF, que inclusive colaborei recentemente adicionando o suporte a fontes embarcadas através de um array de bytes que vai dentro da sua própria aplicação, removendo a necessidade de distribuir as fontes em si (https://github.com/jung-kurt/gofpdf/pull/79).

O resultado do GoDiffExplorer é um PDF como este:

 

O projeto e as instruções de como instalar e usar estão na página do projeto:

https://github.com/prsolucoes/godiffexporter

 

Espero ter ajudado com este artigo.

Obrigado e até o próximo post pessoal.

Android – Debug de aplicação via WiFi usando ADB sem precisar de root

Olá,

Recentemente tive a necessidade de rodar a aplicação pelo Android Studio sem usar cabo, por questões de comodidade mesmo, e após pesquisar e fazer vários testes, preparei um tutorial sem simples.

  1. Desconectar o seu dispositivo do computador, caso esteja.
  2. Conectar o seu computador de desenvolvimento e o seu dispositivo Android na mesma rede WiFi.
  3. Habilitar o modo desenvolvedor em seu dispositivo (Configurações > Sobre > Apertar 7 vezes em Número da versão).
  4. Habilitar a depuração USB (Configurações > Programador > Depuração USB).
  5. Obtenha o IP do seu dispositivo em Configurações > Sobre > Status > Endereço IP.
  6. Abrir o terminal e executar (troque o IP abaixo pelo IP do seu dispositivo):
    adb tcpip 5555
    adb connect 192.168.0.103:5555
  7. Rodar a aplicação no Android Studio normalmente e se tudo deu certo seu dispositivo aparecerá na lista de devices como se estivesse conectado via cabo.

 

Espero ter ajudado com este artigo.

Obrigado e até o próximo post pessoal.

Mobile – Como as redes de anúncios (Ad Networks) realizam o tracking de campanhas

Olá pessoal,

Uma dúvida muito comum e também uma informação muito importante, é saber como fazer o tracking (ou rastreamento) de um usuário que fez o download e instalou um determinado aplicativo através de um link, banner ou uma campanha em geral.

É importante entender que não existe um jeito fácil, simples e universal para que isso aconteça e pode ser que alguma informação se perca no meio do caminho dependendo das ações dos usuários. Cada plataforma resolveu este problema de um jeito diferente.

No caso da Apple funciona assim:

Um usuário utiliza uma ferramenta de anúncios que irá exibir um banner, link ou algo do tipo no dispositivo do usuário. O link contido neste banner é um link que contém uma informação especial chamada pela Apple de IDFA, que consiste em um token específico para anúncios e é único por device. A Apple não permite o uso desse token outro fim além de usá-lo para tracking de anúncios e qualquer tentativa fora esta terá o app rejeitado, como está em sua documentação (Link 1, Link 2, Link 3).

Vou usar o exemplo do Google Analytics para explicar como ele consegue através do IDFA fazer o tracking de suas campanhas.

Um anúncio exibido pelo Google em suas redes de anúncio teria um link com uma estrutura parecida com esta:

http://click.google-analytics.com/redirect?
tid=UA-1234-1 // Google Analytics Tracking ID.
&idfa=BBA44F63-E469-42BA-833A-2AC550310CB3 // Identifier for Advertising (IDFA)
&aid=com.bundle.myapp // App ID.
&cs=network // Campaign source.
&cm=cpc // Campaign medium.
&cn=campaign_name // Campaign name.
&url=https%3A//itunes.apple.com/us/app/myApp/id123%3Fmt%3D8 // Redirect URL to iTunes.

Esse link do anúncio do Google vai registrar no servidor deles que você clicou nele e vai gravar as informações que ele deseja para depois juntar as peças e cruzar as informações. Após gravar o que ele precisa, ele vai redirecionar você para a loja da Apple, indo direto para o aplicativo desejado quando você clicou no anúncio.

Quando você instalar o aplicativo desejado, o SDK do Google contido dentro do seu aplicativo vai obter o IDFA do seu aparelho e enviar para o servidor deles. Seria algo assim:

Ah, então você é o IDFA “ABC123456” que clicou na campanha “C123”, estou adicionando +1 no contador de instalação, bem como todas as informações do seu dispositivo. Obrigado.

Na documentação do Google, tem mais detalhes, mas a regra é esta.

https://developers.google.com/analytics/solutions/ios-install-tracking#redirect 

Segue uma imagem que o Google fez para exemplificar seu fluxo:

ios-install-tracking-redirect

A segunda solução do Google Analytics é fazer com que a rede de anúncios envie assincronamente um “ping” para a URL:

click.google-analytics.com/ping?param1=value1&param2=value2

E com isso poderá ser feita a contabilidade também server-side posteriormente pelas ferramentas.

 

No caso do Google funciona assim:

O Google criou uma classe que atua como um Broadcast Receiver, que receberá estes dados assincronamente quando um usuário instalar o aplicativo através de uma campanha.

Basicamente o Google Play vai fazer um broadcast com a informação somente quando o aplicativo for instalado pela loja e os dados da campanha estiverem disponíveis, ou seja, se ele veio com os parâmetros de campanha definidos quando ocorreu a instalação.

Estes dados serão consumidos pelo seu broadcast que irá submeter os dados para sua plataforma de anúncios. Se você usa o SDK do Google Analytics e definiu que ele será o “recebedor” destas informações, ele será o responsável por jogar estas informações de campanha para o servidor do Google, ou então você captura e repassa isso para diversas ferramentas manualmente, pois uma limitação do Android é que só pode existir um Broadcast Receiver para Install Referrer.

O AppsFlyer fez um Broadcast Receiver especial que consegue receber estes dados e depois repassar para todos os outros Broadcast Receivers que você tiver, automaticamente (Link de como usar), permitindo então você possuir diversos Broadcast Receivers.

Documentação:

https://developers.google.com/android/reference/com/google/android/gms/tagmanager/InstallReferrerReceiver

https://developers.google.com/android/reference/com/google/android/gms/analytics/CampaignTrackingReceiver

 

Basicamente o link no padrão para o Google Play seria assim:

https://play.google.com/store/apps/details?id=com.example.application&referrer=utm_source%3Dgoogle%26utm_medium%3Dcpc%26utm_term%3Drunning%252Bshoes%26utm_content%3Dlogolink%26utm_campaign%3Dspring_sale

É importante entender que a informação que você terá é o texto dentro do parâmetro “referrer”, que deverá estar no padrão URL Encoded, ou seja, sem os símbolos “%, &, =, etc”.

É importante também usar o gerador de URL para o Google Play para criar a URL dentro do padrão esperado (Link 1, Link 2):

Se você deseja simular isso no Android, sem ter que instalar o aplicativo pela loja, afim de testar o funcionamento, execute os comandos abaixo trocando os parâmetros (Link):

adb shell 
am broadcast -a com.android.vending.INSTALL_REFERRER -n <your.package>/.<path.up.until.your.BroadcastReceiver> --es "referrer" "utm_source=test_source\&utm_medium=test_medium\&utm_term=test_term\&utm_content=test_content\&utm_campaign=test_name"

E caso você queira criar seu Broadcast Receiver crie uma classe com o conteúdo:

public class InstallReferrerReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String referrer = intent.getStringExtra("referrer");

        //Use the referrer
    }
}

E no seu AndroidManifest.xml adicione:

<receiver
    android:name="com.example.android.InstallReferrerReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="com.android.vending.INSTALL_REFERRER" />
    </intent-filter>
</receiver>

 

 

Como funciona no caso do AppsFlyer:

Agora que você já entendeu como as plataformas se utilizam desses recursos, veja como o AppsFlyer mostrou esse funcionamento na rede deles:

Links:

https://support.appsflyer.com/hc/en-us/articles/207032096-Accessing-AppsFlyer-Attribution-Conversion-Data-from-the-SDK-Deferred-Deeplinking-

https://support.appsflyer.com/hc/en-us/articles/207032146-How-Can-I-Get-the-Install-Referrer-URL-from-my-Android-App-Context-

Imagem:

appsflyer-attribution-data

 

No caso do Google, basicamente o usuário vai clicar em um link como este:

app.appsflyer.com/angry-birds-android?pid=tapjoy_int&clickid=1020fe4c7e875&c=Ad1&af_siteid=2684

E quando o Broadcast Receiver for notificado, irá receber algo como:

af_tranid=3M69WKEKDHFPRXPG&pid=tapjoy_int&clickid=1020fe4c7e875&c=Ad1&af_siteid=2684

O AppsFlyer também possui uma aplicação para testar as campanhas antes de enviar o aplicativo para a loja:

Para Android:

https://support.appsflyer.com/hc/en-us/articles/207032136-Testing-AppsFlyer-Android-SDK-Integration-Before-After-Submitting-to-Google-Play

Para iOS:

https://support.appsflyer.com/hc/en-us/articles/207032046-Testing-AppsFlyer-iOS-SDK-Integration-Before-Submitting-to-the-App-Store-

 

Funcionamento geral:

Há diversas formas de fazer este tracking, como por exemplo, por IP. Mas usuários que usam WIFI ou estão dentro de redes específicas podem ter o mesmo IP de saída e esta regra acaba falhando.

O IDFA, no caso da Apple, ajuda neste sentido, pois você sabe quem é o usuário pois o mesmo IDFA clicado é o mesmo que gerou o evento após o aplicativo ser aberto.

É claro que as informações podem se perder, o usuário podem nem mesmo abrir o aplicativo, um problema de conexão pode impedir o envio dos dados, ou ele pode simplesmente desinstalar, enfim, como regra geral essas técnicas funcionam bem e fica fácil entender como este processo funciona agora.

 

Espero ter ajudado com este artigo.

Obrigado e até o próximo post pessoal.

Golandy – Game multiplayer open-source em HTML5 com Phaser + Golang e WebSocket – Versão para desktop, browser, android e iOS

Olá pessoal,

A um tempinho atrás fiz um game bem simples, usando HTML5 + Phaser e Go + WebSocket.

Fiz também os arquivos necessários para rodar o projeto tanto em desktop, web, android e iOS usando o Apache Cordova.

O link do game rodando é:

http://golandy.prsolucoes.com

Os links para baixar se encontram no meu Github, segue:

Cliente: https://github.com/prsolucoes/golandy-web

Servidor: https://github.com/prsolucoes/golandy-server

 

Sobre o jogo, ele é um tipo de clone do clássico bomberman. É multiplayer em tempo real. Fiz usando a engine Phaser e o servidor em Go. Toda a comunicação usa WebSocket e a versão nativa do Google, pois o desempenho da versão Gorilla é horrível.

Os mapas podem ser editados usando o MapEditor/Tiled (padrão tmx).

O game funciona no navegador, no desktop, no android, no iOS e onde mais o Apache Cordova suportar, pois como é em HTML5, qualquer browser roda ele. Em casa por exemplo, minha filha joga na TV.

É claro que o jogo não é perfeito e a comunidade da engine não ajuda muito.

Segue imagem:

Golandy Game Screenshot

 

Espero com este projeto, que a idéia e a arquitetura possam servir de inspiração para outros projetos e trabalhos.

Obrigado e até o próximo post pessoal.

 

Novos projetos open-source: GoCI e GoHC (integração contínua e healthcheck)

Olá pessoal,

Gostaria de compartilhar com vocês os meus dois novos projetos open-source em Go (golang).

1 – GoCI

O GoCI é um projeto para integração contínua de fácil instalação, manutenção e configuração.

Com ele você pode criar suas tarefas de integração através de execuções em CLI ou através de arquivos Javascript.

A inicialização do projeto é feita por dois arquivos principais, o config.ini e o arquivo do seu projeto em JSON, que podem ser vários na verdade.

O GoCI exporta algumas variáveis pro Javascript, a fim de que você possa implementar sua lógica de teste, deploy ou qualquer outra tarefa e ainda controlar cada um destes objetos. Ao manipular estes objetos você acompanha todos os resultados em tempo real através da interface web do GoCI, como os outputs, a barra de progresso, a duração da execução, etc.

Cada tarefa pode mostrar resultados em diversas abas, a aba principal é a Console, onde o output geral aparece ali, além do output normal, você tem output de erro, sucesso, alerta, etc.

Cada tarefa do seu projeto pode ter vários passos (steps), sendo cada passo baseado em um plugin, que como falamos, podem ser “cli” ou “js”.

Porém o projeto não se limita somente a desenvolvimento ou testes e deploy de uma aplicação. Você pode fazer o que quiser dentro dele. Você pode criar mais plugins, caso queira. Eu tenho algumas tarefas por exemplo, que enviam push pro meu device de teste, tenho outra que baixa os arquivos de linguagens atualizados da ferramenta de localização e coloca dentro do projeto.

O projeto vem com uma pasta “extras/sample” com os arquivos de exemplo, embora sejam bem simples.

Toda a interface foi pensada para funcionar perfeitamente em smartphones, tablets ou PCs.

Segue algumas imagens:

Link para o projeto:

https://github.com/prsolucoes/goci 

 

2 – GoHC

O GoHC é um sistema passivo de healthcheck com suporte a notificações quando entra em modo warning ou error. Ele é passivo por não ser de sua responsabilidade realizar a operação de validação, pois criaria um limite e o propósito do projeto é poder criar healthcheck para qualquer coisa que possa entrar em contato com o servidor onde estiver rodando.

Exemplos do que você pode fazer com ele:

  1. Validar se uma URL/servidor/IP está ativo.
  2. Medir tempo de determinadas operações, como o intervalo de tempo de processamento do pagamento do cliente com o seu gateway de pagamento. Você pega este intervalo em sua aplicação e envia pro healthcheck validar se ele está dentro do range de sucesso, alerta ou crítico/erro/falha.
  3. Validar de a quantidade de memória/cpu/disco/network está dentro de um range.
  4. Validar se a quantidade de humidade de uma planta está dentro de um range e emitir um alerta se estiver em nível crítico.

Com este sistema de healthcheck você possui 3 formas de validar a “saúde” do que você precisa monitor e esta validação pode ser automática dentro dos 3 ranges possíveis (sucesso, alerta, erro/falha) ou manual, onde você diz qual é o status manualmente.

  1. Ping – é o tipo mais simples, você chama o healthcheck e ele de acordo com o último ping enviado e o atual verifica em qual das áreas do range você está e envia alertas ou não – mas é você quem diz o tempo do ping para cada range.
  2. Range – é o tipo mais específico, onde você especifica as áreas dos ranges e ao receber um range qualquer, ele valida em qual dos ranges você está baseado no range enviado.
  3. Manual – é o tipo onde você diz o status diretamente, não tem informação de ping ou range neste tipo, o status que você enviar é o que ele vai assumir e pode enviar alertas também caso você especifique.

Tudo isso pode ser acompanhado através de uma interface web bem amigável e que foi pensada para funcionar perfeitamente em smartphones, tablets ou PCs.

Existe na interface hoje o modo lista de healthchecks e o modo dashboard, dependendo de como você quer ver os healthchecks você pode optar por um ou por outro. Se você quer deixar numa televisão, sugiro o modo dashboard.

Os alertas são baseados em plugins. Hoje eu criei apenas alguns, mas essenciais.

  1. CLI – executa algo no servidor no CLI
  2. SendGrid – envia um email usando o sendgrid
  3. PushBullet – envia um push usando o pushbullet
  4. Http Get – faz requisição HTTP GET em uma URL
  5. Slack – envia via webhook uma mensagem para o serviço Slack

A inicialização do projeto é feita por dois arquivos principais, o config.ini e um arquivo JSON chamado healthchecks.json com a lista de seus healthchecks e plugins de alerta.

O projeto vem com uma pasta “extras/sample” com os arquivos de exemplo, embora sejam bem simples.

No arquivo config.ini, você pode especificar uma propriedade chamada warmTime, que define um tempo após a inicialização para o sistema começar a processar os healthchecks.

Segue algumas imagens:

Segue o link do projeto:

https://github.com/prsolucoes/gohc

 

É isso pessoal, espero ter ajudado alguém com estes projetos.

Obrigado e até o próximo post pessoal.