生成された Android SDK を使用する

Firebase SQL Connect クライアント SDK を使用すると、Firebase アプリからサーバーサイドのクエリとミューテーションを直接呼び出すことができます。SQL Connect サービスにデプロイするスキーマ、クエリ、ミューテーションを設計する際に、カスタム クライアント SDK を並行して生成します。次に、この SDK のメソッドをクライアント ロジックに統合します。

他の場所でも説明したように、SQL Connect クエリとミューテーションはクライアント コードによって送信され、サーバーで実行されるわけではないことに注意してください。代わりに、デプロイ時に SQL Connect オペレーションが Cloud Functions のようにサーバーに保存されます。つまり、既存のユーザー(古いアプリ バージョンなど)に影響を与えないように、対応するクライアントサイドの変更をデプロイする必要があります。

そのため、SQL Connect には、サーバーにデプロイされたスキーマ、クエリ、ミューテーションのプロトタイプを作成できる開発環境とツールが用意されています。また、プロトタイプの作成中にクライアントサイド SDK も自動的に生成されます。

サービスアプリとクライアント アプリの更新を繰り返すと、サーバーサイドとクライアントサイドの両方の更新をデプロイする準備が整います。

クライアント開発ワークフローとは何ですか?

スタートガイドでは、SQL Connect の開発フローの全体像を説明しました。このガイドでは、スキーマから Android SDK を生成する方法と、クライアント クエリとミューテーションを操作する方法について詳しく説明します。

まとめると、生成された Android SDK をクライアント アプリで使用するには、次の前提条件の手順を行います。

  1. Firebase を Android アプリに追加します。
  2. Gradle で SQL Connect を依存関係として構成します。
  3. Kotlin Serialization Gradle プラグインと Gradle 依存関係を追加します。

次に、以下のリソースをご覧ください。

  1. アプリのスキーマを開発します。
  2. SDK の生成を設定します。

  3. クライアント コードを初期化してライブラリをインポートする。

  4. クエリとミューテーションの呼び出しを実装する。

  5. SQL Connect エミュレータを設定して使用し、反復処理を行います。

Kotlin SDK を生成する

Firebase CLI を使用して、SQL Connect で生成された SDK をアプリに設定します。init コマンドは、現在のフォルダ内のすべてのアプリを検出し、生成された SDK を自動的にインストールします。

firebase init dataconnect:sdk

プロトタイピング中に SDK を更新する

SQL Connect VS Code 拡張機能がインストールされている場合、生成された SDK は常に最新の状態に保たれます。

SQL Connect VS Code 拡張機能を使用しない場合は、Firebase CLI を使用して、生成された SDK を最新の状態に保つことができます。

firebase dataconnect:sdk:generate --watch

ビルド パイプラインで SDK を生成する

Firebase CLI を使用して、CI/CD ビルドプロセスで SQL Connect SDK を生成できます。

firebase dataconnect:sdk:generate

クライアント コードを設定する

SQL Connect をクライアント コードに組み込む

SQL Connect と生成された SDK を使用するようにクライアント コードを設定するには、まず標準の Firebase 設定手順に沿って操作します。

次に、app/build.gradle.kts の plugins セクションに以下を追加します。

// 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

次に、app/build.gradle.kts の dependencies セクションに以下を追加します。

implementation(platform("com.google.firebase:firebase-bom:35.0.1"))
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

SQL Connect Android SDK を初期化する

SQL Connect の設定に使用した情報を使用して、SQL Connect インスタンスを初期化します。この情報は、Firebase コンソールの [データベースとストレージ] > [SQL Connect] ページで確認できます。

ConnectorConfig オブジェクト

SDK にはコネクタ構成オブジェクトが必要です。

このオブジェクトは、dataconnect.yaml の serviceId と location、connector.yaml の connectorId から自動的に生成されます。

コネクタ インスタンスの取得

構成オブジェクトを設定したら、SQL Connect コネクタ インスタンスを取得します。コネクタのコードは SQL 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)

また、クエリの execute() メソッドを呼び出して新しいクエリ結果を取得した場合にのみ結果を生成する Flow を収集することもできます。

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

リアルタイムの変更をサブスクライブする

SQL Connect からリアルタイム アップデートを取得するをご覧ください。

列挙型フィールドの変更を処理する

アプリのスキーマには列挙型を含めることができ、GraphQL クエリからアクセスできます。

アプリの設計が変更されると、新しい列挙型のサポートされている値を追加することがあります。たとえば、アプリケーションのライフサイクルの後半で、AspectRatio 列挙型に FULLSCREEN 値を追加することにしたとします。

SQL 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()
)

クライアントサイド キャッシュを有効にする

SQL Connect には、オプションのクライアントサイド キャッシュ機能があります。この機能は、connector.yaml ファイルを編集することで有効にできます。この機能を有効にすると、生成されたクライアント SDK はクエリ レスポンスをローカルにキャッシュします。これにより、アプリが行うデータベース リクエストの数を減らし、ネットワークが中断されたときにアプリのデータベース依存部分を動作させることができます。

クライアントサイド キャッシュを有効にするには、コネクタ構成にクライアント キャッシュ構成を追加します。

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

この構成には 2 つのパラメータがあり、どちらも省略可能です。

  • maxAge: クライアント SDK が新しい値を取得するまでの、キャッシュに保存されたレスポンスの最大有効期間。例: 「0」、「30s」、「1h30m」。

    maxAge のデフォルト値は 0 です。これは、レスポンスがキャッシュに保存されるものの、クライアント SDK は常に最新の値を取得することを意味します。キャッシュに保存された値は、CACHE_ONLY が execute() に指定されている場合にのみ使用されます。

  • 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 アプリケーションのプロトタイプを作成してテストする

    ローカル エミュレータを使用するようにクライアントを計測する

    SQL Connect エミュレータは、SQL Connect VS Code 拡張機能または CLI から使用できます。

    エミュレータに接続するためのアプリのインストルメント化は、どちらのシナリオでも同じです。

    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
    
    

    本番環境リソースに切り替えるには、エミュレータに接続するための行をコメントアウトします。

    SQL Connect SDK の SQL 型

    SQL Connect サーバーは、一般的な GraphQL データ型とカスタム GraphQL データ型を表します。これらは SDK で次のように表されます。

    SQL Connect タイプ Kotlin
    文字列 文字列
    Int Int(32 ビット整数)
    浮動小数点数 Double(64 ビット浮動小数点数)
    ブール値 ブール値
    UUID java.util.UUID
    日付 com.google.firebase.dataconnect.LocalDate(16.0.0-beta03 までは java.util.Date)
    タイムスタンプ com.google.firebase.Timestamp
    Int64 長い
    すべて com.google.firebase.dataconnect.AnyValue