Используйте сгенерированные Android SDK

Клиентские SDK Firebase Data Connect позволяют вызывать серверные запросы и мутации непосредственно из приложения Firebase. Вы генерируете пользовательский клиентский SDK параллельно с проектированием схем, запросов и мутаций, которые развертываете в сервисе Data Connect . Затем вы интегрируете методы из этого SDK в свою клиентскую логику.

Как мы уже упоминали ранее, важно отметить, что запросы и мутации Data Connect не отправляются клиентским кодом и не выполняются на сервере. Вместо этого, при развертывании операции Data Connect хранятся на сервере, как и в Cloud Functions. Это означает, что вам необходимо развернуть соответствующие изменения на стороне клиента, чтобы избежать проблем с существующими пользователями (например, в старых версиях приложения).

Именно поэтому Data Connect предоставляет вам среду разработки и инструменты, позволяющие создавать прототипы развернутых на сервере схем, запросов и мутаций. Кроме того, он автоматически генерирует SDK для клиентской части во время создания прототипов.

После внесения изменений в ваши сервисные и клиентские приложения, обновления как на стороне сервера, так и на стороне клиента готовы к развертыванию.

Каков рабочий процесс разработки клиентской части?

Если вы следовали инструкциям в разделе «Начало работы» , вы познакомились с общим процессом разработки Data Connect . В этом руководстве вы найдете более подробную информацию о создании Android SDK на основе вашей схемы, а также о работе с клиентскими запросами и мутациями.

Вкратце, для использования сгенерированных Android SDK в клиентских приложениях вам необходимо выполнить следующие предварительные шаги:

  1. Добавьте Firebase в свое Android- приложение.
  2. Добавьте Data Connect в качестве зависимости в Gradle.
  3. Добавьте плагин Kotlin Serialization и зависимость Gradle.

Затем:

  1. Разработайте схему вашего приложения.
  2. Настройка генерации SDK:

  3. Инициализируйте клиентский код и импортируйте библиотеки .

  4. Реализуйте вызовы запросов и мутаций .

  5. Настройте и используйте эмулятор Data Connect и выполните итерации.

Сгенерируйте свой SDK на Kotlin.

Используйте Firebase CLI для настройки сгенерированных Data Connect SDK в ваших приложениях. Команда init должна обнаружить все приложения в текущей папке и автоматически установить сгенерированные SDK.

firebase init dataconnect:sdk

Обновляйте SDK во время прототипирования.

Если у вас установлено расширение Data Connect для VS Code, оно всегда будет поддерживать сгенерированные SDK в актуальном состоянии.

Если вы не используете расширение Data Connect для VS Code, вы можете использовать Firebase CLI для обновления сгенерированных SDK.

firebase dataconnect:sdk:generate --watch

Генерация SDK в конвейерах сборки

С помощью Firebase CLI можно генерировать SDK Data Connect в процессах сборки CI/CD.

firebase dataconnect:sdk:generate

Настройка клиентского кода

Интегрируйте Data Connect в клиентский код.

Чтобы настроить клиентский код для использования Data Connect и сгенерированного SDK, сначала следуйте стандартным инструкциям по настройке Firebase .

Затем добавьте следующее в раздел plugins в файле app/build.gradle.kts :

// The Firebase team tests with version 1.8.22; however, other 1.8 versions,
// and all newer versions are expected work too.
kotlin("plugin.serialization") version "1.8.22" // MUST match the version of the Kotlin compiler

Затем добавьте следующее в раздел dependencies в файле app/build.gradle.kts :

implementation(platform("com.google.firebase:firebase-bom:34.11.0"))
implementation("com.google.firebase:firebase-dataconnect")
implementation("com.google.firebase:firebase-auth") // Optional
implementation("com.google.firebase:firebase-appcheck") // Optional
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // Newer versions should work too
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1") // Newer versions should work too

Инициализируйте Android SDK Data Connect .

Инициализируйте свой экземпляр Data Connect , используя информацию, которую вы использовали для настройки Data Connect (вся информация доступна на вкладке Data Connect в консоли Firebase ).

Объект ConnectorConfig

Для работы SDK требуется объект конфигурации коннектора.

Этот объект генерируется автоматически на основе serviceId и location в dataconnect.yaml , а также connectorId в connector.yaml .

Получение экземпляра коннектора

Теперь, когда вы настроили объект конфигурации, получите экземпляр коннектора Data Connect . Код для вашего коннектора будет сгенерирован эмулятором Data Connect . Если имя вашего коннектора — movies , а пакет Kotlin — com.myapplication , как указано в connector.yaml , то получите объект коннектора, вызвав:

val connector = com.myapplication.MoviesConnector.instance

Используйте запросы и мутации из вашего Android SDK.

С помощью объекта коннектора вы можете выполнять запросы и мутации, определенные в исходном коде GraphQL. Предположим, ваш коннектор имеет следующие определенные операции:

mutation createMovie($title: String!, $releaseYear: Int!, $genre: String!, $rating: Int!) {
  movie_insert(data: {
    title: $title
    releaseYear: $releaseYear
    genre: $genre
    rating: $rating
  })
}

query getMovieByKey($key: Movie_Key!) {
  movie(key: $key) { id title }
}

query listMoviesByGenre($genre: String!) {
  movies(where: {genre: {eq: $genre}}) {
    id
    title
  }
}

Затем вы можете создать и получить доступ к фильму следующим образом:

val connector = MoviesConnector.instance

val addMovieResult1 = connector.createMovie.execute(
  title = "Empire Strikes Back",
  releaseYear = 1980,
  genre = "Sci-Fi",
  rating = 5
)

val movie1 = connector.getMovieByKey.execute(addMovieResult1.data.key)

println("Empire Strikes Back: ${movie1.data.movie}")

Вы также можете загрузить несколько фильмов:

val connector = MoviesConnector.instance

val addMovieResult2 = connector.createMovie.execute(
  title="Attack of the Clones",
  releaseYear = 2002,
  genre = "Sci-Fi",
  rating = 5
)

val listMoviesResult = connector.listMoviesByGenre.execute(genre = "Sci-Fi")

println(listMoviesResult.data.movies)

Также можно создать Flow , который будет выдавать результат только тогда, когда будет получен новый результат запроса с помощью вызова метода execute() этого запроса.

val connector = MoviesConnector.instance

connector.listMoviesByGenre.flow(genre = "Sci-Fi").collect { data ->
  println(data.movies)
}

connector.createMovie.execute(
  title="A New Hope",
  releaseYear = 1977,
  genre = "Sci-Fi",
  rating = 5
)

connector.listMoviesByGenre.execute(genre = "Sci-Fi") // will cause the Flow to get notified

Обработка изменений в полях перечисления

Схема приложения может содержать перечисления , к которым можно получить доступ с помощью запросов GraphQL .

По мере изменения дизайна приложения вы можете добавлять новые значения, поддерживаемые перечислениями. Например, представьте, что на более позднем этапе жизненного цикла вашего приложения вы решили добавить значение FULLSCREEN в перечисление AspectRatio .

В рабочем процессе Data Connect вы можете использовать локальные инструменты разработки для обновления ваших запросов и SDK.

Однако, прежде чем вы выпустите обновленную версию своих клиентов, старые развернутые клиенты могут перестать работать.

Пример отказоустойчивой реализации

Сгенерированный SDK принудительно обрабатывает неизвестные значения, поскольку код заказчика должен извлечь объект EnumValue , который имеет значение либо EnumValue.Known для известных значений перечисления, либо EnumValue.Unknown для неизвестных значений.

val result = connector.listMoviesByAspectRatio.execute(AspectRatio.WIDESCREEN)
val encounteredAspectRatios = mutableSetOf<String>()

result.data.movies
  .mapNotNull { it.otherAspectRatios }
  .forEach { otherAspectRatios ->
    otherAspectRatios
      .filterNot { it.value == AspectRatio.WIDESCREEN }
      .forEach {
        when (it) {
          is EnumValue.Known -> encounteredAspectRatios.add(it.value.name)
          is EnumValue.Unknown ->
            encounteredAspectRatios.add("[unknown ratio: ${it.stringValue}]")
        }
      }
  }

println(
  "Widescreen movies also include additional aspect ratios: " +
    encounteredAspectRatios.sorted().joinToString()
)

Включите кэширование на стороне клиента.

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

Чтобы включить кэширование на стороне клиента, добавьте конфигурацию кэширования клиента в конфигурацию коннектора:

generate:
  kotlinSdk:
    outputDir: "../android"
    package: "com.google.firebase.dataconnect.generated"
    clientCache:
      maxAge: 5s
      storage: persistent

Данная конфигурация имеет два параметра, оба необязательные:

  • maxAge : Максимальный срок хранения кэшированного ответа до того, как клиентский SDK получит новые значения. Примеры: "0", "30 с", "1 ч 30 мин".

    Значение по умолчанию для maxAge равно 0 , что означает, что ответы кэшируются, но клиентский SDK всегда будет получать актуальные значения. Кэшированные значения будут использоваться только в том случае, если для execute() указан параметр CACHE_ONLY .

  • storage : Клиентский SDK можно настроить для кэширования ответов либо в persistent хранилище, либо в memory . Результаты, кэшированные в persistent хранилище, сохранятся после перезапуска приложения. В Android SDK по умолчанию используется persistent .

После обновления конфигурации кэширования вашего коннектора перегенерируйте клиентские SDK и пересоберите приложение. После этого execute() будет кэшировать ответы и использовать кэшированные значения в соответствии с настроенной вами политикой. Обычно это происходит автоматически, без каких-либо дополнительных действий с вашей стороны; однако обратите внимание на следующее:

  • Поведение функции execute() по умолчанию описано выше: если результат запроса кэширован и кэшированное значение не старше значения maxAge , то используется кэшированное значение. Это поведение по умолчанию называется политикой PREFER_CACHE .

    Вы также можете указать отдельным вызовам функции execute() либо предоставлять только кэшированные значения ( CACHE_ONLY ), либо безусловно получать свежие значения с сервера ( SERVER_ONLY ).

    val queryResult = queryRef.execute(QueryRef.FetchPolicy.CACHE_ONLY)
    
    val queryResult = queryRef.execute(QueryRef.FetchPolicy.SERVER_ONLY)
    

    Создайте прототип и протестируйте свое Android-приложение.

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

    Вы можете использовать эмулятор Data Connect как через расширение Data Connect для VS Code, так и через интерфейс командной строки.

    Процесс подключения приложения к эмулятору одинаков в обоих случаях.

    val connector = MoviesConnector.instance
    
    // Connect to the emulator on "10.0.2.2:9399"
    connector.dataConnect.useEmulator()
    
    // (alternatively) if you're running your emulator on non-default port:
    connector.dataConnect.useEmulator(port = 9999)
    
    // Make calls from your app
    
    

    Чтобы переключиться на производственные ресурсы, закомментируйте строки, отвечающие за подключение к эмулятору.

    Типы данных в SDK Data Connect

    Сервер Data Connect представляет собой стандартные и пользовательские типы данных GraphQL. В SDK они представлены следующим образом.

    Тип Data Connect Котлин
    Нить Нить
    Интерн. Int (32-битное целое число)
    Плавать Число с плавающей запятой типа Double (64-битное число)
    Логический Логический
    UUID java.util.UUID
    Дата com.google.firebase.dataconnect.LocalDate (ранее java.util.Date до версии 16.0.0-beta03)
    Отметка времени com.google.firebase.Timestamp
    Int64 Длинный
    Любой com.google.firebase.dataconnect.AnyValue