【文章內容使用 Gemini 1.5 Pro 自動產生】
將 Flutter 加入現有的 iOS 和 Android 程式碼庫

無論您是為小型代理商工作,為眾多客戶建立行動應用程式,還是為擁有數百個內部應用程式的龐大企業開發,支援多個程式碼庫都可能很困難且昂貴(如果真的要做到)。我們驚訝地發現,一個常見的場景是,一些公司有數十甚至數百個應用程式是用於一個主要的行動平台,但沒有為另一個平台開發。這會讓他們許多使用者(通常是員工)無法像其他人一樣高效地執行相同的任務,從而可能導致價值流失。
Flutter 是一個可以從單一程式碼庫支援多個平台的 UI 架構,它可以幫助解決這些問題。雖然在理想情況下,您可以使用 Flutter 從頭開始建立應用程式,但當公司已經投入時間和金錢開發一個或多個平台的應用程式時,這個計劃通常行不通。
在本教程中,我們將透過學習稱為 add-to-app 的功能,探討一種更務實的方法,即隨著時間推移逐步將現有的 iOS 或 Android 應用程式轉換為 Flutter。雖然此功能並不能立即為您提供完整的 Flutter 應用程式,但它允許您在轉換過程中保持與當前程式碼庫的功能一致性和穩定性,而不是需要完整的重構,而重構可能會充滿意想不到的問題和「陷阱」。
在我們逐步完成本教程時,我們將從一個簡單的基本案例應用程式開始,與您期望從「你好,世界!」範例中得到的結果類似,適用於 iOS 和 Android,而不是加入已經存在的實際應用程式的複雜性。之後,我們將建立將為每個平台新增新視圖(用 Flutter 編寫)所需的基礎架構。在實作 add-to-app 時,預期您已經具備一些 Flutter 的經驗,但本教程盡可能保持簡單,以便專注於如何將 Flutter 加入非 Flutter 應用程式。透過這種方式,您最終將擁有必要的詞彙,並知道在您準備好自己嘗試時該去哪裡尋找。
讓我們開始進行吧!
Flutter 安裝
如果您尚未在電腦上安裝 Flutter SDK,現在正是時候。請按照 此連結 中的說明來設定您的機器。我會在這裡等您:) 如果你想在沒有跟著做的情況下繼續閱讀,那也是完全可以的。
…
都準備好了嗎?太棒了!
因此,將 Flutter 加入現有應用程式的第一步是,毫不意外地,建立一個要加入應用程式的 Flutter 元件。從命令列介面,導航到您想要儲存 Flutter 模組的目錄,並使用 Flutter CLI 工具執行以下命令:
1 | flutter create --template module add_to_app_flutter_module |

這會建立一個基本 Flutter 應用程式並將其放置在一個名為 add_to_app_flutter_module 的新目錄中,不過您可以隨意為模組命名 - 本教程假設您使用的是 add_to_app_flutter_module 名稱。
iOS 安裝
通常,在實作 add-to-app 功能時,您已經有現有的 iOS 或 Android 應用程式。在本教程中,您將從頭開始建立新的應用程式,以便專注於實作基礎。您將從 Xcode 中建立一個全新的 iOS 應用程式開始。如果您沒有使用 Mac 電腦或為 iOS 開發,請隨時跳到 Android 部分,或繼續閱讀以了解此過程。我只會有點失望您沒有閱讀全部內容。啟動 Xcode。當出現第一個選項螢幕時,選擇 App 並點擊 Next。

在下一頁,適當地填寫文字欄位。在本教程中,使用 Storyboard 介面、Swift 作為語言,以及 UIKit App Delegate 作為生命週期。

此時,系統會提示您在電腦上的某個位置建立一個新的目錄,並將您的應用程式放置到其中。在本教程中,將新的 iOS 專案資料夾儲存在與您之前建立的 Flutter 模組相同的父目錄中。建立該目錄後,您將進入 Xcode 專案螢幕,資料夾結構類似於此:

回到命令列,導航到您在上一步中建立的新的 iOS 專案目錄,並使用以下命令初始化 CocoaPods:
1 | pod init |
初始化 Podfile 後,從 CLI 打開它,並將其內容替換為以下內容(請記住將目標名稱從 Add-to-App 更改為反映您自己的應用程式名稱,並將 flutter_application_path 更改為與 Flutter 模組的路徑匹配,如果您使用的是不同的值):
更新 Podfile 後,儲存檔案並執行以下命令將 Flutter 模組連結到新的 iOS 專案:
1 | pod install |
從 iOS 應用程式打開預設 Flutter 頁面
現在 Flutter 模組和 iOS 專案已連結,是時候學習如何從 iOS ViewController 導航到行動應用程式中的 Flutter 頁面了。首先打開 AppDelegate.swift 檔案,將類別設定為繼承 FlutterAppDelegate 而不是預設的 UIAppDelegate。您還想定義一個新的 FlutterEngine 物件,它是用於橋接原生 iOS 應用程式和 Flutter 類別的 Flutter 環境容器:
要完成 simpleFlutterAppDelegate 類別,請建立一個新的應用程式函數,在啟動 iOS 應用程式時註冊 FlutterEngine:
在 AppDelegate 類別中,您只需要執行這些操作(暫時如此)。要啟動預設的 Flutter 螢幕,請轉到專案的 ViewController.swift 檔案(不過,在更完善的應用程式中,您可以使用任何 ViewController)。新增一個名為 showFlutter() 的函數,該函數會擷取 FlutterEngine,並使用預設的 Flutter 輸入點建立一個新的 FlutterViewController 物件,然後顯示它:
接下來,您需要一種方法來呼叫該函數。為簡單起見,直接在 Swift 程式碼中為螢幕定義一個按鈕,不過您可以使用任何適合您的其他導航模式或技術。在本教程中,建立一個新的 UIButton,將其置於螢幕中間,將新的 showFlutter() 函數指定給按鈕的動作,然後將其附加到視圖,所有這些都來自 viewDidLoad() 生命週期函數:
現在嘗試執行應用程式。如果一切按預期進行(祈禱吧!),那麼您應該能夠啟動 iOS 應用程式,點擊 顯示 Flutter! 按鈕,然後觀看新的 Flutter 螢幕彈出:

Android 安裝
現在您已經使 iOS/Flutter 組合正常運作,是時候嘗試設定 Android 應用程式了。就像您對 iOS 專案所做的那樣,建立一個新的 Android 專案,並在第一個螢幕上選擇 基本活動 模板。

在下一頁,為名稱和套件名稱填寫適當的資訊。為了使一切與此範例的 iOS 版本保持一致,請將您的專案儲存在與 Flutter 模組和 iOS 應用程式相同的父目錄下。您還需要確保在本教程中將專案的語言設定為 Kotlin,儘管相同 add-to-app 邏輯適用於使用 Java 編寫的 Android 應用程式。準備好後,點擊藍色的 完成 按鈕。

現在您有了基礎 Android 專案,新增您之前建立的 Flutter 模組。您可以透過轉到 檔案 -> 新建 -> 新模組… 來完成此操作。

從那裡,轉到新視窗底部的 匯入 Flutter 模組 選項,加入 Flutter 模組位置,然後點擊藍色的 完成 按鈕。

接下來,打開 settings.gradle 檔案,並將其內容替換為以下內容:
這裡主要的部分是綁定並將 include_flutter.groovy 檔案加入到專案中。完成後,轉到專案級別的 build.gradle 檔案(位於 Android 專案的根目錄中),新增一個 allprojects 區塊,以便您可以編譯應用程式(這可能在以後不需要,但我遇到了 Android Studio Arctic Fox 的問題,因此我在這裡寫下來,以防有人用得上:))
最後,打開 應用程式級別 的 build.gradle 檔案(位於 your_project_name/app 目錄中),並在 dependencies 節點中新增一行,以將 Flutter 模組作為來源加入到 Android 專案中:
此時,Android 應用程式應該可以編譯和建構,而且您會在 IDE 中看到 Flutter 模組。

從 Android 應用程式打開預設 Flutter 頁面
現在 Android 應用程式的安裝過程已完成,您需要準備好使用新的 Flutter 元件來啟動應用程式。幸運的是,現在安裝已完成,因此這相對容易。首先打開 AndroidManifest.xml 檔案。Flutter add-to-app 使用自訂 FlutterActivity 在 Android 中顯示 Flutter 內容,因此您需要確保在清單中宣告 FlutterActivity,方法是在 application 標籤內新增以下區塊:
接下來,打開 MainActivity.kt 檔案,並將應用程式 FloatingActionButton 顯示的 Snackbar 替換為以下程式碼,以啟動新的 FlutterActivity。
現在,當您點擊 FloatingActionButton 時,您應該會看到 Flutter 頁面直接在您的應用程式中彈出!

除了能夠啟動完整的活動螢幕(類似於您之前在 iOS 中所做的),Android 的額外好處是能夠將 Flutter 元件作為 Fragment 或自訂視圖的一部分來啟動。雖然這兩種技術超出了本教程的範圍,但您可以在官方文件找到如何使用 FlutterFragment 和 FlutterView。
開啟其他 Flutter 螢幕
雖然能夠直接從原生 iOS 或 Android 應用程式開啟 Flutter 螢幕很棒,但考慮到使用 add-to-app 的整個想法是您可以慢慢地實作各種 Flutter 功能,因此 它實際上並沒有達到您想要的程度。要做到這一點,您很可能需要多個輸入點和多個 Flutter 元件。幸運的是,有一種方法可以在原生應用程式中建立多個 Flutter 實例,不過值得注意的是,在撰寫本文時,此功能 處於實驗階段。雖然表面層面的東西很有可能保持不變,但也可能語法或其他細節會在日後發生變化。
首先,透過打開 flutter 模組/lib 目錄中的 main.dart,更新 Flutter 模組中的程式碼以支援第二個螢幕。在 main.dart 中,透過在 main() 的宣告下方新增以下幾行,宣告您的第一個新的輸入點。請注意,此程式碼片段包含一個註釋,將此方法指定為應用程式中的新輸入點。
MySecondAppScreen 只會返回一個具有綠色主題和新標題的新 MaterialApp,以便您可以區分它和 main() 輸入點。
接下來,您可能會注意到您需要為 MySecondaryHomePage 建立另一個程式碼塊。這是一個新的 StatefulWidget,它包含 Flutter 螢幕的狀態物件。
最後,建立新的狀態物件。在本範例中,Widget 會顯示 AppBar 和 Text Widget。
您現在有兩個不同的 Flutter 螢幕可以從原生應用程式啟動。接下來,您將在現有的 Android 範例應用程式中實作新螢幕。
Android 中的多個 Flutter 輸入點
此擴展的 add-to-app 功能透過建立 FlutterEngine 類別的多個實例(與用於顯示單一預設 Flutter 螢幕的工具相同)並將它們儲存在 FlutterEngineGroup 中來執行,然後在需要時呼叫適當的引擎。首先,建立一個新的應用程式類別來初始化 FlutterEngineGroup。
接下來,建立一個輔助類別,在本例中名為 EngineBindings,它會接收輸入點的名稱,並將其懶加載到 FlutterEngineGroup 中,以便可以在原生應用程式中顯示它。這是懶加載的,因為您需要確保應用程式已完全載入,然後再開始建立 FlutterEngine,否則您可能會遇到意想不到的(且難以除錯)競爭條件。
您需要加入的最後一個類別會擴展您在上一節 Android 中使用的 FlutterActivity。建立一個名為 SingleFlutterActivity.kt 的新的 Kotlin 類別檔案,它會擴展 FlutterActivity:
在此檔案中,透過傳入新的輸入點名稱(在本例中為 “secondary”)來初始化 EngineBindings,以匹配您在 Dart 檔案中新增的輸入點的名稱,並為擷取適當的引擎撰寫一個輔助方法:
要完成 FlutterActivity,請使用新建立的引擎從 onCreate()
顯示 Flutter 螢幕。
接下來,您只需要再做幾件事就能完成此範例應用程式。回到 MainActivity,轉到原本用於啟動主要 Flutter 螢幕的 FloatingActionButton,並更改 Intent,使其啟動新的 SingleFlutterActivity 類別。
最後,打開 AndroidManifest.xml,將新的應用程式類別與 application 標籤關聯起來,並新增 SingleFlutterActivity 的活動標籤。
您現在應該能夠執行應用程式,點擊 FloatingActionButton,並看到新的螢幕,而不是預設的 Flutter Widget。

iOS 中的多個 Flutter 輸入點
您還在嗎?太好了!
接下來,您將在 iOS 範例應用程式中新增對多個輸入點的支援。回到 Xcode,打開 AppDelegate 類別,並將所有程式碼替換為這個簡化的版本,它會建立一個單一的 FlutterEngineGroup,可以在整個應用程式中訪問。
類似於您在 Android 應用程式中所做的,建立一個名為 SingleFlutterViewController.swift 的新檔案,它會擴展標準的 FlutterViewController。此類別會接收一個包含您想要使用的輸入點名稱的字串,然後建立並顯示一個新的 FlutterEngine。
最後,返回基礎 ViewController 類別,並更新 showFlutter() 函數,以便它使用指定的輸入點顯示新的 SingleFlutterViewController 類別。
更新完程式碼後,更新 Podfile 以使用 Flutter 模組的最新版本,因為您已將新的輸入點和螢幕程式碼新增到 main.dart 中。完成後,您應該能夠建構和執行 iOS 應用程式,以查看您的原生程式碼切換到新的 Flutter 元件。

總結
嘿,您做到了!恭喜!
在本教程中,您學習了如何將 Flutter 逐步新增到現有的 Android 和 iOS 應用程式中,以建立一個統一且更易於維護的程式碼庫。您已經了解了如何在兩個平台上從單一輸入點新增 Flutter,以及如何建立多個輸入點。如果您有興趣了解更多資訊,我在下方包含了一個連結,連結到 Flutter 的官方文件頁面,該頁面提供了有關 add-to-app 的更多細節資訊,以及討論 平台通道 的連結,平台通道允許您在 Flutter 和原生級別程式碼之間來回通訊。最後,請查看討論 Plugin 和如何撰寫自己的 Plugin 的連結,這些連結可以讓使用 Flutter 為多個平台開發變得更容易,無論是對您還是對開發人員社群。
我們期待看到您的跨平台應用程式實際運作!
將 Flutter 加入現有的 iOS 和 Android 程式碼庫 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。