Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Flutter Introduction

Flutter Introduction

First talk of the first Flutter-Belgium Meetup.

Avatar for Kris Pypen

Kris Pypen

June 06, 2018

Other Decks in Programming

Transcript

  1. Hosted by: Kunstmaan • About 130 people • Teams with

    different technical expertises • Working creatively together with service design, UX, digital and other teams • Accenture Interactive
  2. What is Flutter • Free and open source • Backed

    by Google • Cross platform (iOS, Android, Fuchsia, MacOS, Linux) • Dart lang • Reactive framework • Single code base / git repo • No Javascript bridge • UI Framework
  3. Flutter UI Framework • Building UI in code • Comes

    with a rich set of widgets including Material Design and cupertino widgets • Doesn’t work with OEM widgets or a DOM Webview • Skia 2d engine (google chrome/firefox) • Platform conventions (scrolling, navigation, fonts, icons,...) ◦ So you can even be featured on the app store and google play store • Everything is customizable
  4. Dart language • Reactive • Cross platform • Approachable (C++,

    C#, Swift or Java) • JIT and AOT compiler
  5. Installation Supported dev platforms: Windows, MacOS, Linux (, Chrome OS)

    iOS: XCode, Apple Account Android: enable developer options -> usb debugging
  6. Flutter CLI tool $ flutter doctor Doctor summary (to see

    all details, run flutter doctor -v): [✓] Flutter (Channel master, v0.4.4, on Mac OS X 10.13.4 17E202, locale en-BE) [✓] Android toolchain - develop for Android devices (Android SDK 27.0.3) [!] iOS toolchain - develop for iOS devices (Xcode 9.4) ! CocoaPods out of date (1.5.0 is recommended). CocoaPods is used to retrieve the iOS platform side's plugin code that responds to your plugin usage on the Dart side. Without resolving iOS dependencies with CocoaPods, plugins will not work on iOS. For more info, see https://flutter.io/platform-plugins To upgrade: brew upgrade cocoapods pod setup [✓] Android Studio (version 3.1) [✓] IntelliJ IDEA Ultimate Edition (version 2017.3.5)
  7. Access to native features and SDKs Future<Null> getBatteryLevel() async {

    var batteryLevel = 'unknown'; try { int result = await methodChannel.invokeMethod('getBatteryLevel'); batteryLevel = 'Battery level: $result%'; } on PlatformException { batteryLevel = 'Failed to get battery level.'; } setState(() { _batteryLevel = batteryLevel; }); }
  8. Plugins (pubs) • https://pub.dartlang.org • As an abstraction layer for

    native libraries (ios/android) • Libraries • Widgets
  9. class MyApp extends StatelessWidget { @override Widget build(BuildContext context) {

    Widget titleSection = new Container( padding: const EdgeInsets.all(32.0), child: new Row( children: [ new Expanded( child: new Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ new Container( padding: const EdgeInsets.only(bottom: 8.0), child: new Text( 'Oeschinen Lake Campground', style: new TextStyle( fontWeight: FontWeight.bold, ), ), ), new Text( 'Kandersteg, Switzerland', style: new TextStyle( color: Colors.grey[500], ), ), ], ), ), new Icon( Icons.star, color: Colors.red[500], ), new Text('41'), ], ), ); //... } Coding the Layout
  10. class MyApp extends StatelessWidget { @override Widget build(BuildContext context) {

    //... Column buildButtonColumn(IconData icon, String label) { Color color = Theme.of(context).primaryColor; return new Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ new Icon(icon, color: color), new Container( margin: const EdgeInsets.only(top: 8.0), child: new Text( label, style: new TextStyle( fontSize: 12.0, fontWeight: FontWeight.w400, color: color, ), ), ), ], ); } //... } Coding the Layout
  11. class MyApp extends StatelessWidget { @override Widget build(BuildContext context) {

    //... Widget buttonSection = new Container( child: new Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ buildButtonColumn(Icons.call, 'CALL'), buildButtonColumn(Icons.near_me, 'ROUTE'), buildButtonColumn(Icons.share, 'SHARE'), ], ), ); //... } Coding the Layout
  12. pubspec.yaml name: flutter_gallery dependencies: flutter: sdk: flutter collection: 1.14.6 device_info:

    0.2.0 intl: 0.15.6 dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter flutter: uses-material-design: true assets: - images/image1.png - images/image2.png fonts: - family: Graphic fonts: - asset: packages/flutter_gallery_assets/pesto/fonts/Raleway-Regular.ttf - asset: packages/flutter_gallery_assets/pesto/fonts/Raleway-Medium.ttf weight: 500 - asset: packages/flutter_gallery_assets/pesto/fonts/Raleway-SemiBold.ttf weight: 600 - family: GalleryIcons fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf
  13. Plugins you should have in your pubspec.yml • flutter_launcher_icons •

    http • fluro • get_version • url_launcher • shared_preferences • sentry • FlutterFire plugins
  14. http dart-lang/http import 'package:http/http.dart' as http; var url = "http://example.com/whatsit/create";

    http.post(url, body: {"name": "doodle", "color": "blue"}) .then((response) { print("Response status: ${response.statusCode}"); print("Response body: ${response.body}"); }); http.read("http://example.com/foobar.txt").then(print); Plugins you should have in your pubspec.yml
  15. fluro theyakka/fluro var usersHandler = new Handler(handlerFunc: (BuildContext context, Map<String,

    dynamic> params) { return new UsersScreen(params["id"][0]); }); void defineRoutes(Router router) { router.define("/users/:id", handler: usersHandler); } router.navigateTo(context, "/users/1234", transition: TransitionType.fadeIn); Plugins you should have in your pubspec.yml
  16. get_version AppleEducate/get_version String platformVersion; // Platform messages may fail, so

    we use a try/catch PlatformException. try { platformVersion = await GetVersion.platformVersion; } on PlatformException { platformVersion = 'Failed to get platform version.'; } String projectVersion; // Platform messages may fail, so we use a try/catch PlatformException. try { projectVersion = await GetVersion.projectVersion; } on PlatformException { projectVersion = 'Failed to get project version.'; } String projectCode; // Platform messages may fail, so we use a try/catch PlatformException. try { projectCode = await GetVersion.projectCode; } on PlatformException { projectCode = 'Failed to get build number.'; } Plugins you should have in your pubspec.yml
  17. url_launcher flutter/plugins import 'package:url_launcher/url_launcher.dart'; _launchURL() async { const url =

    'https://flutter.io'; if (await canLaunch(url)) { await launch(url); } else { throw 'Could not launch $url'; } } Plugins you should have in your pubspec.yml
  18. shared_preferences flutter/plugins import 'package:shared_preferences/shared_preferences.dart'; _incrementCounter() async { SharedPreferences prefs =

    await SharedPreferences.getInstance(); int counter = (prefs.getInt('counter') ?? 0) + 1; print('Pressed $counter times.'); await prefs.setInt('counter', counter); } Plugins you should have in your pubspec.yml
  19. sentry flutter/sentry import 'package:sentry/sentry.dart'; final SentryClient sentry = new SentryClient(dsn:

    YOUR_DSN); main() async { try { doSomethingThatMightThrowAnError(); } catch(error, stackTrace) { await sentry.captureException( exception: error, stackTrace: stackTrace, ); } } Plugins you should have in your pubspec.yml
  20. Automated Tests • Unit testing • Widget testing • Integration

    testing import 'package:test/test.dart'; void main() { test('my first unit test', () { var answer = 42; expect(answer, 42); }); }
  21. Automated Tests • Unit testing • Widget testing • Integration

    testing import 'package:test/test.dart'; void main() { test('my first unit test', () { var answer = 42; expect(answer, 42); }); } import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { testWidgets('my first widget test', (WidgetTester tester) async { // You can use keys to locate the widget you need to test var sliderKey = new UniqueKey(); var value = 0.0; // Tells the tester to build a UI based on the widget tree passed to it await tester.pumpWidget( new StatefulBuilder( builder: (BuildContext context, StateSetter setState) { return new MaterialApp( home: new Material( child: new Center( child: new Slider( key: sliderKey, value: value, onChanged: (double newValue) { setState(() { value = newValue; }); }, ), ), ), ); }, ), ); expect(value, equals(0.0)); // Taps on the widget found by key await tester.tap(find.byKey(sliderKey)); // Verifies that the widget updated the value correctly expect(value, equals(0.5)); }); }
  22. Automated Tests • Unit testing • Widget testing • Integration

    testing test('tap on the button, verify result', () async { final SerializableFinder batteryLevelLabel = find.byValueKey('Battery level'); expect(batteryLevelLabel, isNotNull); final SerializableFinder button = find.text('Get Battery Level'); await driver.waitFor(button); await driver.tap(button); String batteryLevel; while (batteryLevel == null || batteryLevel.isEmpty) { batteryLevel = await driver.getText(batteryLevelLabel); } expect(batteryLevel, isNotEmpty); }); $ flutter drive --target=my_app/test_driver/test_battery.dart Run your test:
  23. Some less good news • App size a bit more:

    7Mb • No perfect solution for inline maps yet • Lottie does not work yet… 2dimensions.com • svg support still work in progress • Flutter developers are rare to find
  24. Things to follow • Flutter challenges • @r_FlutterDev • Solido/awesome-flutter,

    iampawan/FlutterExampleApps • https://flutterweekly.net/