dispose method
Tear down per-handle channel subscriptions. The iOS-side manager
instance is NOT released — it's cached per
(userId, stripeCustomerId) and survives across handle disposals.
Calling ZeroSettle.offerManager again returns a new handle bound
to the same underlying state.
Implementation
Future<void> dispose() async {
if (_disposed) return;
_disposed = true;
await _stateSub?.cancel();
await _stateController.close();
// Tell iOS to drop the handle's Combine subscriptions. The cached
// ZSOfferManager instance stays alive for re-use.
try {
await _methodChannel.invokeMethod<void>('disposeHandle');
} catch (_) {
// Channel might already be torn down on the iOS side; non-fatal.
}
}