Check availability
Decide which wallet button to show before the user taps anything. The library reports two flags, checked without blocking the JS thread:
- isSupported: the device can pay with Apple Pay or Google Pay, whether or not a card is set up.
- hasActiveCard: the user has a card ready on one of your
supportedNetworks.
What each flag checks
| iOS | Android | |
|---|---|---|
isSupported | PKPaymentAuthorizationViewController.canMakePayments(): hardware and parental controls allow Apple Pay | isReadyToPay: Google Pay is available, and the user has a card or can add one |
hasActiveCard | canMakePayments(usingNetworks:capabilities:) with your supportedNetworks and merchantCapabilities | isReadyToPay with existingPaymentMethodRequired: true and your supportedNetworks, googlePayAllowedAuthMethods and merchantCapabilities |
Both flags are false when the check fails or, on Android, when Google Pay does not answer within 5 seconds. A value the payment would refuse rejects the payServiceStatus Promise with the configuration error that would fail startPayment: an unknown network, merchant capability or auth method, or a network list the platform offers none of (Google Pay has no idcredit or privateLabel). The hook logs the rejection and reports both flags as false.
Ask the environment you pay in
On Android, the check goes to the Google Pay environment you pass as googlePayEnvironment, 'TEST' by default. In TEST, Google Pay answers hasActiveCard: true whether or not the user has a card (Google's reference), so a production app must pass 'PRODUCTION' to get real answers. An emulator with no Google account signed in answered false even in TEST, so test both signed-in and signed-out devices.
Show the right button
- Android: show the Google Pay button when
isSupportedistrue. A user without a card adds one in the Google Pay sheet. Google offers no separate setup screen, soopenPaymentSetup()does nothing on Android. - iOS: show the Apple Pay buy button when
hasActiveCardistrue. When onlyisSupportedistrue, show the Set up Apple Pay button (buttonType="setUp") and callHybridPaymentHandler.openPaymentSetup()on tap. It opens Wallet (Settings on iPad) to add a card. - Neither platform: when
isSupportedisfalse, hide the wallet buttons and offer another way to pay.
In the example below, the checkout screen owns the hook and the cart, and WalletButton picks the button from the status. The user comes back from Wallet with a card the status does not know about yet, so the screen checks again when the app returns to the foreground:
import { useEffect } from 'react'
import { AppState, Button, Platform, View } from 'react-native'
import {
ApplePayButton,
GooglePayButton,
HybridPaymentHandler,
usePaymentCheckout,
type UsePaymentCheckoutReturn,
} from '@gmisoftware/react-native-pay'
export function CheckoutScreen() {
const checkout = usePaymentCheckout({
merchantName: 'Your Store',
supportedNetworks: ['visa', 'mastercard'],
// The environment you pay in, so the status is real in production.
googlePayEnvironment: 'PRODUCTION',
googlePayMerchantId: 'your_google_pay_merchant_id',
googlePayGateway: 'stripe',
googlePayGatewayMerchantId: 'your_stripe_merchant_id',
})
const { refreshStatus } = checkout
useEffect(() => {
const subscription = AppState.addEventListener('change', (state) => {
if (state === 'active') refreshStatus()
})
return () => subscription.remove()
}, [refreshStatus])
return (
<View>
<Button
title="Add Coffee"
onPress={() => checkout.addItem('Coffee', '4.99')}
/>
{checkout.items.length > 0 && <WalletButton checkout={checkout} />}
</View>
)
}
function WalletButton({ checkout }: { checkout: UsePaymentCheckoutReturn }) {
const { isSupported, hasActiveCard, startPayment } = checkout
// `isSupported` is `false` until the first check settles, and a refresh
// keeps the last answer, so the button does not flicker on return.
if (!isSupported) return null
if (Platform.OS === 'android') {
return (
<GooglePayButton
buttonType="buy"
theme="dark"
onPress={startPayment}
/>
)
}
return hasActiveCard ? (
<ApplePayButton
buttonType="buy"
buttonStyle="black"
onPress={startPayment}
/>
) : (
<ApplePayButton
buttonType="setUp"
buttonStyle="black"
onPress={() => HybridPaymentHandler.openPaymentSetup()}
/>
)
}
The hook checks on mount, and again when supportedNetworks, merchantCapabilities or googlePayEnvironment change. isCheckingStatus is true while a check runs; the flags keep their last values until it settles.
Without the hook
HybridPaymentHandler.payServiceStatus() returns a Promise. Pass the same networks, capabilities and environment as your payment request:
import { HybridPaymentHandler } from '@gmisoftware/react-native-pay'
const { isSupported, hasActiveCard } =
await HybridPaymentHandler.payServiceStatus({
supportedNetworks: ['visa', 'mastercard'],
merchantCapabilities: ['3DS'],
googlePayEnvironment: 'PRODUCTION',
})
Next
- usePaymentCheckout: the hook's availability fields
- HybridPaymentHandler:
payServiceStatusandopenPaymentSetup - Components:
ApplePayButtonandGooglePayButton