Android以Map形式向Cloud Function发送JSON数据报错求助
解决Android调用Cloud Function时的JSON编码错误
问题现象
通过Postman向Cloud Function发送指定JSON数据可正常运行,但Android端以Map形式构造并发送相同结构数据时,出现错误:
Object cannot be encoded in JSON: User(phone=55512345)
相关代码示例
Postman请求数据
{ "data": { "users": [ { "phone": "55512345" }, { "phone": "972525276676" }, { "phone": "55512347" } ] } }
Android代码
private fun addMessage(): Task<String>? { val usr1 = User("55512345") val usr2 = User("972525276676") val usr3 = User("55512347") val userList = listOf(usr1,usr2,usr3) val data: MutableMap<String, Any> = HashMap() data["users"] = userList functions.getHttpsCallable("getUsers") .call(data) .addOnFailureListener { Log.d("DTAG", it.toString()) } .addOnSuccessListener { Log.d("DTAG","Ok: ${it.data.toString()}") } return null }
User数据类
data class User(var phone:String)
Cloud Function代码
exports.getUsers = functions.https.onRequest(async (request, response) => { const data = request.body.data; if (data !== null && data.users !== null) { const users = data.users; const phonelist = users.map(user => user.phone.toString()); const userlist = [] const snapshot = await db.collection("users").get() snapshot.docs.forEach((userDoc) => { const phone = userDoc.get("phone") if(phone === null) return; const isContain = phonelist.reduce((acc, num) => acc || phone.includes(num), false) if(isContain) { userlist.push(userDoc.data()) } }) response.status(200).json({result: userlist}) } else{ response.sendStatus(403) } });
错误原因
- Firebase的
getHttpsCallable().call()方法仅支持序列化JSON原生类型(基本类型、Map、List等),自定义User数据类无法直接被序列化。 - Android端用Callable函数调用方式,但Cloud Function是普通HTTP函数(
onRequest),两者的请求格式处理逻辑不匹配。
解决方法
方法一:将User对象转换为Map结构
直接构造符合JSON格式的Map代替自定义User类,让Callable函数可以正常序列化:
private fun addMessage(): Task<String>? { // 用Map替代User类,构造符合要求的用户列表 val userList = listOf( mapOf("phone" to "55512345"), mapOf("phone" to "972525276676"), mapOf("phone" to "55512347") ) val data: MutableMap<String, Any> = HashMap() data["users"] = userList functions.getHttpsCallable("getUsers") .call(data) .addOnFailureListener { Log.d("DTAG", it.toString()) } .addOnSuccessListener { Log.d("DTAG","Ok: ${it.data.toString()}") } return null }
方法二:适配Cloud Function类型(改用Callable函数)
将Cloud Function从普通HTTP函数(onRequest)改为Callable函数(onCall),匹配Android端的调用方式:
exports.getUsers = functions.https.onCall(async (data, context) => { // Callable函数直接接收data参数,无需解析request.body if (!data?.users) { throw new functions.https.HttpsError('invalid-argument', '缺少用户数据'); } const phonelist = data.users.map(user => user.phone.toString()); const userlist = []; const snapshot = await db.collection("users").get(); snapshot.docs.forEach((userDoc) => { const phone = userDoc.get("phone"); if (!phone) return; const isContain = phonelist.some(num => phone.includes(num)); if (isContain) { userlist.push(userDoc.data()); } }); return {result: userlist}; });
注:
onCall函数会自动处理请求的序列化/反序列化,返回结果也会自动包装成Callable函数要求的格式,同时提供更规范的错误处理机制。
方法三:通过JSON库序列化User类(保留自定义类)
如果不想放弃User数据类,可以用Gson/Moshi等JSON库将User列表转换为可序列化的Map结构:
// 先添加Gson依赖到build.gradle // implementation 'com.google.code.gson:gson:2.10.1' private fun addMessage(): Task<String>? { val usr1 = User("55512345") val usr2 = User("972525276676") val usr3 = User("55512347") val userList = listOf(usr1,usr2,usr3) val gson = Gson() // 将User列表转成List<Map<String, String>> val userMapList = gson.fromJson( gson.toJson(userList), object : TypeToken<List<Map<String, String>>>() {}.type ) val data: MutableMap<String, Any> = HashMap() data["users"] = userMapList functions.getHttpsCallable("getUsers") .call(data) .addOnFailureListener { Log.d("DTAG", it.toString()) } .addOnSuccessListener { Log.d("DTAG","Ok: ${it.data.toString()}") } return null }
内容的提问来源于stack exchange,提问作者Dim
相关产品推荐
相关产品推荐

