使用 Firebase 雲端通訊,為 Flutter 應用程式傳送通知

1. 簡介

上次更新時間:2022 年 4 月 4 日

本程式碼研究室將逐步說明如何使用 Flutter,透過 Firebase 雲端通訊 (FCM) 開發跨平台應用程式。您只需撰寫一段應用程式實作程式碼,就能在 Android、iOS 和網頁這三個平台上順暢建構及執行。您也會瞭解如何在 Flutter 中整合 FCM,以及如何編寫程式碼來接收及傳送訊息。最後,本程式碼研究室會介紹 FCM HTTP v1 API 的平台專屬區塊功能,讓您傳送一則訊息,在不同平台上的行為卻有所不同。

必要條件

對 Flutter 有基本瞭解。

課程內容

  • 如何設定及建立 Flutter 應用程式。
  • 如何新增 FCM 依附元件。
  • 如何將單一 FCM 訊息傳送至應用程式。
  • 如何將主題 FCM 訊息傳送至應用程式。

軟硬體需求

  • 已設定 Dart 和 Flutter 外掛程式的最新穩定版 Android Studio

您可以使用下列任一裝置執行程式碼研究室:

如要使用 iOS 平台執行本程式碼研究室,您需要 iOS 裝置、Apple 開發人員帳戶,以及已安裝 XCode 的 macOS 裝置。

2. Flutter 設定

如果您已設定 Flutter 開發環境,請略過本節。

如要設定 Flutter 開發環境,請按照下列步驟操作:

  1. 為您的作業系統下載並安裝 Flutter:安裝 | Flutter
  2. 確認 Flutter 工具已新增至路徑。
  3. 按照「設定編輯器 | Flutter」一文的說明,設定 Flutter 編輯器。請務必為編輯器安裝 Flutter 和 Dart 外掛程式。在本程式碼研究室的其餘部分,您將使用 Android Studio。
  4. 在指令列中執行 flutter doctor,掃描設定並列出需要修正的任何缺少的依附元件。請按照操作說明修正任何重要的遺漏依附元件。請注意,部分依附元件可能並非必要。舉例來說,如果您不打算開發 iOS 應用程式,缺少 CocoaPods 依附元件就不會造成阻礙。
  5. 執行這項指令,在 fcmflutter 目錄中建立 Flutter 應用程式 flutter create --org com.flutter.fcm --project-name fcmflutter fcmflutter,然後將目錄變更為 fcmflutter
  1. 在 Android Studio 中,依序前往「File」->「Open」,找出 Flutter 應用程式的路徑,然後點選「Open」,在 Android Studio 中開啟專案。應用程式程式碼位於 lib/main.dart 檔案中。

在 Android Studio 工具列中,按一下向下箭頭選取 Android 裝置。如果目標選取器為空白,請安裝虛擬 Android 裝置,或Chrome 瀏覽器或 iOS 模擬器 (如要從網頁瀏覽器或 iOS 裝置啟動應用程式)。你可能需要手動啟動裝置,然後重新整理清單,才能找到目標裝置。

Android Studio 工具列,醒目顯示建構目標選單的下拉式箭頭。

按一下「執行」 Android Studio 中的執行按鈕 即可啟動應用程式。

啟動的 Flutter 示範應用程式 UI

恭喜!您已成功建立 Flutter 應用程式。

3. Firebase 和 FlutterFire 設定

如要使用 Flutter 開發與 Firebase 雲端通訊整合的應用程式,您需要:

  • Firebase 專案。
  • 可正常運作的 Firebase CLI。
  • 安裝 FlutterFire。
  • 使用 flutterfire configure 設定及產生的應用程式。

建立 Firebase 專案

如果您已有 Firebase 專案,可以略過這個步驟。

  1. 使用 Google 帳戶登入 Firebase 控制台
  2. 按一下按鈕建立新專案,然後輸入專案名稱 (例如 fcm4flutter)。
  3. 按一下「繼續」
  4. 如果系統提示,請詳閱並接受 Firebase 條款,然後按一下「繼續」
  5. (選用) 在 Firebase 控制台中啟用 AI 輔助功能 (稱為「Gemini in Firebase」)。
  6. 本程式碼研究室不需要 Google Analytics,因此請關閉 Google Analytics 選項。
  7. 按一下「建立專案」,等待專案佈建完成,然後按一下「繼續」

恭喜!您已成功建立 Firebase 專案。

設定 Firebase CLI

如果已設定 Firebase CLI,可以略過這個步驟。

前往 Firebase CLI 參考資料,下載並安裝 Firebase CLI。使用下列指令,透過 Google 帳戶登入 Firebase:

firebase login

設定 FlutterFire

  1. 使用 flutter pub add firebase_core 指令安裝 FlutterFire 外掛程式。
  2. 安裝 FCM 外掛程式:flutter pub add firebase_messaging
  3. 設定 FlutterFire CLI:dart pub global activate flutterfire_cli
  4. 在 Flutter 中設定 Firebase 專案:flutterfire configure --project=fcm4flutter.使用方向鍵和空格鍵選取平台,或按下 Enter 鍵使用預設平台。

本程式碼研究室使用預設平台 (Android、iOS 和網頁),但您也可以只選取一或兩個平台。如果系統提示輸入 iOS 軟體包 ID,請輸入 com.flutter.fcm.fcmflutter 或自己的 iOS 軟體包 ID,格式為 [company domain name].[project name]。指令執行完成後,請重新整理 Firebase 控制台頁面。您會看到系統已在 Firebase 專案中,為所選平台建立應用程式。

Firebase 控制台的螢幕截圖 (已裁剪),顯示所選平台的已建立應用程式

這個指令會在 lib 目錄下產生 firebase_options.dart 檔案,其中包含初始化所需的所有選項。

為 iOS 設定 Cloud Messaging

  1. 前往 Apple 開發人員頁面,然後按一下「金鑰」分頁中的「建立金鑰」

Apple 開發人員頁面的螢幕截圖 (已裁剪),當中醒目顯示用於建立金鑰的頁面元件

  1. 輸入金鑰名稱,然後勾選「Apple 推播通知服務 (APNs)」Apple 開發人員頁面的螢幕截圖 (已裁剪),以方框特別標出新金鑰名稱的文字框
  2. 下載副檔名為 .p8 的金鑰檔案。Apple 開發人員頁面的螢幕截圖 (已裁剪),當中醒目顯示下載金鑰的按鈕
  3. Firebase 控制台中,前往專案的「專案設定」,然後選擇「Cloud Messaging」分頁標籤。

Firebase 控制台頁面的螢幕截圖 (已裁剪),其中醒目顯示用於更新專案設定的元件

Firebase 控制台頁面的螢幕截圖 (已裁剪),並醒目顯示「雲端通訊」分頁

  1. 在「Cloud Messaging」分頁中,上傳 iOS 應用程式的 APNs 金鑰檔案。輸入「Cloud Messaging」分頁中的 APNs 金鑰 ID,以及 Apple 會員中心中的團隊 ID。Firebase 控制台頁面的螢幕截圖 (已裁剪),醒目顯示上傳 APN 驗證金鑰的按鈕

4. 準備 FCM

應用程式必須先完成下列事項,才能接收 FCM 訊息:

  • 初始化 FlutterFire。
  • 要求通知權限。
  • 向 FCM 註冊,即可取得註冊權杖。

初始化

如要初始化服務,請將主要函式 (lib/main.dart) 替換為下列程式碼:

// core Flutter primitives
import 'package:flutter/foundation.dart';
// core FlutterFire dependency
import 'package:firebase_core/firebase_core.dart';
// generated by 
flutterfire configure
import 'firebase_options.dart';
// FlutterFire's Firebase Cloud Messaging plugin
import 'package:firebase_messaging/firebase_messaging.dart';

// TODO: Add stream controller
// TODO: Define the background message handler

Future<void> main() async {
 WidgetsFlutterBinding.ensureInitialized();
 await Firebase.initializeApp(
   options: DefaultFirebaseOptions.currentPlatform,
 );

 // TODO: Request permission
 // TODO: Register with FCM
 // TODO: Set up foreground message handler
 // TODO: Set up background message handler

 runApp(MyApp());
}

接著在 Android Studio 中執行「Tools」->「Flutter」->「Flutter Pub Get」,載入在「設定 FlutterFire」中新增的套件,並在 Android Studio 中顯示適當 Intellisense 設定的程式碼。

這會初始化目前平台 DefaultFirebaseOptions.currentPlatform 的 FlutterFire,並從產生的 firebase_options.dart 檔案匯入。請注意,initializeApp 是非同步函式,而 await 關鍵字可確保初始化作業完成後,再執行應用程式。

要求權限

應用程式必須要求使用者授予接收通知的權限。firebase_messaging 提供的 requestPermission 方法會顯示對話方塊或彈出式視窗,提示使用者允許或拒絕權限。

首先,將這段程式碼複製到註解 TODO: Request permission 下方的主要函式。傳回的 settings 會指出使用者是否已授予權限。建議只在使用者需要使用必須存取權限的功能時,才要求權限 (例如使用者在應用程式設定中開啟通知時)。為簡化流程,我們會在應用程式啟動時要求權限。

final messaging = FirebaseMessaging.instance;

final settings = await messaging.requestPermission(
 alert: true,
 announcement: false,
 badge: true,
 carPlay: false,
 criticalAlert: false,
 provisional: false,
 sound: true,
);

 if (kDebugMode) {
   print('Permission granted: ${settings.authorizationStatus}');
 }

接著,在 Android Studio 工具列中,從目標選取器選取 Chrome (web),然後再次執行應用程式。

Android Studio 工具列的螢幕截圖 (已裁剪),顯示目標選取器和「執行」按鈕

接著,Chrome 分頁會啟動,並顯示要求權限的彈出式視窗。如果您點選 Allow,Android Studio 控制台會顯示記錄:Permission granted: AuthorizationStatus.authorized。允許或封鎖權限要求後,瀏覽器會連同應用程式一併儲存您的回應,因此不會再次顯示彈出式視窗。請注意,在 Android Studio 再次執行網頁應用程式時,系統可能會再次提示您授予權限。Chrome 分頁的螢幕截圖經過裁剪,顯示要求存取麥克風的彈出式視窗。

註冊

將這段程式碼複製到註解 TODO: Register with FCM 下方的主要函式,向 FCM 註冊。getToken 呼叫會傳回註冊權杖,應用程式伺服器或信任的伺服器環境可使用該權杖傳送訊息給使用者。

// It requests a registration token for sending messages to users from your App server or other trusted server environment.
String? token = await messaging.getToken();

if (kDebugMode) {
  print('Registration Token=$token');
}

在 Android Studio 工具列中選取 Android 裝置,然後執行應用程式。Android Studio 控制台會列印出註冊權杖,如下所示:

I/flutter ( 3717): Permission granted: AuthorizationStatus.authorized
I/flutter ( 3717): Registration Token=dch. . . D2P:APA9. . .kbb4

複製到文字編輯器,因為稍後會用來傳送訊息。

uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:firebase_messaging]

在網頁上接收訊息的額外步驟

網路應用程式需要額外執行兩個步驟,才能取得註冊權杖並監聽傳入的訊息。網頁必須將 VAPID 金鑰傳遞至 getToken,才能授權將要求傳送至支援的網頁推播服務。

首先,在 Firebase 控制台中開啟 Firebase 專案的「Cloud Messaging」分頁,然後向下捲動至「Web configuration」(網頁設定) 區段,找出現有的金鑰配對,或產生新的金鑰配對。按一下醒目顯示的按鈕複製金鑰,即可做為 vapidKey 使用。

網頁設定頁面「網路推播憑證」元件的螢幕截圖 (已裁剪),其中醒目顯示金鑰組

接著,請將「Registration」部分中的註冊碼替換成這組程式碼,然後更新 vapidKey:

// TODO: replace with your own VAPID key
 const vapidKey = "<YOUR_PUBLIC_VAPID_KEY_HERE>";

 // use the registration token to send messages to users from your trusted server environment
 String? token;

 if (DefaultFirebaseOptions.currentPlatform == DefaultFirebaseOptions.web) {
   token = await messaging.getToken(
     vapidKey: vapidKey,
   );
 } else {
   token = await messaging.getToken();
 }

 if (kDebugMode) {
   print('Registration Token=$token');
 }

然後,在專案根目錄的 web/ 目錄下方建立 firebase-messaging-sw.js 檔案。將下列內容複製到 firebase-messaging-sw.js,允許網頁應用程式接收 onMessage 事件。詳情請參閱「在 Service Worker 中設定通知選項」。

importScripts("https://www.gstatic.com/firebasejs/9.6.10/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/9.6.10/firebase-messaging-compat.js");

// todo Copy/paste firebaseConfig from Firebase Console
const firebaseConfig = {
 apiKey: "...",
 authDomain: "...",
 databaseURL: "...",
 projectId: "...",
 storageBucket: "...",
 messagingSenderId: "...",
 appId: "...",
};

firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();

// todo Set up background message handler

接著,在「專案設定」->「一般」分頁下方,向下捲動並找到「Web App」,複製 firebaseConfig 程式碼部分,然後貼到 firebase-messaging-sw.jsFirebase 設定頁面中「網頁應用程式」元件的螢幕截圖 (已裁剪)

最後,在 Android Studio 工具列中,選取目標選取器中的 Chrome (web) 並執行應用程式。在 Android Studio 控制台中,註冊權杖會列印出來,如下所示:

Debug service listening on ws://127.0.0.1:61538/BLQQ3Fg-h7I=/ws
Permission granted: AuthorizationStatus.authorized
Registration Token=fH. . .ue:APA91. . .qwt3chpv

將註冊權杖複製到文字編輯器,以便日後用來傳送訊息。

在 iOS 裝置上接收訊息的額外步驟

如要接收 FCM 訊息,iOS 裝置必須在 Xcode 上啟用「推播通知」和「背景模式」

  1. 在 Android Studio 中,以滑鼠右鍵按一下專案名稱,然後依序選取「Flutter」->「Open iOS module in Xcode」裁剪後的螢幕截圖
  2. 啟動 Xcode 後,請在專案目標的「Signing & Capabilities」分頁中,啟用「Push Notifications」和「Background Modes」。詳情請參閱「設定應用程式」。
  3. 在 Android Studio 工具列中,於目標選取器選取 iOS 裝置,然後執行應用程式。授予通知權限後,註冊權杖會列印在 Android Studio 控制台中。

iOS 應用程式要求傳送通知權限的螢幕截圖 (已裁剪)

恭喜,您已成功向 FCM 註冊應用程式。如要接收訊息,請參閱下一節的說明。

5. 接收來自 FCM 的訊息

設定訊息處理常式

應用程式在前景模式下收到訊息時,需要處理 onMessage 事件;在背景模式下收到訊息時,則需要處理 onBackgroundMessage 事件。

前景訊息處理常式

首先,請在檔案 main.dart 的註解 TODO: Add stream controller 後方新增串流控制器,將訊息從事件處理常式傳遞至 UI。

import 'package:rxdart/rxdart.dart';
// used to pass messages from event handler to the UI
final _messageStreamController = BehaviorSubject<RemoteMessage>();

如要新增 rxdart 依附元件,請從專案目錄執行以下指令:flutter pub add rxdart

接著,在 Android Studio 中執行「Tools」->「Flutter」->「Flutter Pub Get」,載入 rxdart.dart 套件,並在 Android Studio 中顯示適當 Intellisense 設定的程式碼。

接著,在註解 TODO: Set up foreground message handler 後新增事件處理常式,監聽前景訊息。這項函式會列印記錄,並將訊息發布至串流控制器。

 FirebaseMessaging.onMessage.listen((RemoteMessage message) {
   if (kDebugMode) {
     print('Handling a foreground message: ${message.messageId}');
     print('Message data: ${message.data}');
     print('Message notification: ${message.notification?.title}');
     print('Message notification: ${message.notification?.body}');
   }

   _messageStreamController.sink.add(message);
 });

接著,請將 main.dart 檔案中的原始 State 小工具替換為下列程式碼,在 State 小工具中新增串流控制器訂閱者,並在小工具上顯示最後一則訊息。

class _MyHomePageState extends State<MyHomePage> {
 String _lastMessage = "";

 _MyHomePageState() {
   _messageStreamController.listen((message) {
     setState(() {
       if (message.notification != null) {
         _lastMessage = 'Received a notification message:'
             '\nTitle=${message.notification?.title},'
             '\nBody=${message.notification?.body},'
             '\nData=${message.data}';
       } else {
         _lastMessage = 'Received a data message: ${message.data}';
       }
     });
   });
 }

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text(widget.title),
     ),
     body: Center(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         children: <Widget>[
           Text('Last message from Firebase Messaging:',
               style: Theme.of(context).textTheme.titleLarge),
           Text(_lastMessage, style: Theme.of(context).textTheme.bodyLarge),
         ],
       ),
     ),
   );
 }
}

Android/iOS 的背景訊息處理常式

應用程式在背景執行時,訊息會由 onBackgroundMessage 處理常式處理。處理常式應為頂層函式。應用程式移至前景時,您可以處理訊息 (請參閱「處理互動」) 或與應用程式伺服器同步,藉此更新 UI。

在主要函式外部的註解 TODO: Define the background message handler 後方建立處理常式函式,並在主要函式中的註解 TODO: Set up background message handler 後方呼叫該函式。

// TODO: Define the background message handler
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
 await Firebase.initializeApp();

 if (kDebugMode) {
   print("Handling a background message: ${message.messageId}");
   print('Message data: ${message.data}');
   print('Message notification: ${message.notification?.title}');
   print('Message notification: ${message.notification?.body}');
 }
}

void main() {
 ...

 // TODO: Set up background message handler
 FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

 runApp(MyApp());
}

網頁的背景訊息處理常式

自 FlutterFire firebase_messaging 11.2.8 版起,在網頁平台處理背景訊息時,需要使用不同的流程。因此,您需要在 Service Worker web/firebase-messaging-sw.js 中新增個別的訊息處理常式。

messaging.onBackgroundMessage((message) => {
 console.log("onBackgroundMessage", message);
});

設定應用程式伺服器

  1. 在 Android Studio 中開啟 https://github.com/FirebaseExtended/firebase_fcm_flutter/tree/main/server 專案,匯入範例伺服器程式碼。伺服器是以 Gradle 為基礎的 Java 專案,並依附於 firebase-admin SDK,提供 FCM 訊息傳送功能。
  2. 設定 Firebase 服務帳戶,讓 Firebase Admin SDK 授權呼叫 FCM API。在 Firebase 控制台中開啟「專案設定」,然後選取「服務帳戶」分頁標籤。選擇「Java」,然後按一下 Generate new private key 下載設定程式碼片段。螢幕截圖 (已裁剪):醒目顯示專案設定頁面「服務帳戶」元件的 Admin SDK 設定程式碼片段
  3. 將檔案重新命名為 service-account.json,並複製到伺服器專案的 src/main/resources 路徑。

傳送測試訊息

FcmSender.java 檔案中,sendMessageToFcmRegistrationToken 會編寫含有資料酬載的通知訊息。註冊權杖會指定訊息傳送的應用程式例項。

private static void sendMessageToFcmRegistrationToken() throws Exception {
   String registrationToken = "REPLACE_WITH_FCM_REGISTRATION_TOKEN";
   Message message =
       Message.builder()
           .putData("FCM", "https://firebase.google.com/docs/cloud-messaging")
           .putData("flutter", "https://flutter.dev/")
           .setNotification(
               Notification.builder()
                   .setTitle("Try this new app")
                   .setBody("Learn how FCM works with Flutter")
                   .build())
           .setToken(registrationToken)
           .build();

   FirebaseMessaging.getInstance().send(message);

   System.out.println("Message to FCM Registration Token sent successfully!!");
 }
  1. 複製「註冊」部分中的 Android 註冊權杖,然後貼到 registrationToken 變數的值。
  2. 按一下「執行」 Android Studio 中的執行按鈕,執行主要函式並透過 FCM 將訊息傳送給使用者。螢幕截圖經過裁剪,顯示 Android Studio 中 FcmSender.java 主要函式旁的「執行」圖示

Android 應用程式在背景執行時,訊息會顯示在通知匣中。

Android 通知匣中顯示訊息的螢幕截圖 (已裁剪)

Android 應用程式在前台執行時,Android Studio 控制台會顯示「Handling a foreground message」記錄。由於 UI 訂閱了新訊息的串流控制器,因此 UI 中也會顯示訊息內容。

Android 應用程式中顯示的訊息內容螢幕截圖 (已裁剪)

如果您貼上註冊權杖,並從應用程式伺服器或其他受信任的伺服器環境傳送訊息,也會看到類似行為:

  • 如果網頁應用程式在背景執行 (也就是說,網頁應用程式遭到其他視窗隱藏,或另一個分頁處於啟用狀態),您會看到網頁通知。

Chrome 瀏覽器顯示的網頁通知 (已裁剪)

  • 當網頁應用程式位於前景時,你可以對著網頁按一下滑鼠右鍵,然後選取 Inspect,在 Chrome 控制台中查看記錄。UI 中也會顯示訊息內容。Chrome 控制台的螢幕截圖 (已裁剪),顯示偵錯記錄

6. 傳送主題訊息

FCM HTTP v1 API 的平台覆寫功能可讓訊息傳送要求在不同平台上有不同行為。這項功能可用於根據平台顯示不同的通知訊息內容。如果使用主題訊息指定多部裝置 (可能涵蓋多個平台),就能充分發揮這項功能的作用。本節將逐步說明如何讓應用程式接收針對各平台自訂的主題訊息。

訂閱用戶端的主題

如要訂閱主題,請在 Flutter 應用程式的 main.dart 檔案中,於 main 函式結尾呼叫 messaging.subscribeToTopic 方法。

// subscribe to a topic.
const topic = 'app_promotion';
await messaging.subscribeToTopic(topic);

[選用] 從伺服器訂閱網頁主題

如果您不是在網頁平台上開發,可以略過這個部分。

FCM JS SDK 目前不支援用戶端主題訂閱。您可以改用 Admin SDK 的伺服器端主題管理 API 訂閱。這段程式碼說明如何使用 Java Admin SDK 訂閱伺服器端主題。

 private static void subscribeFcmRegistrationTokensToTopic() throws Exception {
   List<String> registrationTokens =
       Arrays.asList(
           "REPLACE_WITH_FCM_REGISTRATION_TOKEN"); // TODO: add FCM Registration Tokens to
   // subscribe
   String topicName = "app_promotion";

   TopicManagementResponse response =     FirebaseMessaging.getInstance().subscribeToTopic(registrationTokens, topicName);
   System.out.printf("Num tokens successfully subscribed %d", response.getSuccessCount());
 }

開啟應用程式伺服器,然後按一下「執行」 Android Studio 中的執行按鈕,在 FcmSubscriptionManager.java 檔案中執行主要函式:

螢幕截圖經過裁剪,顯示 Android Studio 中 FcmSubscriptionManager.java 主要函式旁的「執行」圖示

將訊息連同平台覆寫內容傳送至主題

現在可以傳送主題平台覆寫訊息。在下列程式碼片段中:

  • 您可以使用基本訊息和「A new app is available」標題建構傳送要求。
  • 在 iOS 和網頁平台上,這則訊息會產生標題為「A new app is available」的顯示通知。
  • 這則訊息會在 Android 裝置上產生顯示通知,標題為「A new Android app is available」。
private static void sendMessageToFcmTopic() throws Exception {
   String topicName = "app_promotion";

   Message message =
       Message.builder()
           .setNotification(
               Notification.builder()
                   .setTitle("A new app is available")
                   .setBody("Check out our latest app in the app store.")
                   .build())
           .setAndroidConfig(
               AndroidConfig.builder()
                   .setNotification(
                       AndroidNotification.builder()
                           .setTitle("A new Android app is available")
                           .setBody("Our latest app is available on Google Play store")
                           .build())
                   .build())
           .setTopic("app_promotion")
           .build();

   FirebaseMessaging.getInstance().send(message);

   System.out.println("Message to topic sent successfully!!");
 }

FcmSender.java 檔案的主要函式中,取消註解 sendMessageToFcmTopic();。按一下「執行」 Android Studio 中的執行按鈕 即可傳送主題訊息。

7. 摘要與後續步驟

總而言之,您已瞭解如何使用 Flutter 和 FCM 開發多平台應用程式,包括設定環境、整合依附元件,以及接收和傳送訊息。如要深入瞭解,請參閱下列資料:

程式碼研究室

參考資料