Flutter Demo by KBTG: เขียน Apple Watch เชื่อมกับ Flutter App ด้วย Flutter Method Channel
ก่อนที่เราจะเริ่มโปรเจคใดๆ โดยปกติแล้วทาง PO จะมีพวก Checklist ต่างๆ ช่วยคัดเลือกเทคโนโลยีที่จะใช้ในโปรเจคนั้นๆ แม้แต่ Flutter เอง ทาง PO ก็ต้องเช็คว่าสามารถตอบโจทย์ที่ต้องการทั้งหมดนี้ได้หรือไม่
- บางโจทย์อาจจะบอกว่าต้องการใช้แอปที่ Performance สูงๆ เช่น พวกแอปตัดต่อวิดีโอ
- บางโจทย์อาจจะบอกว่ามี SDK ที่ต้องบังคับใช้ และเป็นของ Native ไม่มีของ Flutter
- บางโจทย์อาจจะบอกว่าต้องต่อ Printer ได้ และบางโจทย์บอกว่าในอนาคตเราจะขยายไปเชื่อมต่อกับ Apple Watch หรือ Native API บางตัว
PO บางคนอาจจะกังวลเรื่องการใช้ Flutter เพราะแม้จะช่วยลดค่าพัฒนาหรือพัฒนาได้เร็วขึ้นจริง สุดท้ายพอโปรเจคใหญ่ขึ้นและมีโจทย์แปลกๆ เพิ่มมา กลัวว่าสุดท้ายจะตอบโจทย์ไม่ได้ หากเป็นเช่นนั้นก็ต้องมาเสียทั้งเวลาทั้งเงินเพื่อเขียนให้เป็น Native ใหม่ทั้งหมด
ตรงนี้ Flutter Method Channel ช่วยท่านได้
Flutter Method Channel
เป็นช่องทางของ Flutter ที่เปิดไว้เพื่อทำการเชื่อมต่อให้ไปที่ Native API และสามารถส่งข้อมูลไปกลับได้ แปลว่าถ้าฟังก์ชันไหนไม่มีใน Flutter เราก็เขียนเองซะเลยด้วย Native ที่ทั้ง iOS/Android
จากที่ได้ลองมาแล้ว หลาย Use Case ใช้ได้สบายครับ ยกตัวอย่างเช่น การต่อกับ Printer ผ่าน Native, ใช้ Native SDK ของ 3rd Party และเชื่อมต่อ API ที่มีเฉพาะใน Native เท่านั้น ผมเคยลองมาหมดแล้วครับ ไม่ติดปัญหาใดๆ
สำหรับบทความนี้ ผมจะมาแสดงวิธีเชื่อมต่อกับ Apple Watch ผ่าน Flutter Method Channel ครับ จริงๆ แล้วทางทีม Flutter ได้เคยทำ Tutorial ไว้ที่นี่
แต่อยากจะบอกว่า… บทความข้างต้นไม่สามารถนำไปใช้ได้หรอกครับ ดังนั้นมาทำตามผมดีกว่า อันนี้พิสูจน์แล้วว่าได้ผลครับ
เพิ่ม Add Watch Extension เข้าไปใน Project
ไปที่ Xcode จากนั้นเลือก File > New > Target
เลือก Platform watchOS > Watch App for iOS App
เราไม่เลือก Watch App นะครับ อันนั้นคือ Watch App ที่อยู่ด้วยตัวเอง ไม่ได้เชื่อมกับ iPhone
ใส่ชื่อ Product Name ที่ต้องการ ผมเลือกใช้ SwiftUI เพราะดูเท่กว่าเขียน Storyboard แบบเก่าๆ 😃 ส่วน Life Cycle เลือกเป็น SwiftUI App พร้อมเอา Include Notification Scene ออก เราไม่ต้องใช้ครับ ถ้าจะใช้เพิ่มทีหลังได้ Notification Scene ไว้สำหรับกรณีที่เราอยากจะปรับแต่ง Notification ที่ได้มาจาก WatchApp ถ้าเราไม่ปรับ iOS จะใช้ของ Default มาแทนครับ
หลังจากสร้างเสร็จหมดแล้ว โปรเจคจะหน้าตาเป็นแบบนี้ครับ ไม่ต้องสนใจ ComplicationController.swift
อันนี้ถูกสร้างขึ้นมาอัตโนมัติจากตัว ClockKit
รายละเอียดเพิ่มเติมเกี่ยวกับ ClockKit ไปอ่านเพิ่มได้ที่นี่ครับ
พูดง่ายๆ คือ UI ที่ไปแสดงในหน้า Dashboard ของ Apple Watch ครับ บางงานที่เราต้องการให้ทำ Background Task หรืองานที่แบบเป็น Corn Job จะใช้ตัว ClockKit อันนี้ ซึ่งเราจะไม่กล่าวถึงใน Tutorial นี้ครับ
เพิ่ม Flutter Method Channel ใน iOS
เราจะมาใส่ Flutter Method Channel ใน Xcode กัน โดยไปเติมฟังก์ชันชื่อ initFlutterChannel
ที่ AppDelegate.swift เพื่อรับข้อมูลที่ส่งมาจาก Flutter
มี 2 ส่วนที่ต้องระวังเป็นพิเศษ คือ
- ชื่อ Channel
com.amorn.watch
ชื่อนี้จะต้องตรงกับชื่อที่อยู่ใน Flutter นะครับ ไม่งั้นจะส่งข้อมูลหากันไม่เจอ ชื่อจะเป็นอะไรก็ได้ แต่อยากให้เป็นชื่อเฉพาะของโปรเจคนั้นๆ ผมมักจะแนะนำให้ใช้ bundleID ครับ - ชื่อ Method
flutterToWatch
ก็ต้องเป็นชื่อเดียวกันครับ ปกติเราจะแยกไว้หลายๆ Method เผื่อมีหลายฟังก์ชันที่จะใช้ของ Native ซึ่งชื่อก็ต้องตรงกับใน Flutter เช่นเดียวกัน ตอนนี้อาจจะงงนิดๆ แต่คำอธิบายด้านล่างจะช่วยให้เห็นภาพมากขึ้นครับ
เพิ่ม Flutter Method Channel ใน Flutter
ที่ initState ให้ใส่ฟังก์ชันลงไปตามด้านล่าง จะเห็นว่าผมใส่ MethodChannel
ชื่อ com.amorn.watch ซึ่งเป็นชื่อเดียวกันกับใน iOS ให้ Flutter รับฟังแต่ Method ที่ชื่อ sendCounterToFlutter ซึ่งเราจะใช้จากที่ Apple Watch ส่งมาให้ iOS และจะส่งผ่านมาให้ Flutter ครับ
ใส่ SwiftUI สำหรับ Apple Watch Layout
ผมจะใช้ตัว “@ObservedObject” ที่คล้ายๆ กับ Stream ใน Dart นะครับ คือจะ Subscribe ViewModel ไว้ ถ้าเกิดมีข้อมูลอะไรเปลี่ยนขึ้นมา ก็จะไปอัพเดต UI ให้อัตโนมัติ
และใน Apple Watch ผมจะมีปุ่มที่เพิ่มข้อมูลทีละสอง เพื่อจะได้เห็นภาพว่าข้อมูลถูกอัพเดตเพราะมาจาก Apple Watch จริงๆ
ใส่ Watch Session
ใน ViewModel ผมจะนำ WCSession ใส่เข้าไปเพื่อ Subscribe ข้อมูลและ Assign ลงไปได้ถูกต้อง โดยข้อมูลที่ได้จะผ่าน Flutter Channel จาก AppDelegate.swift มา จากนั้นจะส่งผ่าน WCSession มาให้ Apple Watch
ส่งข้อมูลให้ Flutter ผ่าน Channel
ส่งข้อมูลกลับ Flutter ผ่าน WatchSession ครับ
ส่งข้อมูลจาก Flutter ผ่าน channel
ง่ายมากๆ ด้วยบรรทัดเดียว
หลังจาก Implement ทั้งหมดนี้เสร็จสิ้น เราก็จะสามารถส่งข้อมูลไปๆ มาๆ ได้ ผมได้อัพโหลด Demo ทั้งหมดนี้ไว้ที่ Github สามารถไปลอง Compile เล่นดูได้ครับ แต่ต้องมี Flutter ติดเครื่องด้วยนะครับ
อันนี้เป็นวิดีโอที่แสดงให้ดูว่า Demo ทำงานยังไง
ที่ผมอยากจะแสดงให้เห็นไม่ใช่แค่ใน Use Case ของ Apple Watch เท่านั้นนะครับ แต่ต้องการให้เห็นว่า Flutter สามารถเชื่อมต่อกับ Native API ได้อย่างไม่มีปัญหาผ่าน Flutter Method Channel ไม่ว่าคุณจะต่อ Printer SDK, Native 3rd Party SDK หรือ Native API ใดๆ ก็สามารถเชื่อมต่อได้ทั้งหมด ฉะนั้นประเด็นที่ PO จะนำไปใส่ใน Checklist ว่า “Flutter จะเชื่อมกับ SDK ของเราได้หรือเปล่า” สามารถติ๊กยืนยันได้เลยครับ
หวังว่าบทความนี้จะช่วยให้ PO กังวลใจกับ Flutter น้อยลง และนำไปเป็นหนึ่งในตัวเลือกการตัดสินใจนะครับ 💃
สำหรับชาวเทคคนไหนที่สนใจเรื่องราวดีๆแบบนี้ หรืออยากเรียนรู้เกี่ยวกับ Product ใหม่ๆ ของ KBTG สามารถติดตามรายละเอียดกันได้ที่เว็บไซต์ www.kbtg.tech