fixed
This commit is contained in:
@@ -28,7 +28,12 @@ public class ColorbookFlowController : IAsyncStartable, IDisposable
|
||||
private IDisposable _selectedSub;
|
||||
private IDisposable _returnToMainMenuSubscription;
|
||||
private bool _navigatingToGameplay;
|
||||
private int _selectCount;
|
||||
// App-session counter, NOT instance state. ColorbookFlowController is scene-scoped: a fresh one
|
||||
// is built every time the Colorbook scene loads, and selecting a drawing unloads the scene — so
|
||||
// each visit makes exactly ONE selection. An instance counter would reset to 0 each visit, land
|
||||
// on 1 (odd) every time, and the "% 2 == 0" show branch would NEVER fire. static persists across
|
||||
// visits for the whole app run (resets on restart), matching the per-session interstitial cap.
|
||||
private static int _selectCount;
|
||||
private CancellationTokenSource _scopeCts;
|
||||
|
||||
public ColorbookFlowController(
|
||||
@@ -65,15 +70,21 @@ public class ColorbookFlowController : IAsyncStartable, IDisposable
|
||||
|
||||
if (!_navigatingToGameplay) _loadingScreen.Hide();
|
||||
|
||||
PrewarmInterstitialAdAsync(ct).Forget();
|
||||
PrewarmInterstitialAdAsync().Forget();
|
||||
}
|
||||
|
||||
private async UniTaskVoid PrewarmInterstitialAdAsync(CancellationToken ct)
|
||||
// Ad ops MUST NOT use the Colorbook scope token. This scene unloads inside HandleSelectionAsync —
|
||||
// the same moment the interstitial should show — which disposes ColorBookLifetimeScope, calls our
|
||||
// Dispose(), and cancels _scopeCts. A scope-bound load/show then aborts mid-flight (load: never
|
||||
// ready; show: await throws OCE, handlers unsubscribed). AdMobAdService is the Boot/Root-scoped,
|
||||
// app-lifetime singleton and self-manages teardown (_lifetimeCts + OnDestroy), so drive ad ops on
|
||||
// CancellationToken.None — they intentionally outlive this scene.
|
||||
private async UniTaskVoid PrewarmInterstitialAdAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_ads.IsInitialized) await _ads.InitializeAsync(ct);
|
||||
if (!_ads.IsReady(AdFormat.Interstitial)) await _ads.LoadAsync(AdFormat.Interstitial, ct);
|
||||
if (!_ads.IsInitialized) await _ads.InitializeAsync(CancellationToken.None);
|
||||
if (!_ads.IsReady(AdFormat.Interstitial)) await _ads.LoadAsync(AdFormat.Interstitial, CancellationToken.None);
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex)
|
||||
@@ -106,19 +117,18 @@ public class ColorbookFlowController : IAsyncStartable, IDisposable
|
||||
|
||||
private async UniTaskVoid HandleSelectionAsync(string templateId)
|
||||
{
|
||||
var ct = _scopeCts?.Token ?? CancellationToken.None;
|
||||
|
||||
_loadingScreen.Show();
|
||||
_loadingScreen.SetProgress(0f);
|
||||
|
||||
// Frequency cap: show an interstitial on every 2nd level open (2nd, 4th, ...). On skip turns
|
||||
// just keep one prewarmed so the next show has an ad ready. Fire-and-forget either way — the
|
||||
// ad overlays the transition while the level loads underneath, so a missed/dropped ad callback
|
||||
// can't stall the flow at 0% anymore.
|
||||
// can't stall the flow at 0% anymore. Ad ops run on CancellationToken.None, NOT the scene
|
||||
// scope token: this scene unloads further down, which would otherwise cancel the show.
|
||||
if (++_selectCount % 2 == 0)
|
||||
ShowInterstitialAdAsync(ct).Forget();
|
||||
ShowInterstitialAdAsync().Forget();
|
||||
else
|
||||
PrewarmInterstitialAdAsync(ct).Forget();
|
||||
PrewarmInterstitialAdAsync().Forget();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -143,7 +153,8 @@ public class ColorbookFlowController : IAsyncStartable, IDisposable
|
||||
// Fire-and-forget interstitial. Shows only if one is already prewarmed; otherwise it kicks a
|
||||
// load for next time and returns immediately. Never blocks the level load — by design the
|
||||
// scene swap below does not depend on the ad's close callback, so the ad can never stall it.
|
||||
private async UniTaskVoid ShowInterstitialAdAsync(CancellationToken ct)
|
||||
// CancellationToken.None: the show must survive this scene's unload (see PrewarmInterstitialAdAsync).
|
||||
private async UniTaskVoid ShowInterstitialAdAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -151,11 +162,11 @@ public class ColorbookFlowController : IAsyncStartable, IDisposable
|
||||
|
||||
if (!_ads.IsReady(AdFormat.Interstitial))
|
||||
{
|
||||
_ads.LoadAsync(AdFormat.Interstitial, ct).Forget();
|
||||
_ads.LoadAsync(AdFormat.Interstitial, CancellationToken.None).Forget();
|
||||
return;
|
||||
}
|
||||
|
||||
await _ads.ShowAsync(AdFormat.Interstitial, ct);
|
||||
await _ads.ShowAsync(AdFormat.Interstitial, CancellationToken.None);
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex)
|
||||
|
||||
Reference in New Issue
Block a user