Flutter: do zero a
publicação
Cícero Duarte / Cinthia Galvão
Cícero Duarte
linkedin.com/in/ciceroduarte
github.com/ciceroduarte
Desenvolvedor iOS
Cinthia Galvão
linkedin.com/in/cinthiagalvao
github.com/cpgalvao
Desenvolvedora Android
Agenda
- Flutter
- Visão geral
- Demo
- Integração com código nativo
- Geração de versão
- Case UOL VivaBem
- Prós / Contras
Motivação
- Oportunidade
- Flutter
- Possível case Google/IO
- App publicado até final de abril
O que é Flutter?
- SDK de desenvolvimento multiplataforma
- Criado pelo Google
- Desempenho
- UI rica e nativa
- Desenvolvimento rápido
- 11/05/2017: Primeira release 0.0.6
- 20/06/2018: Release Preview 1
Instalação
- Entrar em: https://flutter.io/get-started/install/
- Extrair em um diretório e adicionar ao $PATH
$ export PATH=`pwd`/flutter/bin:$PATH
$ flutter doctor
Atualização
$ flutter upgrade
Arquitetura em camadas
Engine (C++) Skia Dart Text
Framework (Dart)
Animation Painting Gestures
Foundation
Rendering
Widgets
Material Cupertino
Dart
- Apresentada pelo Google em 2011
- Substituir o Javascript
- VM ou compilada para Javascript
- Utilizada em produtos internos no Google
Flutter + Dart
- Orientada a objetos
- Opcionalmente tipada
- Declarativa
- StyleGuide bem definido
- Compila para ARM Code
- Ahead-of-time
- Just-in-time
+ =
Ahead-of-time
Just-in-time
🤖
Widgets
Container Column Row Stack Center Padding
Appbar FloatingActionButton TabBar BottomNavigationBar TextField SimpleDialog
StatefulWidgetStatelessWidget
Widget
AssetImage Text Scrollable Animatable
Widgets
Stateless - Imutável,
desenhada apenas uma vez
Stateful - Mutável, método
setState redesenha a widget
AboutPage DetailPage
Construindo um layout
Demo
Internacionalização
dependencies:
flutter_localizations:
sdk: flutter
intl:
intl_translation:
localizationsDelegates: [
// ... app-specific localization delegate[s] here
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'),
const Locale('pt', 'BR'),
// ... other locales the app supports
],
Importar dependências no pubspec.yaml
Implementar delegates e locales
class DemoLocalizations {
static Future<DemoLocalizations> load(Locale locale) {
final String name = locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
final String localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((Null _) {
Intl.defaultLocale = localeName;
return DemoLocalizations();
});
}
static DemoLocalizations of(BuildContext context) {
return Localizations.of<DemoLocalizations>(context, DemoLocalizations);
}
String get title {
return Intl.message(
'Hello World',
name: 'title',
desc: 'Title for the Demo application',
);
}
}
Implementar classe para Localization e Strings internacionalizadas
Executar comandos
$ flutter pub pub run
intl_translation:extract_to_arb
—output-dir=lib/i18n lib/main.dart$ flutter pub pub run
intl_translation:generate_from_arb
--output-dir=lib/i18n
--no-use-deferred-loading
lib/main.dart lib/i18n/intl_messages.arb
appBar: AppBar(
title: Text("Comprar"),
)
Internacionalização 🚀
dependencies:
flutter_localizations:
sdk: flutter
intl:
intl_translation:
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
S.delegate,
],
supportedLocales: S.delegate.supportedLocales,
Utilizar o plugin para extrair strings
Demo
MethodChannel
FlutterMethodChannel
MethodChannel
Integração com código nativo
Flutter
State
iOS
AppDelegate
iOS platform
APIs
3rd-Party
APIs for iOS
FlutterViewController
Android
Activity
Android
platform APIs
3rd-Party
APIs for
Android
FlutterView
Integração com código nativo
static const platform = const MethodChannel(‘tdc_demo_channel');
final String result = await platform.invokeMethod('getNativeText', param);
nativeText = 'Texto final recebido do Nativo: $result';
val channel = MethodChannel(flutterView, "tdc_demo_channel")
channel.setMethodCallHandler { call, result ->
if (call.method == "getNativeText") {
var resultString = getString(R.string.platform_string)
result.success("$resultString ${call.arguments}")
} else {
result.notImplemented()
}
}
let channel = FlutterMethodChannel(name: “tdc_demo_channel”, binaryMessenger: controller)
channel.setMethodCallHandler { (call, result) in
if call.method == "getNativeText" {
let resultString = "Método iOS, parâmetro: (call.arguments ?? "")"
result(resultString + "($0 ?? "")")
} else {
result(FlutterMethodNotImplemented)
}
}
Integração com código nativo
static const platform = const MethodChannel(‘tdc_demo_channel');
final String result = await platform.invokeMethod('getNativeText', param);
nativeText = 'Texto final recebido do Nativo: $result';
val channel = MethodChannel(flutterView, "tdc_demo_channel")
channel.setMethodCallHandler { call, result ->
if (call.method == "getNativeText") {
var resultString = getString(R.string.platform_string)
result.success("$resultString ${call.arguments}")
} else {
result.notImplemented()
}
}
let channel = FlutterMethodChannel(name: “tdc_demo_channel”, binaryMessenger: controller)
channel.setMethodCallHandler { (call, result) in
if call.method == "getNativeText" {
let resultString = "Método iOS, parâmetro: (call.arguments ?? "")"
result(resultString + "($0 ?? "")")
} else {
result(FlutterMethodNotImplemented)
}
}
Integração com código nativo
static const platform = const MethodChannel(‘tdc_demo_channel');
final String result = await platform.invokeMethod('getNativeText', param);
nativeText = 'Texto final recebido do Nativo: $result';
val channel = MethodChannel(flutterView, "tdc_demo_channel")
channel.setMethodCallHandler { call, result ->
if (call.method == "getNativeText") {
var resultString = getString(R.string.platform_string)
result.success("$resultString ${call.arguments}")
} else {
result.notImplemented()
}
}
let channel = FlutterMethodChannel(name: “tdc_demo_channel”, binaryMessenger: controller)
channel.setMethodCallHandler { (call, result) in
if call.method == "getNativeText" {
let resultString = "Método iOS, parâmetro: (call.arguments ?? "")"
result(resultString + "($0 ?? "")")
} else {
result(FlutterMethodNotImplemented)
}
}
NativePageState() {
platform.setMethodCallHandler(_handlerNativeCall);
}
Future<dynamic> _handlerNativeCall(MethodCall call) async {
switch (call.method) {
case "getFlutterText":
return Future.value("Método Flutter, parâmetro: ${call.arguments}");
}
}
channel.invokeMethod("getFlutterText", arguments: "iOSParam", result: {
print(resultString + "($0 ?? "")")
})
channel.invokeMethod(“getFlutterText", “AndroidParam”, object : MethodChannel.Result {
override fun success(p0: Any?) {
resultString = "$resultString $p0"
print(resultString)
}
override fun error(p0: String?, p1: String?, p2: Any?) { }
override fun notImplemented() { }
})
Integração com código nativo
NativePageState() {
platform.setMethodCallHandler(_handlerNativeCall);
}
Future<dynamic> _handlerNativeCall(MethodCall call) async {
switch (call.method) {
case "getFlutterText":
return Future.value("Método Flutter, parâmetro: ${call.arguments}");
}
}
channel.invokeMethod("getFlutterText", arguments: "iOSParam", result: {
print(resultString + "($0 ?? "")")
})
channel.invokeMethod(“getFlutterText", “AndroidParam”, object : MethodChannel.Result {
override fun success(p0: Any?) {
resultString = "$resultString $p0"
print(resultString)
}
override fun error(p0: String?, p1: String?, p2: Any?) { }
override fun notImplemented() { }
})
Integração com código nativo
NativePageState() {
platform.setMethodCallHandler(_handlerNativeCall);
}
Future<dynamic> _handlerNativeCall(MethodCall call) async {
switch (call.method) {
case "getFlutterText":
return Future.value("Método Flutter, parâmetro: ${call.arguments}");
}
}
channel.invokeMethod("getFlutterText", arguments: "iOSParam", result: {
print(resultString + "($0 ?? "")")
})
channel.invokeMethod(“getFlutterText", “AndroidParam”, object : MethodChannel.Result {
override fun success(p0: Any?) {
resultString = "$resultString $p0"
print(resultString)
}
override fun error(p0: String?, p1: String?, p2: Any?) { }
override fun notImplemented() { }
})
Integração com código nativo
Gerando versão Android
$ flutter clean
$ flutter build apk --release
$ zipalign -v -p 4
app-release.apk app-release-final.apk
$ apksigner sign --ks <my-release-key.jks>
--out app-release-final-assinada.apk
app-release-final.apk
$ apksigner verify --print-certs
app-release-final-assinada.apk
Gerando versão iOS
$ flutter clean
$ flutter build ios --release
$ open ios/Runner.xcworkspace
Case
- VivaBem
- Canal de saúde e bem-estar do UOL
- Aplicativo
- Meditação e mindfulness
- Notícias e blogs
- Lembretes
- Aplicativo atraente
- Componentes de UI
- Animações
- Funcionalidades do app
- Reprodução de áudio
- Google Analytics
- Notificações
Case
16/02
20/02
28/02
26/03
23/04
03/05
Proposta do case
Início de POCs
POCs -> início
do projeto
Publicação nas lojas
Android e iOS.
Reunião com cliente
sobre app
Versão release
candidate
Confirmação
SandBox area
no Google I/O
Case
Case
Prós Contras
- Desempenho
- Hot reload
- Integração com código nativo
- Integridade dos layouts
- Webview/Maps
- Integração com views nativas
- Falta de componentes nativos
- Suporte para devices 32bits
- Suporte para Android SDK16+
Links
- Flutter
- https://flutter.io/
- Instalação/Update do ambiente
- https://flutter.io/get-started/install/
- https://flutter.io/upgrading/
- Widgets
- https://flutter.io/tutorials/layout/
- https://flutter.io/widgets/
- Internacionalização
- https://flutter.io/tutorials/internationalization/
- Integração com código nativo
- https://flutter.io/platform-channels/
- Showcase
- https://flutter.io/showcase/
Cícero Duarte
linkedin.com/in/ciceroduarte
Cinthia Galvão
linkedin.com/in/cinthiagalvao
https://github.com/cpgalvao/tdc_demo

Flutter do zero a publicacao

  • 1.
    Flutter: do zeroa publicação Cícero Duarte / Cinthia Galvão
  • 2.
    Cícero Duarte linkedin.com/in/ciceroduarte github.com/ciceroduarte Desenvolvedor iOS CinthiaGalvão linkedin.com/in/cinthiagalvao github.com/cpgalvao Desenvolvedora Android
  • 3.
    Agenda - Flutter - Visãogeral - Demo - Integração com código nativo - Geração de versão - Case UOL VivaBem - Prós / Contras
  • 4.
    Motivação - Oportunidade - Flutter -Possível case Google/IO - App publicado até final de abril
  • 5.
    O que éFlutter? - SDK de desenvolvimento multiplataforma - Criado pelo Google - Desempenho - UI rica e nativa - Desenvolvimento rápido - 11/05/2017: Primeira release 0.0.6 - 20/06/2018: Release Preview 1
  • 6.
    Instalação - Entrar em:https://flutter.io/get-started/install/ - Extrair em um diretório e adicionar ao $PATH $ export PATH=`pwd`/flutter/bin:$PATH $ flutter doctor
  • 7.
  • 8.
    Arquitetura em camadas Engine(C++) Skia Dart Text Framework (Dart) Animation Painting Gestures Foundation Rendering Widgets Material Cupertino
  • 9.
    Dart - Apresentada peloGoogle em 2011 - Substituir o Javascript - VM ou compilada para Javascript - Utilizada em produtos internos no Google
  • 10.
    Flutter + Dart -Orientada a objetos - Opcionalmente tipada - Declarativa - StyleGuide bem definido - Compila para ARM Code - Ahead-of-time - Just-in-time + =
  • 11.
  • 12.
  • 13.
    Widgets Container Column RowStack Center Padding Appbar FloatingActionButton TabBar BottomNavigationBar TextField SimpleDialog
  • 14.
    StatefulWidgetStatelessWidget Widget AssetImage Text ScrollableAnimatable Widgets Stateless - Imutável, desenhada apenas uma vez Stateful - Mutável, método setState redesenha a widget AboutPage DetailPage
  • 15.
  • 16.
  • 17.
    Internacionalização dependencies: flutter_localizations: sdk: flutter intl: intl_translation: localizationsDelegates: [ //... app-specific localization delegate[s] here GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], supportedLocales: [ const Locale('en', 'US'), const Locale('pt', 'BR'), // ... other locales the app supports ], Importar dependências no pubspec.yaml Implementar delegates e locales
  • 18.
    class DemoLocalizations { staticFuture<DemoLocalizations> load(Locale locale) { final String name = locale.countryCode.isEmpty ? locale.languageCode : locale.toString(); final String localeName = Intl.canonicalizedLocale(name); return initializeMessages(localeName).then((Null _) { Intl.defaultLocale = localeName; return DemoLocalizations(); }); } static DemoLocalizations of(BuildContext context) { return Localizations.of<DemoLocalizations>(context, DemoLocalizations); } String get title { return Intl.message( 'Hello World', name: 'title', desc: 'Title for the Demo application', ); } } Implementar classe para Localization e Strings internacionalizadas
  • 19.
    Executar comandos $ flutterpub pub run intl_translation:extract_to_arb —output-dir=lib/i18n lib/main.dart$ flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/i18n --no-use-deferred-loading lib/main.dart lib/i18n/intl_messages.arb
  • 20.
    appBar: AppBar( title: Text("Comprar"), ) Internacionalização🚀 dependencies: flutter_localizations: sdk: flutter intl: intl_translation: localizationsDelegates: [ GlobalMaterialLocalizations.delegate, S.delegate, ], supportedLocales: S.delegate.supportedLocales, Utilizar o plugin para extrair strings
  • 21.
  • 22.
    MethodChannel FlutterMethodChannel MethodChannel Integração com códigonativo Flutter State iOS AppDelegate iOS platform APIs 3rd-Party APIs for iOS FlutterViewController Android Activity Android platform APIs 3rd-Party APIs for Android FlutterView
  • 23.
    Integração com códigonativo static const platform = const MethodChannel(‘tdc_demo_channel'); final String result = await platform.invokeMethod('getNativeText', param); nativeText = 'Texto final recebido do Nativo: $result'; val channel = MethodChannel(flutterView, "tdc_demo_channel") channel.setMethodCallHandler { call, result -> if (call.method == "getNativeText") { var resultString = getString(R.string.platform_string) result.success("$resultString ${call.arguments}") } else { result.notImplemented() } } let channel = FlutterMethodChannel(name: “tdc_demo_channel”, binaryMessenger: controller) channel.setMethodCallHandler { (call, result) in if call.method == "getNativeText" { let resultString = "Método iOS, parâmetro: (call.arguments ?? "")" result(resultString + "($0 ?? "")") } else { result(FlutterMethodNotImplemented) } }
  • 24.
    Integração com códigonativo static const platform = const MethodChannel(‘tdc_demo_channel'); final String result = await platform.invokeMethod('getNativeText', param); nativeText = 'Texto final recebido do Nativo: $result'; val channel = MethodChannel(flutterView, "tdc_demo_channel") channel.setMethodCallHandler { call, result -> if (call.method == "getNativeText") { var resultString = getString(R.string.platform_string) result.success("$resultString ${call.arguments}") } else { result.notImplemented() } } let channel = FlutterMethodChannel(name: “tdc_demo_channel”, binaryMessenger: controller) channel.setMethodCallHandler { (call, result) in if call.method == "getNativeText" { let resultString = "Método iOS, parâmetro: (call.arguments ?? "")" result(resultString + "($0 ?? "")") } else { result(FlutterMethodNotImplemented) } }
  • 25.
    Integração com códigonativo static const platform = const MethodChannel(‘tdc_demo_channel'); final String result = await platform.invokeMethod('getNativeText', param); nativeText = 'Texto final recebido do Nativo: $result'; val channel = MethodChannel(flutterView, "tdc_demo_channel") channel.setMethodCallHandler { call, result -> if (call.method == "getNativeText") { var resultString = getString(R.string.platform_string) result.success("$resultString ${call.arguments}") } else { result.notImplemented() } } let channel = FlutterMethodChannel(name: “tdc_demo_channel”, binaryMessenger: controller) channel.setMethodCallHandler { (call, result) in if call.method == "getNativeText" { let resultString = "Método iOS, parâmetro: (call.arguments ?? "")" result(resultString + "($0 ?? "")") } else { result(FlutterMethodNotImplemented) } }
  • 26.
    NativePageState() { platform.setMethodCallHandler(_handlerNativeCall); } Future<dynamic> _handlerNativeCall(MethodCallcall) async { switch (call.method) { case "getFlutterText": return Future.value("Método Flutter, parâmetro: ${call.arguments}"); } } channel.invokeMethod("getFlutterText", arguments: "iOSParam", result: { print(resultString + "($0 ?? "")") }) channel.invokeMethod(“getFlutterText", “AndroidParam”, object : MethodChannel.Result { override fun success(p0: Any?) { resultString = "$resultString $p0" print(resultString) } override fun error(p0: String?, p1: String?, p2: Any?) { } override fun notImplemented() { } }) Integração com código nativo
  • 27.
    NativePageState() { platform.setMethodCallHandler(_handlerNativeCall); } Future<dynamic> _handlerNativeCall(MethodCallcall) async { switch (call.method) { case "getFlutterText": return Future.value("Método Flutter, parâmetro: ${call.arguments}"); } } channel.invokeMethod("getFlutterText", arguments: "iOSParam", result: { print(resultString + "($0 ?? "")") }) channel.invokeMethod(“getFlutterText", “AndroidParam”, object : MethodChannel.Result { override fun success(p0: Any?) { resultString = "$resultString $p0" print(resultString) } override fun error(p0: String?, p1: String?, p2: Any?) { } override fun notImplemented() { } }) Integração com código nativo
  • 28.
    NativePageState() { platform.setMethodCallHandler(_handlerNativeCall); } Future<dynamic> _handlerNativeCall(MethodCallcall) async { switch (call.method) { case "getFlutterText": return Future.value("Método Flutter, parâmetro: ${call.arguments}"); } } channel.invokeMethod("getFlutterText", arguments: "iOSParam", result: { print(resultString + "($0 ?? "")") }) channel.invokeMethod(“getFlutterText", “AndroidParam”, object : MethodChannel.Result { override fun success(p0: Any?) { resultString = "$resultString $p0" print(resultString) } override fun error(p0: String?, p1: String?, p2: Any?) { } override fun notImplemented() { } }) Integração com código nativo
  • 29.
    Gerando versão Android $flutter clean $ flutter build apk --release $ zipalign -v -p 4 app-release.apk app-release-final.apk $ apksigner sign --ks <my-release-key.jks> --out app-release-final-assinada.apk app-release-final.apk $ apksigner verify --print-certs app-release-final-assinada.apk
  • 30.
    Gerando versão iOS $flutter clean $ flutter build ios --release $ open ios/Runner.xcworkspace
  • 31.
    Case - VivaBem - Canalde saúde e bem-estar do UOL - Aplicativo - Meditação e mindfulness - Notícias e blogs - Lembretes
  • 32.
    - Aplicativo atraente -Componentes de UI - Animações - Funcionalidades do app - Reprodução de áudio - Google Analytics - Notificações Case
  • 33.
    16/02 20/02 28/02 26/03 23/04 03/05 Proposta do case Iníciode POCs POCs -> início do projeto Publicação nas lojas Android e iOS. Reunião com cliente sobre app Versão release candidate Confirmação SandBox area no Google I/O Case
  • 34.
  • 35.
    Prós Contras - Desempenho -Hot reload - Integração com código nativo - Integridade dos layouts - Webview/Maps - Integração com views nativas - Falta de componentes nativos - Suporte para devices 32bits - Suporte para Android SDK16+
  • 36.
    Links - Flutter - https://flutter.io/ -Instalação/Update do ambiente - https://flutter.io/get-started/install/ - https://flutter.io/upgrading/ - Widgets - https://flutter.io/tutorials/layout/ - https://flutter.io/widgets/ - Internacionalização - https://flutter.io/tutorials/internationalization/ - Integração com código nativo - https://flutter.io/platform-channels/ - Showcase - https://flutter.io/showcase/
  • 37.

Notas do Editor

  • #4 [Cinthia] Vamos falar de Flutter, uma visão geral, vamos fazer uma demo, mostrar integração com código Android e iOS, como gerar uma versão para publicar. Também iremos mostrar nosso case que foi destaque no Google I/O, e fechar com prós e contras do Flutter
  • #5 [Cinthia] O que nos levou a descobrir o Flutter? No início do ano, recebemos uma oportunidade/desafio de desenvolver um app em Flutter e esse app tinha chances de ser um case no Google I/O se fosse publicado até o final de abril
  • #6 [Cinthia] O que é Flutter? É um SDK para desenvolvimento de aplicativos multiplataforma, que foi criado pelo Google e tem como princípios: desempenho, o app desenvolvido tem performance de app nativo; UI rica e nativa, com experiência do usuário natural de cada plataforma; e desenvolvimento rápido, através do uso de widgets e do hot reload. A primeira versão do flutter foi lançada há pouco mais de 1 ano e atualmente está na versão Release Preview 1.
  • #7 [Cícero] Para iniciar o desenvolvimento em Flutter, é necessário baixar a SDK, extrair o conteúdo do zip e adicionar o diretório onde foi extraído o flutter, no path. A partir daí, pode ser feito um flutter doctor em um terminal para validar a instalação. Pode ser utilizado o Android Studio ou o IntelliJ, adicionando os plugins do Flutter e do Dart, ou ainda o Visual Studio Code com a extension do Flutter.
  • #8 [Cícero] Para atualizar a versão do Flutter, que está em constante desenvolvimento, basta executar flutter upgrade. Há também outros 2 comandos que serão bastante utilizados: packages get e packages upgrade. Cada vez que o arquivo pubspec.yaml for alterado, adicionando ou alterando um pacote, será necessário executá-los.
  • #9 [Cícero] // Falar em camadas O Flutter essencialmente é organizado em camadas, podemos separar em duas camadas principais, a Engine e o Framework. A Engine é a camada escrita em C/C++ que compõe a estrutura de execução, tendo a Skia, uma biblioteca de renderização 2D e de texto, que também é utilizada por exemplo no Google Chrome e no próprio Android e além da Skia, tem o Dart, que é a linguagem que utilizamos para desenvolver em Flutter. A camada verde é o Framework, é a parte totalmente escrita em Dart, ou seja, tudo que você utiliza na ferramenta é escrito em Dart, ela controla toda a parte de renderização, gestures, animações e possui o principal pilar do Flutter, as Widgets. // Falar sobre framework reativo moderno; // APIs de teste Tudo no Flutter são Widgets, não só componentes visuais como TextFields e Labels, Widgets também são utilizadas para estruturar o layout, como as Widgets de Center, Row e Column. Acima das Widgets podemos ver na mesma camada os itens Material e Cupertino, que são os conjuntos de Widgets específicas para Android e iOS, logicamente Material são as de Android e Cupertino as de iOS
  • #10 [Cícero] Uma das dúvidas mais frequentes sobre o Flutter é: Por que utilizar Dart e não Kotlin, Swift ou Javascript? Para responder essa pergunta temos que analisar as características do Flutter e um pouco da estratégia do Google com relação ao Dart. Eu particularmente nunca tinha ouvido falar em Dart até conhecer o Flutter, então de onde saiu? Apresentada pelo Google a primeira vez em 2011; Objetivo de substituir o Javascript como principal linguagem embutida nos navegadores; Inicialmente podia rodar em uma VM ou compilada para Javascript; Atualmente é utilizada em vários produtos internos no google.
  • #11 [Cícero] O Dart não é a primeira linguagem padrão para desenvolver em Flutter, inicialmente era desenvolvido em Javascript, mas a ideia do time de desenvolvimento do Flutter era criar a melhor maneira de desenvolver para mobile, e utilizando Javascript complicaria a maneira que eles queriam gerar os binários para publicação. Com isso, começaram a buscar e analisar várias linguagem existentes no mercado e a que teve uma maior pontuação geral foi o Dart, mas pq? É orientada a objetos É declarativa, fazendo com que os layouts sejam montados de maneira parecida com CSS É uma linguagem majoritariamente mantida pelo Google Pode ser tipada Curva de aprendizagem Tem um StyleGuide bem definido Compila para ARM Code E o mais importante quesito que torna o Dart essencial para o Flutter é que ele pode ser compilado tanto em Ahead-of-time e como Just-in-time, mas o que é isso?
  • #12 [Cícero] O código da aplicação é compilado direto para código ARM nativo, o que possibilita que a aplicação seja inicializadas com performance de uma aplicação nativa.
  • #13 [Cícero] Com o objetivo de ser a melhor maneira de desenvolver para mobile, um dos principais feedback que o time do Flutter teve foi que um dos pontos que poderiam melhorar era a velocidade do próprio ciclo de desenvolvimento. A maneira mais comum que desenvolvemos é: Escrevemos código, mandamos rodar e esperamos até que o código seja compilado, o pacote seja gerando, instalado no device e no pior dos casos temos que percorrer várias telas até chegar onde acabamos de fazer a alteração, para ver se deu certo. Um dos objetivos do Flutter é cortar esse tempo de espera, é aí que a compilação Just-in-time do Dart cai como uma luva no Flutter, com ela podemos compilar diretamente no device com a aplicação em execução e ver em praticamente tempo real se a alteração deu certo ou não.
  • #14 [Cícero] // Apresentar na prática, mostrando exemplos de uso e falando sobre os benefícios: Como as Widgets são renderizadas na camada do Flutter, ela apresentam o mesmo layout independente da versão do Android ou iOS, ou seja, você terá um layout moderno em devices antigos sem ter que fazer manobras e nem perder performance. Widgets não são compostas com herança, mas sim com composição.
  • #15 [Cinthia] As Widgets são divididas em 2 grandes grupos, o primeiro são as Stateless, que são widgets imutáveis, desenhadas apenas uma vez, como exemplo delas temos os labels de texto, imagens, e no nosso código de exemplo, a AboutPage. As outras são as Stateful, que são mutáveis, onde o método setState redesenha a widget. Os exemplos são views Scrollable, Animadas e a DetailPage do nosso código de exemplo.
  • #16 [Cinthia] Como eu começo construir um layout? A Scaffold Widget permite que itens básicos sejam adicionados na tela, como AppBar, FloatingActionButton, BottomNavigationBar, Drawer, além do conteúdo da tela. Alguns itens de tela, são facilitados, como a ListView, onde cada item pode ser um ListTile, e só é preciso setar o título, o subtítulo e a imagem dos itens, o layout é montado nesse formato.
  • #17 [Cinthia] Agora vamos ver como ajustar um layout. Este é nosso app, ele mostra uma lista de frutas, e quando clicamos em um item, vemos os detalhes de uma fruta. - temos um layout com a imagem da fruta, nome, preço e quantidade, porém, está ruim assim... então vamos centralizar esses itens (Center), verticalmente também (MainAxisAlignment.center). Salvamos e pronto. Este é o hot-reload, que assim que salvamos, atualiza o app no emulador ou no device. - podemos aumentar o texto da imagem da fruta (tst) - podemos aumentar também a fonte do nome da fruta (tst) - a fonte do preço, vamos também deixar negrito (tst). - podemos também colocar um padding para não ficar tão próximo (Padding) - e não é só layout que podemos mudar e ver o resultado imediatamente, vamos alterar nosso FloatingButton, que ao invés de adicionar um item, vamos remover um item (Icon.remove / count--)
  • #18 [Cinthia] Para internacionalizar Strings em dart/flutter, devemos importar as dependências de internacionalização no yaml, implementar os delegates e locales na classe do application
  • #19 [Cinthia] Implementar uma classe para a Localization e descrição de cada uma das Strings internacionalizadas
  • #20 [Cinthia] E por último, executar os 2 comandos: extract_to_arb, que irá gerar o arquivo arb com as Strings extraídas da classe, onde será possível traduzí-las, e depois o generate_from_arb que irá processar as strings traduzidas.
  • #21 [Cinthia] Porém, temos uma maneira mais simples e fácil, que é utilizando o plugin Flutter i18n, onde é necessário importar as dependências de internacionalização no yaml, implementar os delegates e locales na classe do app, e extrair e traduzir as Strings utilizando o plugin
  • #22 [Cícero] Vamos internacionalizar o título da tela de Comprar, então, basta selecionarmos a opção de extrair a string, selecionar a linguagem, e definir um id para essa string. Depois basta fazer este mesmo processo para as demais linguas, ou editar diretamente os arquivos arb
  • #23 [Cinthia] É possível integrar o código do Flutter ao nativo, que para Android pode ser em Java ou Kotlin, e para iOS pode ser em objective-C ou Swift. Para fazer a integração deve ser utilizado um canal, que pode ser utilizado em ambos os sentidos: para o flutter acessar o código nativo ou para o código nativo acessar o flutter.
  • #24 [Cinthia] Aqui vemos um exemplo do código Flutter acessando código nativo
  • #25 primeiramente criamos o channel, que neste caso se chama tdc_demo_channel, e então fazemos um invokeMethod, utilizando esse channel e passando por parâmetro do método invokeMethod, o nome do método nativo e os parâmetros que desejamos enviar ao nativo.
  • #26 Do lado do nativo, tanto para Android, quanto para iOS, também precisamos criar o channel, com o mesmo nome, e implementar o método setMethodCallHandler, onde iremos validar o conteúdo do método, e então implementar o seu conteúdo. No nosso caso, retornamos uma string, com o valor “Método Android ou iOS” e apendamos a essa string, os parâmetros recebidos do flutter. Por fim, enviamos através do result o resultado do método nativo executado.
  • #27 [Cícero] Aqui vemos um exemplo do código nativo acessando código flutter.
  • #28 Da mesma maneira que o sentido inverso, devemos criar o canal, e apenas inverter o que vimos anteriormente: o código nativo chama o método Flutter através do invokeMethod, passando o nome do método Flutter a ser chamado e os parâmetros a serem enviados para esse método. E então implementamos a callback para receber o resultado do método de flutter que foi chamado.
  • #29 Do lado do flutter, implementamos o setMethodCallHandler para receber o chamado do código nativo, e validar o nome do método, e então implementamos o conteúdo do método, retornando o resultado. Neste caso o retorno seria a string “Método flutter, parâmetro” e os parâmetros recebidos do código nativo.
  • #30 [Cinthia] Para gerar a versão final do app Android, basta executar o comando flutter build apk release, passar o zipalign, e assinar o apk. A partir daí, é só subir na loja o apk.
  • #31 [Cícero] Para gerar a versão de iOS, utilizamos o comando flutter build ios release, e abrimos o arquivo do workspace, e então, através do xcode, podemos submeter a versão para a app store
  • #32 [Cícero] Agora vamos falar sobre o app que nos levou a aprender Flutter! Viva bem é o canal de saúde e bem-estar do UOL. E o objetivo era fazer um aplicativo contendo práticas de meditação e mindfulness, notícias e blogs da área, além de lembretes através de notificações para lembrar o usuário de praticar a meditação
  • #33 [Cícero] No VivaBem, nosso foco foi utilizar diversos componentes de UI e trabalhar com animações para gerar um aplicativo atraente. E com reprodução de áudio, utilização do google analytics e push notifications para atender os requisitos do app.
  • #34 [Cinthia] Assim que recebemos a proposta do case e começamos o estudo de Flutter através do desenvolvimento de POCs, de diversos componentes de UI, requests, parser de jsons. Durante os estudos, tivemos uma reunião com o cliente sobre o app e na semana seguinte, iniciamos o projeto. Em 1 mês finalizamos a versão Beta do app e depois de mais 1 mês, quando ficamos aguardando os áudios das meditações e fazendo ajustes no app, publicamos o app nas lojas. E no começo de maio, veio a confirmação que o VivaBem havia sido aprovado para ser um case na SandBox area do Google I/O
  • #35 [Cinthia] Aqui está um vídeo com uma demo do nosso app. Este vídeo foi utilizado na Sandbox do Flutter no Google I/O, e o app está no site do Flutter, na área de Showcase. Se quiserem baixar nosso app, está nas lojas, do Android e do iOS, e esse QRCode tem os links diretos.
  • #36 [Cícero]
  • #37 [Cícero]