15
15
package com .google .firebase .app .distribution ;
16
16
17
17
import static com .google .firebase .app .distribution .ReleaseIdentificationUtils .calculateApkHash ;
18
+ import static com .google .firebase .app .distribution .ReleaseIdentificationUtils .getPackageInfo ;
19
+ import static com .google .firebase .app .distribution .ReleaseIdentificationUtils .getPackageInfoWithMetadata ;
20
+ import static com .google .firebase .app .distribution .TaskUtils .runAsyncInTask ;
18
21
19
22
import android .content .Context ;
20
23
import android .content .pm .PackageInfo ;
21
- import android .content .pm .PackageManager ;
22
24
import androidx .annotation .NonNull ;
25
+ import androidx .annotation .Nullable ;
23
26
import androidx .annotation .VisibleForTesting ;
24
27
import androidx .core .content .pm .PackageInfoCompat ;
25
28
import com .google .android .gms .tasks .Task ;
26
29
import com .google .android .gms .tasks .Tasks ;
27
30
import com .google .firebase .FirebaseApp ;
31
+ import com .google .firebase .app .distribution .FirebaseAppDistributionException .Status ;
28
32
import com .google .firebase .app .distribution .internal .LogWrapper ;
29
33
import com .google .firebase .inject .Provider ;
30
34
import com .google .firebase .installations .FirebaseInstallationsApi ;
@@ -87,82 +91,72 @@ public synchronized Task<AppDistributionReleaseInternal> checkForNewRelease() {
87
91
88
92
this .cachedCheckForNewRelease =
89
93
Tasks .whenAllSuccess (installationIdTask , installationAuthTokenTask )
94
+ .continueWithTask (TaskUtils ::handleTaskFailure )
90
95
.onSuccessTask (
91
- taskExecutor ,
92
- tasks -> {
93
- String fid = installationIdTask .getResult ();
94
- InstallationTokenResult installationTokenResult =
95
- installationAuthTokenTask .getResult ();
96
- try {
97
- AppDistributionReleaseInternal newRelease =
98
- getNewReleaseFromClient (
99
- fid ,
100
- firebaseApp .getOptions ().getApplicationId (),
101
- firebaseApp .getOptions ().getApiKey (),
102
- installationTokenResult .getToken ());
103
- return Tasks .forResult (newRelease );
104
- } catch (FirebaseAppDistributionException ex ) {
105
- return Tasks .forException (ex );
106
- }
107
- })
108
- .continueWithTask (
109
- taskExecutor ,
110
- task ->
111
- TaskUtils .handleTaskFailure (
112
- task ,
113
- Constants .ErrorMessages .NETWORK_ERROR ,
114
- FirebaseAppDistributionException .Status .NETWORK_FAILURE ));
96
+ unused ->
97
+ getNewReleaseFromClientTask (
98
+ installationIdTask .getResult (),
99
+ firebaseApp .getOptions ().getApplicationId (),
100
+ firebaseApp .getOptions ().getApiKey (),
101
+ installationAuthTokenTask .getResult ().getToken ()));
115
102
116
103
return cachedCheckForNewRelease ;
117
104
}
118
105
106
+ private Task <AppDistributionReleaseInternal > getNewReleaseFromClientTask (
107
+ String fid , String appId , String apiKey , String authToken ) {
108
+ return runAsyncInTask (
109
+ taskExecutor , () -> getNewReleaseFromClient (fid , appId , apiKey , authToken ));
110
+ }
111
+
112
+ @ Nullable
119
113
@ VisibleForTesting
120
114
AppDistributionReleaseInternal getNewReleaseFromClient (
121
115
String fid , String appId , String apiKey , String authToken )
122
116
throws FirebaseAppDistributionException {
117
+ AppDistributionReleaseInternal retrievedNewRelease =
118
+ firebaseAppDistributionTesterApiClient .fetchNewRelease (
119
+ fid , appId , apiKey , authToken , firebaseApp .getApplicationContext ());
120
+
121
+ if (retrievedNewRelease == null ) {
122
+ LogWrapper .getInstance ().v (TAG + "Tester does not have access to any releases" );
123
+ return null ;
124
+ }
125
+
126
+ long newReleaseBuildVersion = parseBuildVersion (retrievedNewRelease .getBuildVersion ());
127
+
128
+ if (isOlderBuildVersion (newReleaseBuildVersion )) {
129
+ LogWrapper .getInstance ().v (TAG + "New release has lower version code than current release" );
130
+ return null ;
131
+ }
132
+
133
+ if (isNewerBuildVersion (newReleaseBuildVersion )
134
+ || !isSameAsInstalledRelease (retrievedNewRelease )
135
+ || hasDifferentAppVersionName (retrievedNewRelease )) {
136
+ return retrievedNewRelease ;
137
+ } else {
138
+ LogWrapper .getInstance ().v (TAG + "New release is older or is currently installed" );
139
+ return null ;
140
+ }
141
+ }
142
+
143
+ private long parseBuildVersion (String buildVersion ) throws FirebaseAppDistributionException {
123
144
try {
124
- AppDistributionReleaseInternal retrievedNewRelease =
125
- firebaseAppDistributionTesterApiClient .fetchNewRelease (
126
- fid , appId , apiKey , authToken , firebaseApp .getApplicationContext ());
127
-
128
- if (retrievedNewRelease == null ) {
129
- LogWrapper .getInstance ().v (TAG + "Tester does not have access to any releases" );
130
- return null ;
131
- }
132
-
133
- if (!canInstall (retrievedNewRelease )) {
134
- LogWrapper .getInstance ().v (TAG + "New release has lower version code than current release" );
135
- return null ;
136
- }
137
-
138
- if (isNewerBuildVersion (retrievedNewRelease )
139
- || !isSameAsInstalledRelease (retrievedNewRelease )
140
- || hasDifferentAppVersionName (retrievedNewRelease )) {
141
- return retrievedNewRelease ;
142
- } else {
143
- // Return null if retrieved new release is older or currently installed
144
- LogWrapper .getInstance ().v (TAG + "New release is older or is currently installed" );
145
- return null ;
146
- }
145
+ return Long .parseLong (buildVersion );
147
146
} catch (NumberFormatException e ) {
148
- LogWrapper .getInstance ().e (TAG + "Error parsing buildVersion." , e );
149
147
throw new FirebaseAppDistributionException (
150
- Constants .ErrorMessages .NETWORK_ERROR ,
151
- FirebaseAppDistributionException .Status .NETWORK_FAILURE ,
152
- e );
148
+ "Could not parse build version of new release: " + buildVersion , Status .UNKNOWN , e );
153
149
}
154
150
}
155
151
156
- private boolean canInstall ( AppDistributionReleaseInternal newRelease )
152
+ private boolean isOlderBuildVersion ( long newReleaseBuildVersion )
157
153
throws FirebaseAppDistributionException {
158
- return Long .parseLong (newRelease .getBuildVersion ())
159
- >= getInstalledAppVersionCode (firebaseApp .getApplicationContext ());
154
+ return newReleaseBuildVersion < getInstalledAppVersionCode (firebaseApp .getApplicationContext ());
160
155
}
161
156
162
- private boolean isNewerBuildVersion (AppDistributionReleaseInternal newRelease )
157
+ private boolean isNewerBuildVersion (long newReleaseBuildVersion )
163
158
throws FirebaseAppDistributionException {
164
- return Long .parseLong (newRelease .getBuildVersion ())
165
- > getInstalledAppVersionCode (firebaseApp .getApplicationContext ());
159
+ return newReleaseBuildVersion > getInstalledAppVersionCode (firebaseApp .getApplicationContext ());
166
160
}
167
161
168
162
private boolean hasDifferentAppVersionName (AppDistributionReleaseInternal newRelease )
@@ -179,17 +173,26 @@ boolean isSameAsInstalledRelease(AppDistributionReleaseInternal newRelease)
179
173
return hasSameHashAsInstalledRelease (newRelease );
180
174
}
181
175
182
- // TODO(lkellogg): getIasArtifactId() will likely never be null since it's set to the empty
183
- // string if not present in the response
184
- if ( newRelease . getIasArtifactId () == null ) {
176
+ if ( newRelease . getIasArtifactId () == null || newRelease . getIasArtifactId (). isEmpty ()) {
177
+ LogWrapper . getInstance ()
178
+ . w ( TAG + "AAB release missing IAS Artifact ID. Assuming new release is different." );
185
179
return false ;
186
180
}
187
- // AAB BinaryType
188
- return newRelease
189
- .getIasArtifactId ()
190
- .equals (
191
- ReleaseIdentificationUtils .extractInternalAppSharingArtifactId (
192
- firebaseApp .getApplicationContext ()));
181
+
182
+ String installedIasArtifactId ;
183
+ try {
184
+ installedIasArtifactId =
185
+ ReleaseIdentificationUtils .extractInternalAppSharingArtifactId (
186
+ firebaseApp .getApplicationContext ());
187
+ } catch (FirebaseAppDistributionException e ) {
188
+ LogWrapper .getInstance ()
189
+ .w (
190
+ TAG + "Could not get installed IAS artifact ID. Assuming new release is different." ,
191
+ e );
192
+ return false ;
193
+ }
194
+
195
+ return newRelease .getIasArtifactId ().equals (installedIasArtifactId );
193
196
}
194
197
195
198
private long getInstalledAppVersionCode (Context context ) throws FirebaseAppDistributionException {
@@ -201,19 +204,6 @@ private String getInstalledAppVersionName(Context context)
201
204
return getPackageInfo (context ).versionName ;
202
205
}
203
206
204
- private PackageInfo getPackageInfo (Context context ) throws FirebaseAppDistributionException {
205
- try {
206
- return context .getPackageManager ().getPackageInfo (context .getPackageName (), 0 );
207
- } catch (PackageManager .NameNotFoundException e ) {
208
- LogWrapper .getInstance ()
209
- .e (TAG + "Unable to find package with name " + context .getPackageName (), e );
210
- throw new FirebaseAppDistributionException (
211
- Constants .ErrorMessages .UNKNOWN_ERROR ,
212
- FirebaseAppDistributionException .Status .UNKNOWN ,
213
- e );
214
- }
215
- }
216
-
217
207
@ VisibleForTesting
218
208
String extractApkHash (PackageInfo packageInfo ) {
219
209
File sourceFile = new File (packageInfo .applicationInfo .sourceDir );
@@ -229,25 +219,19 @@ String extractApkHash(PackageInfo packageInfo) {
229
219
230
220
private boolean hasSameHashAsInstalledRelease (AppDistributionReleaseInternal newRelease )
231
221
throws FirebaseAppDistributionException {
232
- try {
233
- Context context = firebaseApp .getApplicationContext ();
234
- PackageInfo metadataPackageInfo =
235
- context
236
- .getPackageManager ()
237
- .getPackageInfo (context .getPackageName (), PackageManager .GET_META_DATA );
238
- String installedReleaseApkHash = extractApkHash (metadataPackageInfo );
239
-
240
- if (installedReleaseApkHash .isEmpty () || newRelease .getApkHash ().isEmpty ()) {
241
- LogWrapper .getInstance ().e (TAG + "Missing APK hash." );
242
- throw new FirebaseAppDistributionException (
243
- Constants .ErrorMessages .UNKNOWN_ERROR , FirebaseAppDistributionException .Status .UNKNOWN );
244
- }
245
- // If the hash of the zipped APK for the retrieved newRelease is equal to the stored hash
246
- // of the installed release, then they are the same release.
247
- return installedReleaseApkHash .equals (newRelease .getApkHash ());
248
- } catch (PackageManager .NameNotFoundException e ) {
249
- LogWrapper .getInstance ().e (TAG + "Unable to locate App." , e );
250
- return false ;
222
+ Context context = firebaseApp .getApplicationContext ();
223
+ PackageInfo metadataPackageInfo = getPackageInfoWithMetadata (context );
224
+ String installedReleaseApkHash = extractApkHash (metadataPackageInfo );
225
+
226
+ if (installedReleaseApkHash == null || installedReleaseApkHash .isEmpty ()) {
227
+ throw new FirebaseAppDistributionException (
228
+ "Could not calculate hash of installed APK" , Status .UNKNOWN );
229
+ } else if (newRelease .getApkHash ().isEmpty ()) {
230
+ throw new FirebaseAppDistributionException (
231
+ "Missing APK hash from new release" , Status .UNKNOWN );
251
232
}
233
+ // If the hash of the zipped APK for the retrieved newRelease is equal to the stored hash
234
+ // of the installed release, then they are the same release.
235
+ return installedReleaseApkHash .equals (newRelease .getApkHash ());
252
236
}
253
237
}
0 commit comments