blog / o que eu aprendi colocando um app react native nas lojas
o que eu aprendi colocando um app react native nas lojas
- Mobile
- React
- Carreira
vamos direto ao ponto. o que você espera que aconteça quando roda isso num app expo legado?
npx expo install expo --fix
a resposta intuitiva costuma ser "atualiza o expo e as libs junto, resolvido". faz sentido pensar assim, o comando existe exatamente pra isso. sqn! =P
só que num app legado, algumas versões atrás, o que acontece é outra coisa: o expo sobe, e aí uma biblioteca nativa quebra. você atualiza ela, e a próxima quebra. atualiza essa, e volta a primeira. vira uma hidra, corta uma cabeça e nascem mais duas...
esse post é a história de como eu escapei dessa hidra com um remendo de duas linhas, e de como esse remendo venceu na data que a play store escolheu, não na minha. no fim eu digo o que eu faria diferente.
pra quem tá começando: "sdk" aqui é o pacote de versões que o expo amarra junto (react native, react, e as libs expo-* que falam com o android e o ios). e "biblioteca nativa" é a que tem código android/ios de verdade dentro dela, não só javascript, então ela precisa combinar com a versão do react native que você tá rodando. é essa combinação que quebra.
como eu fui parar nessa
o começo é sem graça: eu precisava entregar um fix. um. não estava ali por vontade de modernizar nada, não tinha ticket de "atualizar dependências", era só um bug pra corrigir num app que já rodava em produção há bastante tempo.
o problema é que o app não buildava mais. e o caminho óbvio pra fazer buildar de novo era subir a sdk. aí eu rodei o comando lá de cima, e conheci a hidra.
por que isso importa na prática
antes de continuar a história, um aparte que explica o desespero: no mundo web, deploy errado se conserta em cinco minutos. no mobile, não.
o ciclo de UMA correção de bug em produção começa com o build, que já é uma espera:
eas build --platform ios --profile production
depois você manda pro app store connect:
eas submit --platform ios
e aí vem a parte que não tem comando: esperar o review da loja (dias, não minutos) e, depois de aprovado, torcer pro usuário atualizar o app. essa última parte não depende de você de jeito nenhum.
é o quarto passo que complica. mesmo depois de aprovado pelas lojas, quem tem a versão bugada continua com ela até atualizar. não existe "corrigi e todo mundo já tá com a correção", que é o padrão mental de quem vem de web. aqui você depende do cara querer atualizar o app.
pensa assim: web é trocar o cartaz da vitrine, você troca e pronto. mobile é imprimir e distribuir um catálogo, se saiu errado já foi, a versão errada tá na casa das pessoas e você não vai buscar de volta.
então quando eu digo que o app não buildava, entenda: cada tentativa de conserto custava fila de build, e cada erro custava dias.
o remendo
com a hidra crescendo, eu decidi o contrário do óbvio: não subir a sdk. contornar o que estava travando.
o que travava era um null vindo do sistema dentro de uma biblioteca do próprio expo, no trecho que lê as permissões declaradas no manifest. o código nativo assumia que a lista de permissões sempre existia:
// dentro de uma lib nativa, não no meu código
return requestedPermissions.contains(permission)
só que o android pode devolver essa lista como null, e aí o app cai. a correção é literalmente um ? e um valor padrão:
return requestedPermissions?.contains(permission) ?: false
bug que não era meu, em código que eu não controlava, numa lib que eu não podia atualizar sem puxar a hidra inteira junto. então eu fiz um patch na dependência: um diff versionado no meu repo, que entra no node_modules a cada install. duas linhas, sem tocar na sdk, e o fix subiu.
(e isso foi antes de ter o claudio pra jogar um stack trace de gradle dentro e gritar SOS. era eu, o stackoverflow e muita paciência)
o que eu não sabia que estava comprando
o patch aguentou! meses. e nesse meio tempo eu fui aprendendo, na marra, que o review das lojas rejeita muito mais por política do que por código.
tomei negativa por política de privacidade "inválida". o link estava certo, o site no ar, tudo certo do meu lado. só que o revisor, de fora do país, não conseguia alcançar o site. e pra quem tá revisando isso é igualzinho a um link quebrado, né? a apple exige o link na metadata do app store connect e acessível dentro do app, então se não carrega pra ele, rejeitado.
tomei por permissão mal declarada também. no app.json não basta pedir a permissão, você precisa dizer pra quê:
{
"ios": {
"infoPlist": {
"NSCameraUsageDescription": "usado para fotografar o produto na hora do pedido"
}
}
}
esse texto é a purpose string, e a apple exige que ela descreva completamente o uso do dado. "precisamos da sua câmera" não passa. tem que dizer pra quê, permissão por permissão.
e tem o sign in with apple: se o app oferece login social (google, facebook), a apple exige uma opção equivalente que limite a coleta a nome e email e deixe o usuário esconder o email. pra app público com login social, é ele. não é opcional, não tem contorno.
cada uma dessas foi uma ida e volta de dias. e no meio disso, a fila. no plano grátis do eas a build entra numa fila compartilhada e o timeout é de 45 minutos (nos planos pagos, 2 horas), então você espera, e às vezes descobre no fim que falhou. e aí, volta pra fila!
depurar build de mobile é caro por isso, cada tentativa custa.
ah, e o teste, né. o testflight não é nada intuitivo pra quem não é dev: tester que não recebe o convite, tester que recebe e não acha o app. metade do meu suporte a QA era ensinar a instalar o app, não a testar o app.
o dia em que a conta chegou
e então a play store começou a rejeitar por um motivo que não tinha workaround nenhum possível.
aí não tinha mais pra onde correr. removi o patch, subi a sdk, e os commits seguintes foram eu refazendo pedaço por pedaço do app pra se adaptar às libs novas. a hidra que eu tinha evitado meses antes estava lá, inteira, esperando. foi uma batalha épica, tá?
o commit em que eu encaro isso tem uma mensagem que resume bem meu estado de espírito na hora: "updated sdk version for i have faith" (git hygiene is my passion) xD
e aqui tá o aprendizado que eu levei pra sempre: workaround não é dívida que você escolhe quando pagar. quem marca a data é a loja, o sistema operacional, a lib que parou de receber suporte. você escolhe adiar, não escolhe até quando.
o que eu faria diferente
- fazer o patch de novo, sem culpa: ele era a decisão certa pra entregar aquele fix naquela semana
- mas anotar no roadmap, com data minha: "subir sdk até o mês tal", antes que a loja escolhesse a data
- subir sdk uma versão por vez, não pular várias, porque aí você sabe qual libzinha quebrou
- tratar política de privacidade, purpose string e login social como parte da feature, não como burocracia do fim
- contar a fila de build e o review no prazo que eu prometo pro time, porque eles não são "extra", são o trabalho
no fim das contas, o que mudou pra mim foi menos técnico e mais de calendário. errar na web é barato, errar no mobile custa dias de review e uma versão ruim que fica instalada no celular das pessoas. aí você aprende a fazer checklist antes de subir, a usar feature flag no lugar de "corrijo depois", e a testar nos dois sistemas antes de comemorar, porque conserta no android quebra no ios, conserta no ios volta no android. agora entendo o sísifo
engraçado que a lição não é sobre react native nem sobre a apple: é que dívida técnica em plataforma que não é sua vence com juros, e em data que você não escolhe. dá pra adiar bastante, só não dá pra fingir que o prazo não existe. a hidra sempre volta =]