-->

Создавайте виджеты главного экрана iOS с помощью Flutter

Создавайте виджеты главного экрана iOS с помощью Flutter

Hola, Amigos! На связи Сергей Климович, Mobile TeamLead агентства продуктовой разработки Amiga. На Flutter.Много мы рассказывали про Home Widget для Android, пришло время iOS.


Я нашел отличную статью по этой теме и решил поделиться с вами переводом. Поехали!


С выпуском iOS17 Apple вдохнула новую жизнь в виджеты, представив интерактивные виджеты. Посмотрим, как WidgetKit можно интегрировать в существующий проект Flutter.

Инструкции для этой демонстрации будут максимально общими и простыми для выполнения. Будем использовать Movie Picker, вы можете включить его в любой проект Flutter, который пожелаете. В конце будет краткий обзор того, как может выглядеть стилизованная и полностью реализованная версия этой функции с помощью Movie Picker.

В этом уроке будем использовать пакет flutter_widgetkit. Этот пакет невероятно прост в использовании, но его возможности ограничены созданием только виджетов домашнего экрана iOS. Однако в вашем распоряжении есть несколько других пакетов, таких как home_widget, который позволяет создавать виджеты как для iOS, так и для Android, но по сути все они функционируют одинаково для iOS.

(Предисловие)

Прежде чем начать, убедитесь, что у вас выполнены следующие условия:

  • Flutter и Dart установлены и настроены для разработки на вашем компьютере.
  • Xcode установлен и настроен для разработки iOS, включая инструменты командной строки.
  • iOS-эмулятор или реальное устройство на iOS.
(Настройки Flutter)

Шаг 1. Настройте проект Flutter

Если вы еще этого не сделали, создайте новый проект Flutter или используйте существующий. Откройте проект в предпочитаемом редакторе кода. Автор использует Android Studio.

Шаг 2. Добавьте зависимости

В свой pubspec.yaml добавьте пакет flutter_widgetkit:


dependencies:

  flutter:

    sdk: flutter

  flutter_widgetkit: ^1.0.3 # Use the latest version

Шаг 3. Создание домашней страницы

Начнем с создания простого домашнего экрана Flutter. Он будет содержать ElevatedButton и простой файл TextField. Все, что нужно от этой страницы, — это принимать текст в качестве входных данных из TextField, и при нажатии кнопки нужно, чтобы наш виджет iOS обновлялся.

var textController = TextEditingController();  

@override

  Widget build(BuildContext context) {

    return Scaffold(

      body: Center(

        child: Column(

          mainAxisAlignment: MainAxisAlignment.center,

          children: [

            SizedBox(

              width: 250,

              child: TextField(

                controller: textController,

                decoration: InputDecoration(

                  hintText: "Enter widget text",

                ),

              ),

            ),

            const SizedBox(height: 10),

            ElevatedButton(

              onPressed: () {},

              child: const Text("Send to Widget"),

            ),

          ],

        ),

      ),

    );

  }

Шаг 4. Создание WidgetData

Чтобы упростить отправку данных в iOS-виджет, создадим простой WidgetData. Нужно отправить экземпляр класса данных в виде строки JSON, которая может быть проанализирована кодом SwiftUI. На данный момент этот класс содержит только одну переменную — строку с именем text, но она может содержать любые произвольные данные, которые вы хотите отправить в свой виджет.


class WidgetData {

  final String text;

  WidgetData(this.text);

  WidgetData.fromJson(Map<String, dynamic> json) : text = json['text'];

  Map<String, dynamic> toJson() => {'text': text};

}

Шаг 5: Отправка информации

Используем WidgetKit.setItem() для отправки данных в виджет. Для этого метода потребуется key, который будет на стороне Xcode, и значение value будет данными, которые нужно отправить. Важно предоставить группу приложений, которую настроим в XCode всего за секунду, используем group.flutterioswidget.

ElevatedButton(

  onPressed: () {

    WidgetKit.setItem(

        'widgetData',

        jsonEncode(WidgetData(textController.text)),

        'group.flutterioswidget');

    WidgetKit.reloadAllTimelines();

  },

  child: const Text("Push to Widget"),

),

Вызываем WidgetKit.reloadAllTimelines(), он перезагрузит временную шкалу и произойдет перерисовка нашего виджета.


Настройки XCode
Шаг 6. Откройте проект в Xcode
В AndroidStudio или VSCode щелкните правой кнопкой мыши папку ios > нажмите «Открыть в Xcode».

Шаг 7: Создайте новую цель

Нажмите Runner, а затем в левом нижнем углу нажмите кнопку «плюс» (+), чтобы создать новую цель.

Найдите «Расширение виджета» и щелкните результат.


Введите любое имя и нажмите «Готово».

Шаг 8. Назначьте группы приложений

Прежде чем перейти к следующему шагу, нужно назначить AppGroups этим целям. В разделе «Targets» выберите цель виджета, которая была недавно создана, и нажмите плюс (+) рядом с надписью «Capability», чтобы добавить новую. Найдите «AppGroup» и выберите первый результат.

Создайте новую группу приложений, нажав кнопку «плюс» (+). Группа приложений должна начинаться с .group, и очень важно, чтобы это соответствовало тому, что вы указали в коде Flutter.


Теперь нужно добавить такую же возможность Runner. Нажмите на Runner в Targets и повторите шаги, описанные выше.

Теперь всё готово, чтобы принимать данные из нашего приложения Flutter!

(SwiftUI)

Шаг 9. Перейдите к коду виджета

Перейдите к FlutterIOSWidget (или к тому, в котором есть Provider).


Шаг 10. Создание виджета SwiftUi

В нашем примере будет только одна запись данных, а именно строка с именем text.

struct WidgetData: Decodable, Hashable {

    let text: String

}

Далее нужно создать TimelineEntry, назовем его FlutterEntry:


struct FlutterEntry: TimelineEntry {

    let date: Date

    let widgetData: WidgetData?

}

Теперь нужно создать файл Provider. Если вы знакомы со SwiftUI, в этом нет ничего нового. Обратите внимание, что AppGroup, указанная в sharedDefaults, должна совпадать везде, где она была указана.


В getTimeline также создаём новый экземпляр flutterData.

struct Provider: TimelineProvider {

    func placeholder(in context: Context) -> FlutterEntry {

        FlutterEntry(date: Date(), widgetData: WidgetData(text: "Flutter iOS widget!"))

    }


    func getSnapshot(in context: Context, completion: @escaping (FlutterEntry) -> ()) {

        let entry = FlutterEntry(date: Date(), widgetData: WidgetData(text: "Flutter iOS widget!"))

        completion(entry)

    }


    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {

        let sharedDefaults = UserDefaults.init(suiteName: "group.flutterioswidget")

        let flutterData = try? JSONDecoder().decode(WidgetData.self, from: (sharedDefaults?

            .string(forKey: "widgetData")?.data(using: .utf8)) ?? Data())


        let entryDate = Calendar.current.date(byAdding: .hour, value: 24, to: Date())!

        let entry = FlutterEntry(date: entryDate, widgetData: flutterData)


        let timeline = Timeline(entries: [entry], policy: .atEnd)

        completion(timeline)

    }

}

Ниже показано, что виджет просто принимает текст, который был установлен из виджета Flutter, и отображает его.


struct FlutterIOSWidgetEntryView : View {

    var entry: Provider.Entry

    

    var body: some View {

        Text(entry.widgetData?.text ?? "Tap to set message.")

    }

}


struct FlutterIOSWidget: Widget {

    let kind: String = "FlutterIOSWidget"


    var body: some WidgetConfiguration {

        StaticConfiguration(kind: kind, provider: Provider()) { entry in

            FlutterIOSWidgetEntryView(entry: entry)

        }

        .configurationDisplayName("Flutter iOS Widget")

        .description("This is an example Flutter iOS widget.")

    }

}

Вот тут и начинается самое интересное, потому что, обладая небольшими знаниями SwiftUI, можно создать абсолютно любой виджет на основе данных, полученных от приложения Flutter.


На этом всё! Полный пример можно посмотреть на github.


Надеюсь, вам было интересно! Подписывайтесь на наш телеграм-канал Flutter. Много, который мы ведем командой мобильных разработчиков. Рассказываем про свой личный опыт и делимся советами от софт-скиллов до технических знаний.

Хотите связаться с владельцами компании напрямую?
Константин Франгуриди
Константин Франгуриди
Account director

НАПИСАТЬ

Дмитрий Тарасов
Дмитрий Тарасов
СЕО

НАПИСАТЬ