Meu iPhone virou dumbphone, e eu fiz o launcher em React Native
No post do McLovin eu escrevi que iOS e Android ficavam pra depois. Chegou a vez deles, só que por outra porta. O que eu fui fazer no celular não foi roteamento de link, foi tirar tela da minha frente.
O número que me fez parar é brasileiro: segundo a Bain, o brasileiro passa 9 horas e 13 minutos por dia conectado, contra 6 horas e 38 da média mundial. Na mesma pesquisa, tempo de tela é o hábito que ele mais gostaria de mudar, na frente de alimentação e de sedentarismo. Não é que a gente não perceba. A gente percebe, e continua ali.
A minha tela inicial hoje: previsão em cima, os apps como lista de nomes
O que é um dumbphone
Pra quem nunca esbarrou no termo: dumbphone é aquele telefone que só faz ligação e manda SMS. Não roda rede social, não roda jogo, não tem navegador. Foi o que todo mundo tinha antes de 2007, e virou movimento justamente porque deixou de ser o padrão. Nos Estados Unidos os feature phones voltaram a vender, 2,8 milhões em 2023, empurrados pelo detox digital da Geração Z.
E funciona. Um estudo da PNAS Nexus bloqueou a internet móvel de 467 pessoas por duas semanas e atenção, saúde mental e bem-estar melhoraram nos três casos. Mas apenas 25,5% aguentaram o mínimo de 10 dias. O efeito é real e é difícil pra caramba de sustentar. Não estou aqui pra dizer que resolvi isso.
De onde veio a ideia
O que me apresentou o assunto foi o Dumb Phone (dp), do Michael Tigas. Ele troca a tela inicial por uma lista de botões de texto e ainda esconde o resto pelo Tempo de Uso. É bem feito e faz mais coisa que o meu.
Só que eu sou desenvolvedor e gosto de aprender e evoluir, e mobile é a tela que todo mundo tem na mão o dia inteiro. Dava pra estudar isso lendo changelog e assistindo talk, mas aí não tem skin in the game. Resolvi entrar do jeito que ensina: um app meu, que eu uso todo dia, e nas duas lojas.
O que eu fiz
A tela inicial vira uma lista de nomes em texto. Sem ícone, sem badge, sem grade. Você toca no nome e o app abre.
A ideia não é virar monge, é tirar a disputa. A tela de fábrica é uma grade de quadradinhos coloridos brigando pela sua atenção, e os apps que eu abro todo dia são cinco. O resto é barulho que eu rolo pra passar. Trocar ícone por texto tira a cor da equação, e sem cor você para de reconhecer o app de longe e passa a ter que ler. Ler é mais devagar. Devagar é o ponto.
O app é o editor, onde você monta a lista, escolhe a fonte e o alinhamento. O widget é o produto, e é ele que fica na tela.
Onde você monta a lista, com o preview do widget em cima
Por que não só Swift
Esse app já existia em Swift. A primeira versão dele é SwiftUI inteira, mora num repositório meu do lado, e funciona bem. Refazer em React Native foi decisão, não acidente.
O motivo é Android. Eu quero o mesmo app nos dois lugares e não quero escrever ele duas vezes. Essa versão aqui é a primeira, é iOS, e já está montada em cima da parte que vai junto quando eu atravessar. Se eu tivesse seguido em Swift, o Android um dia começaria do zero.
E tem o motivo pessoal: fazia tempo, mas não é a primeira vez. Lá no começo do React Native, quando o framework ainda era novidade, eu fiz uma calculadora de investimentos pra uma instituição financeira, e o que eu entregava no fim era o APK. Então a parte Android dessa aposta não é teoria pra mim, é uma coisa que eu já vivi uma vez.
Fora isso, React nunca saiu do meu caminho: meu dia a dia é Ruby, Rails e React, e React já apareceu neste blog em 2020. O React Native é que andou muito de lá pra cá, e eu queria ver no que ele virou, não no que eu lembrava dele. Pra essa pergunta ter resposta honesta, tem que ser app de verdade, com prazo de verdade.
Onde o JavaScript para
Resposta curta: o React Native cobre a metade de cima, e a plataforma cobra a de baixo.
No Android você troca o launcher inteiro e pronto, o sistema é seu. No iPhone não existe isso. Ninguém substitui a tela inicial do iOS, e é por isso que todo app desse nicho, o meu e o do Michael, chega pelo mesmo caminho: um widget. O widget é a única superfície que a Apple deixa você desenhar ali.
E widget no iOS é SwiftUI, sempre. O WidgetKit não tem runtime de JavaScript, não é preferência minha e não existe biblioteca que mude isso. Ou seja, justo a parte que fica na sua tela, a que importa, é Swift. Hoje são 2.840 linhas de Swift pra 7.371 de TypeScript, quase um terço do app.
Tem mais uma pegadinha, e essa o usuário sente. Um toque no widget não abre outro app direto, o iOS não permite. O toque cai primeiro no app hospedeiro, que aí te encaminha pro destino. Dá pra ver acontecendo, e não tem como esconder.
A frase entre os toques
Em vez de pedir desculpa por esse piscar, eu resolvi preencher ele. Cada pulo mostra uma frase, pelo tempo que você escolher, de zero a quatro segundos, e aí você chega onde ia.
Isso deixou de ser conserto técnico e virou a parte que eu mais gosto. Se a ideia do app é te fazer desacelerar na hora de pegar o telefone, uma pausa obrigatória no meio do caminho não é bug, é exatamente o produto. A limitação da plataforma virou o único momento de silêncio do aparelho.
São 20 frases por idioma, cada uma com autor, e cada idioma puxado da tradição dele em vez de traduzido do inglês. As suas você escreve, e elas nunca são mexidas quando você troca de idioma.
As frases que aparecem no caminho, com quem escreveu
A pegadinha que apaga tudo
Essa é a parte que eu não sabia antes de começar, e é a que quase me custou caro.
O app e o widget são dois processos que nunca conversam direto. O único canal entre eles é um App Group, um UserDefaults compartilhado, guardando uma string JSON. Parece trivial. Não é.
Se você entregar um objeto pro lado nativo em vez de uma string, a ponte converte o true do JavaScript pra 1. O Swift tenta ler aquilo como Bool, levanta erro, o erro escapa, um try? engole ele, e a configuração inteira volta pro padrão de fábrica. Todos os apps que a pessoa adicionou somem. Sem erro na tela, sem log, sem crash.
É por isso que o módulo nativo daqui recebe String e nunca objeto. E é por isso que os 257 testes do projeto quase não olham pra tela: eles cercam os quatro pontos onde estar errado é silencioso. A regra que eu adotei foi testar a falha, não o caminho feliz, porque entrada malformada é o que chega ali de verdade.
Status
O código está aberto em github.com/guilhermeyo/tsp, sob MIT. Roda no meu iPhone todo dia, e a lista da primeira foto é a minha de verdade.
O próximo passo é a App Store. Depois dela, o Android, que é o motivo de tudo isso estar em React Native.
Finalizando
Eu não fiquei mais produtivo de um dia pro outro, e aquele estudo já avisa que segurar isso é a parte difícil. O que mudou foi menor e mais concreto: eu pego o telefone pra fazer uma coisa e saio dele tendo feito aquela coisa.
Tem muita gente hoje contando que tem IA trabalhando 24 horas por dia, sete dias por semana, tocando cem produtos ao mesmo tempo. Entregue mesmo eu vejo pouco. Prefiro o contrário: um app só, terminado, que eu uso todo dia e que qualquer pessoa pode pegar e usar.
E terminar é o que ensina. Eu aprendi React Native lendo sobre React Native, e aprendi mais ainda levando um app até o fim e batendo em cada limite que a plataforma impõe. A base é a mesma que eu venho construindo há anos de carreira, só que aplicada numa tecnologia diferente, e é aí que ela consolida: você descobre o que era conceito de verdade e o que era só costume da ferramenta antiga.
No post do McLovin eu disse que iOS e Android ficavam pra depois. O depois chegou, e a régua que eu me dou é a mesma de lá: o mesmo app nos dois sistemas, escrito uma vez só. Por enquanto está metade entregue.
Fontes
- Dumb Phone (dp) na App Store
- The Simple Phone no GitHub
- Bain Consumer Pulse 2025: brasileiros passam mais de 9 horas por dia conectados
- PNAS Nexus: blocking mobile internet improves attention and mental health
- Counterpoint Research: o retorno dos feature phones nos EUA
- WidgetKit
- Configurando App Groups
Comentários