Supabase Kotlin客户端的基本使用

Supabase Kotlin客户端的基本使用


kotlin

介绍

Supabase | The Open Source Firebase Alternative号称是Firebase的替代方案,这个项目在Github已经获得了将近60K的Star。目前它可用的服务有:

  • Database:使用Postgres作为数据库支持
  • Authentication:每个Suabase项目都配有一个完整的用户管理系统,无需任何其他工具即可工作
  • Storage:一个开源对象存储,具有无限的可扩展性,适用于任何文件类型
  • Edge Functions:以快速部署时间和低延迟执行最接近用户的代码
  • Realtime:实时通过WebSockets全局同步客户端状态,多人协作
  • Vector:用于开发人工智能应用程序的开源矢量数据库

这些服务基本可以用于我目前开发的简单的项目,而且它也不只支持一种客户端。其中有些客户端是由社区维护的,Kotlin就是其中之一

本文只涉及前三个服务

Supabase Kotlin Client - Introduction这个是客户端的使用文档,对于刚学Koltin不久的我来说实在有点晦涩难懂,不过对于理解了基本用法之后就相对流畅一点了

注册账号和创建项目的流程我这里就略过了,不细说了

初始化客户端

要使用他的客户端,需要先获取已经注册好的账户的项目URL和公钥,在下图位置可以找到

然后需要在(:app)build.gradle.kts中引入如下三种依赖:

  • BOM版本管理
  • HTTP请求引擎
  • JSON序列化

目前的最新版是1.4.7,代码如下:

    // 指定版本
    implementation("io.github.jan-tennert.supabase:bom:1.4.7")
    // http客户端 okhttp
    runtimeOnly("io.ktor:ktor-client-okhttp:2.3.5")
    // jackson 序列化
    implementation("io.github.jan-tennert.supabase:serializer-jackson-android:1.4.7")

等待依赖构建完毕,就可以编写实例化客户端的代码了:

        val client = createSupabaseClient(
	        // 项目URL
            supabaseUrl = "https://xxx.supabase.co",
            supabaseKey = "anon",
        ) {
	        // 用于配置客户端,比如加载Database的依赖之类的
        }

我一般都是把这个客户端放在单例里面的,方便使用

Database

首先是数据库的使用,先创建数据表。需要注意的是开启了RLS后(这边先关掉),需要在Authentication配置数据表的Policies,这个有些复杂也有些偏题了,如果有需要的话我可以研究一下再出一篇聊一下

如果在创建字段时没找到到需要的数据类型需要在PgAdmin中手动创建一列并选择数据类型

创建好数据表之后我们可就可以开始使用了,引入依赖:

    implementation("io.github.jan-tennert.supabase:postgrest-kt")

然后修改客户端配置

        val client = createSupabaseClient(
            supabaseUrl = "https://xxx.supabase.co",
            supabaseKey = "<anon key>"
        ) {
            // 配置序列化器
            defaultSerializer = JacksonSerializer()
	        // 安装Database插件
            install(Postgrest)
        }

接下来的步骤:

  • 编写实体类
  • 编写获取数据的代码
// 实体类
data class Demo(val id: Int, val name: String)
// 获取数据的代码
val res = client.postgrest["Demo"].select().decodeList<Demo>()
for (item in res) {
    Log.d("DemoDB", "name: ${item.name}, id: ${item.id}")
}

Authentication

然后就是用户管理的接口使用,这边就简单梳理一下使用邮箱登陆和注册的流程。

  1. 引入依赖
    implementation("io.github.jan-tennert.supabase:gotrue-kt")
  1. 修改客户端配置
    install(GoTrue)
  1. 简单注册
// 注册
val user = supabaseClient.gotrue.signUpWith(Email) {
    email = "example@email.com"
    password = "example-password"
}

注意注册完毕需要在Web管理界面通过用户注册的请求

上面是简单的注册API的使用方式,然后是登陆。我当时看的时候一开始死活获取不到登陆后的回调,没想到他是使用了Kotlin的Flow,当时没理解就浪费了很多的时间 下面我会编写一个封装后的api,思路如下:

  • 使用单例存储登陆状态
  • 实例化后开启Flow监听登陆状态的变化
  • 通过Flow回调响应登陆结果

SupabaseApi是我的另一个单例

class AccessApi {

    companion object {
        // user login status
        var loginStatus: SessionStatus = SessionStatus.NotAuthenticated
        var currentUser: UserInfo? = null
        var loginType: String = "NotAuthenticated"
    }

    init {
        GlobalScope.launch {
            // Flow
            SupabaseApi.supabaseClient.gotrue.sessionStatus.collect {
                loginStatus = it

                when (it) {
                    is SessionStatus.NotAuthenticated -> Log.d("Access Api", "NotAuthenticated")
                    is SessionStatus.Authenticated -> {
                        currentUser = it.session.user
                        loginType = it.session.type
                        Log.d("Access Api", "Authenticated")
                    }
                    is SessionStatus.NetworkError -> Log.d("Access Api", "NetworkError")
                    is SessionStatus.LoadingFromStorage -> Log.d("Access Api", "LoadingFromStorage")
                    else -> Log.d("Access Api", "Unknown")
                }
            }
        }
    }

    suspend fun loginWithEmailAndPassword(inputEmail: String, inputPassword: String) {
        try {
            SupabaseApi.supabaseClient.gotrue.loginWith(Email) {
                email = inputEmail
                password = inputPassword
            }
        } catch (e: Exception) {
            Log.d(
                "Access Api",
                "loginWithEmailAndPassword(inputEmail: String, inputPassword: String) Login field, msg: ${e.message}"
            )
        }
    }

    suspend fun logout() {
        SupabaseApi.supabaseClient.gotrue.logout(LogoutScope.GLOBAL)
    }

}

主要使用的api如下:

  • gotrue.logout(LogoutScope):登出
  • gotrue.loginWith(Email):邮件登陆
  • gotrue.sessionStatus.collect:通过Kotlin协程的Flow获取登陆状态变更事件

我们可以通过currentUser获取当前用户信息,loginStatus获取登陆状态

Storage

最后是Storage,可以简单理解为一个图床之类的服务。

  1. 引入依赖
    implementation("io.github.jan-tennert.supabase:storage-kt")
  1. 修改客户端配置
    install(Storage)
  1. 客户端使用
    // 查询music库中的文件
    val bucket = supabaseClient.storage["music"]
    val files = bucket.list()
    for (file in files) {
        println("name: ${file.name}, id: ${file.id}")
    }
    // 获取指定bucketName的指定文件
    val bucket = SupabaseApi.supabaseClient.storage[bucketName]
    val bytes = bucket.downloadAuthenticated(fileFullPath)

总结

其实我在一开始使用的时候就感觉auth的使用方法有点反直觉的(主要之前前端异步登陆写多了,不习惯),现在理解了之后其实感觉这样写也不错

上面三种服务的基本使用方式我差不多就整理到这里。欢迎大佬多多交流

参考文档:

分享这篇文章