Reduzindo o tamanho do aplicativo Flutter

Tempo de leitura: 6 minutes

A redução do tamanho dos aplicativos é de suma importância, principalmente no âmbito do desenvolvimento de aplicativos entre plataformas. Em nossa busca pela otimização do tamanho de nossos aplicativos, utilizamos os métodos abaixo:

 

Método 1: Resolvedor de ativos

Em nossa base de código, utilizamos amplamente ativos dinâmicos, incluindo webp, png, jpeg, gif, conteúdo JSON, fontes .otf e muito mais. Essa abordagem é orientada pelo nosso objetivo de fornecer conteúdo personalizado, adaptado a cada grupo de usuários. Tradicionalmente, a incorporação desses ativos diretamente na base de código aumenta significativamente o tamanho do download do nosso aplicativo, pois cada ativo contribui para o tamanho geral do pacote. Para enfrentar esse desafio, criamos uma solução estratégica que chamamos de Asset Resolver.

A estratégia do Asset Resolver envolve o aproveitamento dos recursos do AWS S3 Bucket para armazenar nossos ativos nos servidores da Amazon. Em vez de incorporar ativos diretamente na base de código, nós os armazenamos remotamente na nuvem. No tempo de execução, quando o aplicativo requer acesso a esses ativos, ele os recupera dinamicamente do servidor. Essa abordagem otimiza efetivamente o tamanho dos nossos ativos, pois eles são obtidos sob demanda durante o tempo de execução, em vez de serem agrupados com o pacote de download inicial.

Ao adotar a estratégia do Asset Resolver com a integração do AWS S3 Bucket, obtemos vários benefícios importantes.

  • Em primeiro lugar, essa abordagem estratégica reduz significativamente o tamanho do download inicial do aplicativo, pois somente o código essencial e os recursos mínimos são incluídos no pacote.
  • Em segundo lugar, o gerenciamento eficiente de ativos é garantido, pois os ativos podem ser atualizados e modificados no servidor sem exigir atualizações ou redistribuições do aplicativo.
  • Além disso, essa abordagem aumenta a escalabilidade e a flexibilidade gerais, permitindo o gerenciamento eficiente de ativos dinâmicos em várias plataformas e versões de aplicativos.

De modo geral, a estratégia do Asset Resolver nos permite usar ativos com conhecimento de coorte para otimizar o tamanho do nosso aplicativo e, ao mesmo tempo, manter o acesso contínuo aos ativos dinâmicos, melhorando a experiência do usuário e minimizando a sobrecarga de recursos.

Método 2: Otimização de código

  • Minificação e ofuscação: Aproveite o suporte integrado do Flutter para minificação e ofuscação de código para reduzir o tamanho do executável do seu aplicativo.
  • Agitação da árvore: Utilize apenas os pacotes e bibliotecas necessários em seu aplicativo, removendo todas as dependências não utilizadas. Isso pode reduzir significativamente o tamanho final do aplicativo.

 

Método 3: Gerenciamento de dependências

  • Escolha dependências leves: Ao selecionar pacotes de terceiros, opte por aqueles que são bem mantidos, ativamente desenvolvidos e que têm um impacto mínimo no tamanho do seu aplicativo.
  • Evite importações desnecessárias: Importe apenas as partes específicas das bibliotecas de que você precisa em vez de importar a biblioteca inteira para minimizar a inclusão desnecessária de código.

 

Método 4: otimizar fontes

  • Use as fontes do sistema: Sempre que possível, utilize as fontes do sistema em vez das fontes personalizadas para reduzir o tamanho do seu aplicativo. As fontes do sistema já estão instaladas nos dispositivos dos usuários, o que elimina a necessidade de incluí-las no seu aplicativo.
  • Subconjunto de fontes personalizadas: Se forem necessárias fontes personalizadas, considere a possibilidade de subconjuntar essas fontes para incluir apenas os caracteres necessários ao aplicativo. Isso reduz o tamanho do arquivo da fonte e ainda preserva os glifos necessários.

Método 5: componentes diferidos

Os componentes diferidos no Flutter referem-se a uma técnica em que determinadas partes da interface do usuário (UI) ou da lógica do aplicativo são carregadas de forma preguiçosa, somente quando são necessárias. Essa abordagem pode melhorar muito o desempenho, o tamanho do download e a eficiência dos aplicativos Flutter, especialmente em projetos grandes ou complexos.

Aqui estão alguns pontos-chave sobre os componentes diferidos e seus usos:

  • Redução do tamanho do download do aplicativo: Os componentes diferidos contribuem para reduzir o tamanho do download inicial dos aplicativos Flutter. Ao carregar componentes dinamicamente, o tamanho do pacote inicial do aplicativo pode ser menor, pois menos código e recursos são empacotados antecipadamente. Isso é particularmente vantajoso para usuários com espaço de armazenamento limitado ou com conexões de rede mais lentas, pois garante uma instalação mais rápida e reduz a barreira de entrada para experimentar o aplicativo.
  • Modularização e divisão de código: Os componentes diferidos promovem a modularização e a divisão do código, permitindo que os desenvolvedores organizem sua base de código com mais eficiência. Isso pode levar a uma melhor capacidade de manutenção, escalabilidade e colaboração entre os membros da equipe que trabalham em diferentes partes do aplicativo.
  • Carregamento progressivo: Os componentes diferidos podem ser carregados progressivamente, permitindo que o aplicativo exiba conteúdo significativo para os usuários enquanto recursos adicionais são carregados em segundo plano. Isso ajuda a manter o envolvimento e a satisfação do usuário, mesmo durante os períodos de carregamento.

Ao implementar estrategicamente técnicas de carregamento diferido, os desenvolvedores podem criar aplicativos mais eficientes e responsivos.

No Flutter, podemos adiar tanto um módulo quanto um arquivo Dart, permitindo o carregamento eficiente de componentes com base em condições de tempo de execução ou interações do usuário.

Etapas para criar componentes diferidos no Flutter

Etapa 1

Adicione a biblioteca central do Play ao arquivo android/app/build.gradle do projeto raiz.

dependencies {
   implementation "com.google.android.play:core:1.8.0"
}

Etapa 2

Habilite o SplitCompat em seu aplicativo Flutter adicionando a seguinte linha ao elemento do aplicativo em android/app/src/main/AndroidManifest.xml.

android:name="io.flutter.embedding.android.FlutterPlayStoreSplitApplication"

 

Etapa 3

Habilite os componentes diferidos em seu aplicativo Flutter adicionando o seguinte ao arquivo pubspec.yaml localizado na raiz do seu projeto.

# A seção a seguir é específica para os pacotes do Flutter.

flutter:
deferred-components:

 

Etapa 4

Crie um Deferred Component, que pode ser um simples widget do Flutter ou um módulo inteiro.

Ponto de entrada do Deferred Module:

import 'package:demo_module/hello_screen.dart';
import 'package:flutter/material.dart';

class DemoModuleHome extends StatefulWidget {
 const DemoModuleHome({super.key});

 @override
 State<DemoModuleHome> createState() => _DemoModuleHomeState();
}

class _DemoModuleHomeState extends State<DemoModuleHome> {
 @override
 Widget build(BuildContext context) {
   return HelloScreen();
 }
}
import 'package:demo_module/screen_1.dart';
import 'package:demo_module/screen_2.dart';
import 'package:flutter/material.dart';

class HelloScreen extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text('Hello Screen'),
     ),
     body: Center(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         children: [
           Text(
             'Hello',
             style: TextStyle(fontSize: 24),
           ),
           SizedBox(height: 20),
           ElevatedButton(
             onPressed: () {
               Navigator.push(
                 context,
                 MaterialPageRoute(builder: (context) => ScreenOne()),
               );
             },
             child: Text('Open Screen One'),
           ),
           SizedBox(height: 10),
           ElevatedButton(
             onPressed: () {
               Navigator.push(
                 context,
                 MaterialPageRoute(builder: (context) => ScreenTwo()),
               );
             },
             child: Text('Open Screen Two'),
           ),
         ],
       ),
     ),
   );
 }
}
import 'package:flutter/material.dart';

class ScreenOne extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text('Screen One'),
     ),
     body: Center(
       child: Text(
         'This is Screen One',
         style: TextStyle(fontSize: 24),
       ),
     ),
   );
 }
}
import 'package:flutter/material.dart';

class ScreenTwo extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text('Screen Two'),
     ),
     body: Center(
       child: Text(
         'This is Screen Two',
         style: TextStyle(fontSize: 24),
       ),
     ),
   );
 }
}

Etapa 5

Uso de um componente diferido.

Para usar o componente diferido em seu aplicativo, você pode usar um FutureBuilder para carregar o componente de forma assíncrona e exibir um indicador de carregamento enquanto o componente estiver sendo carregado.

import 'package:flutter/material.dart';
import 'package:demo_module/main.dart' deferred as deferredBox;

class HomeWidget extends StatefulWidget {
 const HomeWidget({super.key});

 @override
 State<HomeWidget> createState() => _HomeWidgetState();
}

class _HomeWidgetState extends State<HomeWidget> {
 late Future<void> _libraryFuture;

 @override
 void initState() {
   // TODO: implement initState
   super.initState();
   _libraryFuture = deferredBox.loadLibrary();
 }
 @override
 Widget build(BuildContext context) {
   return FutureBuilder<void>(
     future: _libraryFuture,
     builder: (context, snapshot) {
       if (snapshot.connectionState == ConnectionState.done) {
         if (snapshot.hasError) {
           return Text('Error: ${snapshot.error}');
         }
         return deferredBox.DemoModuleHome();
       }
       return const CircularProgressIndicator();
     },
   );
 }
}

 

Etapa 6

Para criar seu aplicativo com componentes diferidos, execute o seguinte comando.

flutter build appbundle

 

Etapa 7

Na primeira execução, o validador do Flutter pode falhar com problemas que precisam ser resolvidos. A ferramenta fornecerá recomendações sobre como configurar o projeto e corrigir esses problemas. Ela também gerará arquivos que precisam ser movidos ou substituídos manualmente no diretório android. Siga as recomendações da ferramenta e mova ou substitua os arquivos gerados conforme necessário para configurar corretamente o projeto.

<projectDirectory>/deferred_components_loading_units.yaml

Você precisará copiar as unidades de carregamento desse arquivo e colá-las no arquivo pubspec.yaml, além de mencionar o componente no arquivo settings.gradle localizado no diretório android.

flutter:
 deferred-components:
   - name: sampleComponent
     libraries:
       - package:deferred_component_poc/demo_module/
include ':app', ':sampleComponent'

Da mesma forma, atualize cada arquivo na pasta android.

strings.xml 
            loc: <projectDir>/android/app/src/main/res/values/strings.xml

android_deferred_components_setup_files
loc: <projectDir>/android/<componentName>

AndroidManifest.xml
loc: <projectDir>/android/app/src/main/AndroidManifest.xml

Etapa 8

Executar novamente o comando

flutter build appbundle

Depois de executar o comando build appbundle, examine a saída do terminal para verificar a presença da mensagem “Deferred components prebuild validation passed”. Essa confirmação significa que os componentes pré-construídos incluídos no arquivo .aab foram submetidos a uma validação bem-sucedida e estão prontos para utilização.

Se a mensagem mencionada acima não for exibida, isso pode indicar um problema com os componentes pré-construídos. Nesses casos, talvez seja necessário reconstruir o aplicativo ou os componentes pré-construídos para corrigir o problema. Depois de resolver o problema, execute novamente o comando build appbundle para produzir um novo arquivo .aab contendo componentes pré-construídos devidamente validados

 

Etapa 9

Execução do aplicativo

flutter run

 

Impacto no tamanho do aplicativo com o Deferred Component

Em nossa análise comparativa, começamos a criar dois projetos distintos para explorar o impacto dos componentes diferidos nos aplicativos Flutter. Cada projeto foi equipado com ativos que totalizavam aproximadamente 4 MB de tamanho. Após um exame minucioso, observamos uma diferença notável nos tamanhos de download entre o projeto que incorporava componentes diferidos e o que não tinha essa otimização.

O projeto integrado com componentes diferidos apresentou um tamanho de download aproximadamente 5,3 MB menor do que o projeto sem esse recurso.

Essa redução significativa no tamanho do download ressalta a eficácia do emprego de componentes diferidos na redução da pegada geral dos aplicativos Flutter, aumentando assim a acessibilidade e melhorando a experiência do usuário, especialmente para usuários com largura de banda limitada ou restrições de armazenamento.