1. บทนำ
วิดเจ็ตคืออะไร
สำหรับนักพัฒนาแอป Flutter คำจำกัดความทั่วไปของวิดเจ็ตหมายถึงคอมโพเนนต์ UI ที่สร้างขึ้นโดยใช้เฟรมเวิร์ก Flutter ในบริบทของโค้ดแล็บนี้ วิดเจ็ตหมายถึงแอปเวอร์ชันมินิที่แสดงข้อมูลของแอปโดยไม่ต้องเปิดแอป ใน Android วิดเจ็ตจะอยู่ในหน้าจอหลัก ใน iOS คุณจะเพิ่มวิดเจ็ตลงในหน้าจอหลัก หน้าจอล็อก หรือมุมมองวันนี้ได้

วิดเจ็ตมีความซับซ้อนได้มากเพียงใด
วิดเจ็ตหน้าจอหลักส่วนใหญ่ใช้งานง่าย โดยอาจมีข้อความพื้นฐาน กราฟิกเรียบง่าย หรือการควบคุมพื้นฐานใน Android ทั้ง Android และ iOS จำกัดคอมโพเนนต์ UI และฟีเจอร์ที่คุณใช้ได้

สร้าง UI สำหรับวิดเจ็ต
เนื่องจากข้อจำกัดของ UI เหล่านี้ คุณจึงวาด UI ของวิดเจ็ตหน้าจอหลักโดยใช้เฟรมเวิร์ก Flutter โดยตรงไม่ได้ แต่คุณสามารถเพิ่มวิดเจ็ตที่สร้างด้วยเฟรมเวิร์กของแพลตฟอร์ม เช่น Jetpack Compose หรือ SwiftUI ลงในแอป Flutter ได้ Codelab นี้จะอธิบายตัวอย่างการแชร์ทรัพยากรระหว่างแอปกับวิดเจ็ตเพื่อหลีกเลี่ยงการเขียน UI ที่ซับซ้อนซ้ำ
สิ่งที่คุณจะสร้าง
ใน Codelab นี้ คุณจะได้สร้างวิดเจ็ตหน้าจอหลักทั้งใน Android และ iOS สำหรับแอป Flutter อย่างง่าย โดยใช้แพ็กเกจ home_widget ซึ่งช่วยให้ผู้ใช้สามารถอ่านบทความได้ วิดเจ็ตจะทำสิ่งต่อไปนี้
- แสดงข้อมูลจากแอป Flutter
- แสดงข้อความโดยใช้ชิ้นงานแบบอักษรที่แชร์จากแอป Flutter
- แสดงรูปภาพของวิดเจ็ต Flutter ที่แสดงผล

แอป Flutter นี้มี 2 หน้าจอ (หรือเส้นทาง) ดังนี้
- ส่วนแรกจะแสดงรายการบทความข่าวพร้อมบรรทัดแรกและคำอธิบาย
- ส่วนที่ 2 แสดงบทความฉบับเต็มพร้อมแผนภูมิที่สร้างขึ้นโดยใช้
CustomPaint
.

สิ่งที่คุณจะได้เรียนรู้
- วิธีสร้างวิดเจ็ตหน้าจอหลักใน iOS และ Android
- วิธีใช้แพ็กเกจ home_widget เพื่อแชร์ข้อมูลระหว่างวิดเจ็ตหน้าจอหลักกับแอป Flutter
- วิธีลดปริมาณโค้ดที่คุณต้องเขียนใหม่
- วิธีอัปเดตวิดเจ็ตหน้าจอหลักจากแอป Flutter
2. ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์
สำหรับทั้ง 2 แพลตฟอร์ม คุณต้องมี Flutter SDK และIDE คุณสามารถใช้ IDE ที่ต้องการเพื่อทำงานกับ Flutter ได้ ซึ่งอาจเป็น Visual Studio Code ที่มีส่วนขยาย Dart Code และ Flutter หรือ Android Studio หรือ IntelliJ ที่ติดตั้งปลั๊กอิน Flutter และ Dart
วิธีสร้างวิดเจ็ตหน้าจอหลักของ iOS
- คุณเรียกใช้ Codelab นี้ได้ในอุปกรณ์ iOS จริงหรือโปรแกรมจำลอง iOS
- คุณต้องกำหนดค่าระบบ macOS ด้วย Xcode IDE ซึ่งจะติดตั้งคอมไพเลอร์ที่จำเป็นต่อการสร้างแอปเวอร์ชัน iOS
วิธีสร้างวิดเจ็ตหน้าจอหลักของ Android
- คุณเรียกใช้ Codelab นี้ได้ในอุปกรณ์ Android จริงหรือโปรแกรมจำลอง Android
- คุณต้องกำหนดค่าระบบพัฒนาด้วย Android Studio ซึ่งจะติดตั้งคอมไพเลอร์ที่จำเป็นต่อการสร้างแอปเวอร์ชัน Android
รับโค้ดเริ่มต้น
ดาวน์โหลดโปรเจ็กต์เวอร์ชันเริ่มต้นจาก GitHub
จากบรรทัดคำสั่ง ให้โคลนที่เก็บ GitHub ลงในไดเรกทอรี flutter-codelabs โดยใช้คำสั่งต่อไปนี้
$ git clone https://github.com/flutter/codelabs.git flutter-codelabs
หลังจากโคลนที่เก็บแล้ว คุณจะเห็นโค้ดสำหรับ Codelab นี้ในไดเรกทอรี flutter-codelabs/homescreen_codelab ไดเรกทอรีนี้มีโค้ดโปรเจ็กต์ที่เสร็จสมบูรณ์แล้วสำหรับแต่ละขั้นตอนในโค้ดแล็บ
เปิดแอปเริ่มต้น
เปิดไดเรกทอรี flutter-codelabs/homescreen_codelab/step_03 ใน IDE ที่ต้องการ
ติดตั้งแพ็กเกจ
เพิ่มแพ็กเกจที่จำเป็นทั้งหมดลงในไฟล์ pubspec.yaml ของโปรเจ็กต์แล้ว หากต้องการดึงข้อมูลทรัพยากร Dependency ของโปรเจ็กต์ ให้เรียกใช้คำสั่งต่อไปนี้
$ flutter pub get
3. เพิ่มวิดเจ็ตหน้าจอหลักพื้นฐาน
ก่อนอื่น ให้เพิ่มวิดเจ็ตหน้าจอหลักโดยใช้เครื่องมือแพลตฟอร์มดั้งเดิม
สร้างวิดเจ็ตหน้าจอหลักของ iOS ขั้นพื้นฐาน
การเพิ่มส่วนขยายแอปไปยังแอป Flutter iOS จะคล้ายกับการเพิ่มส่วนขยายแอปไปยังแอป SwiftUI หรือ UIKit ดังนี้
- เรียกใช้
open ios/Runner.xcworkspaceในหน้าต่างเทอร์มินัลจากไดเรกทอรีโปรเจ็กต์ Flutter หรือคลิกขวาที่โฟลเดอร์ ios จาก VSCode แล้วเลือกเปิดใน Xcode ซึ่งจะเปิดพื้นที่ทำงาน Xcode เริ่มต้นในโปรเจ็กต์ Flutter - เลือกไฟล์ → ใหม่ → เป้าหมายจากเมนู ซึ่งจะเป็นการเพิ่มเป้าหมายใหม่ลงในโปรเจ็กต์
- รายการเทมเพลตจะปรากฏขึ้น เลือกส่วนขยายวิดเจ็ต
- พิมพ์ "NewsWidgets" ลงในช่องชื่อผลิตภัณฑ์สำหรับวิดเจ็ตนี้ ล้างทั้งช่องทำเครื่องหมายรวมกิจกรรมถ่ายทอดสดและรวมเจตนาในการกำหนดค่า
ตรวจสอบโค้ดตัวอย่าง
เมื่อเพิ่มเป้าหมายใหม่ Xcode จะสร้างโค้ดตัวอย่างตามเทมเพลตที่คุณเลือก ดูข้อมูลเพิ่มเติมเกี่ยวกับโค้ดที่สร้างขึ้นและ WidgetKit ได้ที่เอกสารประกอบส่วนขยายแอปของ Apple
แก้ไขข้อบกพร่องและทดสอบวิดเจ็ตตัวอย่าง
- ก่อนอื่น ให้อัปเดตการกำหนดค่าของแอป Flutter คุณต้องดำเนินการนี้เมื่อเพิ่มแพ็กเกจใหม่ในแอป Flutter และวางแผนที่จะเรียกใช้เป้าหมายในโปรเจ็กต์จาก Xcode หากต้องการอัปเดตการกำหนดค่าของแอป ให้เรียกใช้คำสั่งต่อไปนี้ในไดเรกทอรีแอป Flutter
$ flutter build ios --config-only
- คลิก Runner เพื่อแสดงรายการเป้าหมาย เลือกเป้าหมายวิดเจ็ตที่คุณเพิ่งสร้าง NewsWidgets แล้วคลิกเรียกใช้ เรียกใช้เป้าหมายวิดเจ็ตจาก Xcode เมื่อเปลี่ยนโค้ดวิดเจ็ต iOS

- หน้าจอจำลองหรือหน้าจออุปกรณ์ควรแสดงวิดเจ็ตหน้าจอหลักพื้นฐาน หากไม่เห็น ให้เพิ่มลงในหน้าจอ คลิกหน้าจอหลักค้างไว้ แล้วคลิก + ที่มุมซ้ายบน

- ค้นหาชื่อแอป สำหรับ Codelab นี้ ให้ค้นหา "วิดเจ็ตหน้าจอหลัก"

- เมื่อเพิ่มวิดเจ็ตหน้าจอหลักแล้ว วิดเจ็ตควรแสดงข้อความง่ายๆ ที่ระบุเวลา
การสร้างวิดเจ็ต Android พื้นฐาน
- หากต้องการเพิ่มวิดเจ็ตหน้าจอหลักใน Android ให้เปิดไฟล์บิลด์ของโปรเจ็กต์ใน Android Studio คุณดูไฟล์นี้ได้ที่ android/build.gradle หรือคลิกขวาที่โฟลเดอร์ android จาก VSCode แล้วเลือกเปิดใน Android Studio
- หลังจากสร้างโปรเจ็กต์แล้ว ให้ค้นหาไดเรกทอรีแอปที่มุมซ้ายบน เพิ่มวิดเจ็ตหน้าจอหลักใหม่ลงในไดเรกทอรีนี้ คลิกขวาที่ไดเรกทอรี เลือกใหม่ -> วิดเจ็ต -> วิดเจ็ตแอป

- Android Studio จะแสดงแบบฟอร์มใหม่ เพิ่มข้อมูลพื้นฐานเกี่ยวกับวิดเจ็ตหน้าจอหลัก รวมถึงชื่อคลาส ตำแหน่ง ขนาด และภาษาต้นฉบับ
สำหรับ Codelab นี้ ให้ตั้งค่าต่อไปนี้
- กล่องชื่อชั้นเรียนไปยัง NewsWidget
- ความกว้างขั้นต่ำ (เซลล์) เป็น 3
- ความสูงขั้นต่ำ (เซลล์) เป็น 3
ตรวจสอบโค้ดตัวอย่าง
เมื่อคุณส่งแบบฟอร์ม Android Studio จะสร้างและอัปเดตไฟล์หลายไฟล์ การเปลี่ยนแปลงที่เกี่ยวข้องกับโค้ดแล็บนี้แสดงอยู่ในตารางด้านล่าง
การดำเนินการ | ไฟล์เป้าหมาย | เปลี่ยน |
อัปเดต |
| เพิ่มตัวรับใหม่ที่ลงทะเบียน NewsWidget |
สร้าง |
| กำหนด UI ของวิดเจ็ตหน้าจอหลัก |
สร้าง |
| กำหนดการกำหนดค่าวิดเจ็ตหน้าจอหลัก คุณปรับขนาดหรือชื่อของวิดเจ็ตได้ในไฟล์นี้ |
สร้าง |
| มีโค้ด Kotlin เพื่อเพิ่มฟังก์ชันการทำงานให้กับวิดเจ็ตหน้าจอหลัก |
ดูรายละเอียดเพิ่มเติมเกี่ยวกับไฟล์เหล่านี้ได้ตลอดทั้ง Codelab นี้
แก้ไขข้อบกพร่องและทดสอบวิดเจ็ตตัวอย่าง
ตอนนี้เรียกใช้แอปพลิเคชันและดูวิดเจ็ตหน้าจอหลัก เมื่อสร้างแอปแล้ว ให้ไปที่หน้าจอการเลือกแอปพลิเคชันของอุปกรณ์ Android แล้วกดไอคอนโปรเจ็กต์ Flutter นี้ค้างไว้ เลือกวิดเจ็ตจากเมนูป๊อปอัป

อุปกรณ์ Android หรือโปรแกรมจำลองจะแสดงวิดเจ็ตหน้าจอหลักเริ่มต้นสำหรับ Android
4. ส่งข้อมูลจากแอป Flutter ไปยังวิดเจ็ตหน้าจอหลัก
คุณปรับแต่งวิดเจ็ตหน้าจอหลักพื้นฐานที่สร้างขึ้นได้ อัปเดตวิดเจ็ตหน้าจอหลักเพื่อแสดงพาดหัวและข้อมูลสรุปของบทความข่าว ภาพหน้าจอด้านล่างแสดงตัวอย่างวิดเจ็ตหน้าจอหลักที่แสดงพาดหัวและข้อมูลสรุป

หากต้องการส่งข้อมูลระหว่างแอปกับวิดเจ็ตหน้าจอหลัก คุณต้องเขียนโค้ด Dart และโค้ดเนทีฟ ส่วนนี้จะแบ่งกระบวนการนี้ออกเป็น 3 ส่วน
- การเขียนโค้ด Dart ในแอป Flutter ที่ทั้ง Android และ iOS ใช้ได้
- การเพิ่มฟังก์ชันการทำงานของ iOS ดั้งเดิม
- การเพิ่มฟังก์ชันการทำงานของ Android แบบเนทีฟ
การใช้กลุ่มแอป iOS
หากต้องการแชร์ข้อมูลระหว่างแอปหลักใน iOS กับส่วนขยายวิดเจ็ต เป้าหมายทั้ง 2 รายการต้องอยู่ในกลุ่มแอปเดียวกัน ดูข้อมูลเพิ่มเติมเกี่ยวกับกลุ่มแอปได้ที่เอกสารประกอบเกี่ยวกับกลุ่มแอปของ Apple
อัปเดตรหัสชุดซอฟต์แวร์
ใน Xcode ให้ไปที่การตั้งค่าของเป้าหมาย ในแท็บการลงนามและความสามารถ ให้ตรวจสอบว่าได้ตั้งค่าทีมและตัวระบุแพ็กเกจแล้ว
เพิ่มกลุ่มแอปไปยังเป้าหมาย Runner และเป้าหมาย NewsWidgetExtension ทั้ง 2 รายการใน Xcode โดยทำดังนี้
เลือก + ความสามารถ -> กลุ่มแอป แล้วเพิ่มกลุ่มแอปใหม่ ทำซ้ำสำหรับทั้งเป้าหมาย Runner (แอปหลัก) และเป้าหมายวิดเจ็ต

เพิ่มโค้ด Dart
ทั้งแอป iOS และ Android สามารถแชร์ข้อมูลกับแอป Flutter ได้หลายวิธี ในการสื่อสารกับแอปเหล่านี้ ให้ใช้ประโยชน์จากkey/value Store ในเครื่องของอุปกรณ์ iOS เรียก Store นี้ว่า UserDefaults และ Android เรียก Store นี้ว่า SharedPreferences แพ็กเกจ home_widget จะรวม API เหล่านี้ไว้ด้วยกันเพื่อลดความซับซ้อนในการบันทึกข้อมูลไปยังแพลตฟอร์มใดแพลตฟอร์มหนึ่ง และช่วยให้วิดเจ็ตหน้าจอหลักดึงข้อมูลที่อัปเดตได้

ข้อมูลบรรทัดแรกและคำอธิบายมาจากไฟล์ news_data.dart ไฟล์นี้มีข้อมูลจำลองและคลาสข้อมูล NewsArticle
lib/news_data.dart
class NewsArticle {
final String title;
final String description;
final String? articleText;
NewsArticle({
required this.title,
required this.description,
this.articleText = loremIpsum,
});
}
อัปเดตค่าบรรทัดแรกและคำอธิบาย
หากต้องการเพิ่มฟังก์ชันการอัปเดตวิดเจ็ตหน้าจอหลักจากแอป Flutter ให้ไปที่ไฟล์ lib/home_screen.dart แทนที่เนื้อหาของไฟล์ด้วยโค้ดต่อไปนี้ จากนั้นแทนที่ <YOUR APP GROUP> ด้วยตัวระบุสำหรับกลุ่มแอป
lib/home_screen.dart
import 'package:flutter/material.dart';
import 'package:home_widget/home_widget.dart'; // Add this import
import 'article_screen.dart';
import 'news_data.dart';
// TODO: Replace with your App Group ID
const String appGroupId = '<YOUR APP GROUP>'; // Add from here
const String iOSWidgetName = 'NewsWidgets';
const String androidWidgetName = 'NewsWidget'; // To here.
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
void updateHeadline(NewsArticle newHeadline) { // Add from here
// Save the headline data to the widget
HomeWidget.saveWidgetData<String>('headline_title', newHeadline.title);
HomeWidget.saveWidgetData<String>(
'headline_description', newHeadline.description);
HomeWidget.updateWidget(
iOSName: iOSWidgetName,
androidName: androidWidgetName,
);
} // To here.
class _MyHomePageState extends State<MyHomePage> {
@override // Add from here
void initState() {
super.initState();
HomeWidget.setAppGroupId(appGroupId);
// Mock read in some data and update the headline
final newHeadline = getNewsStories()[0];
updateHeadline(newHeadline);
} // To here.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Top Stories'),
centerTitle: false,
titleTextStyle: const TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.black)),
body: ListView.separated(
separatorBuilder: (context, idx) {
return const Divider();
},
itemCount: getNewsStories().length,
itemBuilder: (context, idx) {
final article = getNewsStories()[idx];
return ListTile(
key: Key('$idx ${article.hashCode}'),
title: Text(article.title!),
subtitle: Text(article.description!),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return ArticleScreen(article: article);
},
),
);
},
);
},
));
}
}
ฟังก์ชัน updateHeadline จะบันทึกคู่คีย์/ค่าไว้ในที่เก็บข้อมูลในเครื่องของอุปกรณ์ headline_title คีย์มีค่าของ newHeadline.title headline_description คีย์มีค่าของ newHeadline.description ฟังก์ชันนี้ยังแจ้งแพลตฟอร์มเนทีฟว่าสามารถดึงและแสดงข้อมูลใหม่สำหรับวิดเจ็ตหน้าจอหลักได้
แก้ไข FloatingActionButton
เรียกใช้ฟังก์ชัน updateHeadline เมื่อกด floatingActionButton ดังที่แสดง
lib/article_screen.dart
// New: import the updateHeadline function
import 'home_screen.dart';
...
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Updating home screen widget...'),
));
// New: call updateHeadline
updateHeadline(widget.article);
},
label: const Text('Update Homescreen'),
),
...
การเปลี่ยนแปลงนี้จะทําให้เมื่อผู้ใช้กดปุ่มอัปเดตบรรทัดแรกจากหน้าบทความ ระบบจะอัปเดตรายละเอียดวิดเจ็ตหน้าจอหลัก
อัปเดตโค้ด iOS เพื่อแสดงข้อมูลบทความ
หากต้องการอัปเดตวิดเจ็ตหน้าจอหลักสำหรับ iOS ให้ใช้ Xcode
เปิดไฟล์ NewsWidgets.swift ใน Xcode โดยทำดังนี้
กำหนดค่า TimelineEntry
แทนที่โครงสร้าง SimpleEntry ด้วยโค้ดต่อไปนี้
ios/NewsWidgets/NewsWidgets.swift
// The date and any data you want to pass into your app must conform to TimelineEntry
struct NewsArticleEntry: TimelineEntry {
let date: Date
let title: String
let description:String
}
โครงสร้าง NewsArticleEntry นี้กำหนดข้อมูลขาเข้าที่จะส่งไปยังวิดเจ็ตหน้าจอหลักเมื่อมีการอัปเดต ประเภท TimelineEntry ต้องมีพารามิเตอร์วันที่ ดูข้อมูลเพิ่มเติมเกี่ยวกับโปรโตคอล TimelineEntry ได้ที่เอกสารประกอบ TimelineEntry ของ Apple
แก้ไข View ที่แสดงเนื้อหา
แก้ไขวิดเจ็ตหน้าจอหลักเพื่อแสดงบรรทัดแรกและคำอธิบายของบทความข่าวแทนวันที่ หากต้องการแสดงข้อความใน SwiftUI ให้ใช้มุมมอง Text หากต้องการซ้อนมุมมองใน SwiftUI ให้ใช้มุมมอง VStack
แทนที่NewsWidgetEntryViewมุมมองที่สร้างขึ้นด้วยโค้ดต่อไปนี้
ios/NewsWidgets/NewsWidgets.swift
//View that holds the contents of the widget
struct NewsWidgetsEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
Text(entry.title)
Text(entry.description)
}
}
}
แก้ไขผู้ให้บริการเพื่อบอกวิดเจ็ตหน้าจอหลักว่าจะอัปเดตเมื่อใดและอย่างไร
แทนที่ Provider ที่มีอยู่ด้วยโค้ดต่อไปนี้ จากนั้นแทนที่ตัวระบุกลุ่มแอปด้วย <YOUR APP GROUP>
ios/NewsWidgets/NewsWidgets.swift
struct Provider: TimelineProvider {
// Placeholder is used as a placeholder when the widget is first displayed
func placeholder(in context: Context) -> NewsArticleEntry {
// Add some placeholder title and description, and get the current date
NewsArticleEntry(date: Date(), title: "Placeholder Title", description: "Placeholder description")
}
// Snapshot entry represents the current time and state
func getSnapshot(in context: Context, completion: @escaping (NewsArticleEntry) -> ()) {
let entry: NewsArticleEntry
if context.isPreview{
entry = placeholder(in: context)
}
else{
// Get the data from the user defaults to display
let userDefaults = UserDefaults(suiteName: <YOUR APP GROUP>)
let title = userDefaults?.string(forKey: "headline_title") ?? "No Title Set"
let description = userDefaults?.string(forKey: "headline_description") ?? "No Description Set"
entry = NewsArticleEntry(date: Date(), title: title, description: description)
}
completion(entry)
}
// getTimeline is called for the current and optionally future times to update the widget
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
// This just uses the snapshot function you defined earlier
getSnapshot(in: context) { (entry) in
// atEnd policy tells widgetkit to request a new entry after the date has passed
let timeline = Timeline(entries: [entry], policy: .atEnd)
completion(timeline)
}
}
}
Provider ในโค้ดก่อนหน้าเป็นไปตาม TimelineProvider Provider มี 3 วิธีดังนี้
placeholderวิธีนี้จะสร้างรายการตัวยึดตำแหน่งเมื่อผู้ใช้ดูตัวอย่างวิดเจ็ตหน้าจอหลักเป็นครั้งแรก

- วิธี
getSnapshotจะอ่านข้อมูลจากค่าเริ่มต้นของผู้ใช้และสร้างรายการสำหรับเวลาปัจจุบัน - เมธอด
getTimelineจะแสดงรายการไทม์ไลน์ ซึ่งจะมีประโยชน์เมื่อคุณมีช่วงเวลาที่คาดการณ์ได้ในการอัปเดตเนื้อหา Codelab นี้ใช้ฟังก์ชัน getSnapshot เพื่อรับสถานะปัจจุบัน.atEndเมธอดจะบอกให้วิดเจ็ตหน้าจอหลักรีเฟรชข้อมูลหลังจากเวลาปัจจุบันผ่านไป
แสดงความคิดเห็นใน NewsWidgets_Previews
การใช้ตัวอย่างอยู่นอกขอบเขตของโค้ดแล็บนี้ ดูรายละเอียดเพิ่มเติมเกี่ยวกับการแสดงตัวอย่างวิดเจ็ตหน้าจอหลักของ SwiftUI ได้ที่เอกสารประกอบของ Apple เกี่ยวกับการแก้ไขข้อบกพร่องของวิดเจ็ต
บันทึกไฟล์ทั้งหมดและเรียกใช้เป้าหมายแอปและวิดเจ็ตอีกครั้ง
เรียกใช้เป้าหมายอีกครั้งเพื่อตรวจสอบว่าแอปและวิดเจ็ตหน้าจอหลักทำงานได้
- เลือกสคีมาแอปใน Xcode เพื่อเรียกใช้เป้าหมายแอป
- เลือกสคีมาของส่วนขยายใน Xcode เพื่อเรียกใช้เป้าหมายของส่วนขยาย
- ไปยังหน้าบทความในแอป
- คลิกปุ่มเพื่ออัปเดตพาดหัว วิดเจ็ตหน้าจอหลักควรจะอัปเดตบรรทัดแรกด้วย
อัปเดตโค้ด Android
เพิ่ม XML ของวิดเจ็ตหน้าจอหลัก
ใน Android Studio ให้อัปเดตไฟล์ที่สร้างในขั้นตอนก่อนหน้า เปิดไฟล์ res/layout/news_widget.xml ซึ่งจะกำหนดโครงสร้างและเลย์เอาต์ของวิดเจ็ตหน้าจอหลัก เลือกโค้ดที่มุมขวาบน แล้วแทนที่เนื้อหาของไฟล์นั้นด้วยโค้ดต่อไปนี้
android/app/res/layout/news_widget.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/widget_container"
style="@style/Widget.Android.AppWidget.Container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android:color/white"
android:theme="@style/Theme.Android.AppWidgetContainer">
<TextView
android:id="@+id/headline_title"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/headline_description"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/headline_title"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="4dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="16sp" />
</RelativeLayout>
XML นี้กำหนดมุมมองข้อความ 2 รายการ รายการหนึ่งสำหรับบรรทัดแรกของบทความ และอีกรายการหนึ่งสำหรับคำอธิบายบทความ มุมมองข้อความเหล่านี้ยังกำหนดการจัดรูปแบบด้วย คุณจะกลับมาที่ไฟล์นี้ตลอดทั้ง Codelab นี้
อัปเดตฟังก์ชันการทำงานของ NewsWidget
เปิดNewsWidget.ktไฟล์ซอร์สโค้ด Kotlin ไฟล์นี้มีคลาสที่สร้างขึ้นชื่อ NewsWidget ซึ่งขยายคลาส AppWidgetProvider
คลาส NewsWidget มี 3 เมธอดจากคลาสแม่ คุณจะแก้ไขเมธอด onUpdate Android จะเรียกใช้เมธอดนี้สำหรับวิดเจ็ตในช่วงเวลาที่กำหนด
แทนที่เนื้อหาของไฟล์ NewsWidget.kt ด้วยโค้ดต่อไปนี้
android/app/java/com.mydomain.homescreen_widgets/NewsWidget.kt
// Import will depend on App ID.
package com.mydomain.homescreen_widgets
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.widget.RemoteViews
// New import.
import es.antonborri.home_widget.HomeWidgetPlugin
/**
* Implementation of App Widget functionality.
*/
class NewsWidget : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
) {
for (appWidgetId in appWidgetIds) {
// Get reference to SharedPreferences
val widgetData = HomeWidgetPlugin.getData(context)
val views = RemoteViews(context.packageName, R.layout.news_widget).apply {
val title = widgetData.getString("headline_title", null)
setTextViewText(R.id.headline_title, title ?: "No title set")
val description = widgetData.getString("headline_description", null)
setTextViewText(R.id.headline_description, description ?: "No description set")
}
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
ตอนนี้เมื่อมีการเรียกใช้ onUpdate Android จะรับค่าล่าสุดจากที่เก็บข้อมูลในเครื่องโดยใช้วิธี the widgetData.getString() จากนั้นจะเรียกใช้ setTextViewText เพื่อเปลี่ยนข้อความที่แสดงในวิดเจ็ตหน้าจอหลัก
ทดสอบการอัปเดต
ทดสอบแอปเพื่อให้แน่ใจว่าวิดเจ็ตหน้าจอหลักจะอัปเดตข้อมูลใหม่ หากต้องการอัปเดตข้อมูล ให้ใช้อัปเดตหน้าจอหลัก FloatingActionButton ในหน้าบทความ วิดเจ็ตหน้าจอหลักควรจะอัปเดตชื่อบทความ

5. การใช้แบบอักษรที่กำหนดเองของแอป Flutter ในวิดเจ็ตหน้าจอหลักของ iOS
ตอนนี้คุณได้กำหนดค่าวิดเจ็ตหน้าจอหลักให้อ่านข้อมูลที่แอป Flutter ให้ไว้แล้ว แอป Flutter มีแบบอักษรที่กำหนดเองซึ่งคุณอาจต้องการใช้ในวิดเจ็ตหน้าจอหลัก คุณใช้แบบอักษรที่กำหนดเองในวิดเจ็ตหน้าจอหลักของ iOS ได้ การใช้แบบอักษรที่กำหนดเองในวิดเจ็ตหน้าจอหลักไม่พร้อมใช้งานใน Android
อัปเดตโค้ด iOS
Flutter จัดเก็บชิ้นงานใน mainBundle ของแอปพลิเคชัน iOS คุณเข้าถึงชิ้นงานในชุดนี้ได้จากโค้ดวิดเจ็ตหน้าจอหลัก
ในโครงสร้าง NewsWidgetsEntryView ในไฟล์ NewsWidgets.swift ให้ทำการเปลี่ยนแปลงต่อไปนี้
สร้างฟังก์ชันตัวช่วยเพื่อรับเส้นทางไปยังไดเรกทอรีชิ้นงาน Flutter:
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
// New: Add the helper function.
var bundle: URL {
let bundle = Bundle.main
if bundle.bundleURL.pathExtension == "appex" {
// Peel off two directory levels - MY_APP.app/PlugIns/MY_APP_EXTENSION.appex
var url = bundle.bundleURL.deletingLastPathComponent().deletingLastPathComponent()
url.append(component: "Frameworks/App.framework/flutter_assets")
return url
}
return bundle.bundleURL
}
...
}
ลงทะเบียนแบบอักษรโดยใช้ URL ไปยังไฟล์แบบอักษรที่กำหนดเอง
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
// New: Register the font.
init(entry: Provider.Entry){
self.entry = entry
CTFontManagerRegisterFontsForURL(bundle.appending(path: "/fonts/Chewy-Regular.ttf") as CFURL, CTFontManagerScope.process, nil)
}
...
}
อัปเดตมุมมองข้อความบรรทัดแรกเพื่อใช้แบบอักษรที่กำหนดเอง
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
var body: some View {
VStack {
// Update the following line.
Text(entry.title).font(Font.custom("Chewy", size: 13))
Text(entry.description)
}
}
...
}
เมื่อคุณเรียกใช้วิดเจ็ตหน้าจอหลัก วิดเจ็ตจะใช้แบบอักษรที่กำหนดเองสำหรับพาดหัวตามที่แสดงในรูปภาพต่อไปนี้

6. การแสดงผลวิดเจ็ต Flutter เป็นรูปภาพ
ในส่วนนี้ คุณจะแสดงกราฟจากแอป Flutter เป็นวิดเจ็ตหน้าจอหลัก
วิดเจ็ตนี้มีความท้าทายมากกว่าข้อความที่คุณแสดงบนหน้าจอหลัก การแสดงแผนภูมิ Flutter เป็นรูปภาพนั้นง่ายกว่าการพยายามสร้างใหม่โดยใช้คอมโพเนนต์ UI ดั้งเดิมมาก
เขียนโค้ดวิดเจ็ตหน้าจอหลักเพื่อแสดงแผนภูมิ Flutter เป็นไฟล์ PNG วิดเจ็ตหน้าจอหลักจะแสดงรูปภาพนั้นได้
เขียนโค้ด Dart
ในฝั่ง Dart ให้เพิ่มเมธอด renderFlutterWidget จากแพ็กเกจ home_widget เมธอดนี้รับวิดเจ็ต ชื่อไฟล์ และคีย์ โดยจะแสดงผลรูปภาพของวิดเจ็ต Flutter และบันทึกลงในคอนเทนเนอร์ที่แชร์ ระบุชื่อรูปภาพในโค้ดและตรวจสอบว่าวิดเจ็ตหน้าจอหลักเข้าถึงคอนเทนเนอร์ได้ key จะบันทึกเส้นทางแบบเต็มของไฟล์เป็นสตริงในพื้นที่เก็บข้อมูลในเครื่องของอุปกรณ์ ซึ่งจะช่วยให้วิดเจ็ตหน้าจอหลักค้นหาไฟล์ได้หากมีการเปลี่ยนชื่อในโค้ด Dart
สำหรับโค้ดแล็บนี้ คลาส LineChart ในไฟล์ lib/article_screen.dart จะแสดงแผนภูมิ เมธอดการสร้างจะแสดงผล CustomPainter ที่วาดแผนภูมินี้ลงบนหน้าจอ
หากต้องการใช้ฟีเจอร์นี้ ให้เปิดไฟล์ lib/article_screen.dart นำเข้าแพ็กเกจ home_widget จากนั้นแทนที่โค้ดในคลาส _ArticleScreenState ด้วยโค้ดต่อไปนี้
lib/article_screen.dart
import 'package:flutter/material.dart';
// New: import the home_widget package.
import 'package:home_widget/home_widget.dart';
import 'home_screen.dart';
import 'news_data.dart';
...
class _ArticleScreenState extends State<ArticleScreen> {
// New: add this GlobalKey
final _globalKey = GlobalKey();
String? imagePath;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.article.title!),
),
// New: add this FloatingActionButton
floatingActionButton: FloatingActionButton.extended(
onPressed: () async {
if (_globalKey.currentContext != null) {
var path = await HomeWidget.renderFlutterWidget(
const LineChart(),
fileName: 'screenshot',
key: 'filename',
logicalSize: _globalKey.currentContext!.size,
pixelRatio:
MediaQuery.of(_globalKey.currentContext!).devicePixelRatio,
);
setState(() {
imagePath = path as String?;
});
}
updateHeadline(widget.article);
},
label: const Text('Update Homescreen'),
),
body: ListView(
padding: const EdgeInsets.all(16.0),
children: [
Text(
widget.article.description!,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 20.0),
Text(widget.article.articleText!),
const SizedBox(height: 20.0),
Center(
// New: Add this key
key: _globalKey,
child: const LineChart(),
),
const SizedBox(height: 20.0),
Text(widget.article.articleText!),
],
),
);
}
}
ตัวอย่างนี้ทำการเปลี่ยนแปลง 3 อย่างในคลาส _ArticleScreenState
สร้าง GlobalKey
GlobalKey จะรับบริบทของวิดเจ็ตที่เฉพาะเจาะจง ซึ่งจำเป็นต่อการรับขนาดของวิดเจ็ตนั้น
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
// New: add this GlobalKey
final _globalKey = GlobalKey();
...
}
เพิ่ม imagePath
พร็อพเพอร์ตี้ imagePath จะจัดเก็บตำแหน่งของรูปภาพที่วิดเจ็ต Flutter แสดง
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
...
// New: add this imagePath
String? imagePath;
...
}
เพิ่มคีย์ลงในวิดเจ็ตเพื่อแสดงผล
_globalKey มีวิดเจ็ต Flutter ที่แสดงผลเป็นรูปภาพ ในกรณีนี้ วิดเจ็ต Flutter คือ Center ที่มี LineChart
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
...
Center(
// New: Add this key
key: _globalKey,
child: const LineChart(),
),
...
}
- บันทึกวิดเจ็ตเป็นรูปภาพ
ระบบจะเรียกใช้เมธอด renderFlutterWidget เมื่อผู้ใช้คลิก floatingActionButton วิธีการนี้จะบันทึกไฟล์ PNG ที่ได้เป็น "screenshot" ไปยังไดเรกทอรีคอนเทนเนอร์ที่แชร์ นอกจากนี้ เมธอดนี้ยังบันทึกเส้นทางแบบเต็มไปยังรูปภาพเป็นคีย์ชื่อไฟล์ในพื้นที่เก็บข้อมูลของอุปกรณ์ด้วย
lib/article_screen.dart
class _ArticleScreenState extends State<ArticleScreen> {
...
floatingActionButton: FloatingActionButton.extended(
onPressed: () async {
if (_globalKey.currentContext != null) {
var path = await HomeWidget.renderFlutterWidget(
LineChart(),
fileName: 'screenshot',
key: 'filename',
logicalSize: _globalKey.currentContext!.size,
pixelRatio:
MediaQuery.of(_globalKey.currentContext!).devicePixelRatio,
);
setState(() {
imagePath = path as String?;
});
}
updateHeadline(widget.article);
},
...
}
อัปเดตโค้ด iOS
สำหรับ iOS ให้อัปเดตโค้ดเพื่อรับเส้นทางไฟล์จากที่เก็บข้อมูลและแสดงไฟล์เป็นรูปภาพโดยใช้ SwiftUI
เปิดไฟล์ NewsWidgets.swift เพื่อทำการเปลี่ยนแปลงต่อไปนี้
เพิ่ม filename และ displaySize ลงใน NewsArticleEntry struct
พร็อพเพอร์ตี้ filename จะมีสตริงที่แสดงเส้นทางไปยังไฟล์รูปภาพ พร็อพเพอร์ตี้ displaySize จะเก็บขนาดของวิดเจ็ตหน้าจอหลักในอุปกรณ์ของผู้ใช้ ขนาดของวิดเจ็ตหน้าจอหลักมาจากcontext
ios/NewsWidgets/NewsWidgets.swift
struct NewsArticleEntry: TimelineEntry {
...
// New: add the filename and displaySize.
let filename: String
let displaySize: CGSize
}
อัปเดตplaceholder ฟังก์ชัน
รวมตัวยึดตำแหน่ง filename และ displaySize
ios/NewsWidgets/NewsWidgets.swift
func placeholder(in context: Context) -> NewsArticleEntry {
NewsArticleEntry(date: Date(), title: "Placeholder Title", description: "Placeholder description", filename: "No screenshot available", displaySize: context.displaySize)
}
รับชื่อไฟล์จาก userDefaults ใน getSnapshot
ซึ่งจะตั้งค่าตัวแปร filename เป็นค่า filename ในพื้นที่เก็บข้อมูล userDefaults เมื่อวิดเจ็ตหน้าจอหลักอัปเดต
ios/NewsWidgets/NewsWidgets.swift
func getSnapshot(
...
let title = userDefaults?.string(forKey: "headline_title") ?? "No Title Set"
let description = userDefaults?.string(forKey: "headline_description") ?? "No Description Set"
// New: get fileName from key/value store
let filename = userDefaults?.string(forKey: "filename") ?? "No screenshot available"
...
)
สร้าง ChartImage ที่แสดงรูปภาพจากเส้นทาง
ChartImage View จะสร้างรูปภาพจากเนื้อหาของไฟล์ที่สร้างขึ้นในฝั่ง Dart ในที่นี้ คุณตั้งค่าขนาดเป็น 50% ของเฟรม
ios/NewsWidgets/NewsWidgets.swift
struct NewsWidgetsEntryView : View {
...
// New: create the ChartImage view
var ChartImage: some View {
if let uiImage = UIImage(contentsOfFile: entry.filename) {
let image = Image(uiImage: uiImage)
.resizable()
.frame(width: entry.displaySize.height*0.5, height: entry.displaySize.height*0.5, alignment: .center)
return AnyView(image)
}
print("The image file could not be loaded")
return AnyView(EmptyView())
}
...
}
ใช้ ChartImage ในเนื้อหาของ NewsWidgetsEntryView
เพิ่มมุมมอง ChartImage ลงในเนื้อหาของ NewsWidgetsEntryView เพื่อแสดง ChartImage ในวิดเจ็ตหน้าจอหลัก
ios/NewsWidgets/NewsWidgets.swift
VStack {
Text(entry.title).font(Font.custom("Chewy", size: 13))
Text(entry.description).font(.system(size: 12)).padding(10)
// New: add the ChartImage to the NewsWidgetEntryView
ChartImage
}
ทดสอบการเปลี่ยนแปลง
หากต้องการทดสอบการเปลี่ยนแปลง ให้เรียกใช้ทั้งเป้าหมายแอป Flutter (Runner) และเป้าหมายส่วนขยายจาก Xcode อีกครั้ง หากต้องการดูรูปภาพ ให้ไปที่หน้าบทความหน้าใดหน้าหนึ่งในแอป แล้วกดปุ่มเพื่ออัปเดตวิดเจ็ตหน้าจอหลัก

อัปเดตโค้ด Android
โค้ด Android ทำงานเหมือนกับโค้ด iOS
- เปิดไฟล์
android/app/res/layout/news_widget.xmlซึ่งมีองค์ประกอบ UI ของวิดเจ็ตหน้าจอหลัก แทนที่เนื้อหาด้วยโค้ดต่อไปนี้
android/app/res/layout/news_widget.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/widget_container"
style="@style/Widget.Android.AppWidget.Container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android:color/white"
android:theme="@style/Theme.Android.AppWidgetContainer">
<TextView
android:id="@+id/headline_title"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/headline_description"
style="@style/Widget.Android.AppWidget.InnerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/headline_title"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="4dp"
android:background="@android:color/white"
android:text="Title"
android:textSize="16sp" />
<!--New: add this image view -->
<ImageView
android:id="@+id/widget_image"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_below="@+id/headline_description"
android:layout_alignBottom="@+id/headline_title"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="-134dp"
android:layout_weight="1"
android:adjustViewBounds="true"
android:background="@android:color/white"
android:scaleType="fitCenter"
android:src="@android:drawable/star_big_on"
android:visibility="visible"
tools:visibility="visible" />
</RelativeLayout>
โค้ดใหม่นี้จะเพิ่มรูปภาพลงในวิดเจ็ตหน้าจอหลัก ซึ่งจะแสดงไอคอนดาวทั่วไป (ในตอนนี้) แทนที่ไอคอนดาวนี้ด้วยรูปภาพที่คุณบันทึกไว้ในโค้ด Dart
- เปิดไฟล์
NewsWidget.ktแทนที่เนื้อหาด้วยโค้ดต่อไปนี้
android/app/java/com.mydomain.homescreen_widgets/NewsWidget.kt
// Import will depend on App ID.
package com.mydomain.homescreen_widgets
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.widget.RemoteViews
import java.io.File
import es.antonborri.home_widget.HomeWidgetPlugin
/**
* Implementation of App Widget functionality.
*/
class NewsWidget : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
) {
for (appWidgetId in appWidgetIds) {
val widgetData = HomeWidgetPlugin.getData(context)
val views = RemoteViews(context.packageName, R.layout.news_widget).apply {
val title = widgetData.getString("headline_title", null)
setTextViewText(R.id.headline_title, title ?: "No title set")
val description = widgetData.getString("headline_description", null)
setTextViewText(R.id.headline_description, description ?: "No description set")
// New: Add the section below
// Get chart image and put it in the widget, if it exists
val imageName = widgetData.getString("filename", null)
val imageFile = File(imageName)
val imageExists = imageFile.exists()
if (imageExists) {
val myBitmap: Bitmap = BitmapFactory.decodeFile(imageFile.absolutePath)
setImageViewBitmap(R.id.widget_image, myBitmap)
} else {
println("image not found!, looked @: ${imageName}")
}
// End new code
}
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
โค้ด Dart นี้จะบันทึกภาพหน้าจอไปยังพื้นที่เก็บข้อมูลในเครื่องด้วยคีย์ filename นอกจากนี้ ยังรับเส้นทางแบบเต็มของรูปภาพและสร้างออบเจ็กต์ File จากรูปภาพนั้นด้วย หากมีรูปภาพอยู่ โค้ด Dart จะแทนที่รูปภาพในวิดเจ็ตหน้าจอหลักด้วยรูปภาพใหม่
- โหลดแอปซ้ำแล้วไปที่หน้าจอของบทความ กดอัปเดตหน้าจอหลัก วิดเจ็ตหน้าจอหลักจะแสดงแผนภูมิ
7. ขั้นตอนถัดไป
ยินดีด้วย
ขอแสดงความยินดี คุณสร้างวิดเจ็ตหน้าจอหลักสำหรับแอป Flutter iOS และ Android ได้สำเร็จแล้ว
การลิงก์ไปยังเนื้อหาในแอป Flutter
คุณอาจต้องการนำผู้ใช้ไปยังหน้าใดหน้าหนึ่งในแอป ทั้งนี้ขึ้นอยู่กับว่าผู้ใช้คลิกที่ใด ตัวอย่างเช่น ในแอปข่าวจากโค้ดแล็บนี้ คุณอาจต้องการให้ผู้ใช้เห็นบทความข่าวสำหรับพาดหัวที่แสดง
ฟีเจอร์นี้อยู่นอกขอบเขตของโค้ดแล็บนี้ คุณดูตัวอย่างการใช้สตรีมที่แพ็กเกจ home_widget มีให้เพื่อระบุการเปิดแอปจากวิดเจ็ตหน้าจอหลักและส่งข้อความจากวิดเจ็ตหน้าจอหลักผ่าน URL ได้ ดูข้อมูลเพิ่มเติมได้ที่เอกสารประกอบเกี่ยวกับการทำ Deep Link ใน docs.flutter.dev
การอัปเดตวิดเจ็ตในเบื้องหลัง
ใน Codelab นี้ คุณได้ทริกเกอร์การอัปเดตวิดเจ็ตหน้าจอหลักโดยใช้ปุ่ม แม้ว่าการดำเนินการนี้จะสมเหตุสมผลสำหรับการทดสอบ แต่ในโค้ดเวอร์ชันที่ใช้งานจริง คุณอาจต้องการให้แอปอัปเดตวิดเจ็ตหน้าจอหลักในเบื้องหลัง คุณสามารถใช้ปลั๊กอิน Workmanager เพื่อสร้างงานในเบื้องหลังเพื่ออัปเดตทรัพยากรที่วิดเจ็ตหน้าจอหลักต้องการ ดูข้อมูลเพิ่มเติมได้ที่ส่วนการอัปเดตเบื้องหลังในแพ็กเกจ home_widget
สำหรับ iOS คุณยังสามารถให้วิดเจ็ตหน้าจอหลักส่งคำขอเครือข่ายเพื่ออัปเดต UI ได้ด้วย หากต้องการควบคุมเงื่อนไขหรือความถี่ของคำขอนั้น ให้ใช้ไทม์ไลน์ ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ไทม์ไลน์ได้ที่เอกสารประกอบของ Apple เรื่อง "การอัปเดตวิดเจ็ตให้เป็นปัจจุบัน"