Learn how to fix common issues with the PayPal component on Android.
| Issue | Description | Next steps |
|---|---|---|
| PayPal SDK not loading | Logcat shows PayPal SDK not loaded. This could be due to network issues, incorrect configuration, or SSL/TLS errors. |
|
| Button not rendering | The PayPal button doesn't appear in the container. |
|
| Validation errors | You receive errors via the onSubmitError callback. |
|
| Funding source issues | Certain funding sources not available. |
|
| WebView crashes or freezes | WebView becomes unresponsive or crashes app. |
|
| WebView not available | The button fails to render and there's a WebView initialisation error. |
|
| Network connectivity | The SDK fails to load and there are timeout errors. |
|
| SSL/TLS certificate errors | WebView fails to load with SSL errors. This could be due to expired certificates, incorrect device time, or outdated WebView. |
|
| Memory issues | The app crashes or becomes unresponsive during payment. |
|
| Back button not working | The Android back button doesn't cancel the PayPal flow. |
|
| Configuration lost on rotation | The component state is lost on screen rotation. |
|
| Missing script parameters | One-click payment isn't working. |
|
| Component not disposing | There are memory leaks or resource retention. |
|
| Event callbacks not firing | onSuccess, onError, or other callbacks not called. |
|
| Shipping address validation fails | The shipping address was rejected by PayPal. |
|
| Payment authorisation fails | The payment starts but fails to complete. For example, due to insufficient PayPal funds, declined payment method, or fraud detection. |
|
| Debug mode issues | Debug mode isn't working or is causing errors. |
|
| Button styling not applied | The button doesn't match the expected style. |
|
| Multiple buttons rendering incorrectly | Buttons overlap or don't display properly with setOfButtons. |
|
| Locale/language issues | The button is displayed in the wrong language. |
|
| Consent component not working | The consent checkbox doesn't affect payment. |
|
| Toggle component issues | The toggle doesn't switch payment methods. |
|
| Pre-built component issues | The pre-built component isn't rendering sub-components. |
|
To diagnose issues, enable comprehensive logging.
val paypalConfig = PayPalComponentConfig(
queryParams = PayPalQueryParams(
debug = true // Only use in development
)
)// In your Application class or before SDK initialisation
if (BuildConfig.DEBUG) {
WebView.setWebContentsDebuggingEnabled(true)
}Use these filters to debug PayPal issues:
# PXP Checkout logs
adb logcat | grep -E "(PxpCheckout|PXP)"
# PayPal-specific logs
adb logcat | grep -E "(PayPal|paypal)"
# WebView-related logs
adb logcat | grep -E "(WebView|chromium)"
# Network-related logs
adb logcat | grep -E "(OkHttp|Retrofit|Network)"
# Comprehensive debugging
adb logcat | grep -E "(PxpCheckout|PayPal|WebView)" -A 5val paypalConfig = PayPalComponentConfig(
onSuccess = { data ->
Log.d("PayPal", "✓ Payment successful")
Log.v("PayPal", "Success data: $data")
processPayment(data)
},
onError = { error ->
Log.e("PayPal", "✗ Payment error: $error")
Log.e("PayPal", "Stack trace:", Exception(error))
handleError(error)
},
onCancel = {
Log.w("PayPal", "⚠ Payment cancelled by user")
handleCancellation()
},
onOrderCreated = { orderData ->
Log.i("PayPal", "📦 Order created: $orderData")
trackOrderCreation(orderData)
},
onScriptLoaded = {
Log.d("PayPal", "✓ PayPal SDK script loaded")
hideLoadingIndicator()
}
)When to use: Before rendering any PayPal component, verify that Android System WebView is installed and functional on the device. This is critical because the PayPal SDK requires WebView to render the payment interface.
What it does: Attempts to retrieve the currently installed WebView package. If WebView is not installed, disabled, or corrupted, this function returns false. It uses exception handling because getCurrentWebViewPackage() may throw exceptions on devices without WebView support.
Integration: Call this function in your Activity's onCreate() or before creating the PayPal component. If it returns false, display an error message and prompt the user to install or update WebView from the Play Store.
fun checkWebViewAvailability(context: Context): Boolean {
return try {
val webViewPackage = WebView.getCurrentWebViewPackage()
webViewPackage != null
} catch (e: Exception) {
Log.e("PayPal", "WebView not available", e)
false
}
}
// Usage example:
if (!checkWebViewAvailability(context)) {
// Show error and prompt user to install WebView
promptWebViewUpdate(context)
return
}
// Proceed with PayPal component creationWhen to use: Before initiating a payment flow or when diagnosing network-related errors. The PayPal SDK requires an active internet connection to load scripts and process payments.
What it does: Uses the modern ConnectivityManager API (API 23+) to check not only if a network connection exists, but also if it has validated internet connectivity. NET_CAPABILITY_INTERNET checks for a network route to the internet, while NET_CAPABILITY_VALIDATED confirms the connection has been tested and verified by the system.
Integration: Call this function before creating the PayPal component or in response to network errors. Display a user-friendly message if the network is unavailable and optionally implement a retry mechanism.
Required permissions: Add <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> to your AndroidManifest.xml.
fun isNetworkAvailable(context: Context): Boolean {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val network = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
// Usage example:
if (!isNetworkAvailable(context)) {
Toast.makeText(context, "No internet connection. Please check your network.", Toast.LENGTH_LONG).show()
return
}
// Proceed with PayPal SDK initialisationWhen to use: During performance testing, when diagnosing crashes or unresponsiveness, or proactively before loading the PayPal WebView. WebView components can consume significant memory, especially during payment flows.
What it does: Calculates the app's current memory usage in megabytes by checking the Java runtime heap. It compares used memory against the maximum available heap size and logs a warning if available memory drops below 50 MB, which could lead to OutOfMemoryError exceptions.
Integration: Call this function before creating PayPal components, during payment flow, or when users report performance issues. Consider calling it periodically in development builds. In production, only call when diagnosing specific issues to avoid performance overhead.
Important notes:
- Memory values are for the Java heap only, not total app memory.
- Low memory situations (<50 MB available) may cause WebView crashes.
- Consider reducing
maxHeightPercentor optimising other memory-heavy operations if memory is constrained.
fun checkMemoryStatus() {
val runtime = Runtime.getRuntime()
val usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024
val maxMemory = runtime.maxMemory() / 1024 / 1024
val availableMemory = maxMemory - usedMemory
Log.d("PayPal", "Memory: $usedMemory MB used, $availableMemory MB available")
if (availableMemory < 50) {
Log.w("PayPal", "Low memory warning")
}
}
// Usage example:
checkMemoryStatus()
if (Runtime.getRuntime().freeMemory() / 1024 / 1024 < 50) {
// Consider deferring heavy operations or showing a warning
Log.w("PayPal", "Low memory condition detected before PayPal component creation")
}When to use: Before creating a PayPal component to catch configuration errors early. This prevents runtime errors and provides clear feedback about what's wrong with the configuration.
What it does: Performs validation checks on PayPalComponentConfig to ensure all required fields are present and that types match the expected format. Specifically validates that renderType and fundingSources are correctly configured, as mismatches between these fields are a common source of errors.
Integration: Call this function after building your configuration object but before passing it to the component. In development, consider making this a requirement. In production, you can use it to log warnings or provide fallback configurations.
Important notes:
- For
standalonerenderType,fundingSourcesmust be a String (e.g.,"paypal") - For
setOfButtonsrenderType,fundingSourcesmust be a List<String> (e.g.,listOf("paypal", "paylater")) - You'll need to define a
ValidationResultdata class or replace it with your own error handling mechanism
// Define the ValidationResult data class
data class ValidationResult(
val isValid: Boolean,
val errors: List<String>
)
fun validatePayPalConfig(config: PayPalComponentConfig): ValidationResult {
val errors = mutableListOf<String>()
if (config.renderType.isNullOrEmpty()) {
errors.add("renderType is required")
}
if (config.fundingSources == null) {
errors.add("fundingSources is required")
}
if (config.renderType == "standalone" && config.fundingSources !is String) {
errors.add("fundingSources must be a String for standalone renderType")
}
if (config.renderType == "setOfButtons" && config.fundingSources !is List<*>) {
errors.add("fundingSources must be a List<String> for setOfButtons renderType")
}
return ValidationResult(
isValid = errors.isEmpty(),
errors = errors
)
}
// Usage example:
val config = PayPalComponentConfig(
renderType = "standalone",
fundingSources = "paypal"
// ... other config
)
val validation = validatePayPalConfig(config)
if (!validation.isValid) {
Log.e("PayPal", "Configuration errors: ${validation.errors.joinToString()}")
// Show error to user or fix configuration
return
}
// Proceed with component creationWhen to use: In Jetpack Compose screens containing PayPal components where you need to handle the Android back button or gesture navigation. This ensures users can exit the payment flow gracefully and that cleanup happens properly.
What it does: Uses Compose's BackHandler to intercept back button/gesture events. This allows you to log the cancellation, show a confirmation dialog if needed, trigger the PayPal onCancel callback, and navigate away from the payment screen cleanly.
Integration: Place the BackHandler at the top level of your Composable function containing the PayPal component. It will automatically be enabled when the Composable is active and disabled when it leaves the composition.
Important notes:
BackHandleris part ofandroidx.activity:activity-compose.- The callback triggers before the normal back press behaviour.
- You can optionally show a confirmation dialog before cancelling the payment.
- For Activity-based navigation, override
onBackPressed()in your Activity instead.
@Composable
fun PayPalScreen(navController: NavController) {
var showExitDialog by remember { mutableStateOf(false) }
BackHandler {
Log.d("PayPal", "Back pressed during payment flow")
// Option 1: Exit immediately
navController.popBackStack()
// Option 2: Show confirmation dialog
// showExitDialog = true
}
// Optional: Confirmation dialog
if (showExitDialog) {
AlertDialog(
onDismissRequest = { showExitDialog = false },
title = { Text("Cancel Payment?") },
text = { Text("Are you sure you want to cancel this payment?") },
confirmButton = {
TextButton(onClick = {
showExitDialog = false
navController.popBackStack()
}) {
Text("Yes, Cancel")
}
},
dismissButton = {
TextButton(onClick = { showExitDialog = false }) {
Text("Continue Payment")
}
}
)
}
// PayPal component rendering
}When to use: After detecting that WebView is not available, outdated, or corrupted using the checkWebViewAvailability() function. This provides a user-friendly way to resolve WebView issues rather than showing a generic error.
What it does: Displays an AlertDialog prompting the user to update Android System WebView. When the user taps "Update", it opens the Google Play Store directly to the WebView app page using a market:// URI scheme. This provides a seamless experience for resolving WebView-related issues.
Integration: Call this function when checkWebViewAvailability() returns false or when WebView initialisation fails. This is typically in your Activity's onCreate() or in a utility function that validates prerequisites before showing the payment UI.
Important notes:
- The
market://scheme will open the Play Store app if installed. - If Play Store is not available, wrap in try-catch and show alternative instructions.
- Consider adding a "Cancel" button to let users dismiss the dialog.
- Test on devices with WebView disabled to verify the user experience.
- This only works for devices that support WebView (Android 5.0+).
fun promptWebViewUpdate(context: Context) {
AlertDialog.Builder(context)
.setTitle("Update required")
.setMessage("Please update Android System WebView to use PayPal payments")
.setPositiveButton("Update") { _, _ ->
try {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("market://details?id=com.google.android.webview")
// Add flag to avoid adding Play Store to back stack
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
// Fallback to web browser if Play Store not available
Log.e("PayPal", "Play Store not available", e)
val webIntent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("https://play.google.com/store/apps/details?id=com.google.android.webview")
}
context.startActivity(webIntent)
}
}
.setNegativeButton("Cancel", null)
.setCancelable(false) // Prevent dismissing without action
.show()
}
// Usage example:
if (!checkWebViewAvailability(context)) {
Log.e("PayPal", "WebView not available on device")
promptWebViewUpdate(context)
return // Don't proceed with PayPal component creation
}If you've tried the solutions above and still experience issues:
- Check the logs: Enable debug mode and review logcat output for detailed error messages.
- Verify configuration: Double-check all required parameters are set correctly.
- Test on different devices: Some issues may be device or Android version specific.
- Check PayPal dashboard: Review transaction history and error logs in the Unity Portal.
- Contact support: Provide logcat output, device information, and steps to reproduce the issue.