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 ;
@@ -88,81 +92,70 @@ public synchronized Task<AppDistributionReleaseInternal> checkForNewRelease() {
88
92
this .cachedCheckForNewRelease =
89
93
Tasks .whenAllSuccess (installationIdTask , installationAuthTokenTask )
90
94
.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 ));
95
+ unused ->
96
+ getNewReleaseFromClientTask (
97
+ installationIdTask .getResult (),
98
+ firebaseApp .getOptions ().getApplicationId (),
99
+ firebaseApp .getOptions ().getApiKey (),
100
+ installationAuthTokenTask .getResult ().getToken ()));
115
101
116
102
return cachedCheckForNewRelease ;
117
103
}
118
104
105
+ private Task <AppDistributionReleaseInternal > getNewReleaseFromClientTask (
106
+ String fid , String appId , String apiKey , String authToken ) {
107
+ return runAsyncInTask (
108
+ taskExecutor , () -> getNewReleaseFromClient (fid , appId , apiKey , authToken ));
109
+ }
110
+
111
+ @ Nullable
119
112
@ VisibleForTesting
120
113
AppDistributionReleaseInternal getNewReleaseFromClient (
121
114
String fid , String appId , String apiKey , String authToken )
122
115
throws FirebaseAppDistributionException {
116
+ AppDistributionReleaseInternal retrievedNewRelease =
117
+ firebaseAppDistributionTesterApiClient .fetchNewRelease (
118
+ fid , appId , apiKey , authToken , firebaseApp .getApplicationContext ());
119
+
120
+ if (retrievedNewRelease == null ) {
121
+ LogWrapper .getInstance ().v (TAG + "Tester does not have access to any releases" );
122
+ return null ;
123
+ }
124
+
125
+ long newReleaseBuildVersion = parseBuildVersion (retrievedNewRelease .getBuildVersion ());
126
+
127
+ if (isOlderBuildVersion (newReleaseBuildVersion )) {
128
+ LogWrapper .getInstance ().v (TAG + "New release has lower version code than current release" );
129
+ return null ;
130
+ }
131
+
132
+ if (isNewerBuildVersion (newReleaseBuildVersion )
133
+ || !isSameAsInstalledRelease (retrievedNewRelease )
134
+ || hasDifferentAppVersionName (retrievedNewRelease )) {
135
+ return retrievedNewRelease ;
136
+ } else {
137
+ LogWrapper .getInstance ().v (TAG + "New release is older or is currently installed" );
138
+ return null ;
139
+ }
140
+ }
141
+
142
+ private long parseBuildVersion (String buildVersion ) throws FirebaseAppDistributionException {
123
143
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
- }
144
+ return Long .parseLong (buildVersion );
147
145
} catch (NumberFormatException e ) {
148
- LogWrapper .getInstance ().e (TAG + "Error parsing buildVersion." , e );
149
146
throw new FirebaseAppDistributionException (
150
- Constants .ErrorMessages .NETWORK_ERROR ,
151
- FirebaseAppDistributionException .Status .NETWORK_FAILURE ,
152
- e );
147
+ "Could not parse build version of new release: " + buildVersion , Status .UNKNOWN , e );
153
148
}
154
149
}
155
150
156
- private boolean canInstall ( AppDistributionReleaseInternal newRelease )
151
+ private boolean isOlderBuildVersion ( long newReleaseBuildVersion )
157
152
throws FirebaseAppDistributionException {
158
- return Long .parseLong (newRelease .getBuildVersion ())
159
- >= getInstalledAppVersionCode (firebaseApp .getApplicationContext ());
153
+ return newReleaseBuildVersion < getInstalledAppVersionCode (firebaseApp .getApplicationContext ());
160
154
}
161
155
162
- private boolean isNewerBuildVersion (AppDistributionReleaseInternal newRelease )
156
+ private boolean isNewerBuildVersion (long newReleaseBuildVersion )
163
157
throws FirebaseAppDistributionException {
164
- return Long .parseLong (newRelease .getBuildVersion ())
165
- > getInstalledAppVersionCode (firebaseApp .getApplicationContext ());
158
+ return newReleaseBuildVersion > getInstalledAppVersionCode (firebaseApp .getApplicationContext ());
166
159
}
167
160
168
161
private boolean hasDifferentAppVersionName (AppDistributionReleaseInternal newRelease )
@@ -179,17 +172,26 @@ boolean isSameAsInstalledRelease(AppDistributionReleaseInternal newRelease)
179
172
return hasSameHashAsInstalledRelease (newRelease );
180
173
}
181
174
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 ) {
175
+ if ( newRelease . getIasArtifactId () == null || newRelease . getIasArtifactId (). isEmpty ()) {
176
+ LogWrapper . getInstance ()
177
+ . w ( TAG + "AAB release missing IAS Artifact ID. Assuming new release is different." );
185
178
return false ;
186
179
}
187
- // AAB BinaryType
188
- return newRelease
189
- .getIasArtifactId ()
190
- .equals (
191
- ReleaseIdentificationUtils .extractInternalAppSharingArtifactId (
192
- firebaseApp .getApplicationContext ()));
180
+
181
+ String installedIasArtifactId ;
182
+ try {
183
+ installedIasArtifactId =
184
+ ReleaseIdentificationUtils .extractInternalAppSharingArtifactId (
185
+ firebaseApp .getApplicationContext ());
186
+ } catch (FirebaseAppDistributionException e ) {
187
+ LogWrapper .getInstance ()
188
+ .w (
189
+ TAG + "Could not get installed IAS artifact ID. Assuming new release is different." ,
190
+ e );
191
+ return false ;
192
+ }
193
+
194
+ return newRelease .getIasArtifactId ().equals (installedIasArtifactId );
193
195
}
194
196
195
197
private long getInstalledAppVersionCode (Context context ) throws FirebaseAppDistributionException {
@@ -201,19 +203,6 @@ private String getInstalledAppVersionName(Context context)
201
203
return getPackageInfo (context ).versionName ;
202
204
}
203
205
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
206
@ VisibleForTesting
218
207
String extractApkHash (PackageInfo packageInfo ) {
219
208
File sourceFile = new File (packageInfo .applicationInfo .sourceDir );
@@ -229,25 +218,19 @@ String extractApkHash(PackageInfo packageInfo) {
229
218
230
219
private boolean hasSameHashAsInstalledRelease (AppDistributionReleaseInternal newRelease )
231
220
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 ;
221
+ Context context = firebaseApp .getApplicationContext ();
222
+ PackageInfo metadataPackageInfo = getPackageInfoWithMetadata (context );
223
+ String installedReleaseApkHash = extractApkHash (metadataPackageInfo );
224
+
225
+ if (installedReleaseApkHash == null || installedReleaseApkHash .isEmpty ()) {
226
+ throw new FirebaseAppDistributionException (
227
+ "Could not calculate hash of installed APK" , Status .UNKNOWN );
228
+ } else if (newRelease .getApkHash ().isEmpty ()) {
229
+ throw new FirebaseAppDistributionException (
230
+ "Missing APK hash from new release" , Status .UNKNOWN );
251
231
}
232
+ // If the hash of the zipped APK for the retrieved newRelease is equal to the stored hash
233
+ // of the installed release, then they are the same release.
234
+ return installedReleaseApkHash .equals (newRelease .getApkHash ());
252
235
}
253
236
}
0 commit comments