Desenvolver uma app iOS nativa

Escrita · 11 mai 2024

Desenvolver uma app iOS nativa

Criar um registador de ciclismo e corrida

Como pequeno projeto paralelo, espremido entre o meu trabalho normal, tenho estado a trabalhar em algo do meu interesse pessoal: uma app nativa de registo de treinos para iOS. Queria tornar o meu smartwatch obsoleto e usar o telemóvel para registar os treinos. Será assim tão difícil recolher dados de sensores em pormenor com as APIs nativas do Swift?

Contexto

Se tens acompanhado o meu blogue, isto talvez não seja surpresa, mas adoro andar de bicicleta e comecei há pouco a correr um bocado. Tenho bastante experiência a registar os meus treinos, com Garmin, Strava, Omata, Wahoo, Biostrap, Whoop e várias apps e sensores. Acho que os dados de saúde e de fitness são úteis para conheceres o teu desempenho físico e para teres algum tipo de responsabilização perante ti próprio (por exemplo, para te motivar a continuar os treinos).

Nada nos faz sentir tão vivos como sair para uma atividade física, adoro treinar!
Nada nos faz sentir tão vivos como sair para uma atividade física, adoro treinar!

O nerd que há em mim adora o grande conjunto de dados, os muitos tipos de sensores disponíveis são um banquete para a minha curiosidade, mas isso choca com o meu desejo de minimalismo e simplicidade. Precisas mesmo de todos os dados de treino? Não basta simplesmente ouvir o teu corpo? Não sei, mas aprecio a capacidade de um smartwatch registar treinos com grande pormenor e (quase) sem esforço. Gosto de como o Apple Watch pode ser usado para registar sessões de treino, além das suas capacidades como relógio de ferramenta moderno e substituto do telemóvel. Embora perceba que a maioria das pessoas usa o smartwatch e pronto, eu gosto de relógios mecânicos à moda antiga como um Rolex, um Tudor, um Grand Seiko ou até algo feito por medida. Embora aprecie ambos, puxa-me mais para os relógios mecânicos quando tenho de escolher entre smartwatches e relógios mecânicos.

A ideia para a app: Gran Fondo

E se houvesse uma app para telemóvel que recolhesse todos os dados de treino que queres, sem complicações nem confusão? Imaginei-a assim:

  • Simples: tem de 'sair do teu caminho', pensada para 'simplesmente funcionar', sem teres de mexer em infinitas definições ou opções. Basta carregar em 'iniciar' e começar o treino.
  • Flexível: usa a app de várias formas: monta ou leva o telemóvel à vista para dados em tempo real, ou mete-o no bolso e deixa-o trabalhar em segundo plano.
  • Poderosa: liga sensores de frequência cardíaca, cadência, potência e velocidade por Bluetooth; suporta vários sensores, o ideal se usas bicicletas diferentes.
  • Amiga do Apple Health: guarda todos os dados no Apple Health com o máximo de pormenor, incluindo os percursos dos treinos e as medições individuais de potência, cadência e velocidade. Assim podes analisar as gravações em qualquer app que suporte o Apple Health, como o Strava, o WHOOP, o HealthFit e muitas outras.
  • Honesta: sem anúncios nem venda de dados. Sem contas nem registo. Os teus dados devem ficar privados, seguros e no teu dispositivo.

Nenhuma das apps de desporto e fitness existentes para telemóvel cumpre tudo isto. A maioria é desnecessariamente complexa ou foi, de alguma forma, desenhada para levar os teus dados e servir quem fez a app ou a sua plataforma. Será que eu conseguia fazer melhor?

Construir a app

Sabendo porquê e o quê, comecei por escolher o método preferido para construir a app.

Nativa vs. híbrida/web

Na maior parte do trabalho que faço, prefiro usar tecnologias web abertas e livres (de liberdade), como HTML, JavaScript e CSS, ou software de servidor publicado com uma licença de software livre, como a GPL. Neste caso concreto, precisava de ser extremamente eficiente em termos de energia e de me integrar a fundo com o sistema operativo do telemóvel. A melhor forma de o fazer num iPhone é abraçar por completo o kit de desenvolvimento de software da Apple: fazer a app de forma nativa em Swift com SwiftUI e seguir o mais de perto possível a documentação técnica e as diretrizes de design.

Programação assistida por IA

Embora tenha as minhas reservas, usar IA para programar é o que mais atenção tem recebido ultimamente. Há quem afirme que tecnologias como o Copilot ou o ChatGPT tornariam os programadores obsoletos. Conheço bem a IA, já a usei para gerar código, e ensino as pessoas a usá-la, mas nunca a tinha usado para construir uma app iOS completa. Achei que seria a oportunidade perfeita para ver quão capaz é a IA em algo mais complexo do que um simples excerto de um script. Vamos descobrir quão obsoleto eu sou como programador nesta era moderna da IA...

GPS e sensores Bluetooth Low Energy

Depois de configurar o meu ambiente Xcode, pedi ao ChatGPT da OpenAI que me desse código para ler dados de localização GPS e para gerar as classes Swift necessárias para detetar e ligar a sensores Bluetooth. Caramba, caí mesmo naquela toca do coelho!

A minha bicicleta com sensores Bluetooth ligados ao meu MacBook com o Xcode
A minha bicicleta com sensores Bluetooth ligados ao meu MacBook com o Xcode

A questão da programação assistida por IA é que SIM, funciona; mas só PARCIALMENTE. Dá-te peças que funcionam, mas que não encaixam na perfeição e não funcionam necessariamente em conjunto. Ver o código que gera é como ouvir os ecos de uma grande canção: reconheces que se parece com alguma coisa, mas não é a mesma coisa que ouvir a banda tocar ao vivo, quanto mais cantá-la tu!

Peguei nas peças da IA e fui ler a documentação relevante por mim, o que se mostrou muito mais eficaz, porque me permitiu perceber realmente o que o mecanismo devia fazer. A IA ajudou-me a encontrar as coisas que precisava de aprender. Registar a localização GPS foi surpreendentemente fácil com o Core_Location da Apple. Fazer o sensor Bluetooth ligar-se à app revelou-se muito mais difícil, pois envolve muitos passos distintos:

  • Detetar dispositivos Bluetooth: procurar na área próxima quaisquer dispositivos disponíveis que estejam a emitir
  • Ligar a um dispositivo Bluetooth: estabelecer e manter uma ligação entre a app e o dispositivo
  • Descobrir as características do dispositivo Bluetooth: não existe um dispositivo Bluetooth simples, tens de fazer a tua própria 'descoberta' das capacidades e funcionalidades do dispositivo; muitos dispositivos emitem vários sinais diferentes, tanto de dados de sensores como de mecanismos de controlo e de parâmetros operacionais, como o nível da bateria.
  • Subscrever as características: no fim, subscreves um fluxo de dados sintonizando os rádios Bluetooth numa determinada característica Bluetooth.
  • Descodificar os dados: dada a sua natureza eficiente em energia, recebes dados mínimos em bits em bruto; tens de descodificar tu os pacotes de dados; o difícil é que cada sensor, de qualquer fabricante, codifica os dados à sua maneira.

Toma como exemplo um sensor relativamente 'simples', como um sensor de cadência que se coloca no pedal da bicicleta e serve para determinar as rotações por minuto numa sessão de ciclismo. Quão difícil pode ser? Pensei que a especificação oficial do Bluetooth me daria todos os pormenores necessários... NADA DISSO! Um simples sensor de cadência é surpreendentemente complexo:

  • Perfil Bluetooth combinado para velocidade e cadência no ciclismo: qualquer sensor de cadência identifica-se sempre como sensor de velocidade e de cadência, e tens de descobrir as suas capacidades 'em tempo real'.
  • Pacotes de dados não uniformes: o conteúdo dos dados depende das capacidades atuais do sensor (por exemplo, se detetou alguma coisa); tens de interpretar o pacote de dados bit a bit, verificando as possíveis flags que indicam o que o bit seguinte representa.
  • Dados não triviais: não esperes um valor claro para a "cadência"; o sensor dá-te uma contagem acumulada de rotações e uma marca temporal rudimentar da última alteração detetada; tens de usar estes valores para calcular a métrica que queres medir.

A IA deu-me algum código de exemplo, mas não funcionou com o meu sensor em particular. Com uma app de depuração de Bluetooth, a Bluefy, consegui perceber melhor os dados que o sensor estava a transmitir. Encontrei um excerto de código Java no blogue oficial do Bluetooth que me deu algumas pistas para interpretar os dados dos sensores. Adaptei esse código a vários perfis de sensores diferentes e traduzi-o para Swift. Isto deu-me um primeiro protótipo funcional.

Primeiro protótipo da app a funcionar com um sensor Bluetooth de frequência cardíaca e o respetivo conjunto de dados inicial, mostrado noutra app que faz uns gráficos bonitos (HealthFit)
Primeiro protótipo da app a funcionar com um sensor Bluetooth de frequência cardíaca e o respetivo conjunto de dados inicial, mostrado noutra app que faz uns gráficos bonitos (HealthFit)

Design de UI/UX

Uma das principais razões por que gosto da app de treino do Apple Watch é a forma como a interface de utilizador (UI) foi pensada para proporcionar uma experiência de utilizador (UX) agradável. A app no relógio tem botões bastante grandes que carregas para iniciar uma gravação, e é praticamente só isso. A app tem poucas opções, o seu design tem opinião própria, mas está bem pensado. É um contraste enorme com dispositivos como os Garmin, que oferecem uma infinidade de opções de personalização. O truque é encontrar um bom equilíbrio entre flexibilidade nos casos de uso e uma configuração por defeito que funcione bem.

A app de treino do Apple Watch mostra botões grandes para iniciar um treino, sem necessidade de configuração adicional
A app de treino do Apple Watch mostra botões grandes para iniciar um treino, sem necessidade de configuração adicional

Com um sistema de fixação como o QuadLock, podes prender firmemente o telemóvel ao guiador da bicicleta. Isto significa que o iPhone pode substituir o teu Garmin como ciclocomputador. Os iPhones modernos têm um ecrã sempre ligado que mostra informação de forma eficiente em energia, desde que uses o kit de desenvolvimento de software da Apple, que traz várias otimizações integradas. Depois de muitos, muitos, quilómetros com o meu ciclocomputador Garmin, fiquei com uma vista com campos de dados em tempo real para velocidade, potência e frequência cardíaca. O que gosto nos dispositivos Garmin Edge mais avançados é que conseguem desenhar um gráfico. Isto permite-te manter os olhos na estrada quando é importante e dar uma vista de olhos aos dados históricos um pouco mais tarde.

Usei a disposição de dados do meu Garmin Edge como inspiração para desenhar o layout da minha app quando usada como ciclocomputador montado
Usei a disposição de dados do meu Garmin Edge como inspiração para desenhar o layout da minha app quando usada como ciclocomputador montado
Esboço de design a descrever a disposição pretendida
Esboço de design a descrever a disposição pretendida
A testar a app na minha bicicleta com uma capa e um suporte QuadLock
A testar a app na minha bicicleta com uma capa e um suporte QuadLock

Para maximizar a eficiência energética, decidi usar as bibliotecas de gráficos da própria Apple: Swift Charts. Um problema que encontrei ao desenvolver isto é que as medições dos sensores chegam em intervalos e momentos diferentes. É preciso criar algum tipo de mecanismo de sincronização para que os pontos de dados tenham marcas temporais comuns, para os poderes comparar e relacionar. Desenhei este mecanismo para sincronizar também as atualizações da UI: assim, todos os gráficos e pontos de dados são atualizados numa única passagem, otimizando o desempenho do CPU e dos gráficos (e, por isso, a bateria). Como bónus, incluí suporte para diferentes intervalos de tempo, o que permite aos gráficos mostrar os dados do último minuto, dos últimos 5 minutos, 15 minutos, da última hora ou do treino inteiro.

Diferentes configurações de dados em tempo real
Diferentes configurações de dados em tempo real

A app mostra automaticamente os gráficos disponíveis consoante os sensores ligados, o que evita configurações diferentes quando tens mais do que uma bicicleta. Se tocares num gráfico, ele maximiza ou minimiza. Se tocares no intervalo de dados (por exemplo, "últimos 5 minutos"), podes alternar entre intervalos. A app memoriza a tua configuração e prepara-te automaticamente para o treino seguinte. Como todas as áreas de toque e botões são bastante grandes, funcionam bem quando as mãos estão suadas ou quando usas luvas.

Cabe no bolso: otimizar para uso em segundo plano e consumo de energia

Outra forma que imaginei para usar a app era levá-la no bolso, como app em segundo plano. Isso permitiria uma recolha de dados discreta: abres a app e guardas o telemóvel. Adoro a ideia de ter um 'conjunto de dados completo' de todas as minhas voltas de bicicleta e corridas, sem precisar de ter a app em destaque o tempo todo. Muitos treinos de corrida e de bicicleta não são assim tão interessantes.

Tenho magia no bolso: a app regista os treinos em segundo plano, e durante as gravações mostra apenas um widget no ecrã inicial
Tenho magia no bolso: a app regista os treinos em segundo plano, e durante as gravações mostra apenas um widget no ecrã inicial

Por defeito, o sistema operativo iOS da Apple limita estritamente as opções das apps para correrem em segundo plano. Isto maximiza a duração da bateria e a privacidade do utilizador. Se seguires as diretrizes da Apple e pedires corretamente ao utilizador as permissões necessárias, podes de facto desenhar a tua app para funcionar na perfeição em segundo plano. Passei a apreciar mesmo o esforço da Apple em otimizar toda a pilha, para as apps serem mais eficientes em energia. Resumindo, o sistema operativo diz "não nos ligues, nós ligamos-te": controla quando a tua app faz as suas coisas, o que lhe permite sincronizar, combinar e processar em lote tarefas diferentes nos núcleos eficientes em energia dos chips Apple Silicon.

Numa ronda de testes com uma versão protótipo da app, consegui recolher mais de 127 mil (!!) pontos de dados durante um percurso de bicicleta de 8 horas, com uma única carga da bateria do iPhone e com o ecrã ligado o tempo todo. Se jogares segundo as regras da Apple, tens mesmo o poder (por assim dizer). Desenvolver esta app levou-me mesmo longe, ha!

"Goin' the extra mile": 8 horas na bicicleta para testar o consumo de bateria (nota: ainda sobram 23% de carga!)
"Goin' the extra mile": 8 horas na bicicleta para testar o consumo de bateria (nota: ainda sobram 23% de carga!)

Os verdadeiros artistas publicam

Dizem que o caminho para o inferno está pavimentado de boas intenções... Por isso, gosto mesmo de terminar os meus projetos. Para uma app, isso significa publicá-la na AppStore. Prepará-la para o escrutínio da Apple e vê-la aprovada pelos revisores da AppStore é mais um marco. É importante, porque te obriga a pensar na integração (dos novos utilizadores) e no modelo de rendimento.

Integração

Uma tarefa particularmente difícil ao construir uma app é guiar quem é novo na app sobre como a usar. Uma ótima interface ajuda, mas, dada a integração profunda da app com o Apple Health, os dados de localização e os sensores Bluetooth, há ainda a necessidade de pedir permissões com delicadeza.

Capturas de ecrã do processo de integração da app: pedir permissões e guiar os novos utilizadores
Capturas de ecrã do processo de integração da app: pedir permissões e guiar os novos utilizadores

Tens de desenhar o processo para que não falhe quando as pessoas recusam certas permissões. A Apple é muito rígida nisto: as pessoas têm o direito de recusar. É trabalho teu fazer a app funcionar sem permissões ou só com algumas. É um desafio extra.

Modelo de rendimento para financiar o desenvolvimento

Embora não consiga exagerar a importância do software livre, de liberdade, não posso ignorar que tenho uma família para sustentar. Mas, acima de tudo, encontrar pessoas dispostas a pagar pelo teu produto pode servir como validação extra da tua ideia. Sê aberto e honesto sobre o teu modelo de rendimento e isso ajuda-te a financiar o teu próprio projeto; não dependas de investidores nem de capital de risco, financia tu o teu desenvolvimento!

Desenhar um paywall para a minha app: não é o meu pedido favorito aos utilizadores, mas não deixa de ser muito importante.
Desenhar um paywall para a minha app: não é o meu pedido favorito aos utilizadores, mas não deixa de ser muito importante.

Não precisas de pagar para experimentar a app. O ecrã de pagamento só aparece quando as pessoas usam mesmo a app (e pode sempre ser dispensado). Porque não experimentas tu mesmo? Podes encontrar a app aqui.

Futuro

Dizem que é preciso comer a própria comida de cão: vou continuar a desenvolver a app usando-a eu próprio. Não espero que este projeto seja uma vitória (monetária) rápida, mas se for de utilidade prática para mim, é provável que outra pessoa também o ache útil.

Não é uma sessão de depuração qualquer: Fietselfstedentocht 2024
Não é uma sessão de depuração qualquer: Fietselfstedentocht 2024

Uma coisa de que gosto neste projeto é que dá pouco trabalho mantê-lo a andar, porque gosto de treinar. Depurar novas versões desta app envolve muitas vezes sair para uma sessão de corrida ou de ciclismo. Quem disse que desenvolver software era um trabalho sedentário?!

Conclusão

Muita gente tem 'grandes ideias', poucas pessoas as vão realmente concretizar. É isso que distingue quem faz do resto. Gosto de fazer coisas, porque o processo obriga-te a entrar a fundo na matéria. Aprendes imenso e ganhas experiência que os outros não têm. Raios, constrói-a tu mesmo, faz dela a tua!

← Mais textos