Skip to content

Commit

Permalink
feat(app): add Play Services available utilities (#3601)
Browse files Browse the repository at this point in the history
Co-authored-by: Mike Diarmid <[email protected]>

[publish]
  • Loading branch information
russellwheatley authored Jun 3, 2020
1 parent af511c7 commit 0b0f858
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 2 deletions.
45 changes: 45 additions & 0 deletions docs/app/utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,48 @@ async function bootstrap() {
}
}
```

# Android - Checking Play Services

It is useful to know if the Android device has play services available, and what to do in response to certain use cases:

```js
import { utils } from '@react-native-firebase/app';

async function checkPlayServicesExample() {
const {
status,
isAvailable,
hasResolution,
isUserResolvableError,
} = utils.playServicesAvailability;
// all good and valid \o/
if (isAvailable) return Promise.resolve();
// if the user can resolve the issue i.e by updating play services
// then call Google Play's own/default prompting functionality
if (isUserResolvableError || hasResolution) {
switch (status) {
case 1:
// SERVICE_MISSING - Google Play services is missing on this device.
// show something to user
// and then attempt to install if necessary
return utils.makePlayServicesAvailable();
case 2:
// SERVICE_VERSION_UPDATE_REQUIRED - The installed version of Google Play services is out of date.
// show something to user
// and then attempt to update if necessary
return utils.resolutionForPlayServices();

default:
// some default dialog / component?
// use the link below to tailor response to status codes to suit your use case
// https://developers.google.com/android/reference/com/google/android/gms/// common/ConnectionResult#SERVICE_VERSION_UPDATE_REQUIRED
if (isUserResolvableError) return utils.promptForPlayServices();
if (hasResolution) return utils.resolutionForPlayServices();
}
}
// There's no way to resolve play services on this device
// probably best to show a dialog / force crash the app
return Promise.reject(new Error('Unable to find a valid play services version.'));
}
```
18 changes: 18 additions & 0 deletions packages/app/e2e/utils.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,22 @@ describe('utils()', () => {
should.equal(firebase.utils().isRunningInTestLab, false);
});
});

describe('playServicesAvailability', () => {
it('returns isAvailable and Play Service status', async () => {
const playService = await firebase.utils().playServicesAvailability;
//iOS always returns { isAvailable: true, status: 0}
should(playService.isAvailable).equal(true);
should(playService.status).equal(0);
});
});

describe('getPlayServicesStatus', () => {
it('returns isAvailable and Play Service status', async () => {
const status = await firebase.utils().getPlayServicesStatus();
//iOS always returns { isAvailable: true, status: 0}
should(status.isAvailable).equal(true);
should(status.status).equal(0);
});
});
});
157 changes: 155 additions & 2 deletions packages/app/lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,92 @@ export namespace Utils {
FilePath: FilePath;
}

/**
* For further information on the status codes available & what they represent, please head over
* to ConnectionResult documentation:
* https://developers.google.com/android/reference/com/google/android/gms/common/ConnectionResult
*/
export enum PlayServicesAvailabilityStatusCodes {
API_UNAVAILABLE = 16,
CANCELED = 13,
DEVELOPER_ERROR = 10,
DRIVE_EXTERNAL_STORAGE_REQUIRED = 1500,
INTERNAL_ERROR = 8,
INTERRUPTED = 15,
INVALID_ACCOUNT = 5,
LICENSE_CHECK_FAILED = 11,
NETWORK_ERROR = 7,
RESOLUTION_REQUIRED = 6,
RESTRICTED_PROFILE = 20,
SERVICE_DISABLED = 3,
SERVICE_INVALID = 9,
SERVICE_MISSING = 1,
SERVICE_MISSING_PERMISSION = 19,
SERVICE_UPDATING = 18,
SERVICE_VERSION_UPDATE_REQUIRED = 2,
SIGN_IN_FAILED = 17,
SIGN_IN_REQUIRED = 4,
SUCCESS = 0,
TIMEOUT = 14,
}

export interface PlayServicesAvailability {
/**
* Returns a numeric status code. Please refer to Android documentation
* for further information:
* https://developers.google.com/android/reference/com/google/android/gms/common/ConnectionResult
*
* ```js
* firebase.utils().playServicesAvailability.status;
* ```
*
* @android Android only - iOS returns 0
*/
status: PlayServicesAvailabilityStatusCodes;

/**
* Returns a boolean indicating whether Play Store is available on the device
*
* ```js
* firebase.utils().playServicesAvailability.isAvailable;
* ```
*
* @android Android only - iOS returns true
*/
isAvailable: boolean;

/**
* If Play Services is not available on the device, hasResolution indicates
* whether it is possible to do something about it (e.g. install Play Services).
*
* ```js
* firebase.utils().playServicesAvailability.hasResolution;
* ```
* @android Android only - iOS returns undefined
*/
hasResolution: boolean | undefined;

/**
* If an error was received, this indicates whether the error is resolvable
*
* ```js
* firebase.utils().playServicesAvailability.isUserResolvableError;
* ```
* @android Android only - iOS returns undefined
*/
isUserResolvableError: boolean | undefined;

/**
* A human readable error string
*
* ```js
* firebase.utils().playServicesAvailability.error;
* ```
* @android Android only - iOS returns undefined
*/
error: string | undefined;
}

/**
* The React Native Firebase Utils service interface.
*
Expand All @@ -375,11 +461,78 @@ export namespace Utils {
*/
export class Module extends FirebaseModule {
/**
* Returns true if this app is running inside a Firebase Test Lab environment. Always returns false on iOS.
* Returns true if this app is running inside a Firebase Test Lab environment.
*
* @android
* #### Example
*
* ```js
* const isRunningInTestLab = await firebase.utils().isRunningInTestLab;
* ```
* @android Android only - iOS returns false
*/
isRunningInTestLab: boolean;
/**
* Returns PlayServicesAvailability properties
*
* #### Example
*
* ```js
* const PlayServicesAvailability = await firebase.utils().playServicesAvailability;
* ```
*
* @android Android only - iOS always returns { isAvailable: true, status: 0 }
*/
playServicesAvailability: PlayServicesAvailability;

/**
* Returns PlayServicesAvailability properties
*
* #### Example
*
* ```js
* const PlayServicesAvailability = await firebase.utils().getPlayServicesStatus();
* ```
*
* @android Android only - iOS always returns { isAvailable: true, status: 0 }
*/
getPlayServicesStatus(): Promise<PlayServicesAvailability>;

/**
* A prompt appears on the device to ask the user to update play services
*
* #### Example
*
* ```js
* await firebase.utils().promptForPlayServices();
* ```
*
* @android Android only - iOS returns undefined
*/
promptForPlayServices(): Promise<void>;
/**
* Attempts to make Google Play services available on this device
*
* #### Example
*
* ```js
* await firebase.utils().makePlayServicesAvailable();
* ```
*
* @android Android only - iOS returns undefined
*/
makePlayServicesAvailable(): Promise<void>;
/**
* Resolves an error by starting any intents requiring user interaction.
*
* #### Example
*
* ```js
* await firebase.utils().resolutionForPlayServices();
* ```
*
* @android Android only - iOS returns undefined
*/
resolutionForPlayServices(): Promise<void>;
}
}

Expand Down
41 changes: 41 additions & 0 deletions packages/app/lib/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,47 @@ class FirebaseUtilsModule extends FirebaseModule {
return this.native.isRunningInTestLab;
}

get playServicesAvailability() {
if (isIOS) {
return {
isAvailable: true,
status: 0,
};
}
return this.native.androidPlayServices;
}

getPlayServicesStatus() {
if (isIOS) {
return Promise.resolve({
isAvailable: true,
status: 0,
});
}
return this.native.androidGetPlayServicesStatus();
}

promptForPlayServices() {
if (isIOS) {
return Promise.resolve();
}
return this.native.androidPromptForPlayServices();
}

makePlayServicesAvailable() {
if (isIOS) {
return Promise.resolve();
}
return this.native.androidMakePlayServicesAvailable();
}

resolutionForPlayServices() {
if (isIOS) {
return Promise.resolve();
}
return this.native.androidGetPlayServicesStatus();

This comment has been minimized.

Copy link
@Bardiamist

Bardiamist Jul 1, 2020

@russellwheatley Here is should be return this.native.androidResolutionForPlayServices();

}

logInfo(...args) {
return logger.logInfo(...args);
}
Expand Down

0 comments on commit 0b0f858

Please sign in to comment.