Flutter(六):Flutter_Boost接入現有原生工程(iOS+Android)

来源:https://www.cnblogs.com/anywherego/archive/2022/10/10/16776393.html
-Advertisement-
Play Games

一、新建原生工程和Flutter Module 1、新建Android工程 搭建一個空的Android工程FlutterDemo_Android模擬已經存在的原有工程 Android項目配置: 2、新建iOS工程 搭建一個空的iOS工程FlutterDemo_iOS模擬已經存在的原有工程 Xcode ...


一、新建原生工程和Flutter Module

1、新建Android工程

搭建一個空的Android工程FlutterDemo_Android模擬已經存在的原有工程
Android項目配置:

2、新建iOS工程

搭建一個空的iOS工程FlutterDemo_iOS模擬已經存在的原有工程
Xcode項目配置

搭建Pod:
在工程目錄下執行

pod init
pod install

3、新建Flutter Module

這裡使用AndroidStudio做Flutter開發環境

3.1 AndroidStudio添加Flutter插件

3.2 新建Flutter Module

第一步:File -> New Flutter Project

第二步:選擇Flutter

第三步:配置Flutter Module

flutter_demo_module

完成目錄結構

二、Flutter Boost 配置

1、Flutter_Module工程

1.修改pubspec.yaml文件:

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2

  # add
  flutter_boost:  
    git:
      url: 'https://github.com/alibaba/flutter_boost.git'
      ref: '4.1.0'

然後執行flutter pub get下載flutter_boost到module中

2.新增willpop.dart頁面做為跳轉目標頁

import 'package:flutter/material.dart';

class WillPopRoute extends StatefulWidget {
  const WillPopRoute({Key? key, this.title}) : super(key: key);

  final String? title;

  @override
  State<StatefulWidget> createState() => _WillPopRouteState();
}

class _WillPopRouteState extends State<WillPopRoute> {
  bool shouldPop = true;
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        return shouldPop;
      },
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter Demo'),
        ),
      ),
    );
  }
}

3.修改main.dart文件,配置頁面路由

import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter_demo_module/willpop.dart';

void main() {
  CustomFlutterBinding();
  runApp(const MyApp());
}

class CustomFlutterBinding extends WidgetsFlutterBinding
    with BoostFlutterBinding {}


class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
    // 配置路由
  static Map<String, FlutterBoostRouteFactory> routerMap = {
    'flutterPage': (settings, uniqueId) {
      return PageRouteBuilder<dynamic>(
          settings: settings, pageBuilder: (_, __, ___) => const WillPopRoute());
    }
  };

  Route<dynamic>? routeFactory(RouteSettings settings, String? uniqueId) {
    FlutterBoostRouteFactory? func = routerMap[settings.name!];
    if (func == null) {
      return null;
    }
    return func(settings, uniqueId);
  }

  @override
  void initState() {
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return FlutterBoostApp(routeFactory);
  }

}

2、Android跳轉Flutter:

1.setting.gralde添加:

setBinding(new Binding([gradle: this]))
evaluate(new File(
        settingsDir.parentFile,
        'flutter_demo_module/.android/include_flutter.groovy'
))
include ':flutter_demo_module'
project(':flutter_demo_module').projectDir = new File('../flutter_demo_module')

註意:new Binding([gradle: this])會有紅色提示,不用管

2.app的AndroidManifest添加:

<activity
    android:name="com.idlefish.flutterboost.containers.FlutterBoostActivity"
    android:theme="@style/Theme.AppCompat"
    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
    android:hardwareAccelerated="true"
    android:windowSoftInputMode="adjustResize" >

</activity>
<meta-data android:name="flutterEmbedding"
    android:value="2">
</meta-data>

註意這一步之後執行gradle sync,如果遇到問題,可以參考文章最後的問題集錦

3.FlutterBoost初始化

自定義Application

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        FlutterBoost.instance().setup(this, object : FlutterBoostDelegate {
            override fun pushNativeRoute(options: FlutterBoostRouteOptions) {
                // 原生跳轉
            }

            override fun pushFlutterRoute(options: FlutterBoostRouteOptions) {
                // Flutter跳轉
            }
        }, FlutterBoost.Callback { engine: FlutterEngine? -> })
    }
}

配置app的AndroidManifest

<application
        android:name=".MyApp"
        ...
</application>

4.Android跳轉代碼

val params: Map<String, Any> = HashMap()
val intent: Intent = FlutterBoostActivity.CachedEngineIntentBuilder(
    FlutterBoostActivity::class.java
)
    .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.opaque)
    .destroyEngineWithActivity(false)
    .url("flutterPage")
    .urlParams(params)
    .build(context)
startActivity(intent)

3、iOS跳轉Flutter:

1.修改Pod文件

step1. load file

flutter_application_path = '../flutter_demo_module'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

step2. install function

install_all_flutter_pods(flutter_application_path)

step3 post_install

post_install do |installer|
  flutter_post_install(installer) if defined?(flutter_post_install)
end

完整pod文件

# Flutter Module Path
# step1 load file
flutter_application_path = '../flutter_demo_module'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

target 'FlutterDemo_iOS' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!
  
  # step2 install function
  install_all_flutter_pods(flutter_application_path)
end

# step3 post_install
post_install do |installer|
  flutter_post_install(installer) if defined?(flutter_post_install)
end

執行pod install,podhelper.rb 腳本會把你的 plugins, Flutter.framework,和 App.framework 集成到你的項目中。

備註:
Flutter.framework 是 Flutter engine 的框架, App.framework 是你的 Dart 代碼的編譯產物。

2.添加Delegate

定義FlutterDelegate

import UIKit
import Flutter
import flutter_boost
import FlutterPluginRegistrant


class MyBoostAppDelegate: NSObject,FlutterBoostDelegate {
    
    static let shared = MyBoostAppDelegate()

    ///您用來push的導航欄
    var navigationController:UINavigationController?

    ///用來存返回flutter側返回結果的表
    var resultTable:Dictionary<String,([AnyHashable:Any]?)->Void> = [:];

    func pushNativeRoute(_ pageName: String!, arguments: [AnyHashable : Any]!) {

        //可以用參數來控制是push還是pop
        let isPresent = arguments["isPresent"] as? Bool ?? false
        let isAnimated = arguments["isAnimated"] as? Bool ?? true
        //這裡根據pageName來判斷生成哪個vc,這裡給個預設的了
        let targetViewController = UIViewController()

        if(isPresent){
            self.navigationController?.present(targetViewController, animated: isAnimated, completion: nil)
        }else{
            self.navigationController?.pushViewController(targetViewController, animated: isAnimated)
        }
    }

    func pushFlutterRoute(_ options: FlutterBoostRouteOptions!) {
        let vc:FBFlutterViewContainer = FBFlutterViewContainer()
        vc.setName(options.pageName, uniqueId: options.uniqueId, params: options.arguments,opaque: options.opaque)

        //用參數來控制是push還是pop
        let isPresent = (options.arguments?["isPresent"] as? Bool)  ?? false
        let isAnimated = (options.arguments?["isAnimated"] as? Bool) ?? true

        //對這個頁面設置結果
        resultTable[options.pageName] = options.onPageFinished;

        //如果是present模式 ,或者要不透明模式,那麼就需要以present模式打開頁面
        if(isPresent || !options.opaque){
            self.navigationController?.present(vc, animated: isAnimated, completion: nil)
        }else{
            self.navigationController?.pushViewController(vc, animated: isAnimated)
        }
    }

    func popRoute(_ options: FlutterBoostRouteOptions!) {
        //如果當前被present的vc是container,那麼就執行dismiss邏輯
        if let vc = self.navigationController?.presentedViewController as? FBFlutterViewContainer,vc.uniqueIDString() == options.uniqueId{

            //這裡分為兩種情況,由於UIModalPresentationOverFullScreen下,生命周期顯示會有問題
            //所以需要手動調用的場景,從而使下麵底部的vc調用viewAppear相關邏輯
            if vc.modalPresentationStyle == .overFullScreen {

                //這裡手動beginAppearanceTransition觸發頁面生命周期
                self.navigationController?.topViewController?.beginAppearanceTransition(true, animated: false)

                vc.dismiss(animated: true) {
                    self.navigationController?.topViewController?.endAppearanceTransition()
                }
            }else{
                //正常場景,直接dismiss
                vc.dismiss(animated: true, completion: nil)
            }
        }else{
            self.navigationController?.popViewController(animated: true)
        }
        //否則直接執行pop邏輯
        //這裡在pop的時候將參數帶出,並且從結果表中移除
        if let onPageFinshed = resultTable[options.pageName] {
            onPageFinshed(options.arguments)
            resultTable.removeValue(forKey: options.pageName)
        }
    }
}

修改AppDelegate

import UIKit
import flutter_boost

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
       
        //創建代理,做初始化操作
        let delegate = MyBoostAppDelegate.shared
        FlutterBoost.instance().setup(application, delegate: delegate) { engine in

        }
        return true
    }
}

跳轉Flutter頁面代碼

    @IBAction func clickButton(_ sender: Any) {
        MyBoostAppDelegate.shared.navigationController = self.navigationController
        let options = FlutterBoostRouteOptions()
        options.pageName = "flutterPage"
        FlutterBoost.instance().open(options)
    }

問題集錦

1.Android導入Flutter Module報錯Failed to apply plugin class ‘FlutterPlugin’

setting.gradle修改Model值為RepositoriesMode.PREFER_PROJECT

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
    repositories {
        google()
        mavenCentral()
    }
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • MGR 的新主選舉演算法,在節點版本一致的情況下,其實也挺簡單的。 首先比較權重,權重越高,選為新主的優先順序越高。 如果權重一致,則會進一步比較節點的 server_uuid。server_uuid 越小,選為新主的優先順序越高。 所以,在節點版本一致的情況下,會選擇權重最高,server_uuid 最 ...
  • Hadoop是Apache基金會旗下最知名的基礎架構開源項目之一。自2006年誕生以來,逐步發展成為海量數據存儲、處理最為重要的基礎組件,形成了非常豐富的技術生態。 作為國內頂尖的 Hadoop 開源生態技術峰會,第四屆 China Apache Hadoop Meetup於 2022年9月24日在 ...
  • 點亮 ⭐️ Star · 照亮開源之路 GitHub:https://github.com/apache/dolphinscheduler ​ 版本發佈 感謝本次的 Release Manager --@zhuangchong,是他主導了我們這個版本的發佈流程,引導社區進行版本內容溝通,發版前的問題 ...
  • 摘要:GaussDB(DWS) 中鎖等待可以設置等待超時相關參數,一旦等鎖的時間超過參數配置值會拋錯。 本文分享自華為雲社區《GaussDB(DWS) 鎖相關參數及視圖詳解》,作者: yd_220527686。 一、鎖相關參數 GaussDB(DWS) 中鎖等待可以設置等待超時相關參數,一旦等鎖的時 ...
  • 先說一下為什麼需要備份MySQL數據? 一句話總結就是:為了保證數據的安全性。 如果我們把數據只存儲在一個地方,如果物理機器損壞,會導致數據丟失,無法恢復。 還有就是我們每次手動修改線上數據之前,為了安全起見,都需要先備份數據。防止人為的誤操作,導致弄髒數據或弄丟數據。 ...
  • MatrixOne從入門到實踐——物聯網平臺架構升級 公司介紹 西安天能軟體科技有限責任公司,成立於2018年,公司自成立起集中力量精心打造物聯網平臺,擁有集自主研發、終端生產、銷售、服務一體的物聯網平臺及服務團隊,已為國內外300多家物聯網企業、千萬級物聯網設備提供合作支持。 公司在物聯網領域擁有 ...
  • 在應用開發的早期,數據量少,開發人員開發功能時更重視功能上的實現,隨著生產數據的增長,很多SQL語句開始暴露出性能問題,對生產的影響也越來越大,有時可能這些有問題的SQL就是整個系統性能的瓶頸。 ...
  • [Android開發學iOS系列] iOS寫UI的幾種方式 作為一個現代化的平臺, iOS的發展也經歷了好幾個時代. 本文講講iOS寫UI的幾種主要方式和各自的特點. iOS寫UI的方式 在iOS中寫UI有多種選擇, 大的分類: 使用UIKit還是SwiftUI. 在使用UIKit的情形下, 還根據 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...