Разработка Android-приложений с несколькими входами с помощью последней экспериментальной функции Flutter

Разработка Android-приложений с несколькими входами с помощью последней экспериментальной функции Flutter

4 апреля 2023 г.

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

Постановка задачи

Во время работы над другим проектом Flutter я столкнулся с интригующей и несколько необычной задачей. Проект должен был функционировать как POS-терминал на ОС Android и других мобильных устройствах, но с упрощенной версией приложения, которое выполняло функции обычного приложения с единой точкой входа на стандартных устройствах iOS и Android, без платежей и печати счетов. С другой стороны, расширенная полнофункциональная версия POS-терминала требовала специального лаунчера, а приложение было построено и установлено таким образом, что оно имело несколько точек входа, ведущих к отдельным частям функциональности, без доступа из одной точки в другую. (например, из каталогов в отчеты).

Хотя это конкретный случай, который в настоящее время применим только к Android, я нашел репозиторий Flutter GitHub wiki, чтобы быть полезным в начале моей работы. Однако по какой-то причине это не работало должным образом и вызвало проблемы с моим проектом.

Хотя это экспериментальная функция и крайний случай в разработке, я решил создать тестовое приложение, чтобы облегчить любые будущие попытки. На следующих страницах я объясню это тестовое приложение и то, как его можно использовать для упрощения процесса создания Android-приложений с несколькими входами с помощью Flutter.

Тестовое приложение

Тестовое приложение, которое я создал для упрощения создания Android-приложений с несколькими входами с помощью Flutter, состоит из трех страниц, каждая из которых имеет свой уникальный цвет, заголовок и кнопки для навигации. Эти страницы называются Amber, Blue и Purple, и их можно найти на AppBar. Приложение имеет три отдельные точки входа при сохранении одного и того же имени пакета.

* Точка входа «3 цвета» обеспечивает полную функциональность с навигацией между всеми тремя страницами. * Точка входа «2 цвета» обрезает первую страницу и разрешает доступ только к синей и фиолетовой страницам. * Точка входа «1 цвет» ведет только на фиолетовую страницу.

Эта структура обеспечивает четкое разделение функций, при этом каждая точка входа ведет к разным наборам функций.

Вид

Single entry app (on the left) and multiple entry app (on the right)

Этапы воспроизведения

Создание простого приложения Flutter с несколькими записями — это простой процесс, который можно выполнить, выполнив несколько простых шагов. Для начала вы можете следовать руководству, приведенному в этой статье. Кроме того, вы можете клонировать мой образец приложения, ссылка на который приведена в нижнем колонтитуле этой статьи, чтобы увидеть пример того, как это можно сделать.

Давайте углубимся в код Android, чтобы определить варианты, которые мы создаем:

Чтобы реализовать функциональность с несколькими входами в нашем приложении Flutter, нам нужно определить два или более варианта сборки в файле app/build.gradle. Для целей этой статьи я создал два варианта сборки: «одиночный» и «множественный»:

productFlavors {

    multiple {
        dimension "app"
        versionCode 1
        versionName "1.0.0"
    }

    single {
        dimension "app"
        versionCode 1
        versionName "1.0.0"
    }
}

Для каждого варианта сборки нам нужно создать специальный каталог в структуре проекта. Структура каталогов будет выглядеть примерно так:

Project structure in Android

«Основной» каталог в кодовой базе Android будет содержать общие ресурсы и простую точку входа, но он не будет использоваться для процесса сборки.

С другой стороны, «множественный» каталог будет содержать несколько реализаций BaseActivity, которые отвечают за определение имени точки входа для приложения Flutter:

abstract class BaseActivity : FlutterActivity() {

    abstract var entryPoint: String

    override fun getDartEntrypointFunctionName() = entryPoint

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) =
            GeneratedPluginRegistrant.registerWith(flutterEngine)
}

В «одиночном» каталоге есть только одна AllColorsActivity, которая является довольно общей реализацией:

class AllColorsActivity : FlutterActivity() {}

Последним шагом на стороне Android нашего приложения Flutter с несколькими входами является объявление действий в файле AndroidManifest с отдельным заголовком для каждой точки входа:

<activity
    android:name=".AllColorsActivity"
    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
    android:exported="true"
    android:hardwareAccelerated="true"
    android:label="All 3 colors"
    android:launchMode="singleTop"
    android:theme="@style/LaunchTheme"
    android:windowSoftInputMode="adjustResize">
    <meta-data
        android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
        android:resource="@drawable/launch_background" />

    <meta-data
        android:name="io.flutter.embedding.android.NormalTheme"
        android:resource="@style/NormalTheme" />
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Когда вы разрабатываете свое приложение в Android Studio, очень важно создать отдельные конфигурации сборки для ситуаций, связанных с одной и несколькими записями. Помните, что последний шаг в этом процессе так же важен, как и первый:

Build configuration for single and multiple entry point builds

Часть Flutter проста и интуитивно понятна, а некоторый код просто создан для лучшей демонстрации функций.

В файле main.dart создайте основную точку входа вместе с несколькими альтернативными точками входа, как показано в коде. Чтобы предотвратить использование TreeShaking в деблокированном режиме, обязательно пометьте альтернативные точки входа аннотацией @pragma(‘vm:entry-point’).

void main() => runApp(
      MultiEntryApp(
        initialRoute: defaultRoute,
        primaryColor: Colors.blueGrey,
      ),
    );

@pragma('vm:entry-point')
void amber() => runApp(
  MultiEntryApp(
    initialRoute: amberRoute,
    primaryColor: Colors.pink,
  ),
);

В нашем приложении Flutter с несколькими входами каждая точка входа начинается с собственного имени маршрута, что значительно упрощает создание маршрута. Ключ к этой функциональности лежит в генерации маршрутов, что ограничивает доступ к некоторым экранам для каждой конкретной точки входа. Определяя маршруты таким образом, мы можем гарантировать, что пользователи смогут получить доступ только к экранам, которые имеют отношение к их точке входа, обеспечивая четкий и интуитивно понятный пользовательский интерфейс:

const String defaultRoute = "/";
const String amberRoute = "/amber";
const String blueRoute = "/blue";
const String purpleRoute = "/purple";

Код для создания маршрута может быть не самым элегантным или сложным, но он прост и понятен:

Route<dynamic> generateRoute(RouteSettings settings, String initial) {
  switch (initial) {
    case blueRoute:
      return CupertinoPageRoute(builder: (context) => BluePage(false));
    case purpleRoute:
      return CupertinoPageRoute(builder: (context) => PurplePage(false));
    case amberRoute:
      return CupertinoPageRoute(builder: (context) => AmberPage(false));
    default:
      return _allRoutes(settings);
  }
}

И на этом мы рассмотрели все ключевые компоненты создания многоканального приложения Flutter.

Важные примечания

  • Чтобы предотвратить удаление точек входа в нашем приложении Flutter во время процесса встряхивания дерева, важно пометить их аннотацией @pragma(‘vm:entry-point’). Это указывает компилятору сохранить точки входа в конечном исполняемом файле, гарантируя, что они доступны для использования приложением.
  • Чтобы обеспечить правильную маршрутизацию нашего многоканального приложения Flutter и избежать путаницы, рекомендуется использовать initialRoute: «/» в MaterialApp.
  • В более ранних версиях Flutter использование экспериментальной функции потенциально могло вызвать проблемы с SplashScreen. Однако начиная с Flutter v1.12 и В будущих версиях это больше не проблема, поскольку экран-заставка теперь определяется в метаданных активности с помощью «io.flutter.app.android.SplashScreenUntilFirstFrame».

Обзор

Подводя итог, можно сказать, что хотя методы и подходы, обсуждаемые в этой статье, могут работать не для каждой ситуации или проекта, они дают ценную информацию о процессе создания многоканального приложения Flutter. Для разработчиков важно оставаться гибкими и адаптироваться к потребностям проекта и пользователей. Делясь своим опытом и идеями, мы можем побуждать других изучать возможности Flutter и расширять границы разработки мобильных приложений.

https://github.com/ВадимПинчук/multiple_entry?embedable=true

:::информация Также опубликовано здесь

:::


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE