我正在尝试使用Firebase令牌来验证我对Rest API的调用。我可以使用以下代码异步生成令牌。
FirebaseUser mUser = App.getFirebaseAuth().getCurrentUser();
if (mUser!=null) {
mUser.getIdToken(false)
.addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
public void onComplete(@NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
ID_TOKEN = task.getResult().getToken();
} else {
Log.e(App.TAG, "Firebase Token task ended with error.");
}
}
});
} else {
Log.i(App.TAG,"User is null, no Firebase Token available");
}
ID_TOKEN是一个保存结果的静态字符串变量。 问题是,我正在构建我的请求并添加身份验证标头。
headers.put("Authentication",
"Bearer + ID_TOKEN);
问题是,由于Firebase令牌是异步检索的,因此ID_TOKEN变量为空。我尝试使用
强制线程等待任务Tasks.await(任务)
但我得到一个例外,说在主线程中无法调用await。
还有其他方法可以同步获取令牌,还是让线程等到任务完成?
答案 0 :(得分:4)
我现在就是这样做的:
private suspend fun getTokenResult (firebaseUser: FirebaseUser) = suspendCoroutine<GetTokenResult?> { continuation ->
firebaseUser.getIdToken(true).addOnCompleteListener {
if (it.isSuccessful) {
continuation.resume(it.result)
} else {
continuation.resume(null)
}
}
使用挂起的函数和延续机制。因此,如果您使用的是 Coroutines
,这可能是最简单的方法
答案 1 :(得分:1)
我已经做到了,并且效果很好。 这是主要的类:
object FcmToken {
@JvmStatic
fun getToken(): String? {
val task = FirebaseInstanceId.getInstance().instanceId
try {
val result = Tasks.await(task)
return result.token
} catch (e: ExecutionException) {
throw IllegalArgumentException("")
} catch (e: InterruptedException) {
throw IllegalArgumentException("")
}
}
}
在视图模型中。
viewModelScope.launch(Dispatchers.IO) {
val result = FcmToken.getToken(viewModelScope)
Log.e("result", result.toString())
}
答案 2 :(得分:0)
强制某些东西在主线程上同步运行是一个非常糟糕的主意。它可能会锁定您的应用程序,并可能导致它到ANR。这就是为什么当你试图运行Tasks.await()
时Android会抱怨它 - 它知道可能存在问题。
学习如何以正确的方式执行异步编程会好得多。您必须在您必须提供的侦听器中接收令牌。
Please read this blog了解有关Firebase API异步原因的更多信息。
答案 3 :(得分:0)
如果可能,只需将以下所有操作(如headers.put(...)
移到onComplete
块中即可。这将保证执行顺序。
答案 4 :(得分:0)
我遇到了同样的问题,当我得到407时,我需要在Retrofit Authenticator中更新令牌。我使用CountDownLatch
override fun authenticate(route: Route?, response: Response): Request? {
val user = FirebaseAuth.getInstance().currentUser
var token: String? = null
val lock = CountDownLatch(1)
user?.getIdToken(true)?.addOnCompleteListener { task ->
if (task.isSuccessful) {
token = task.result?.token
if (token == null) {
lock.countDown() //<--unlock
return@addOnCompleteListener
}
//save token
} else {
lock.countDown() //<--unlock
return@addOnCompleteListener
}
}
lock.await() //<--wait unlock
return if (token != null)
response.request().newBuilder().header(AUTHORIZATION_KEY, token).build()
else null
}