Commit e3ee015
fix(react-native-iap): avoid iOS listener cleanup crash after unmount (#262)
## Summary
This keeps the iOS StoreKit-backed singleton native purchase and
purchase-error listeners attached for the app session while JavaScript
subscriptions are still removed normally.
`useIAP` keeps internal state updates mount-guarded during post-purchase
refresh, but still delivers `onPurchaseSuccess` for a purchase event
that already entered before unmount so apps can call
`finishTransaction`.
## Why
In a React Native app using `useIAP` from a modal-like plans screen,
dismissing the screen can unmount the hook while StoreKit/Nitro purchase
listener work is still in flight. The JS subscription cleanup removes
the JS callback, but when it is also the last callback it previously
disposed the native iOS listener immediately.
On iOS release builds this can abort during screen dismissal. Keeping
the singleton native listener attached for the app session avoids that
teardown race while still removing the JS callback, so unmounted screens
no longer receive new purchase, purchase-error, promoted-product, or
billing-issue callbacks.
For a purchase event that already entered before unmount,
`onPurchaseSuccess` remains deliverable after the pending refresh
completes. That callback is the documented `finishTransaction` site, and
dropping it would risk leaving the purchase unfinished.
Android behavior is unchanged: native listener removal still happens
when the last JS listener is removed.
## Validation
- `yarn typecheck:lib` in `libraries/react-native-iap`
- `yarn lint` in `libraries/react-native-iap`
- `yarn lint:tsc` in `libraries/react-native-iap`
- `yarn test:ci --watchman=false --silent` in
`libraries/react-native-iap`
- `git diff --check`
- Consumer app validation with a patch-package version of the same fix:
`npm run typecheck`
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Purchase success callbacks now remain deliverable when a related
screen or component is unmounted, while preventing updates to inactive
state.
* Improved iOS purchase and error listener handling so removing a
JavaScript listener does not interrupt native purchase updates.
* Improved Android listener cleanup and re-subscription behavior after
the final JavaScript listener is removed.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Hyo <hyo@hyo.dev>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>1 parent d724875 commit e3ee015
4 files changed
Lines changed: 172 additions & 9 deletions
File tree
- libraries/react-native-iap/src
- __tests__
- hooks
- hooks
Lines changed: 61 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
53 | 54 | | |
54 | 55 | | |
55 | 56 | | |
| |||
121 | 122 | | |
122 | 123 | | |
123 | 124 | | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
124 | 185 | | |
125 | 186 | | |
126 | 187 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
214 | 214 | | |
215 | 215 | | |
216 | 216 | | |
217 | | - | |
| 217 | + | |
218 | 218 | | |
219 | 219 | | |
220 | 220 | | |
| |||
226 | 226 | | |
227 | 227 | | |
228 | 228 | | |
229 | | - | |
230 | | - | |
| 229 | + | |
231 | 230 | | |
232 | 231 | | |
233 | | - | |
| 232 | + | |
234 | 233 | | |
235 | | - | |
| 234 | + | |
| 235 | + | |
236 | 236 | | |
237 | 237 | | |
238 | 238 | | |
239 | 239 | | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
240 | 256 | | |
241 | | - | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
242 | 261 | | |
243 | 262 | | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
244 | 301 | | |
245 | | - | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
246 | 323 | | |
247 | 324 | | |
248 | 325 | | |
| |||
435 | 512 | | |
436 | 513 | | |
437 | 514 | | |
438 | | - | |
| 515 | + | |
| 516 | + | |
439 | 517 | | |
440 | 518 | | |
441 | 519 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
591 | 591 | | |
592 | 592 | | |
593 | 593 | | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
594 | 599 | | |
595 | 600 | | |
596 | 601 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
451 | 451 | | |
452 | 452 | | |
453 | 453 | | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
454 | 461 | | |
455 | 462 | | |
456 | 463 | | |
| |||
498 | 505 | | |
499 | 506 | | |
500 | 507 | | |
501 | | - | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
502 | 521 | | |
503 | 522 | | |
504 | 523 | | |
| |||
0 commit comments