Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

給 iOS 工程師的 Flutter 開發

859 views

Published on

給 iOS 工程師的 Flutter 開發

Published in: Technology

給 iOS 工程師的 Flutter 開發

  1. 1. 給 iOS ⼯工程師的 Flutter 開發 zonble zonble@gmail.com
  2. 2. Flutter • https://flutter.io • ⼀一個寄宿在⽬目前 iOS、Android 平台上的新平台 • 是設計給 Google 未來來作業系統 Fuchsia 的應⽤用程式開發層 • Dart VM + Skia Render 引擎 • 在 iOS/Android App 中包入 Flutter Framework 後,執⾏行行 Dart code,同⼀一個 App 在不同平台可以 render 出相同的效果 • 可以與 ObjC/Swift/Java/Kotlin 橋接 • 重新發明 Flash?
  3. 3. ⽤用 Flutter 可能有什什麼好處? • 以⽬目前的執⾏行行效能與完成度來來看,似乎不能不管 • 如果同時需要開發 iOS/Android,可以⼤大量量共⽤用程式碼 • iOS/Android 上可以 Render 出⼀一樣的畫⾯面,設計師可以只 需要做⼀一套設計 • 現在就先投資未來來的 Google 作業系統,以及 Flutter 還可 能移植到 Windows/Mac/瀏覽器執⾏行行的可能
  4. 4. ⽤用 Flutter 會犧牲什什麼 • 還不⽀支援⼀一些 iPhone 的特殊功能,如 3D Touch • 不過你的 App 本來來也就沒在⽀支援 3D Touch • 犧牲跟 macOS/tvOS/watchOS 共⽤用程式碼的機會 • 不過你本來來也沒在⽀支援 • 好的 Dart 語⾔言的⼯工程師不好找 • 不過反正你本來來也找不到好的 ObjC/Swift/Java/Kotlin ⼯工 程師
  5. 5. ⽤用 Flutter 會犧牲什什麼 • 在 iOS 上由於⽤用的不是 UIKit 元件,看起來來會比較像 Google Photo 的感覺,⽽而不像「很 Apple」的 App • 無法使⽤用 XCTest 測試 • 上線後,從 iOS 的 crash log 中看不出 Dart 程式的問題 • 專案會與 Firebase 變得更更緊密,因為現在供 Flutter 使⽤用的 BaaS、Analytics…都只有 Firebase 這個選擇
  6. 6. 使⽤用 Flutter 的挑戰 • Flutter 無法使⽤用⼀一些平台專屬功能,⽽而可能需要寫與該平 台橋接的程式,所以現階段還是得懂⼀一定的 iOS/Android 開發 • 哪些部分⽤用 Flutter 寫,哪些寫在 iOS/Android 橋接端,非 常挑戰 App 架構的能⼒力力
  7. 7. 安裝 • 先裝好 Xcode 以及 Android Studio • 去 https://flutter.io/setup-macos/ 下載 zip 檔解壓 • 執⾏行行 flutter doctor 看看少了了什什麼 • ⽤用 homebrew 裝 ideviceinstaller 以及 ios-deploy • IDE 可⽤用 Android Studio 或 VSCode
  8. 8. iOS ⼯工程師如何進入? • Dart 程式語⾔言 • Flutter 的設計典範 • Dart 與 Flutter 的套件/⽣生態系
  9. 9. Dart 程式語⾔言
  10. 10. Dart 程式語⾔言 • 這年年頭的 OO 語⾔言其實都差不多,但還是有少部分差異異 • Dart 除了了可以在 Flutter 執⾏行行以外,也可以編譯成 JS 在網 ⾴頁使⽤用,也可以單獨在 Dart VM 執⾏行行 • 所以 Dart 可以寫單獨的 CLI 程式,在 server side 執⾏行行 • Dart 在網⾴頁上可以搭配 Angular 使⽤用…不過這年年頭好像寫 Angular 的⼈人比較少
  11. 11. 單獨安裝 Dart • ⽤用 homebrew 安裝 dart • brew install dart • 同時建議安裝 stagehand,Dart 的新專案產⽣生器 • pub global activate stagehand
  12. 12. 開始新專案 Swift Package Manager $swift package init init 後可接 --type empty|library|executable| system-module Dart $stagehand [project type] Project type 可接 • console-full • package-simple • server-shelf • web-angular…
  13. 13. Dependency iOS/Swift 開發 • 可使⽤用 SPM package 或是 Cocoapods • Cocoapods 可在 https:// cocoapods.org/ 查詢 • SPM Package 的 Dependency 設定寫在 Package.swift 中 • 使⽤用 swift package update 更更新 Dart • 使⽤用 pub • 可在 https:// pub.dartlang.org/ 查詢 • Dependency 設定寫在 pubspec.yaml 中 • ⽤用 pub get 指令更更新
  14. 14. 變數、常數 Swift var -> 可以變動 let -> 不可變動 Dart var -> 可以變動 final -> 不可變動 const -> 全域的常數
  15. 15. Class Swift class Sample { var x:Int init (x: Int) { self.x = x
 } func someMethod() { self.hi()
 }
 } var sample = Sample(x: 1) Dart class Sample { int x = 0; Sample(this.x) {
 } someMethod() { this.hi();
 }
 } Sample sample = new Sample(1);
  16. 16. 字串串格式 Swift Package Manager var x = “1 + 1 = ( 1 + 1)” print(x) Dart String x = “1 + 1 = ${ 1 + 1}”; print(x);
  17. 17. 匿名函式 Swift { x in … } 或 { $0.doSomething() } Dart (int x) { …
 } 或寫成單⾏行行 (x) => doSomething(x);
  18. 18. 匿名函式 Swift class MyClass { var f: ((Int)->Int)? } var x = MyClass() x.f = { $0 + 1 } print("(x.f!(2))" // Swift 也可以⽤用 typealias Dart // ⼀一定要⽤用 typedef typedef int Call(int); class MyClass { Call f; } main() { var x = new MyClass(); x.f = (i) => i + 1; print(x.f(2)); }
  19. 19. Nullability Swift 必須要將任何變數的形態設定 為 optional,才可以將變數指 向 nil。 Dart 可以將任意變數指向 null,任 何變數⼀一開始不給予值也是 null,但是可以使⽤用與 Swift 相同的 ?? 語法判斷是否是 null。
  20. 20. Callback Swift • URLSessionTask 使⽤用 Closure 處理理 callback • 加裝 promise kit 等套件之 後,可以使⽤用 promise 語 法 Dart • import ‘dart/async’; • 使⽤用 Future 物件 • 可使⽤用 Promise 語法或是 async/await
  21. 21. Delegate? • 在 ObjC/Swift 中⼤大量量使⽤用 Delegate Pattern • 在 Dart 中改⽤用 Stream Controller • Stream Controller 可以⽤用來來發送事件,Listener 則監聽從 Stream Controller 發送的事件
  22. 22. Stream Controller in Dart import 'dart:async'; class MyClass { StreamController controller = new StreamController.broadcast(); Stream get didSomething = controller.stream; someMethod() { this.controller.add(‘Test’);
 }
 } MyClass obj = new MyClass(); obj.didSomething.listen( (String s) { print(s); });
  23. 23. Dart 也有叫做 Delegate 的東⻄西 • 不是每個叫做 Delegate 的東⻄西都是同樣意思 • ObjC/Swift 的 Delegate 通常⽤用在 Model 或 View 發⽣生改變 的時候,⽤用來來通知 Controller,也就是 Controller 是 Model 或 View 的 Delegate • Dart 上也可以實作 ObjC/Swift 的 delegate,⽤用 abstract 代 替 protocol…但好像沒有⼈人這麼做
  24. 24. Dart 也有叫做 Delegate 的東⻄西 • Dart 的 Delegate 則指的是某個物件要使⽤用的規則,比較是 ⼀一種純 Model 物件 • Dart 的 Delegate 很像 CocoaTouch 中 UICollectionView 與 UICollectionViewLayout 的關係 • 像是 Flutter 的 GirdView 的 delegate,就是 Grid 有幾⾏行行、 間距多少…等邏輯
  25. 25. Notification Center? • 有類似的東⻄西 https://github.com/stevenroose/dart-events • 另外也有⼈人在 Flutter 上實作 redux https:// pub.dartlang.org/packages/flutter_redux
  26. 26. Flutter
  27. 27. 這個框架的設計概念念跟你 以前寫過的東⻄西差很多喔
  28. 28. Widget Model/Builder • iOS 上畫⾯面主要由 View Controller/View 組成,View Controller 管理理⼀一個 view property,然後在上⾯面新增/移除 subview • Flutter 的畫⾯面是由 Widget 組成,每個 Widget ⼜又都是⼀一個 builder,build 出這個 Widget 下有哪些內部的 Widget • …其實 Flutter 裡頭什什麼都是 Widget • Build 出的 Widget 再交給 Flutter 的 Renderer 給 render 成畫⾯面 • 某⽅方⾯面來來看,Flutter 的架構中比較沒有明確的 MVC 之分,⼀一個 Widget 像是扮演了了 Controller 與 View 的⾓角⾊色,但本質上 Widget 卻⼜又是 Model…
  29. 29. Widget Model/Builder • Widget 在 Build 出底下的 Widget 之後,就無法再改動, 要改變畫⾯面,就要再 Build ⼀一次,Build 出另外⼀一份 Widget • ⼀一個 widget 有點像是 Web 開發的 Virtual DOM,但比較不 同的時,Flutter 的 widget model 沒有做 HTML Tag/CSS 分離,⽽而是 widget 本⾝身就帶有樣式的性質 • Widget 做的事情也超過 DOM Element,Layout/動畫/
  30. 30. 對比 iOS 開發看 Widget • iOS 上,每個 view 的重繪,是在對 UIView 呼叫 setNeedDisplay 之後,才會呼叫 UIView 的 drawRect: 或 是 CALayer 的 drawInContext: 重繪 • 更更新⼀一個 widget 似乎有點類似:對 Widget 的 State 呼叫 setState() 後,才會重新 build 出⼀一份 widget ,由這份 widget render 出新的畫⾯面 • 也有點像是在 Vue.js 裡頭對某個 component 呼叫 $nextTick()
  31. 31. Widget 有兩兩種 • Stateless Widget:Widget build 出來來之後就不會改變內部 widget,往往⽤用在最⼤大或最⼩小的元件。最⼤大如整個 App 的 框架(MaterialApp Class)最⼩小的元件如⽂文字框(Text Class) • Stateful Widget:會改變狀狀態的 widget,負責掌管⼀一個 State 屬性,在 State 中再負責 build 出 widget。⼤大多時間 我們會寫這類的 Widget。
  32. 32. App:第⼀一個 Widget void main() => runApp(new MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return new MaterialApp( title: ‘My App', theme: new ThemeData( primarySwatch: Colors.blue, ), home: new HomePage(title: ‘Home Page’), ); } } // 然後我們就可以繼續寫 HomePage class
  33. 33. Widget 有兩兩種 • 在前⾯面的範例例中 • MyApp 是 Stateless Widget • Home Page 是 Stateful Widget
  34. 34. Decorator 風格 • 在其他框架中的元件屬性,在 Flutter 中則往往設計成被另 外⼀一個 Widget 包裝起來來 • ⼀一堆⽂文字置中: Center -> Column -> [Text, Text] • 圖形放在圓框裡:Box Decoration -> Image
  35. 35. ⼀一堆⽂文字置中
  36. 36. 把圖放在圓框裡頭
  37. 37. 處理理觸控事件 • 有些元件本⾝身就有 onTap,可以傳入匿名函式或某個物件 的 method • 所有的物件都可以被包在 GestureDetector 當中
  38. 38. Navigation
  39. 39. Widget 不⼀一定是 UI Element
  40. 40. 什什麼時候去呼叫 Web API? • 可以使⽤用 Future Block • 或是在 initState 的時候,呼叫 Web API call,在 Promise 結束的時候呼叫 setState() 更更新畫⾯面 • 如果要做⾴頁⾯面 retry 的話,後⾯面這種作法可能比較好
  41. 41. Widget 深度往往深得亂七八糟…
  42. 42. Scaffold • ⼀一個 App 最常⽤用的框架 • AppBar -> 類似 iOS NavigationBar • Drawer -> 漢堡選單 • Floating Action Button -> Material Design 的特殊 UI • Bottom Navigation Bar -> 類似 iOS 的 TabBar
  43. 43. 建構畫⾯面的流程 • 從 Home Page 建置 Scaffold • 根據各種⾏行行為,更更換 Scaffold 中的 body
  44. 44. ⼀一些眉眉⾓角⾓角 • ListView 與 Grid View 只能單個 Section,如果想要多 Section 的 ListView 或 GridView,要改⽤用 CustomScrollView • CustomScrollView 的 children 得要⽤用 SliverListView 以及 SliverGridView,⽽而不是直接把 ListView 或 GridView 放進 去
  45. 45. Flutter Plug-in
  46. 46. Flutter Plug-in • 有些跟平台有關的事情,Flutter 不直接⽀支援 • 可以⾃自⼰己撰寫與平台橋接的程式(Platform Channel) https://flutter.io/platform-channels/ • 或是安裝已經有⼈人包好的 Flutter Plug-in
  47. 47. Open URL • 在 iOS 上可以呼叫 UIApplication 的 openURL: 以及 canOpenURL: • Flutter 上要安裝 url_launcher https://pub.dartlang.org/ packages/url_launcher • 改寫 pubspec.yaml 然後⽤用 flutter packages get 更更新 dependencies
  48. 48. 學習資源 • Flutter 原廠⽂文件 https://flutter.io/docs/ • Coding with Flutter https://medium.com/coding-with- flutter • Google IO 2018 其實沒講什什麼東⻄西

×