30
30
import android .util .Base64 ;
31
31
32
32
import androidx .annotation .NonNull ;
33
+ import androidx .annotation .WorkerThread ;
33
34
35
+ import com .google .android .gms .tasks .Task ;
36
+ import com .google .android .gms .tasks .Tasks ;
34
37
import com .google .firebase .FirebaseApp ;
35
38
import com .google .firebase .FirebaseOptions ;
36
- import com .google .firebase .iid .FirebaseInstanceId ;
37
39
import com .google .firebase .messaging .FirebaseMessaging ;
38
40
41
+ import java .io .IOException ;
42
+ import java .lang .reflect .InvocationTargetException ;
43
+ import java .lang .reflect .Method ;
44
+ import java .util .concurrent .ExecutionException ;
45
+
39
46
class PushRegistratorFCM extends PushRegistratorAbstractGoogle {
40
47
41
48
// project_info.project_id
@@ -54,11 +61,64 @@ String getProviderName() {
54
61
return "FCM" ;
55
62
}
56
63
64
+ @ WorkerThread
57
65
@ Override
58
- String getToken (String senderId ) throws Throwable {
66
+ String getToken (String senderId ) throws ExecutionException , InterruptedException , IOException {
59
67
initFirebaseApp (senderId );
60
- FirebaseInstanceId instanceId = FirebaseInstanceId .getInstance (firebaseApp );
61
- return instanceId .getToken (senderId , FirebaseMessaging .INSTANCE_ID_SCOPE );
68
+
69
+ try {
70
+ return getTokenWithClassFirebaseMessaging ();
71
+ } catch (NoClassDefFoundError | NoSuchMethodError e ) {
72
+ // Class or method wil be missing at runtime if firebase-message older than 21.0.0 is used.
73
+ OneSignal .Log (
74
+ OneSignal .LOG_LEVEL .INFO ,
75
+ "FirebaseMessaging.getToken not found, attempting to use FirebaseInstanceId.getToken"
76
+ );
77
+ }
78
+
79
+ // Fallback for firebase-message versions older than 21.0.0
80
+ return getTokenWithClassFirebaseInstanceId (senderId );
81
+ }
82
+
83
+ // This method is only used if firebase-message older than 21.0.0 is in the app
84
+ // We are using reflection here so we can compile with firebase-message:22.0.0 and newer
85
+ // - This version of Firebase has completely removed FirebaseInstanceId
86
+ @ Deprecated
87
+ @ WorkerThread
88
+ private String getTokenWithClassFirebaseInstanceId (String senderId ) throws IOException {
89
+ // The following code is equivalent to:
90
+ // FirebaseInstanceId instanceId = FirebaseInstanceId.getInstance(firebaseApp);
91
+ // return instanceId.getToken(senderId, FirebaseMessaging.INSTANCE_ID_SCOPE);
92
+ Exception exception ;
93
+ try {
94
+ Class <?> FirebaseInstanceIdClass = Class .forName ("com.google.firebase.iid.FirebaseInstanceId" );
95
+ Method getInstanceMethod = FirebaseInstanceIdClass .getMethod ("getInstance" , FirebaseApp .class );
96
+ Object instanceId = getInstanceMethod .invoke (null , firebaseApp );
97
+ Method getTokenMethod = instanceId .getClass ().getMethod ("getToken" , String .class , String .class );
98
+ Object token = getTokenMethod .invoke (instanceId , senderId , "FCM" );
99
+ return (String ) token ;
100
+ } catch (ClassNotFoundException e ) {
101
+ exception = e ;
102
+ } catch (NoSuchMethodException e ) {
103
+ exception = e ;
104
+ } catch (IllegalAccessException e ) {
105
+ exception = e ;
106
+ } catch (InvocationTargetException e ) {
107
+ exception = e ;
108
+ }
109
+
110
+ throw new Error ("Reflection error on FirebaseInstanceId.getInstance(firebaseApp).getToken(senderId, FirebaseMessaging.INSTANCE_ID_SCOPE)" , exception );
111
+ }
112
+
113
+ @ WorkerThread
114
+ private String getTokenWithClassFirebaseMessaging () throws ExecutionException , InterruptedException {
115
+ // We use firebaseApp.get(FirebaseMessaging.class) instead of FirebaseMessaging.getInstance()
116
+ // as the latter uses the default Firebase app. We need to use a custom Firebase app as
117
+ // the senderId is provided at runtime.
118
+ FirebaseMessaging fcmInstance = firebaseApp .get (FirebaseMessaging .class );
119
+ // FirebaseMessaging.getToken API was introduced in firebase-messaging:21.0.0
120
+ Task <String > tokenTask = fcmInstance .getToken ();
121
+ return Tasks .await (tokenTask );
62
122
}
63
123
64
124
private void initFirebaseApp (String senderId ) {
0 commit comments