Flutter製チャットアプリを支える技術 / Technologies that support a Flutter chat application

Flutter製チャットアプリを支える技術 / Technologies that support a Flutter chat application

# Flutter Meetup Osaka #2で発表した資料です。
https://flutter-jp.connpass.com/event/159013/

# Flutter製チャットアプリを支える技術 on Qiita
https://qiita.com/kwmt@github/items/2e81b46d62beb091d18b

# Flutter chat application on GitHub
https://github.com/kwmt/flutter-inconne

# Clean Architectureに関して
https://speakerdeck.com/yasi/flutter-development-as-usual

Ce6acc3536b0e0340b5f0569d3394c9c?s=128

Yasutaka Kawamoto

February 28, 2020
Tweet

Transcript

  1. Flutter੡νϟοτΞϓϦ Λࢧ͑Δٕज़ Flutter Meetup Osaka #2 2020/02/28

  2. • Տຊ ହ޹(͔Θ΋ͱ ΍͔ͨ͢) • ॴଐɿגࣜձࣾ tech vein 
 AndroidɺiOSΞϓϦΤϯδχΞ

    • kwmt • @kwmt27 • Flutter Meetup Osaka #1(2018/06)͔Β
 FlutterΛ৮Γͩͨ͠ • ࣗݾ঺հ ʮॳग़ɿٕज़ධ࿦ࣾץʰιϑτ΢ΣΞσβΠϯ2019೥4݄߸ʱʯ
  3. 2018೥ʹνϟοτΞϓϦΛϦϦʔε

  4. QiitaʹνϟοτΞϓϦ։ൃͷ஌ݟΛॻ͍ͨ ※2020/02/27ݱࡏ

  5. • Google is able to guarantee a high quality camera

    performance • Automated CameraX test lab • Populated with devices from various manufactures • Test hundreds of devices • Various test types • Functional, integration, end-to-end use case, performance, etc. ݄͝ͱͷ͍͍Ͷ਺ ※2020/02/27ݱࡏ
  6. • Google is able to guarantee a high quality camera

    performance • Automated CameraX test lab • Populated with devices from various manufactures • Test hundreds of devices • Various test types • Functional, integration, end-to-end use case, performance, etc. ݄͝ͱͷ͍͍Ͷ਺ ※2020/02/27ݱࡏ
  7. • νϟοτΞϓϦͷػೳ • ձһొ࿥ɾϩάΠϯ • νϟοτϧʔϜʢҎԼɺϧʔϜʣ࡞੒Ͱ͖Δ • ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ • ϧʔϜҰཡΛݟΔ͜ͱ͕Ͱ͖Δ

    • طଘͷϧʔϜʹϢʔβʔ͕ࢀՃͰ͖Δ • ࣗ෼ͷϓϩϑΟʔϧΛݟΔ͜ͱ͕Ͱ͖Δ • ΞϓϦ಺՝ۚͰఆظߪಡͰ͖Δ • ͳͲ… • ։ൃऀͷͨΊͷػೳ • Analytics • Crashlytics • AdMob ͜ͷهࣄͰॻ͍ͨͷ͸
  8. • ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ ࠓճ঺հ͢Δػೳ

  9. • จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ • νϟοτϝοηʔδΛૹ৴͢Δ • ϝοηʔδϦετΛදࣔ͢Δ ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ

  10. • จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ • νϟοτϝοηʔδΛૹ৴͢Δ • ϝοηʔδϦετΛදࣔ͢Δ ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ

  11. จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ

  12. จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ

  13. TextEditingControllerΛ࢖͏ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(()

    { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ });
  14. TextEditingControllerΛ࢖͏ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(()

    { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ });
  15. TextEditingControllerΛ࢖͏ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(()

    { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ });
  16. TextEditingControllerΛ࢖͏ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(()

    { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ });
  17. ૹ৴Ϙλϯͷ४උ IconButton( icon: Icon(Icons.send), color: Colors.blueAccent, onPressed: _isEmpty ? null

    : () {…} ); bool _isEmpty = true;
  18. ૹ৴Ϙλϯͷ४උ IconButton( icon: Icon(Icons.send), color: Colors.blueAccent, onPressed: _isEmpty ? null

    : () {…} ); bool _isEmpty = true;
  19. ϦεφʔΛ࣮૷ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(()

    { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ });
  20. ϦεφʔΛ࣮૷ TextFormField( controller: _textEditingController,
 … ), _textEditingController = TextEditingController(); _textEditingController.addListener(()

    { // TextFormFieldʹมߋ͕͋Ε͹ݺ͹ΕΔɻ setState(() { _isEmpty = _textEditingController.text.isEmpty; }); });
  21. • จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ • νϟοτϝοηʔδΛૹ৴͢Δ • ϝοηʔδϦετΛදࣔ͢Δ ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ

  22. νϟοτϝοηʔδΛૹ৴͢Δ ϝοηʔδΛ σʔλϕʔεʹอଘ

  23. Firestoreͷσʔλొ࿥ྫ _firestore .collection("rooms") .document(room.id) .collection("messages") .document() .setData(<String, dynamic>{ 'content': "͸Ζʔ",

    'created_at': createdAt, … }); );
  24. Firestoreͷσʔλొ࿥ྫ _firestore .collection("rooms") .document(room.id) .collection("messages") .document() .setData(<String, dynamic>{ 'content': "͸Ζʔ",

    'created_at': createdAt, … }); );
  25. ϝοηʔδϦετʹϦΞϧλΠϜʹ൓ө

  26. ϝοηʔδϦετʹϦΞϧλΠϜʹ൓ө

  27. ϝοηʔδϦετʹϦΞϧλΠϜʹ൓ө _firestore .collection(“rooms") .document(room.id) .collection("messages") .orderBy("created_at", descending: true) .snapshots() .listen((querySnapshot)

    { // σʔλ͕มߋ͞Εͨͱ͖ɺ͜͜ʹ௨஌͕͘Δɻ // querySnapShot.documentsͷ֤documentͷdataͰɺ // อଘͨ͠σʔλΛऔಘͰ͖Δɻ }
  28. ը૾ΛΞοϓϩʔυ͢Δ

  29. ը૾ΛΞοϓϩʔυ͢Δ

  30. ը૾ΛΞοϓϩʔυ͢Δ <ը૾>

  31. ը૾ΛΞοϓϩʔυ͢Δ <ը૾> ը૾μ΢ϯϩʔυURL

  32. ը૾ΛΞοϓϩʔυ͢Δ <ը૾> ը૾μ΢ϯϩʔυURL ը૾μ΢ϯϩʔυURL

  33. ը૾Ξοϓϩʔυͷίʔυྫ var snapshot = await _storage .ref() .child('${timestamp}_${basename(file.path)}') .putFile( file,

    StorageMetadata( contentType: "image/jpeg", )) .onComplete; if (snapshot.error == null) { var url = await snapshot.ref.getDownloadURL(); // FirestoreʹurlΛૹ৴ }
  34. ը૾Ξοϓϩʔυͷίʔυྫ var snapshot = await _storage .ref() .child('${timestamp}_${basename(file.path)}') .putFile( file,

    StorageMetadata( contentType: "image/jpeg", )) .onComplete; if (snapshot.error == null) { var url = await snapshot.ref.getDownloadURL(); // FirestoreʹurlΛૹ৴ }
  35. • จࣈΛೖྗ࢝͠ΊͨΒɺૹ৴ϘλϯΛ༗ޮʹ͢Δ • νϟοτϝοηʔδΛૹ৴͢Δ • ϝοηʔδϦετΛදࣔ͢Δ ϧʔϜͰνϟοτ(ςΩετɺը૾ͷૹ৴)͕Ͱ͖Δ

  36. ϝοηʔδϦετΛදࣔ͢Δ 1൪Լ͕࠷৽ͷϝοηʔδ

  37. ListView ListView.builder( itemBuilder: (context, position) { return <֤ߦͷWidget>; }, );

  38. ListViewΛٯॱͰදࣔ ListView.builder( reverse: true, itemBuilder: (context, position) { return <֤ߦͷWidget>;

    }, );
  39. Ϧετͷ֤ߦͷϨΠΞ΢τ

  40. Ϧετͷ֤ߦͷϨΠΞ΢τ

  41. Ϧετͷ֤ߦͷϨΠΞ΢τ Row

  42. Ϧετͷ֤ߦͷϨΠΞ΢τ Row

  43. Ϧετͷ֤ߦͷϨΠΞ΢τ Row Column

  44. γϯϓϧͳϦετͷϨΠΞ΢τ https://api.flutter.dev/flutter/material/ListTile-class.html

  45. γϯϓϧͳϦετͷϨΠΞ΢τ ListTile( leading: FlutterLogo(size: 56.0), title: Text('Two-line ListTile'), subtitle: Text('Here

    is a second line'), trailing: Icon(Icons.more_vert), )
  46. γϯϓϧͳϦετͷϨΠΞ΢τ ListTile( leading: FlutterLogo(size: 56.0), title: Text('Two-line ListTile'), subtitle: Text('Here

    is a second line'), trailing: Icon(Icons.more_vert), )
  47. γϯϓϧͳϦετͷϨΠΞ΢τ ListTile( leading: FlutterLogo(size: 56.0), title: Text('Two-line ListTile'), subtitle: Text('Here

    is a second line'), trailing: Icon(Icons.more_vert), )
  48. γϯϓϧͳϦετͷϨΠΞ΢τ ListTile( leading: FlutterLogo(size: 56.0), title: Text('Two-line ListTile'), subtitle: Text('Here

    is a second line'), trailing: Icon(Icons.more_vert), )
  49. γϯϓϧͳϦετͷϨΠΞ΢τ ListTile( leading: FlutterLogo(size: 56.0), title: Text('Two-line ListTile'), subtitle: Text('Here

    is a second line'), trailing: Icon(Icons.more_vert), )
  50. νϟοτΞϓϦͰ͸ϧʔϜҰཡͰ࢖༻

  51. ·ͱΊ

  52. • ϝοηʔδೖྗத͔Ͳ͏͔͸ɺTextEditingControllerͰ൑ அͰ͖Δ • ը૾΋ςΩετͷૹ৴͸ɺFirebaseͷϓϥάΠϯͰ؆୯ ʹอଘͰ͖Δ • FlutterͷϦετදࣔ͸ListViewͰ௒؆୯ ·ͱΊ

  53. Φʔϓϯιʔεʹ͠·ͨ͠ʂ TODO: GitHubͷը૾ΛషΔ https://github.com/kwmt/flutter-inconne ˑελʔΛ๨Εͣʹ͆

  54. Clean Architectureʹؔͯ͠͸ͪ͜Β https://speakerdeck.com/yasi/flutter-development-as-usual

  55. Thank you @kwmt27