В моей компании мы постепенно переносим наши собственные приложения на Flutter. На данный момент Flutter встроен как модуль в собственные приложения. Чтобы ускорить процесс и избавиться от нативных проектов, мы пытаемся показать оставшиеся нативные экраны через представление платформы Flutter и переписать их позже.
Итак, в качестве теста я запустил побочный проект, и из приложения Flutter показано, что собственный экран iOS довольно прост, и все работает так, как ожидалось. Итак, теперь я делаю то же самое в нашем собственном проекте приложения (с flutter в качестве модуля), но при навигации по представлению платформы я получаю ошибку платформы в Xcode:
flutter: [MAIN] -> PlatformDispatcher.instance.onError
Есть ли принципиальная разница в регистрации вещей в двух подходах??
Большое спасибо за ваше время и помощь. Это файлы из стороннего проекта. AppDelegate:
импортировать UIKit импортировать флаттер @UIApplicationMain @objc класс AppDelegate: FlutterAppDelegate { // определяем каналы метода вар методChannel: FlutterMethodChannel? вар NativeViewerPlatformCahannel: FlutterMethodChannel? переопределить приложение func( _ приложение: UIApplication, DidFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Бул { // создаем экземпляр корневого vc как флаттер vc пусть контроллер: FlutterViewController = окно?.rootViewController как! Флаттервиевконтроллер; // инициализируем каналы метода MethodChannel = FlutterMethodChannel (имя: «test_platform_channel»,binaryMessenger: контроллер.binaryMessenger); NativeViewerPlatformCahannel = FlutterMethodChannel (имя: «native_viewer_platform_channel»,binaryMessenger: контроллер.binaryMessenger); // канал метода тестирования MethodChannel?.invokeMethod("swift_to_flutter", аргументы: ["Создан экземпляр канала метода AppDelegate"]); // устанавливаем обработчик вызова метода self.methodChannel?.setMethodCallHandler({ //[слабое я] (вызов: FlutterMethodCall, результат: @escaping FlutterResult) -> Пустота в self.methodChannel?.invokeMethod("swift_to_flutter", аргументы: ["Создан экземпляр обработчика вызова метода AppDelegate"]); переключатель (вызов.метод) { случай «тест»: self.methodChannel?.invokeMethod("swift_to_flutter", аргументы: ["Обработчик вызова метода AppDelegate: получен вызов тестового метода"]); по умолчанию: Распечатать("") } }) GeneratedPluginRegistrant.register(с: self); // MARK: NATIVE в настройке Flutter слабый регистратор var = self.registrar(forPlugin: "имя-плагина"); let Factory = DynamicNativeViewFactory(messenger: registrar!.messenger()) self.registrar(forPlugin: "")!.register( фабрика, withId: "") вернуть super.application(application, DidFinishLaunchingWithOptions: launchOptions) } } Завод:
импортировать Flutter импортировать UIKit класс DynamicNativeViewFactory: NSObject, FlutterPlatformViewFactory { частный мессенджер var: FlutterBinaryMessenger init (мессенджер: FlutterBinaryMessenger) { self.messenger = мессенджер супер.инит() } функция создания( рамка withFrame: CGRect, viewIdentifier viewId: Int64, аргументы args: Есть? ) -> FlutterPlatformView { print("DynamicNativeViewFactory инициализация") вернуть DynamicNativeView( рамка: рамка, идентификатор просмотра: идентификатор просмотра, аргументы: аргументы, binaryMessenger: мессенджер) } публичная функция createArgsCodec() -> FlutterMessageCodec & НСОбжектПротокол { вернуть FlutterStandardMessageCodec.sharedInstance() } } класс DynamicNativeView: NSObject, FlutterPlatformView { частная переменная _view: UIView = UIView(); в этом( кадр: CGRect, viewIdentifier viewId: Int64, аргументы args: Любой?, МессенджерbinaryMessenger: FlutterBinaryMessenger? ) { print("Инициализация DynamicNativeView") если let params = args как? [Строка:ЛюбойОбъект] { var screen: String = params["screen"] as! Нить; if let vc = ViewControllerGetter(rawValue: screen)?.getViewController(with: params) { _view = vc.view; } } супер.инит() } func view() -> UIView { вернуть _view } } Получатель vc:
импортировать фундамент перечисление ViewControllerGetter: String { кейс viewController случай viewController2 func getViewController (с параметрами: [String: AnyObject]?) -> UIViewController? { переключить себя { случай .viewController: если пусть vcParams = params { пусть vc = ViewController(); vc.buttonTitleA = params!["параметр 1"] as! Нить; vc.buttonTitleB = params!["параметр 2"] as! Нить; вернуть ВК } случай .viewController2: если пусть vcParams = params { пусть vc = ViewController2(); vc.buttonTitleA = params!["параметр 1"] as! Нить; vc.buttonTitleB = params!["параметр 2"] as! Нить; вернуть ВК } } вернуть ноль } } Вид платформы:
import 'dart:io'; импортируйте «dart:developer» как консоль; импортировать «пакет: флаттер/cupertino.dart»; импортировать «пакет: флаттер/материал.dart»; импортировать «пакет: flutter/services.dart»; импортировать «пакет:native_in_fluter/adaptive_platform_view.dart»; класс NativeViewer расширяет StatefulWidget { окончательный заголовок строки; конечная строка ownScreen; окончательная Map viewParams; const NativeViewer( {супер.ключ, требуется это.title, требуется this.viewParams, требуется this.nativeScreen}); @переопределить State createState() => _NativeViewerState(); } класс _NativeViewerState расширяет State { поздний канал MethodChannel; // = const MethodChannel('test_platform_channel'); @переопределить недействительный initState() { супер.initState(); канал = const MethodChannel('native_viewer_platform_channel'); Channel.setMethodCallHandler((вызов) { console.log('Набор NativeViewer setMethodCallHandler'); переключатель (вызов.метод) { случай 'swift_to_flutter': консоль.log( 'swift_to_flutter получен в NativeViewer с аргументами ${call.arguments}'); перерыв; по умолчанию: } вернуть вызов.аргументы; }); } @переопределить Сборка виджета (контекст BuildContext) { динамическая задняя кнопка = Платформа.isIOS ? CupertinoIcons.back : Icons.arrow_back; // Это используется на стороне платформы для регистрации представления. const String viewType = ''; // Передаем параметры на сторону платформы. окончательная карта CreationParams = widget.viewParams; вернуть эшафот( AppBar: AppBar( BackgroundColor: Theme.of(context).colorScheme.inversePrimary, Название: Текст( виджет.название, // стиль: const TextStyle(fontSize: 30, цвет: Colors.white), ), ведущий: IconButton( значок: Значок (backButton), // цвет: Colors.redAccent, onPressed: () { Navigator.pop(контекст); }), ), тело: AdatptivePlatformView( родной экран: виджет.nativeScreen, тип просмотра: тип просмотра, LayoutDirection: TextDirection.ltr, СозданиеПарамс: СозданиеПарамс, CreationParamsCodec: const StandardMessageCodec(), ), ); } } класс AdatptivePlatformView расширяет StatelessWidget { конечная строка ownScreen; окончательная строка viewType; окончательное динамическое созданиеParams; окончательное TextDirection? направление макета; окончательный MessageCodec? созданиеParamsCodec; const AdatptivePlatformView( {супер.ключ, требуется this.viewType, это.creationParams, это.creationParamsCodec, это.layoutDirection, требуется this.nativeScreen}); @переопределить Сборка виджета (контекст BuildContext) { вернуть Platform.isAndroid ? АндроидВью( тип просмотра: тип просмотра, LayoutDirection: TextDirection.ltr, СозданиеПарамс: СозданиеПарамс, CreationParamsCodec: const StandardMessageCodec(), ) : UiKitView( тип просмотра: тип просмотра, LayoutDirection: TextDirection.ltr, СозданиеПарамс: СозданиеПарамс, CreationParamsCodec: const StandardMessageCodec(), ); } }