同步获取Firebase用户令牌

时间:2018-02-15 23:06:32

标签: android firebase firebase-authentication

我正在尝试使用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。

还有其他方法可以同步获取令牌,还是让线程等到任务完成?

5 个答案:

答案 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
}