src | theme | class | highlighter | mdc | drawings | image | selectable | title | author | export | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
./cover.md |
default |
text-center |
shiki |
true |
|
/side-logo.png |
true |
Flutter |
Pablo Leon Rodrigues |
|
"Flutter" é um framework que permite construir aplicações nativas cross-plataform (iOs, Android, Windows, Web, Mac) usando um único código fonte/linguagem de programação.
Desenvolvido em 2015 pelo Google o Flutter é "open source" e possuí licença de distribuição BSD. Ele utiliza a linguagem de programação "DART".
Ao programar usando DART e o Flutter framework, o sdk gera código nativo para a plataforma de destino.
Podemos dividir o flutter em dois componentes principais:
- SDK(Software development kit): ferramenta de compilação que gera código nativo.
- Framework: onde ficam a biblioteca de componentes, packages e funções.
A documentação do Flutter explica bem o que é preciso para configurar o ambiente de desenvolvimento em sua máquina em qualquer sistema operacional que você esteja usando, "docs"
- "JDK" 11 ou superior
- Visual Studio Code, "VS"
- Emulador "Genymotion"
- "GIT"
- Adroid SDK and Android tools( mais fácil usar o android studio para fazer isso)
O Flutter pode ser baixado em: https://docs.flutter.dev/get-started/install/linux/desktop
sudo apt-get update -y && sudo apt-get upgrade -y
sudo apt-get install -y curl git unzip xz-utils zip libglu1-mesa
sudo apt-get install \
clang cmake git \
ninja-build pkg-config \
libgtk-3-dev liblzma-dev \
libstdc++-12-dev
- Baixe o "pacote" de instalação
- Crie uma pasta para instalar
/usr/bin/flutter
- Descompacte o pacote na pasta criada
~/Downloads/flutter_linux_3.19.6-stable.tar.xz /usr/bin/flutter
- Adicione a pasta ao path do usuário.
echo 'export PATH="$/usr/bin/flutter/bin:$PATH"' >> ~/.bash_profile
O Flutter pode ser baixado em: https://docs.flutter.dev/get-started/install/windows#get-the-flutter-sdk
Extraia a pasta flutter do arquivo zip para a pasta C:\ do seu PC Pronto, agora certifique-se que ficou esse caminho e já lembre dele.
No windows precisamos adicionar a variável de ambiente do flutter no sistema.
- Painel de controle -> Editar variáveis de ambiente
- Variáveis de ambiente
- Variáveis do sistema
- Path
- Adicionar o caminho C:\flutter\bin
Após esses passo podemos testar a instalação do flutter usando o Flutter doctor.
flutter doctor
No android studio podemos instalar os dois plugins:
::right::
No visual studio podemos instalar os dois plugins:
Dart é uma linguagem de programação free e "open source" para desenvolver aplicativos multiplataforma.
Dentre suas características podemos destacar, tipagem forte, multi-platform, null safety, orientado a objetos e Hot Reload.
Ele compila código para ARM
, x64
, RISC-V
código de máquina, Javascript
e WebAssembly
.
Primeiro criaremos um arquivo com a extensão .dart
que identifica um código fonte dart hello.dart
.
void main() {
print("Hello, World!");
}
Depois podemos chamar o dart para executar o código
dart run hello.dart
Um programa em dart sempre vai começar com uma função main()
.
::right::
Se os plugins do Flutter e Dart estiverem corretamente instalados no visual studio code podemos rodar utilizando o
botão run em cima da função main
.
Uma instrução é uma instrução que declara um tipo ou instrui o programa a executar uma tarefa. Uma instrução
sempre termina com ponto e vírgula (;)
String message = 'Welcome to Dart!';
No Dart, um bloco é uma sequência de zero ou mais instruções. Um bloco é cercado por chaves ({})
. São utilizados em
blocos de controle como if else
, while
, do while
e for
.
{
String message = 'Welcome to Dart!';
print(message);
}
::right::
Literais são valores primitivos no programa. Por exemplo, um inteiro tem o seguinte literal 10
Para formar uma string literal, coloque o texto entre aspas simples (')
, aspas duplas (")
ou aspas triplas (""")
.
'Welcome to Dart!'
O dart utiliza três tipos de comentários, linha (//)
, bloco (/**/)
e doc (///)
/// documentação para variavel hello
String hello = "hello";
Na programação, você precisa gerenciar valores como números, strings e booleanos. Para armazenar esses valores em programas, você usa variáveis. Uma variável é um identificador que armazena um valor de um tipo específico.
Por definição, uma variável está associada a um tipo e possui um nome.
int
– representa números inteiros -1, 0, 1, 2double
– representa decimais 0.5, e 9.98String
– representa texto "Good Morning!"bool
– representa Booleantrue
efalse
Constantes são declaradas com const
antes do nome. const string constante = 'TESTE'
::right::
void main() {
int statusCode = 200;
int response = statusCode;
print('statusCode: $statusCode');
}
statusCode: 200
int httpStatusCode, response;
int httpStatusCode = 200;
var httpStatusCode = 200;
String message = "OK";
var message = "OK";
A palavra-chave const
permite definir constantes que são conhecidas em tempo de compilação. Para definir constantes
cujos valores são conhecidos em tempo de execução, use a palavra-chave final
com a seguinte sintaxe:
final type finalVariable;
Nesta sintaxe, você usa a palavra-chave final
, o tipo da variável e o nome da variável.
Ao contrário da palavra-chave const
, você não precisa inicializar a finalVariable na declaração imediatamente.
O exemplo a seguir mostra como declarar a variável final currentTime e atribuir a ela a hora atual
retornada por DateTime.now()
::right::
void main() {
final DateTime currentTime;
currentTime = DateTime.now();
print(currentTime);
}
Depois de inicializar uma variável final
ela vira uma constante e não pode ter seu valor alterado. Ao tentar alterar
é disparado um erro.
Em uma string podemos usar a (\)
como escape para inserir caracteres especiais.
void main() {
String message = 'It\'s me.';
print(message);
}
Podemos fazer interpolação de texto com ($)
para inserir o valor de uma variável e concatenar com um texto.
O mesmo também serve para expressões usando (${})
var price = 10;
var tax = 0.08;
var message = 'The $price is base price';
var message = '= ${price + price * tax}';
::right::
Podemos identificar o tamanho em caracteres de uma strin chamando a propriedade length
void main() {
var message = 'Hello';
print(message.length);
}
Ou acessar cada elemento da string como se fosse um array
void main() {
var message = 'Hello';
print(message[0]);
print(message[1]);
print(message[2]);
print(message[3]);
print(message[4]);
}
Para criar uma string com mais de uma linha podemos utilizar (```)
void main() {
var sql = '''select phone
from phone_books
where name =?''';
print(sql);
}
select phone
from phone_books
where name =?
::right::
Resumindo
- Uma string é uma sequência de unidades de código UTF-16.
- O tipo String representa strings.
- Use a propriedade str.length para obter o comprimento do str.
- Use str[index] para acessar um caractere no índice do str.
- Use o operador + para concatenar duas strings.
- Strings são imutáveis.
- Use aspas triplas para formar strings multilinhas.
void main() {
bool isWeekend = true;
String weather = "rainy";
if (isWeekend) {
if (weather == "sunny") {
print("Sol");
}
if (weather == "rainy") {
print("Chuva");
}
}
}
::right::
void main() {
bool isWeekend = true;
String weather = "rainy";
if (isWeekend) {
if (weather == "sunny") {
print("Sol");
} else {
print("Chuva");
}
}
}
::right::
void main() {
bool isWeekend = true;
String weather = "rainy";
if (isWeekend) {
if (weather == "sunny") {
print("Sol");
} else if (weather == "rainy"){
print("Chuva");
} else {
print("Nevando");
}
}
}
::right::
void main() {
int dayNumber = 3;
String dayName = "";
switch (dayNumber) {
case 1:
dayName = "Sunday";
break;
case 2:
dayName = "Monday";
break;
default:
dayName = "Invalid day";
break;
}
print(dayName);
}
::right::
void main() {
int current = 0;
while (current < 5) {
current++;
print(current);
}
}
::right::
void main() {
int number = 0;
do {
number++;
print(number);
} while (number < 5);
}
::right::
void main() {
int total = 0;
for (var i = 1; i <= 10; i++) {
total += i;
}
print(total);
}
::right::
void main() {
String txt = "Dart is awesome!";
for (int i = 0; i < txt.length; i++) {
if (txt[i] == 's') {
print("found at index $i");
break;
}
}
}
O break para o loop quando atingido.
::right::
void main() {
int total = 0, i = 0;
while (i < 10) {
i++;
if (i % 2 == 0) {
continue;
}
total += i;
print(i);
}
print('Total: $total');
}
O continue pula para a próxima iteração do loop
::right::
Para criar nosso primeiro aplicativo vamos chamar usar o flutter create aplicativo
. Isso vai fazer download de um
exemplo de aplicativo para iniciar o projeto.
Para executar o aplicativo que vamos construir precisamos de um dispositivo, ele pode ser um emulador(máquina virtual), podemos executar em um container web no chrome ou ainda podemos conectar um dispositivo para fazer a instalação por uma conexão entre o dispositivo e o mobile.
Para executar podemos usar flutter run
dentro da pasta do projeto.
Dentre eles podemos usar, AVD e Genymotion ou a lib do genymotion Scrcpy
lib
: código fonte do projetowindows, linux, android, ios, web
: projeto na linguagem destino da plataforma após compilar. Podemos alterar alguma config nelas.pubspec.yml
: na raíz do projeto, este arquivo contém configurações e pacotes, imagens, fontes, tudo o que vamos precisar indicar como dependência no projeto, tanto para desenvolver, quanto na hora de rodar o projeto. Sempre ao alterar esse arquivo, devemos rodar o comandoflutter pub get
o qual faz o download das
::right::
import 'package:flutter/material.dart';
void main() { //inicializa a aplicação
runApp(MyApp());
}
class MyApp extends StatelessWidget { // widget raiz
@override //metodo que constrói a árvore de widgets
Widget build(BuildContext context) {
return MaterialApp( //aqui usamos o widget MaterialApp
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text("Explorando Widgets"),
),
body: Text("hello world"),
)
);
}
}
Se tudo ocorreu corretamente, vamos ter um logo similar ao abaixo:
➜ colors flutter run
Launching lib/main.dart on sdk gphone64 x86 64 in debug mode...
Running Gradle task 'assembleDebug'... 15.3s
✓ Built build/app/outputs/flutter-apk/app-debug.apk
Installing build/app/outputs/flutter-apk/app-debug.apk... 692ms
Syncing files to device sdk gphone64 x86 64... 69ms
Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h List all available interactive commands.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
A Dart VM Service on sdk gphone64 x86 64 is available at:
http://127.0.0.1:34337/y67dqh5Tn7M=/
The Flutter DevTools debugger and profiler on sdk gphone64 x86 64 is available at:
http://127.0.0.1:9101?uri=http://127.0.0.1:34337/y67dqh5Tn7M=/
O resultado é o app ao lado, executando.
Ao clicar no botão do canto inferior direito o texto da tela deve atualizar.
Para isso a tela possuí um widget statefull que é atualizado toda vez que o state for alterado, sendo que toda vez que o botão é clicado uma função setState é chamada para isso.
No Flutter tudo é considerado um widget, o próprio app é um widget
que encapsula outros widgets
.
O Flutter não utiliza widgets nativos ele gera uma implementação própria que controla cada pixel desenhado.
Podemos usar o outline para ver árvore de widgets do aplicativo.
https://docs.flutter.dev/ui/widgets
::right::
widgets sem estado(stateless) são o tipo de widget que não armazena nenhum estado. Ou seja, eles não armazenam valores que podem mudar. Por exemplo, um ícone é sem estado, você define a imagem do ícone quando a cria e depois não muda mais.
::right::
um widget com estado(statefull) significa que ele pode acompanhar as alterações e atualizar a interface do usuário com base nessas alterações.
Para trabalhar com widgets stateful
utilizamos o state
que gerenciar os dados mantidos pelo widget.
Por exemplo ao usar o setState
avisamos o flutter que precisamos chamar o método build
novamente.
A primeira função que o flutter executa na criação de um estado é o createState()
, que vai inicializar o state
em um widget.
Depois tem o método initState()
, que vai executar na inicialização do widget, esse método pode ser sobrescrito
utilizando a anotação @override
para ser alterado, sendo possível adicionar funcionalidades dentro dele
como conexão com banco, chamadas externas
etc.
Após isso ele chama o didChangeDependencies()
utilizado para verificar se os valores passados para o widget foram
alterados em tempo de execução, buscando os valores atualizados.
Então é feito o build()
, responsável por renderizar o app na tela. Esse método alteramos para criar o visual do widget.
Após o build o flutter utiliza o método didUpdateWidget()
para verificar se houve alteração e se o widget foi
atualizado. E no final temos os métodos deactivate()
e disposal()
, o deactivate desativa o widget e o disposal
é para quando ele é removido da árvore de widgets.
Vamos criar um app que pode alterar sua própria cor de tema conforme a escolha do usuário.
Vamos começar escondendo a flag de debug do sistema, para isso vamos adicionar uma nova propriedade no Material e
adicionar debugShowCheckedModeBanner: false,
. Digite r
no terminal para atualizar a aplicação.
Adicione também algumas propriedades no widget appBar
, como o centerTitle: true
, ou o bloco style
por exemplo:
title: const Text(
'widget.title',
style: TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold
),),
::right::
Vamos criar os botões para selecionar as cores.
class _MyHomePageState extends
State<MyHomePage> {
final Map<String, Color> colors = {
'blue': Colors.blue,
'red': Colors.red,
'green': Colors.green,
'yellow': Colors.yellow,
'purple': Colors.purple,
'teal': Colors.teal,
'orange': Colors.orange
};
Color? selectedColor;
Precisamos de uma função para alterar a cor selecionada.
void _setColor(String colorName,
Color color) {
setState(() {
selectedColor = color;
});
}
E depois na appBar
precisamos alterar
appBar: AppBar(
backgroundColor: selectedColor ??
Colors.black,
::right::
body: Column(
crossAxisAlignment:
CrossAxisAlignment.stretch,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
for (var entry in colors.entries)
Container(
margin: const EdgeInsets.all(10),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: entry.value,
minimumSize: const Size(300, 60),
),
child: Text(''),
onPressed: () => _setColor(
entry.key, entry.value),
),
), ],));
O comando flutter pub get é usado para gerenciar as dependências do projeto. Quando você executa esse comando, o Flutter baixa e instala todas as bibliotecas e pacotes especificados no arquivo pubspec.yaml, que é onde as dependências do seu projeto são definidas.
O Flutter lê o arquivo pubspec.yaml para identificar quais pacotes e versões foram especificados como dependências,
ao executar o comando flutter pub add nome_da_lib
o flutter vai instalar a biblioteca nome_da_lib
, os pacotes
que não estão disponíveis na máquina local são baixados do repositório do Dart (https://pub.dev) e armazenados em uma
pasta chamada .pub-cache
no seu sistema.
Usamos o SharedPreferences para armazenar a cor escolhida pelo usuário. Para instalar a lib do shared_preferences
executamos o comando flutter pub add shared_preferences
.
void _setColor(String colorName, Color color) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('color', colorName);
print(prefs);
setState(() {
selectedColor = color;
});
}
void _getColor() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? colorName = prefs.getString('color');
setState(() {
selectedColor = colors[colorName];
});
}
Usando o MaterialPageRoute
podemos navegar entre uma tela e outra. Para isso vamos criar uma pasta para telas, e
dentro da mesma as páginas. Crie um novo arquivo .dart e digite o atalho stless
ou stful
.
Aqui a navegação é feita utilizando o push
e pop
navigator. Esse método é mais utilizado em aplicativos mais simples
e de menor porte.
IconButton(
icon: const Icon(Icons.settings),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ConfiguracoesPage()),
);
},
),
Podemos utilizar o routes criamos uma estrutura que é similar a uma pilha(stack), também chamado de named routes
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// Define as rotas
routes: {
'/': (context) => HomePage(), // Página inicial
'/second': (context) => SecondPage(), // Página secundária
},
// Rota inicial
initialRoute: '/',
);
}
}
O BuildContext
é um conceito utilizado dentro dos widgets do Flutter. Ele é uma referência para a posição na árvore
de widgets onde um widget está sendo construído e fornece uma maneira de acessar várias propriedades e métodos
relevantes para essa localização.
@override
Widget build(BuildContext context) {
return MaterialApp(
Através dele podemos acessar informações como o tema e a localização do widget. Ele permite que você percorra e manipule a árvore de widgets, acesse widgets herdados e execute operações específicas de contexto, como navegação.
Vamos criar uma lista para exibir dados, para isso usaremos o widget ListView
ListView(
children: const [
Text("Curso1"),
Text("Curso2"),
Text("Curso3"),
],
)
Essa forma é utilizada para criar uma lista fixa, onde sempre teremos uma quantidade fixa.
::right::
Outra forma é com uma lista dinâmica onde podemos utilizamos uma quantidade x de itens, para isso usamos um count
e um
item builder
. Podemos scrollDirection: Axis.horizontal
List<String> lista = [
'Curso1',
'Curso2',
'Curso3'
]
ListView.builder(
itemCount: lista.length,
itemBuilder: (context, index) {
return Text(lista[index]);
},
),
Outra opção é a utilização de um ListTile
ListView.builder(
itemCount: lista.length,
itemBuilder: (context, index) {
return ListTile(
leading: Icon(Icons.map),
title: Text(
lista[index]
),
subtitle: Text("Subtitulo"),
trailing: Icon(
Icons.arrow_forward_ios
),
);
},
),
::right::
home: Scaffold(
appBar: AppBar(
title: const Text(title),
),
body: ListView(
children: const <Widget>[
ListTile(
leading: Icon(Icons.map),
title: Text('Map'),
),
ListTile(
leading: Icon(Icons.photo_album),
title: Text('Album'),
),
ListTile(
leading: Icon(Icons.phone),
title: Text('Phone'),
),
],),),
ListView.builder(
itemCount: courses.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
child: Text("CS")
),
title: Text(courses[index]),
subtitle: Text("Subtitulo"),
trailing: Icon(
Icons.arrow_forward_ios
),
);
},
),
::right::
Card(
elevation: 5,
child: ListTile(
leading: const CircleAvatar(
child: Text("CS")
),
title: Text(courses[index]),
subtitle: const Text("Subtitulo"),
trailing: const Icon(
Icons.arrow_forward_ios
),),
);
Digamos que precisamos buscar uma lista de dados de uma fonte externa como uma api ou servidor.
List<String> lista = [];
getLista() {
return = ['Curso 1', 'Curso 2', 'Curso 3'];
}
Para mostrar essa lista podemos usar o método initState()
esse método precisa da anotação @override, pois é nativo
nos widgets.
@override
void initState() {
super.initState();
lista = getLista();
}
Para isso vamos criar um método que simula uma busca externa que demora 10 segundos.
Future<List<String>> getLista() async {
return Future.delayed(const Duration(seconds: 10), () {
return ['Curso1', 'Curso2', 'Curso3'];
});
}
@override
void initState() async {
super.initState();
lista = await getLista();
}
O problema é o método initState não é assíncrono(async
).
Para isso podemos usar o widget FutureBuilder.
FutureBuilder(
future: coursesFuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return Card(
elevation: 5,
child: ListTile(
title: Text(snapshot.data![index]),
leading: const CircleAvatar(
child: Text("CS"),),
trailing: const Icon(Icons.arrow_forward_ios),
subtitle: const Text("Subtitulo do curso"),),);},);
} else {
return Center( child: CircularProgressIndicator() );
}},)
A estrutura do de formulários no flutter é criada dentro de um widget Form
. Para referênciar esse formulário usamos um
GlobalKey
por exemplo final _formKey = GlobalKey<FormState>();
.
Dentro de cada FormField podemos definir um atributo validator
onde podemos verificar o value do campo, e em
determinado momento podemos verificar o status do form com _formKey.currentState!.validate()
para validar os campos
do formulário.
child: TextFormField(
decoration: const InputDecoration(
border: OutlineInputBorder(), labelText: 'Usuário'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Usuário é obrigatório';
}
return null;
},
)),
Podemos verificar o estaod dos validators
do form, para então prosseguir com a lógica dele.
Padding(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
initialValue: nome,
onSaved: (value) => nome = value ?? '',
validator: (value) {
if (value == null || value.isEmpty) {
return 'Insira um nome';
}
return null;
},
),
),
::right::
No caso abaixo se todos os
campos do form estiverem válidos podemos chamar o método save
que vai excecutar
o onSaved
de cada elemento.
final _formKey = GlobalKey<FormState>();
updateUsuario() async {
if(_formKey.currentState!.validate()) {
_formKey.currentState!.save();
Vamos começar a trabalhar com uma API, sendo uma das abordagens mais utilizadas atualmente. Primeiro
vamos criar um modelo do usuário, para isso usuario.dart
na pasta models ou entity...
class Usuario {
String? id;
String? nome;
String? email;
String? senha;
Usuario({
this.id,
this.nome,
this.email,
this.senha,
});
::right::
Map<String, dynamic> toJson() {
return {
'id': id,
'nome': nome,
'email': email,
'senha': senha,
};
}
factory Usuario.fromJson(
Map<String, dynamic> json) {
return Usuario(
id: json['id']?.toString(),
nome: json['nome'] ?? '',
email: json['email'] ?? '',
senha: json['senha'] ?? '',
);
}
}
Para trabalhar com API's REST, vamos usar a lib HTTP
. Instalamos usando o flutter pub add http
.
Para começar vamos listar os usuários que vem da API.
Future<List<Usuario>> _futureUsuarios = Future.value([]);
@override
void initState() {
super.initState();
_loadUsuarios();
}
void _loadUsuarios() {
setState(() {
_futureUsuarios = getUsuarios();
});
}
O médoto getUsuarios
vai buscar na API a lista de usuários.
Future<List<Usuario>> getUsuarios() async {
try {
String url ='https://mockapi.io/api/usuarios';
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
List<dynamic> data = json.decode(response.body);
return data.map((item) {
return Usuario.fromJson(item);
}).toList();
} else {
throw Exception('Falha na requisição: ${response.statusCode}');
}
} catch (e) {
throw Exception('Erro ao buscar os dados da API.');
}
}
FutureBuilder(
future: _futureUsuarios,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Usuario> dados = snapshot.data!;
return ListView.builder(
itemCount: dados.length,
itemBuilder: (context, index) {
return Card(...)
}
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
//Update
final response = await http.put(
Uri.parse('https://mockapi.io/api/usuarios/${widget.usuario?.id}'),
headers: {'Content-Type': 'application/json'},
body: json.encode(usuarioParaSalvar.toJson()),
);
//Remove
final response = await http.delete(
Uri.parse('https://mockapi.io/api/usuarios/${widget.usuario?.id}')
);
Push Notifications são uma forma de comunicação com os usuários, podendo enviar mensagens mesmo que o aplicativo esteja fechado, é possível também mandar para usuários específicos ou um grupo de usuários de acordo com a necessidade.
Para isso vamos usar a plataforma do Firebase
, lá vamos criar um projeto para gerênciar todo o resto.
O Firebase fornece uma biblioteca para facilitar a instalação chamada firebase-cli
A instalação é de acordo com o SO.
Após a instalação podemos efetuar login no firebase usando o terminal. Isso vai abrir uma janela para autenticação.
firebase login
Com o projeto criado no firebase vamos listar os projetos e inicializar o projeto do firebase no projeto local.
firebase projects:list
firebase init
Precisamos adicionar também as bibliotecas do firebase:
flutter pub add firebase_core
flutter pub add firebase_messaging
E então vamos configurar
dart pub global activate flutterfire_cli
flutterfire configure
Depois vamos alterar o main para trabalhar com notificações, adicionar o import 'dart:io'
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
); // Solicita permissão para o aplicativo
final notificationSettings = await FirebaseMessaging.instance.requestPermission(provisional: true);
// Listener para mensagens recebidas enquanto o app está em foreground
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Message data: ${message.data}');
if (message.notification != null) {
print('Message also contained a notification: ${message.notification}');
}
});// Listener para quando a mensagem é clicada e o app estava em background
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('A new onMessageOpenedApp event was published!');
// Handle the message and navigate to a specific screen, if needed.
}); // Verifica se o app foi iniciado por uma mensagem
RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
print('App opened by a notification: ${initialMessage.data}');
}
runApp(const MyApp());
Podemos adicionar bibliotecas e widgets modificando o pub pubspec.yaml
dependencies:
flutter:
sdk: flutter
http: ^0.13.3
shared_preferences: ^2.0.6
Aqui podemos especificar a versão escolhida, apontar uma versão mínima ou deixar sem versão para ao rodar o flutter pub get pegar a última versão do repositório.
Outra forma é utilizar o flutter pub add nomedalib
, que vai buscar a última versão e adicionar ao pubspec.yaml
::right::
flutter clean
flutter pub get
flutter build apk
O flutter clean
, vai remover o conteúdo gerado automáticamente e arquivos temporários, o pub get
vai atualizar o
projeto com as dependências do pubspec
novamente, enquanto o build apk
vai compilar o projeto executando o Gradle
e gerar o executável.
Running Gradle task
'assembleRelease'...45.9s
✓ Built
build/app/outputs/flutter-apk/app.apk
(19.6MB).
https://www.youtube.com/@Fireship
https://www.youtube.com/@RobertBrunhage
https://www.youtube.com/@FilledStacks
https://flutterparainiciantes.com.br/
https://docs.flutter.dev/ui/design/material
https://docs.flutter.dev/ui/interactivity
https://developer.android.com/studio/run/managing-avds?hl=pt-br
https://github.com/Genymobile/scrcpy/blob/master/doc/linux.md