🦜

KotlinでSupabaseを使う

2024/02/22に公開

📕Overview

KotlinとJetpack Composeのキャッチアップを最近はしており、API通信するアプリやFirebaseと組み合わせたものを作ってみたことはあるもののSupabaseは使ったことがなかった。
新しい技術には興味があるので、やってみることにした。

タイラーさんの動画を参考に進めていきます。
https://www.youtube.com/watch?v=_iXUVJ6HTHU

でもバージョンが違ったりするのか調整は必要だったような。

補足情報
このチュートリアルをこなすには、SupabaseとAndroidの知識がある人を前提に書いております。

このチュートリアルを私は、やってみたがタイラーさんの動画を参考にしつつバージョンの管理をしないと進められなかった。
https://supabase.com/docs/guides/getting-started/quickstarts/kotlin?utm_source=youtube&utm_medium=video&utm_term=tips&utm_content=_iXUVJ6HTHU

Ktorのバージョンは、リンク先に合わせる。私は2.3.8にした。
https://ktor.io/docs/http-client-engines.html

🧷summary

チュートリアルをやってみましょう。まずは、プロジェクトを作るか、すでに作ってあるものに、国の情報を保存するテーブルを作ってください。

countriesを作成するクエリ
-- Create the table
CREATE TABLE countries (
  id SERIAL PRIMARY KEY,
  name VARCHAR(255) NOT NULL
);
-- Insert some sample data into the table
INSERT INTO countries (name) VALUES ('United States');
INSERT INTO countries (name) VALUES ('Canada');
INSERT INTO countries (name) VALUES ('Mexico');

SQL editorで実行する:

次に、URLとanon keyをコピーしておく。

Jetpack Composeのプロジェクトを作成する。build.gradle.ktsにSupabaseのパッケージを追加する。今後は、Kotlinのコードでパッケージの管理をするようです。
https://developer.android.com/build/migrate-to-kotlin-dsl?hl=ja

build.gradle.ktsのファイル
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
    // 1.9.0を追加
    kotlin("plugin.serialization") version "1.9.0"
}

android {
    namespace = "com.example.androidsupabaseapp"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.example.androidsupabaseapp"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary = true
        }
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.1"
    }
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
}

dependencies {

    implementation("androidx.core:core-ktx:1.12.0")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
    implementation("androidx.activity:activity-compose:1.8.2")
    implementation(platform("androidx.compose:compose-bom:2023.08.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.ui:ui-graphics")
    implementation("androidx.compose.ui:ui-tooling-preview")
    implementation("androidx.compose.material3:material3")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
    androidTestImplementation(platform("androidx.compose:compose-bom:2023.08.00"))
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    debugImplementation("androidx.compose.ui:ui-tooling")
    debugImplementation("androidx.compose.ui:ui-test-manifest")
    // Supabaseの依存関係を追加
    implementation(platform("io.github.jan-tennert.supabase:bom:2.0.0-alpha-1"))
    implementation("io.github.jan-tennert.supabase:postgrest-kt")
    implementation("io.ktor:ktor-client-android:2.3.8")
    implementation("io.github.jan-tennert.supabase:serializer-moshi:2.0.0-alpha-1")
}

AndroidManifest.xmlのファイルにパーミッションの許可をするコードを追加する。追加したら、画面右上の白い象さんのボタンを押す。Sync Nowと同じ機能みたいです。

<uses-permission android:name="android.permission.INTERNET" />

MainActivity.ktにSupabaseからデータを取得するコードを追加する。

アプリのコード
package com.example.androidsupabaseapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.androidsupabaseapp.ui.theme.AndroidSupabaseAppTheme
import io.github.jan.supabase.createSupabaseClient
import io.github.jan.supabase.postgrest.Postgrest
import io.github.jan.supabase.postgrest.from
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable

// API call する Supabase Clien を追加
val supabase = createSupabaseClient(
    supabaseUrl = "https://***************",
    supabaseKey = "*************************mCkg-TJP0Hl8"
) {
    install(Postgrest)
}

// Country クラスを追加
@Serializable
data class Country(
    val id: Int,
    val name: String,
)


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AndroidSupabaseAppTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    CountriesList()
                }
            }
        }
    }
}

// Supabaseから取得したデータを表示するComposable関数を作成
@Composable
fun CountriesList() {
    var countries by remember { mutableStateOf<List<Country>>(listOf()) }
    LaunchedEffect(Unit) {
        withContext(Dispatchers.IO) {
            countries = supabase.from("countries")
                .select().decodeList<Country>()
        }
    }
    LazyColumn {
        items(
            countries,
            key = { country -> country.id },
        ) { country ->
            Text(
                country.name,
                modifier = Modifier.padding(8.dp),
            )
        }
    }
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    AndroidSupabaseAppTheme {
        CountriesList()
    }
}

ビルドして、データの取得に成功すると、UIにテーブルのデータが表示されます。

🧑‍🎓thoughts

Supabaseは、FlutterとReactでしか使ったことがなかったので、Kotlinで使ってみると、技術の幅が広がって面白いなと思いました。Firebase以外のBassを使ってネイティブアプリを色々作るのを探求してみたいな〜と考えております。

Discussion