1919
2020#include " app/src/embedded_file.h"
2121#include " app/src/include/firebase/future.h"
22+ #include " app/src/include/firebase/internal/mutex.h"
2223#include " app/src/reference_counted_future_impl.h"
2324#include " app/src/util_android.h"
2425#include " app_check/app_check_resources.h"
@@ -100,6 +101,27 @@ static const JNINativeMethod kNativeJniAppCheckProviderMethods[] = {
100101 reinterpret_cast <void *>(JniAppCheckProvider_nativeGetToken)},
101102};
102103
104+ // clang-format off
105+ #define JNI_APP_CHECK_LISTENER_METHODS (X ) \
106+ X (Constructor, " <init>" , " (J)V" )
107+ // clang-format on
108+
109+ METHOD_LOOKUP_DECLARATION (jni_app_check_listener,
110+ JNI_APP_CHECK_LISTENER_METHODS)
111+ METHOD_LOOKUP_DEFINITION (
112+ jni_app_check_listener,
113+ " com/google/firebase/appcheck/internal/cpp/JniAppCheckListener" ,
114+ JNI_APP_CHECK_LISTENER_METHODS)
115+
116+ JNIEXPORT void JNICALL JniAppCheckListener_nativeOnAppCheckTokenChanged (
117+ JNIEnv* env, jobject clazz, jlong c_app_check, jobject token);
118+
119+ static const JNINativeMethod kNativeJniAppCheckListenerMethods [] = {
120+ {" nativeOnAppCheckTokenChanged" ,
121+ " (JLcom/google/firebase/appcheck/AppCheckToken;)V" ,
122+ reinterpret_cast <void *>(JniAppCheckListener_nativeOnAppCheckTokenChanged)},
123+ };
124+
103125static const char * kApiIdentifier = " AppCheck" ;
104126
105127static AppCheckProviderFactory* g_provider_factory = nullptr ;
@@ -127,13 +149,24 @@ bool CacheAppCheckMethodIds(
127149 FIREBASE_ARRAYSIZE (kNativeJniAppCheckProviderMethods )))) {
128150 return false ;
129151 }
152+ // Cache the JniAppCheckListener class and register the native callback
153+ // methods.
154+ if (!(jni_app_check_listener::CacheClassFromFiles (env, activity,
155+ &embedded_files) &&
156+ jni_app_check_listener::CacheMethodIds (env, activity) &&
157+ jni_app_check_listener::RegisterNatives (
158+ env, kNativeJniAppCheckListenerMethods ,
159+ FIREBASE_ARRAYSIZE (kNativeJniAppCheckListenerMethods )))) {
160+ return false ;
161+ }
130162 return app_check::CacheMethodIds (env, activity);
131163}
132164
133165void ReleaseAppCheckClasses (JNIEnv* env) {
134166 app_check::ReleaseClass (env);
135167 jni_provider_factory::ReleaseClass (env);
136168 jni_provider::ReleaseClass (env);
169+ jni_app_check_listener::ReleaseClass (env);
137170}
138171
139172// Release cached Java classes.
@@ -195,7 +228,7 @@ JNIEXPORT void JNICALL JniAppCheckProvider_nativeGetToken(
195228 jobject task_completion_source_global =
196229 env->NewGlobalRef (task_completion_source);
197230
198- // Defines a c ++ callback method to call
231+ // Defines a C ++ callback method to call
199232 // JniAppCheckProvider.HandleGetTokenResult with the resulting token
200233 auto token_callback{[j_provider_global, task_completion_source_global](
201234 firebase::app_check::AppCheckToken token,
@@ -219,6 +252,13 @@ JNIEXPORT void JNICALL JniAppCheckProvider_nativeGetToken(
219252 provider->GetToken (token_callback);
220253}
221254
255+ JNIEXPORT void JNICALL JniAppCheckListener_nativeOnAppCheckTokenChanged (
256+ JNIEnv* env, jobject clazz, jlong c_app_check, jobject token) {
257+ auto app_check_internal = reinterpret_cast <AppCheckInternal*>(c_app_check);
258+ AppCheckToken cpp_token = CppTokenFromAndroidToken (env, token);
259+ app_check_internal->NotifyTokenChanged (cpp_token);
260+ }
261+
222262AppCheckInternal::AppCheckInternal (App* app) : app_(app) {
223263 future_manager ().AllocFutureApi (this , kAppCheckFnCount );
224264
@@ -284,16 +324,40 @@ AppCheckInternal::AppCheckInternal(App* app) : app_(app) {
284324 FIREBASE_ASSERT (!util::CheckAndClearJniExceptions (env));
285325 env->DeleteLocalRef (j_factory);
286326 }
327+
328+ // Add a token-changed listener and give it a pointer to the C++ listeners.
329+ jobject j_listener =
330+ env->NewObject (jni_app_check_listener::GetClass (),
331+ jni_app_check_listener::GetMethodId (
332+ jni_app_check_listener::kConstructor ),
333+ reinterpret_cast <jlong>(this ));
334+ FIREBASE_ASSERT (!util::CheckAndClearJniExceptions (env));
335+ env->CallVoidMethod (app_check_impl_,
336+ app_check::GetMethodId (app_check::kAddAppCheckListener ),
337+ j_listener);
338+ FIREBASE_ASSERT (!util::CheckAndClearJniExceptions (env));
339+ j_app_check_listener_ = env->NewGlobalRef (j_listener);
340+ env->DeleteLocalRef (j_listener);
287341 } else {
288342 app_check_impl_ = nullptr ;
343+ j_app_check_listener_ = nullptr ;
289344 }
290345}
291346
292347AppCheckInternal::~AppCheckInternal () {
293348 future_manager ().ReleaseFutureApi (this );
294349 JNIEnv* env = app_->GetJNIEnv ();
295350 app_ = nullptr ;
351+ listeners_.clear ();
296352
353+ if (j_app_check_listener_ != nullptr ) {
354+ env->CallVoidMethod (
355+ app_check_impl_,
356+ app_check::GetMethodId (app_check::kRemoveAppCheckListener ),
357+ j_app_check_listener_);
358+ FIREBASE_ASSERT (!util::CheckAndClearJniExceptions (env));
359+ env->DeleteGlobalRef (j_app_check_listener_);
360+ }
297361 if (app_check_impl_ != nullptr ) {
298362 env->DeleteGlobalRef (app_check_impl_);
299363 }
@@ -314,7 +378,7 @@ ReferenceCountedFutureImpl* AppCheckInternal::future() {
314378
315379void AppCheckInternal::SetAppCheckProviderFactory (
316380 AppCheckProviderFactory* factory) {
317- // Store the c ++ factory in a static variable.
381+ // Store the C ++ factory in a static variable.
318382 // Whenever an instance of AppCheck is created, it will read this variable
319383 // and install the factory as it is initialized.
320384 g_provider_factory = factory;
@@ -357,9 +421,28 @@ Future<AppCheckToken> AppCheckInternal::GetAppCheckTokenLastResult() {
357421 future ()->LastResult (kAppCheckFnGetAppCheckToken ));
358422}
359423
360- void AppCheckInternal::AddAppCheckListener (AppCheckListener* listener) {}
424+ void AppCheckInternal::AddAppCheckListener (AppCheckListener* listener) {
425+ MutexLock lock (listeners_mutex_);
426+ auto it = std::find (listeners_.begin (), listeners_.end (), listener);
427+ if (it == listeners_.end ()) {
428+ listeners_.push_back (listener);
429+ }
430+ }
431+
432+ void AppCheckInternal::RemoveAppCheckListener (AppCheckListener* listener) {
433+ MutexLock lock (listeners_mutex_);
434+ auto it = std::find (listeners_.begin (), listeners_.end (), listener);
435+ if (it != listeners_.end ()) {
436+ listeners_.erase (it);
437+ }
438+ }
361439
362- void AppCheckInternal::RemoveAppCheckListener (AppCheckListener* listener) {}
440+ void AppCheckInternal::NotifyTokenChanged (AppCheckToken token) {
441+ MutexLock lock (listeners_mutex_);
442+ for (AppCheckListener* listener : listeners_) {
443+ listener->OnAppCheckTokenChanged (token);
444+ }
445+ }
363446
364447} // namespace internal
365448} // namespace app_check
0 commit comments