mnemo_cards/mnemo_cards_web_v2/lib/utils/adsgram_stub.dart
AI Agent 3de4932ae2 feat(web_v2): Complete Ads Reward Flow - Integrate Adsgram SDK
Task ID: WEB-001
Priority: high

Changes:

Completed by: AI Agent
Duration: 877383ms
2025-11-21 09:57:19 +00:00

227 lines
6.8 KiB
Dart

/// Real Adsgram SDK interface using JavaScript interop
///
/// This provides a Dart interface to the Adsgram JavaScript SDK.
/// The SDK is loaded via script tag in web/index.html:
/// <script src="https://sad.adsgram.ai/js/sad.min.js"></script>
///
/// The JavaScript bridge functions are defined in web/foos.js
library;
import 'dart:developer' as developer;
import 'dart:js_util' as js_util;
/// Configuration for Adsgram ad display
class AdsgramAd {
/// Adsgram block ID (required)
final String blockId;
/// Reward amount (for tracking purposes)
final int rewardAmount;
/// Callback invoked when ad completes successfully
final void Function()? onReward;
/// Callback invoked when ad fails or is closed early
final void Function(String error)? onError;
const AdsgramAd({
required this.blockId,
required this.rewardAmount,
this.onReward,
this.onError,
});
}
/// Adsgram SDK interface for showing rewarded ads
class Adsgram {
static final Adsgram _instance = Adsgram._internal();
static Adsgram get instance => _instance;
Adsgram._internal();
/// Check if Adsgram SDK is available in the JavaScript environment
bool get isAvailable {
try {
final adsgram = js_util.getProperty<dynamic>(js_util.globalThis, 'Adsgram');
return adsgram != null;
} catch (e) {
return false;
}
}
/// Show a rewarded ad using the Adsgram JavaScript SDK
///
/// This method:
/// 1. Validates the ad configuration
/// 2. Checks SDK availability
/// 3. Sets up JavaScript callbacks for reward/error events
/// 4. Calls the JavaScript showAdWithBlockId() function
/// 5. Handles ad lifecycle events via callbacks
///
/// Throws [Exception] if SDK is not available or ad fails to show
/// Throws [ArgumentError] if ad configuration is invalid
Future<void> showRewardedAd(AdsgramAd adConfig) async {
// Validate block ID
if (adConfig.blockId.trim().isEmpty) {
final error = 'Block ID is required and cannot be empty';
developer.log(error, name: 'Adsgram');
adConfig.onError?.call(error);
throw ArgumentError.value(
adConfig.blockId,
'blockId',
error,
);
}
// Check SDK availability
if (!isAvailable) {
final error = 'Adsgram SDK not available. Make sure sad.min.js is loaded.';
developer.log(error, name: 'Adsgram');
adConfig.onError?.call(error);
throw Exception(error);
}
// Validate that JavaScript bridge functions exist
try {
final showAdFunction = js_util.getProperty<dynamic>(
js_util.globalThis,
'showAdWithBlockId',
);
if (showAdFunction == null) {
final error = 'JavaScript bridge function showAdWithBlockId not found. Make sure foos.js is loaded.';
developer.log(error, name: 'Adsgram');
adConfig.onError?.call(error);
throw Exception(error);
}
} catch (e) {
final error = 'Failed to access JavaScript bridge: $e';
developer.log(error, name: 'Adsgram');
adConfig.onError?.call(error);
throw Exception(error);
}
try {
developer.log(
'Showing rewarded ad with block ID: ${adConfig.blockId}',
name: 'Adsgram',
);
// Set up callbacks in JavaScript before showing ad
await _setupCallbacks(adConfig);
// Call the JavaScript showAdWithBlockId function
// The function is defined in web/foos.js and handles the Adsgram SDK
await js_util.promiseToFuture<void>(
js_util.callMethod(
js_util.globalThis,
'showAdWithBlockId',
<Object?>[adConfig.blockId],
),
);
developer.log('Ad show request completed', name: 'Adsgram');
// Note: The actual reward/error callbacks are triggered from JavaScript
// when ad completes or fails
} catch (e, s) {
developer.log(
'Failed to show ad',
error: e,
stackTrace: s,
name: 'Adsgram',
);
// If JavaScript call fails, call error callback
final errorMessage = 'Failed to show ad: $e';
adConfig.onError?.call(errorMessage);
rethrow;
}
}
/// Set up JavaScript callbacks for ad completion
///
/// Creates JavaScript wrapper functions that call the Dart callbacks
/// These are registered with the JavaScript bridge in foos.js
Future<void> _setupCallbacks(AdsgramAd adConfig) async {
try {
// Create JavaScript function for reward callback
final rewardJsFunction = js_util.allowInterop(() {
developer.log('Ad reward callback triggered', name: 'Adsgram');
adConfig.onReward?.call();
});
// Create JavaScript function for error callback
final errorJsFunction = js_util.allowInterop((dynamic error) {
final errorMessage = error?.toString() ?? 'Unknown error';
developer.log(
'Ad error callback triggered: $errorMessage',
name: 'Adsgram',
);
adConfig.onError?.call(errorMessage);
});
// Register callbacks with JavaScript bridge
// Check if callback functions exist before calling
final setRewardCallback = js_util.getProperty<dynamic>(
js_util.globalThis,
'setRewardCallback',
);
final setErrorCallback = js_util.getProperty<dynamic>(
js_util.globalThis,
'setErrorCallback',
);
if (setRewardCallback == null || setErrorCallback == null) {
throw Exception(
'JavaScript bridge callback functions not found. Make sure foos.js is loaded.',
);
}
js_util.callMethod<void>(
js_util.globalThis,
'setRewardCallback',
<Object?>[rewardJsFunction],
);
js_util.callMethod<void>(
js_util.globalThis,
'setErrorCallback',
<Object?>[errorJsFunction],
);
developer.log('Callbacks registered with JavaScript bridge', name: 'Adsgram');
} catch (e, s) {
developer.log(
'Failed to set up callbacks',
error: e,
stackTrace: s,
name: 'Adsgram',
);
rethrow;
}
}
/// Alternative method to show ad with specific block ID
///
/// This allows dynamic block ID configuration without creating
/// an AdsgramAd object. Prefer using [showRewardedAd] for better
/// error handling and callback management.
///
/// Throws [Exception] if ad fails to show
@Deprecated('Use showRewardedAd() instead for better error handling')
Future<void> showAdWithBlockId(String blockId) async {
if (!isAvailable) {
throw Exception('Adsgram SDK not available');
}
try {
await js_util.promiseToFuture<void>(
js_util.callMethod(
js_util.globalThis,
'showAdWithBlockId',
<Object?>[blockId],
),
);
} catch (e) {
throw Exception('Failed to show ad with block ID $blockId: $e');
}
}
}