跳到主要内容

Android Kotlin 快速开始

准备工作

在开始之前,请确保您已完成以下准备:

  1. 开通云开发环境开通云开发环境
  2. 获取 API 访问凭证:在 CloudBase 控制台 获取环境 ID 和 API 密钥

更多详情请参考:Android Kotlin 完整文档

添加 CloudBase AI 开发插件

可选:如果你使用 AI 编程助手(如 Cursor、Claude Code、CodeBuddy 等)进行开发,建议先完成本步骤,让 AI 具备 CloudBase 开发能力。

复制 AI Prompt 粘贴到 AI IDE

在 AI 对话中输入:

帮我把 CloudBase 接好,按下面做:
1. 打开 https://docs.cloudbase.net/skill.md,按说明完成接入。
2. 接入完成后告诉我,并建议最相关的下一步。

查看 skill.md →

使用 Skills 开发

对 AI 说:

使用 CloudBase Skills:在 Android Kotlin 应用中集成 CloudBase HTTP API

Skills 使用文档 →

也可以手动安装 CloudBase Skills:

npx skills add tencentcloudbase/cloudbase-skills -y

身份认证

suspend fun signUpWithPhoneCode(cloudbase: CloudBaseClient, phoneNumber: String, verificationCode: String, username: String? = null, password: String? = null, captchaToken: String? = null): Map<String, Any>? {
// 步骤1: 发送短信验证码
val sendBody = mutableMapOf<String, Any>(
"phone_number" to if (phoneNumber.startsWith("+86")) phoneNumber else "+86$phoneNumber",
"target" to "NON_USER" // "NON_USER" - 账号不存在才发送; "ANY" - 不限制
)

val sendHeaders = captchaToken?.let { mapOf("x-captcha-token" to it) } ?: emptyMap()

val sendResult = cloudbase.request<Map<String, Any>>(
method = "POST",
path = "/auth/v1/verification",
body = sendBody,
customHeaders = sendHeaders,
typeToken = object : TypeToken<Map<String, Any>>() {}
)

if (sendResult == null) {
println("发送验证码失败")
return null
}

val verificationId = sendResult["verification_id"] as? String ?: return null
println("验证码发送成功! ID: $verificationId")

// 步骤2: 验证验证码
val verifyResult = cloudbase.request<Map<String, Any>>(
method = "POST",
path = "/auth/v1/verification/verify",
body = mapOf(
"verification_id" to verificationId,
"verification_code" to verificationCode
),
typeToken = object : TypeToken<Map<String, Any>>() {}
)

if (verifyResult == null) {
println("验证码错误")
return null
}

val verificationToken = verifyResult["verification_token"] as? String ?: return null
println("验证成功!")

// 步骤3: 使用验证令牌注册
val signUpBody = mutableMapOf<String, Any>(
"phone_number" to if (phoneNumber.startsWith("+86")) phoneNumber else "+86$phoneNumber",
"verification_token" to verificationToken
)

// 可选:添加用户名和密码
username?.let { signUpBody["username"] = it }
password?.let { signUpBody["password"] = it }

val signUpResult = cloudbase.request<Map<String, Any>>(
method = "POST",
path = "/auth/v1/signup",
body = signUpBody,
typeToken = object : TypeToken<Map<String, Any>>() {}
)

if (signUpResult != null) {
val accessToken = signUpResult["access_token"] as? String
val userId = signUpResult["sub"] as? String

println("注册成功! 用户ID: $userId")
println("访问令牌: ${accessToken?.take(20)}...")

// 更新访问令牌
accessToken?.let { cloudbase.updateAccessToken(it) }
return signUpResult
}

println("注册失败")
return null
}

// 使用示例
// lifecycleScope.launch {
// val result = signUpWithPhoneCode(cloudbase, "13800138000", "123456", "myusername", "mypassword")
// if (result != null) {
// println("手机号注册成功")
// }
// }

云存储

import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File

suspend fun uploadFile(cloudbase: CloudBaseClient, filePath: String, objectId: String? = null): Map<String, String>? = withContext(Dispatchers.IO) {
// 上传文件到云存储
val file = File(filePath)

if (!file.exists()) {
println("文件不存在: $filePath")
return@withContext null
}

val finalObjectId = objectId ?: "uploads/${System.currentTimeMillis()}-${file.name}"

// 1. 获取上传信息
val uploadInfo = cloudbase.request<List<Map<String, Any>>>(
method = "POST",
path = "/v1/storages/get-objects-upload-info",
body = listOf(mapOf("objectId" to finalObjectId)),
typeToken = object : TypeToken<List<Map<String, Any>>>() {}
)

if (uploadInfo.isNullOrEmpty()) {
return@withContext null
}

val info = uploadInfo[0]
val uploadUrl = info["uploadUrl"] as String

try {
// 2. 上传文件
val fileData = file.readBytes()
val uploadHeaders = mapOf(
"Authorization" to (info["authorization"] as String),
"X-Cos-Security-Token" to (info["token"] as String),
"X-Cos-Meta-Fileid" to (info["cloudObjectMeta"] as String)
)

val requestBuilder = Request.Builder()
.url(uploadUrl)
.put(fileData.toRequestBody())

uploadHeaders.forEach { (key, value) ->
requestBuilder.header(key, value)
}

val client = OkHttpClient()
val uploadResponse = client.newCall(requestBuilder.build()).execute()

if (uploadResponse.isSuccessful) {
val result = mapOf(
"cloudObjectId" to (info["cloudObjectId"] as String),
"downloadUrl" to (info["downloadUrl"] as String),
"objectId" to finalObjectId
)

println("文件上传成功:")
println("- 对象ID: ${result["objectId"]}")
println("- 下载URL: ${result["downloadUrl"]}")

return@withContext result
}

println("文件上传失败: ${uploadResponse.code}")
return@withContext null
} catch (e: Exception) {
println("文件上传失败: ${e.message}")
e.printStackTrace()
return@withContext null
}
}

// 使用示例
// lifecycleScope.launch {
// val result = uploadFile(cloudbase, "/path/to/example.jpg")
// println(result)
// }

云函数

suspend fun callFunction(cloudbase: CloudBaseClient, functionName: String, data: Map<String, Any>? = null): Map<String, Any>? {
// 调用云函数
val result = cloudbase.request<Map<String, Any>>(
method = "POST",
path = "/v1/functions/$functionName",
body = data ?: emptyMap<String, Any>(),
typeToken = object : TypeToken<Map<String, Any>>() {}
)

if (result != null) {
println("云函数调用结果: $result")
}
return result
}

// 使用示例
// lifecycleScope.launch {
// val result = callFunction(cloudbase, "{%FUNCTION_NAME%}")
// println(result)
// }

大模型

import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.MediaType.Companion.toMediaType
import com.google.gson.Gson

suspend fun streamText(cloudbase: CloudBaseClient, model: String, subModel: String, messages: List<Map<String, String>>): String? = withContext(Dispatchers.IO) {
// 流式文本生成
val payload = mapOf(
"model" to subModel,
"messages" to messages,
"stream" to true
)

val url = "${cloudbase.baseUrl}/v1/ai/$model/chat/completions"
val gson = Gson()

val requestBody = gson.toJson(payload).toRequestBody("application/json".toMediaType())

val request = Request.Builder()
.url(url)
.header("Content-Type", "application/json")
.header("Accept", "text/event-stream")
.header("Authorization", "Bearer ${cloudbase.accessToken}")
.post(requestBody)
.build()

try {
val client = OkHttpClient()
val response = client.newCall(request).execute()

if (response.isSuccessful) {
println("AI 流式响应:")
var fullContent = ""

response.body?.source()?.use { source ->
while (!source.exhausted()) {
val line = source.readUtf8Line() ?: continue

if (line.startsWith("data: ")) {
val dataStr = line.substring(6)
if (dataStr.trim() != "[DONE]") {
try {
val chunkData = gson.fromJson(dataStr, Map::class.java)
val choices = chunkData["choices"] as? List<*>
val delta = (choices?.get(0) as? Map<*, *>)?.get("delta") as? Map<*, *>
val content = delta?.get("content") as? String ?: ""

if (content.isNotEmpty()) {
print(content)
fullContent += content
}
} catch (e: Exception) {
// 忽略JSON解析错误
}
}
}
}
}

println()
return@withContext fullContent
} else {
println("AI 调用失败: ${response.code}")
return@withContext null
}
} catch (e: Exception) {
println("AI 调用失败: ${e.message}")
e.printStackTrace()
return@withContext null
}
}

// 使用示例
// lifecycleScope.launch {
// val response = streamText(
// cloudbase,
// "{%AI_MODEL_NAME%}",
// "{%AI_SUB_MODEL_NAME%}",
// listOf(
// mapOf("role" to "system", "content" to "请严格按照七言绝句或七言律诗的格律要求创作"),
// mapOf("role" to "user", "content" to "春天")
// )
// )
// println("\n完整回复: $response")
// }