Skip to content

Commit 0b0f858

Browse files
feat(app): add Play Services available utilities (#3601)
Co-authored-by: Mike Diarmid <mike.diarmid@gmail.com> [publish]
1 parent af511c7 commit 0b0f858

4 files changed

Lines changed: 259 additions & 2 deletions

File tree

docs/app/utils.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,48 @@ async function bootstrap() {
4444
}
4545
}
4646
```
47+
48+
# Android - Checking Play Services
49+
50+
It is useful to know if the Android device has play services available, and what to do in response to certain use cases:
51+
52+
```js
53+
import { utils } from '@react-native-firebase/app';
54+
55+
async function checkPlayServicesExample() {
56+
const {
57+
status,
58+
isAvailable,
59+
hasResolution,
60+
isUserResolvableError,
61+
} = utils.playServicesAvailability;
62+
// all good and valid \o/
63+
if (isAvailable) return Promise.resolve();
64+
// if the user can resolve the issue i.e by updating play services
65+
// then call Google Play's own/default prompting functionality
66+
if (isUserResolvableError || hasResolution) {
67+
switch (status) {
68+
case 1:
69+
// SERVICE_MISSING - Google Play services is missing on this device.
70+
// show something to user
71+
// and then attempt to install if necessary
72+
return utils.makePlayServicesAvailable();
73+
case 2:
74+
// SERVICE_VERSION_UPDATE_REQUIRED - The installed version of Google Play services is out of date.
75+
// show something to user
76+
// and then attempt to update if necessary
77+
return utils.resolutionForPlayServices();
78+
79+
default:
80+
// some default dialog / component?
81+
// use the link below to tailor response to status codes to suit your use case
82+
// https://developers.google.com/android/reference/com/google/android/gms/// common/ConnectionResult#SERVICE_VERSION_UPDATE_REQUIRED
83+
if (isUserResolvableError) return utils.promptForPlayServices();
84+
if (hasResolution) return utils.resolutionForPlayServices();
85+
}
86+
}
87+
// There's no way to resolve play services on this device
88+
// probably best to show a dialog / force crash the app
89+
return Promise.reject(new Error('Unable to find a valid play services version.'));
90+
}
91+
```

packages/app/e2e/utils.e2e.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,22 @@ describe('utils()', () => {
2929
should.equal(firebase.utils().isRunningInTestLab, false);
3030
});
3131
});
32+
33+
describe('playServicesAvailability', () => {
34+
it('returns isAvailable and Play Service status', async () => {
35+
const playService = await firebase.utils().playServicesAvailability;
36+
//iOS always returns { isAvailable: true, status: 0}
37+
should(playService.isAvailable).equal(true);
38+
should(playService.status).equal(0);
39+
});
40+
});
41+
42+
describe('getPlayServicesStatus', () => {
43+
it('returns isAvailable and Play Service status', async () => {
44+
const status = await firebase.utils().getPlayServicesStatus();
45+
//iOS always returns { isAvailable: true, status: 0}
46+
should(status.isAvailable).equal(true);
47+
should(status.status).equal(0);
48+
});
49+
});
3250
});

packages/app/lib/index.d.ts

Lines changed: 155 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,92 @@ export namespace Utils {
360360
FilePath: FilePath;
361361
}
362362

363+
/**
364+
* For further information on the status codes available & what they represent, please head over
365+
* to ConnectionResult documentation:
366+
* https://developers.google.com/android/reference/com/google/android/gms/common/ConnectionResult
367+
*/
368+
export enum PlayServicesAvailabilityStatusCodes {
369+
API_UNAVAILABLE = 16,
370+
CANCELED = 13,
371+
DEVELOPER_ERROR = 10,
372+
DRIVE_EXTERNAL_STORAGE_REQUIRED = 1500,
373+
INTERNAL_ERROR = 8,
374+
INTERRUPTED = 15,
375+
INVALID_ACCOUNT = 5,
376+
LICENSE_CHECK_FAILED = 11,
377+
NETWORK_ERROR = 7,
378+
RESOLUTION_REQUIRED = 6,
379+
RESTRICTED_PROFILE = 20,
380+
SERVICE_DISABLED = 3,
381+
SERVICE_INVALID = 9,
382+
SERVICE_MISSING = 1,
383+
SERVICE_MISSING_PERMISSION = 19,
384+
SERVICE_UPDATING = 18,
385+
SERVICE_VERSION_UPDATE_REQUIRED = 2,
386+
SIGN_IN_FAILED = 17,
387+
SIGN_IN_REQUIRED = 4,
388+
SUCCESS = 0,
389+
TIMEOUT = 14,
390+
}
391+
392+
export interface PlayServicesAvailability {
393+
/**
394+
* Returns a numeric status code. Please refer to Android documentation
395+
* for further information:
396+
* https://developers.google.com/android/reference/com/google/android/gms/common/ConnectionResult
397+
*
398+
* ```js
399+
* firebase.utils().playServicesAvailability.status;
400+
* ```
401+
*
402+
* @android Android only - iOS returns 0
403+
*/
404+
status: PlayServicesAvailabilityStatusCodes;
405+
406+
/**
407+
* Returns a boolean indicating whether Play Store is available on the device
408+
*
409+
* ```js
410+
* firebase.utils().playServicesAvailability.isAvailable;
411+
* ```
412+
*
413+
* @android Android only - iOS returns true
414+
*/
415+
isAvailable: boolean;
416+
417+
/**
418+
* If Play Services is not available on the device, hasResolution indicates
419+
* whether it is possible to do something about it (e.g. install Play Services).
420+
*
421+
* ```js
422+
* firebase.utils().playServicesAvailability.hasResolution;
423+
* ```
424+
* @android Android only - iOS returns undefined
425+
*/
426+
hasResolution: boolean | undefined;
427+
428+
/**
429+
* If an error was received, this indicates whether the error is resolvable
430+
*
431+
* ```js
432+
* firebase.utils().playServicesAvailability.isUserResolvableError;
433+
* ```
434+
* @android Android only - iOS returns undefined
435+
*/
436+
isUserResolvableError: boolean | undefined;
437+
438+
/**
439+
* A human readable error string
440+
*
441+
* ```js
442+
* firebase.utils().playServicesAvailability.error;
443+
* ```
444+
* @android Android only - iOS returns undefined
445+
*/
446+
error: string | undefined;
447+
}
448+
363449
/**
364450
* The React Native Firebase Utils service interface.
365451
*
@@ -375,11 +461,78 @@ export namespace Utils {
375461
*/
376462
export class Module extends FirebaseModule {
377463
/**
378-
* Returns true if this app is running inside a Firebase Test Lab environment. Always returns false on iOS.
464+
* Returns true if this app is running inside a Firebase Test Lab environment.
379465
*
380-
* @android
466+
* #### Example
467+
*
468+
* ```js
469+
* const isRunningInTestLab = await firebase.utils().isRunningInTestLab;
470+
* ```
471+
* @android Android only - iOS returns false
381472
*/
382473
isRunningInTestLab: boolean;
474+
/**
475+
* Returns PlayServicesAvailability properties
476+
*
477+
* #### Example
478+
*
479+
* ```js
480+
* const PlayServicesAvailability = await firebase.utils().playServicesAvailability;
481+
* ```
482+
*
483+
* @android Android only - iOS always returns { isAvailable: true, status: 0 }
484+
*/
485+
playServicesAvailability: PlayServicesAvailability;
486+
487+
/**
488+
* Returns PlayServicesAvailability properties
489+
*
490+
* #### Example
491+
*
492+
* ```js
493+
* const PlayServicesAvailability = await firebase.utils().getPlayServicesStatus();
494+
* ```
495+
*
496+
* @android Android only - iOS always returns { isAvailable: true, status: 0 }
497+
*/
498+
getPlayServicesStatus(): Promise<PlayServicesAvailability>;
499+
500+
/**
501+
* A prompt appears on the device to ask the user to update play services
502+
*
503+
* #### Example
504+
*
505+
* ```js
506+
* await firebase.utils().promptForPlayServices();
507+
* ```
508+
*
509+
* @android Android only - iOS returns undefined
510+
*/
511+
promptForPlayServices(): Promise<void>;
512+
/**
513+
* Attempts to make Google Play services available on this device
514+
*
515+
* #### Example
516+
*
517+
* ```js
518+
* await firebase.utils().makePlayServicesAvailable();
519+
* ```
520+
*
521+
* @android Android only - iOS returns undefined
522+
*/
523+
makePlayServicesAvailable(): Promise<void>;
524+
/**
525+
* Resolves an error by starting any intents requiring user interaction.
526+
*
527+
* #### Example
528+
*
529+
* ```js
530+
* await firebase.utils().resolutionForPlayServices();
531+
* ```
532+
*
533+
* @android Android only - iOS returns undefined
534+
*/
535+
resolutionForPlayServices(): Promise<void>;
383536
}
384537
}
385538

packages/app/lib/utils/index.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,47 @@ class FirebaseUtilsModule extends FirebaseModule {
3131
return this.native.isRunningInTestLab;
3232
}
3333

34+
get playServicesAvailability() {
35+
if (isIOS) {
36+
return {
37+
isAvailable: true,
38+
status: 0,
39+
};
40+
}
41+
return this.native.androidPlayServices;
42+
}
43+
44+
getPlayServicesStatus() {
45+
if (isIOS) {
46+
return Promise.resolve({
47+
isAvailable: true,
48+
status: 0,
49+
});
50+
}
51+
return this.native.androidGetPlayServicesStatus();
52+
}
53+
54+
promptForPlayServices() {
55+
if (isIOS) {
56+
return Promise.resolve();
57+
}
58+
return this.native.androidPromptForPlayServices();
59+
}
60+
61+
makePlayServicesAvailable() {
62+
if (isIOS) {
63+
return Promise.resolve();
64+
}
65+
return this.native.androidMakePlayServicesAvailable();
66+
}
67+
68+
resolutionForPlayServices() {
69+
if (isIOS) {
70+
return Promise.resolve();
71+
}
72+
return this.native.androidGetPlayServicesStatus();
73+
}
74+
3475
logInfo(...args) {
3576
return logger.logInfo(...args);
3677
}

0 commit comments

Comments
 (0)