diff --git a/README.md b/README.md index 67ea0600..db1cd5c9 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,32 @@ useEffect(() => { }, []); ``` +For convenience, Stripe Terminal SDK also provides an util that handles all needed Android permissions. +In order to use it follow below instrustions: + +```tsx +import { requestNeededAndroidPermissions } from 'stripe-terminal-react-native'; + +try { + const granted = await requestNeededAndroidPermissions({ + accessFineLocation: { + title: 'Location Permission Permission', + message: 'App needs access to your Location', + buttonPositive: 'Accept', + }, + }); + if (granted) { + // init SDK + } else { + console.error( + 'Location and BT services are required in order to connect to a reader.' + ); + } +} catch (e) { + console.error(e); +} +``` + #### Manifest To enable compatibility the library with the latest Android 12 please make sure that you add following requirements: diff --git a/docs/set-up-your-sdk.md b/docs/set-up-your-sdk.md index 63e9ec35..617cdd9d 100644 --- a/docs/set-up-your-sdk.md +++ b/docs/set-up-your-sdk.md @@ -85,7 +85,7 @@ useEffect(() => { PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, { title: 'Location Permission Permission', - message: 'App needs access to your Location ', + message: 'App needs access to your Location', buttonPositive: 'Accept', } ); @@ -102,6 +102,32 @@ useEffect(() => { }, []); ``` +For convenience, Stripe Terminal SDK also provides an util that handles all needed Android permissions. +In order to use it follow below instrustions: + +```tsx +import { requestNeededAndroidPermissions } from 'stripe-terminal-react-native'; + +try { + const granted = await requestNeededAndroidPermissions({ + accessFineLocation: { + title: 'Location Permission Permission', + message: 'App needs access to your Location', + buttonPositive: 'Accept', + }, + }); + if (granted) { + // init SDK + } else { + console.error( + 'Location and BT services are required in order to connect to a reader.' + ); + } +} catch (e) { + console.error(e); +} +``` + #### Manifest To enable compatibility the library with the latest Android 12 please make sure that you ad following requirements: diff --git a/example/src/App.tsx b/example/src/App.tsx index 029f6518..ca629594 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -6,13 +6,7 @@ import { TransitionPresets, } from '@react-navigation/stack'; import HomeScreen from './screens/HomeScreen'; -import { - Alert, - PermissionsAndroid, - Platform, - StatusBar, - StyleSheet, -} from 'react-native'; +import { Alert, Platform, StatusBar, StyleSheet } from 'react-native'; import { colors } from './colors'; import { LogContext, Log, Event } from './components/LogContext'; import DiscoverReadersScreen from './screens/DiscoverReadersScreen'; @@ -27,11 +21,11 @@ import ReadReusableCardScreen from './screens/ReadReusableCardScreen'; import LogListScreen from './screens/LogListScreen'; import LogScreen from './screens/LogScreen'; import RegisterInternetReaderScreen from './screens/RegisterInternetReaderScreen'; -import { isAndroid12orHigher } from './utils'; import { Reader, Location, useStripeTerminal, + requestNeededAndroidPermissions, } from 'stripe-terminal-react-native'; import { LogBox } from 'react-native'; @@ -107,50 +101,23 @@ export default function App() { useEffect(() => { async function handlePermissions() { try { - const granted = await PermissionsAndroid.request( - PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, - { - title: 'Location Permission', - message: 'App needs access to your Location ', + const granted = await requestNeededAndroidPermissions({ + accessFineLocation: { + title: 'Location Permission Permission', + message: 'App needs access to your Location', buttonPositive: 'Accept', - } - ); - - if (hasGrantedPermission(granted)) { - if (isAndroid12orHigher()) { - const grantedBT = await PermissionsAndroid.request( - PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT, - { - title: 'BT Permission', - message: 'App needs access to Bluetooth ', - buttonPositive: 'Accept', - } - ); - - const grantedBTScan = await PermissionsAndroid.request( - PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN, - { - title: 'BT Permission', - message: 'App needs access to Bluetooth ', - buttonPositive: 'Accept', - } - ); - if ( - hasGrantedPermission(grantedBT) && - hasGrantedPermission(grantedBTScan) - ) { - handlePermissionsSuccess(); - return; - } else { - handlePermissionsError(); - return; - } - } + }, + }); + if (granted) { handlePermissionsSuccess(); } else { - handlePermissionsError(); + console.error( + 'Location and BT services are required in order to connect to a reader.' + ); } - } catch {} + } catch (e) { + console.error(e); + } } if (Platform.OS === 'android') { handlePermissions(); @@ -160,12 +127,6 @@ export default function App() { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const handlePermissionsError = () => { - console.error( - 'Location and BT services are required in order to connect to a reader.' - ); - }; - const handlePermissionsSuccess = async () => { const { error } = await initStripe({ logLevel: 'verbose', @@ -177,10 +138,6 @@ export default function App() { } }; - const hasGrantedPermission = (status: string) => { - return status === PermissionsAndroid.RESULTS.GRANTED; - }; - const addLogs = (newLog: Log) => { const updateLog = (log: Log) => log.name === newLog.name diff --git a/src/index.tsx b/src/index.tsx index 6adfbb70..9ca50068 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -17,3 +17,6 @@ export { withStripeTerminal, WithStripeTerminalProps, } from './components/withStripeTerminal'; + +// utils +export { requestNeededAndroidPermissions } from './utils/androidPermissionsUtils'; diff --git a/src/utils/androidPermissionsUtils.ts b/src/utils/androidPermissionsUtils.ts new file mode 100644 index 00000000..b37f9b2c --- /dev/null +++ b/src/utils/androidPermissionsUtils.ts @@ -0,0 +1,59 @@ +import { PermissionsAndroid, Platform } from 'react-native'; + +const defaultFineLocationParams = { + title: 'Location Permission', + message: 'App needs access to your Location', + buttonPositive: 'Accept', +}; + +type PermissionsProps = { + accessFineLocation?: { + title: string; + message: string; + buttonPositive: string; + }; +}; + +const isAndroid12orHigher = () => + Platform.OS === 'android' && Platform.Version >= 31; + +export async function requestNeededAndroidPermissions({ + accessFineLocation = defaultFineLocationParams, +}: PermissionsProps | undefined = {}): Promise { + let hasGrantedLocationPermissions = false; + let hasGrantedBluetoothPermissions = false; + + const grantedFineLocation = await PermissionsAndroid.request( + PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, + accessFineLocation || defaultFineLocationParams + ); + + if (hasGrantedPermission(grantedFineLocation)) { + hasGrantedLocationPermissions = true; + + if (isAndroid12orHigher()) { + const grantedBT = await PermissionsAndroid.request( + // BLUETOOTH_CONNECT doesn't support customization + PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT + ); + + const grantedBTScan = await PermissionsAndroid.request( + // BLUETOOTH_SCAN doesn't support customization + PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN + ); + if ( + hasGrantedPermission(grantedBT) && + hasGrantedPermission(grantedBTScan) + ) { + hasGrantedBluetoothPermissions = true; + } + } else { + hasGrantedBluetoothPermissions = true; + } + } + return hasGrantedBluetoothPermissions && hasGrantedLocationPermissions; +} + +const hasGrantedPermission = (status: string) => { + return status === PermissionsAndroid.RESULTS.GRANTED; +};