Skip to content

[EXTERNAL] fix(google): guard showInAppMessages against BillingClient runtime crashes (#3367) by @matteinn#3368

Merged
MonikaMateska merged 2 commits into
mainfrom
external/matteinn/fix/#3367-billingwrapper-npe
Apr 20, 2026
Merged

[EXTERNAL] fix(google): guard showInAppMessages against BillingClient runtime crashes (#3367) by @matteinn#3368
MonikaMateska merged 2 commits into
mainfrom
external/matteinn/fix/#3367-billingwrapper-npe

Conversation

@MonikaMateska

@MonikaMateska MonikaMateska commented Apr 20, 2026

Copy link
Copy Markdown
Member

Checklist

  • If applicable, unit tests
  • If applicable, create follow-up issues for purchases-ios and hybrids

Motivation

This PR hardens showInAppMessagesIfNeeded against a remaining Play Billing crash path.
Resolves #3273, which has not been fully solved by a previous
tentative.

Description

Even after lifecycle/window attachment checks,
BillingClient.showInAppMessages(...) can still throw a RuntimeException (including NullPointerException) due to an internal race in Play Billing.

This is a defensive boundary around third-party BillingClient behavior: it complements previous activity/window checks by handling exceptions that can still occur between pre-checks and BillingClient’s internal view/token access.

Here's exactly what changed:

  • Wrapped the showInAppMessages(...) invocation in BillingWrapper with a try/catch
  • On exception, log the error and skip showing the in-app message instead of crashing the app
  • Added new log string: BILLING_INAPP_MESSAGE_SHOW_EXCEPTION
  • Added a regression unit test that simulates showInAppMessages(...) throwing a NullPointerException and verifies that there are no crash and that the error is logged

Note

Low Risk
Small defensive change limited to in-app message display: it only adds exception handling and logging, plus a unit test, with minimal behavior impact beyond avoiding a crash.

Overview
Prevents app crashes when Google Play Billing’s BillingClient.showInAppMessages throws a RuntimeException despite lifecycle/window checks, by wrapping the call in a try/catch and logging a new BILLING_INAPP_MESSAGE_SHOW_EXCEPTION error instead of propagating the crash.

Adds a regression test that forces showInAppMessages to throw (e.g., NullPointerException) and asserts the wrapper logs the error and continues without crashing.

Reviewed by Cursor Bugbot for commit fc5cd08. Bugbot is set up for automated code reviews on this repo. Configure here.

Checklist

  • If applicable, unit tests
  • If applicable, create follow-up issues for purchases-ios and hybrids

Motivation

Description

… runtime crashes (#3367)

<!-- Thank you for contributing to Purchases! Before pressing the
"Create Pull Request" button, please provide the following: -->

### Checklist
- [x] If applicable, unit tests
- [ ] If applicable, create follow-up issues for `purchases-ios` and
hybrids

### Motivation
<!-- Why is this change required? What problem does it solve? -->
<!-- Please link to issues following this format: Resolves #999999 -->
This PR hardens `showInAppMessagesIfNeeded` against a remaining Play
Billing crash path.
Resolves #3273,
which has not been fully solved by a previous
[tentative](#3274).

### Description
<!-- Describe your changes in detail -->
<!-- Please describe in detail how you tested your changes -->

Even after lifecycle/window attachment checks,
`BillingClient.showInAppMessages(...)` can still throw a
`RuntimeException` (including `NullPointerException`) due to an internal
race in Play Billing.

This is a defensive boundary around third-party BillingClient behavior:
it complements previous activity/window checks by handling exceptions
that can still occur between pre-checks and BillingClient’s internal
view/token access.

Here's exactly what changed:
- Wrapped the `showInAppMessages(...)` invocation in `BillingWrapper`
with a try/catch
- On exception, log the error and skip showing the in-app message
instead of crashing the app
- Added new log string: BILLING_INAPP_MESSAGE_SHOW_EXCEPTION
- Added a regression unit test that simulates `showInAppMessages(...)`
throwing a `NullPointerException` and verifies that there are no crash
and that the error is logged

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk defensive change that only adds exception handling and
logging around a third-party call; behavior changes only when Play
Billing throws unexpectedly.
> 
> **Overview**
> Prevents a remaining Play Billing crash path by wrapping
`BillingClient.showInAppMessages(...)` in
`BillingWrapper.showInAppMessagesIfNeeded` with a `try/catch` and
logging an error instead of crashing.
> 
> Adds a new log string (`BILLING_INAPP_MESSAGE_SHOW_EXCEPTION`) and a
regression unit test that simulates `showInAppMessages` throwing (e.g.,
`NullPointerException`) and asserts it is logged and does not crash.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5e8afd5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@MonikaMateska MonikaMateska requested a review from a team as a code owner April 20, 2026 08:52
@MonikaMateska MonikaMateska added the pr:fix A bug fix label Apr 20, 2026
@MonikaMateska MonikaMateska enabled auto-merge April 20, 2026 09:29
@MonikaMateska MonikaMateska added this pull request to the merge queue Apr 20, 2026
@codecov

codecov Bot commented Apr 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.34%. Comparing base (64bafd5) to head (fc5cd08).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
.../com/revenuecat/purchases/google/BillingWrapper.kt 66.66% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3368      +/-   ##
==========================================
- Coverage   79.36%   79.34%   -0.02%     
==========================================
  Files         354      354              
  Lines       14259    14268       +9     
  Branches     1951     1951              
==========================================
+ Hits        11316    11321       +5     
- Misses       2140     2144       +4     
  Partials      803      803              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Merged via the queue into main with commit 6bd868e Apr 20, 2026
36 checks passed
@MonikaMateska MonikaMateska deleted the external/matteinn/fix/#3367-billingwrapper-npe branch April 20, 2026 09:51
matteinn pushed a commit to matteinn/purchases-android that referenced this pull request Apr 28, 2026
**This is an automatic release.**

## RevenueCat SDK
### 🐞 Bugfixes
* fix: move Google BillingClient connection off the main thread (RevenueCat#3369)
via Toni Rico (@tonidero)
* [EXTERNAL] fix(google): guard showInAppMessages against BillingClient
runtime crashes (RevenueCat#3367) by @matteinn (RevenueCat#3368) via Monika Mateska
(@MonikaMateska)

## RevenueCatUI SDK
### Paywallv2
#### 🐞 Bugfixes
* Add Workflows network layer (RevenueCat#3300) via Cesar de la Vega (@vegaro)

### 🔄 Other Changes
* Fix `revenuecat.useWorkflowsEndpoint` compiler flag (RevenueCat#3374) via Cesar
de la Vega (@vegaro)
* Create paywall from workflow response. Add `USE_WORKFLOWS_ENDPOINT`
BuildConfig (RevenueCat#3350) via Cesar de la Vega (@vegaro)
* Refactor: Remove unnecessary lint suppressions (RevenueCat#3373) via cursor[bot]
(@cursor[bot])
* Bump fastlane-plugin-revenuecat_internal from `a1eed48` to `b822f01`
(RevenueCat#3371) via dependabot[bot] (@dependabot[bot])
* Bump fastlane from 2.232.2 to 2.233.0 (RevenueCat#3370) via dependabot[bot]
(@dependabot[bot])
* Attempt to fix `AssertionError` "ms is denormalized" in
`QueryPurchasesUseCaseTest` (RevenueCat#3361) via Cesar de la Vega (@vegaro)
* Update baseline profiles (RevenueCat#3296) via Jaewoong Eum (@skydoves)
* fix: reduce precision for flaky HeaderDirectHeroImage snapshot (RevenueCat#3362)
via Cesar de la Vega (@vegaro)
* Fix test failures reported twice (RevenueCat#3360) via Cesar de la Vega
(@vegaro)
* refactor: extract `updateStateFromOffering` in `PaywallViewModel`
(RevenueCat#3359) via Cesar de la Vega (@vegaro)
* [Fix] Include parent tabs component_name in tab-control switch
interaction events (RevenueCat#3358) via Monika Mateska (@MonikaMateska)
* Refactor: Remove unnecessary lint suppressions (RevenueCat#3348) via cursor[bot]
(@cursor[bot])
* fix: always upload CI test results even when tests fail (RevenueCat#3357) via
Cesar de la Vega (@vegaro)
* refactor: extract `RevenueCatDialogScaffold` (RevenueCat#3355) via Cesar de la
Vega (@vegaro)
* Fix Slack notifications for nightly integration tests (RevenueCat#3354) via Toni
Rico (@tonidero)
* UI events for paywall component interactions (RevenueCat#3287) via Monika
Mateska (@MonikaMateska)
* Bump fastlane-plugin-revenuecat_internal from `20911d1` to `a1eed48`
(RevenueCat#3351) via dependabot[bot] (@dependabot[bot])

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Primarily a version bump and release automation updates (docs
deploy/redirect and changelog); no functional library code changes
beyond updating embedded version constants.
> 
> **Overview**
> Cuts the `10.2.1` release by updating version references across the
repo (Gradle `VERSION_NAME`, internal `frameworkVersion`, sample/test
app dependency pins, and `.version`).
> 
> Updates the docs release pipeline and website redirect to publish and
point at `10.2.1`, and refreshes `CHANGELOG.md`/`CHANGELOG.latest.md`
with the 10.2.1 release notes.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a0a325b. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:fix A bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NPE BillingWrapper$showInAppMessagesIfNeeded$2$2.invoke

3 participants