feat(web_v2): Complete Ads Reward Flow - Integrate Adsgram SDK
Task ID: WEB-001 Priority: high Changes: Completed by: AI Agent Duration: 877383ms
This commit is contained in:
parent
19f0b952c0
commit
3de4932ae2
9 changed files with 335 additions and 62 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"component": "web_v2",
|
"component": "web_v2",
|
||||||
"current_task_id": "WEB-003",
|
"current_task_id": "WEB-001",
|
||||||
"iteration_count": 3,
|
"iteration_count": 4,
|
||||||
"max_iterations": 10,
|
"max_iterations": 10,
|
||||||
"started_at": "2025-11-21T00:31:28.302997+00:00",
|
"started_at": "2025-11-21T00:31:28.302997+00:00",
|
||||||
"last_commit": null,
|
"last_commit": null,
|
||||||
|
|
|
||||||
|
|
@ -279,4 +279,4 @@
|
||||||
"component": "web_v2"
|
"component": "web_v2"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -1 +1 @@
|
||||||
cbc289e61044aa6e6f63e7abe894d47e
|
1c4dc119e18bcf1ad36e5635fba58ce0
|
||||||
|
|
@ -38,6 +38,6 @@ _flutter.buildConfig = {"engineRevision":"d3d45dcf251823c1769909cd43698d126db38d
|
||||||
|
|
||||||
_flutter.loader.load({
|
_flutter.loader.load({
|
||||||
serviceWorkerSettings: {
|
serviceWorkerSettings: {
|
||||||
serviceWorkerVersion: "4289911251"
|
serviceWorkerVersion: "2237867940"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,5 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
|
||||||
<script src="https://telegram.org/js/telegram-web-app.js" defer=""></script>
|
|
||||||
<script src="https://sad.adsgram.ai/js/sad.min.js"></script>
|
|
||||||
<script src="foos.js"></script>
|
|
||||||
</head>
|
|
||||||
<head>
|
<head>
|
||||||
<!--
|
<!--
|
||||||
If you are serving your web app in a path other than the root, change the
|
If you are serving your web app in a path other than the root, change the
|
||||||
|
|
@ -37,6 +32,16 @@
|
||||||
|
|
||||||
<title>mnemo_cards_web_v2</title>
|
<title>mnemo_cards_web_v2</title>
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
|
|
||||||
|
<!-- External SDKs -->
|
||||||
|
<!-- Telegram Web App SDK -->
|
||||||
|
<script src="https://telegram.org/js/telegram-web-app.js" defer></script>
|
||||||
|
|
||||||
|
<!-- Adsgram SDK for rewarded ads - must load before foos.js -->
|
||||||
|
<script src="https://sad.adsgram.ai/js/sad.min.js"></script>
|
||||||
|
|
||||||
|
<!-- JavaScript bridge for Adsgram SDK integration -->
|
||||||
|
<script src="foos.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="flutter_bootstrap.js" async></script>
|
<script src="flutter_bootstrap.js" async></script>
|
||||||
|
|
|
||||||
|
|
@ -52,12 +52,28 @@ class Adsgram {
|
||||||
/// Show a rewarded ad using the Adsgram JavaScript SDK
|
/// Show a rewarded ad using the Adsgram JavaScript SDK
|
||||||
///
|
///
|
||||||
/// This method:
|
/// This method:
|
||||||
/// 1. Sets up JavaScript callbacks for reward/error events
|
/// 1. Validates the ad configuration
|
||||||
/// 2. Calls the JavaScript showAdWithBlockId() function
|
/// 2. Checks SDK availability
|
||||||
/// 3. Handles ad lifecycle events via callbacks
|
/// 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 [Exception] if SDK is not available or ad fails to show
|
||||||
|
/// Throws [ArgumentError] if ad configuration is invalid
|
||||||
Future<void> showRewardedAd(AdsgramAd adConfig) async {
|
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) {
|
if (!isAvailable) {
|
||||||
final error = 'Adsgram SDK not available. Make sure sad.min.js is loaded.';
|
final error = 'Adsgram SDK not available. Make sure sad.min.js is loaded.';
|
||||||
developer.log(error, name: 'Adsgram');
|
developer.log(error, name: 'Adsgram');
|
||||||
|
|
@ -65,11 +81,23 @@ class Adsgram {
|
||||||
throw Exception(error);
|
throw Exception(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adConfig.blockId.isEmpty) {
|
// Validate that JavaScript bridge functions exist
|
||||||
final error = 'Block ID is required';
|
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');
|
developer.log(error, name: 'Adsgram');
|
||||||
adConfig.onError?.call(error);
|
adConfig.onError?.call(error);
|
||||||
throw ArgumentError(error);
|
throw Exception(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -131,6 +159,22 @@ class Adsgram {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register callbacks with JavaScript bridge
|
// 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.callMethod<void>(
|
||||||
js_util.globalThis,
|
js_util.globalThis,
|
||||||
'setRewardCallback',
|
'setRewardCallback',
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
@TestOn('browser') // These tests require JavaScript interop, so they must run on browser
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:mnemo_cards_web_v2/utils/adsgram_stub.dart';
|
import 'package:mnemo_cards_web_v2/utils/adsgram_stub.dart';
|
||||||
|
|
||||||
|
|
@ -40,9 +41,45 @@ void main() {
|
||||||
adConfig.onError?.call('test error');
|
adConfig.onError?.call('test error');
|
||||||
expect(errorMessage, equals('test error'));
|
expect(errorMessage, equals('test error'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('creates ad config with only reward callback', () {
|
||||||
|
bool rewardCalled = false;
|
||||||
|
|
||||||
|
final adConfig = AdsgramAd(
|
||||||
|
blockId: '12345',
|
||||||
|
rewardAmount: 1,
|
||||||
|
onReward: () {
|
||||||
|
rewardCalled = true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(adConfig.onReward, isNotNull);
|
||||||
|
expect(adConfig.onError, isNull);
|
||||||
|
|
||||||
|
adConfig.onReward?.call();
|
||||||
|
expect(rewardCalled, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('creates ad config with only error callback', () {
|
||||||
|
String? errorMessage;
|
||||||
|
|
||||||
|
final adConfig = AdsgramAd(
|
||||||
|
blockId: '12345',
|
||||||
|
rewardAmount: 1,
|
||||||
|
onError: (error) {
|
||||||
|
errorMessage = error;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(adConfig.onReward, isNull);
|
||||||
|
expect(adConfig.onError, isNotNull);
|
||||||
|
|
||||||
|
adConfig.onError?.call('test error');
|
||||||
|
expect(errorMessage, equals('test error'));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group('Adsgram', () {
|
group('Adsgram SDK Integration', () {
|
||||||
test('isAvailable returns false when SDK not loaded', () {
|
test('isAvailable returns false when SDK not loaded', () {
|
||||||
final adsgram = Adsgram.instance;
|
final adsgram = Adsgram.instance;
|
||||||
// In test environment, JavaScript interop won't have Adsgram SDK
|
// In test environment, JavaScript interop won't have Adsgram SDK
|
||||||
|
|
@ -50,18 +87,12 @@ void main() {
|
||||||
expect(adsgram.isAvailable, isFalse);
|
expect(adsgram.isAvailable, isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('showRewardedAd throws when SDK not available', () async {
|
test('showRewardedAd throws Exception when SDK not available', () async {
|
||||||
final adsgram = Adsgram.instance;
|
final adsgram = Adsgram.instance;
|
||||||
bool errorCallbackCalled = false;
|
bool errorCallbackCalled = false;
|
||||||
String? errorMessage;
|
String? errorMessage;
|
||||||
|
|
||||||
const adConfig = AdsgramAd(
|
final adConfig = AdsgramAd(
|
||||||
blockId: '12345',
|
|
||||||
rewardAmount: 1,
|
|
||||||
onError: null,
|
|
||||||
);
|
|
||||||
|
|
||||||
final adConfigWithCallback = AdsgramAd(
|
|
||||||
blockId: '12345',
|
blockId: '12345',
|
||||||
rewardAmount: 1,
|
rewardAmount: 1,
|
||||||
onError: (error) {
|
onError: (error) {
|
||||||
|
|
@ -70,20 +101,11 @@ void main() {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test without callback
|
// Should throw Exception (not ArgumentError) when SDK unavailable
|
||||||
expect(
|
expect(
|
||||||
() => adsgram.showRewardedAd(adConfig),
|
() => adsgram.showRewardedAd(adConfig),
|
||||||
throwsException,
|
throwsA(isA<Exception>()),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test with callback
|
|
||||||
expect(
|
|
||||||
() => adsgram.showRewardedAd(adConfigWithCallback),
|
|
||||||
throwsException,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Note: In actual test environment, callbacks may not be called
|
|
||||||
// because JavaScript interop is not available
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('showRewardedAd throws ArgumentError when blockId is empty', () async {
|
test('showRewardedAd throws ArgumentError when blockId is empty', () async {
|
||||||
|
|
@ -104,21 +126,140 @@ void main() {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('showAdWithBlockId throws when SDK not available', () async {
|
test('showRewardedAd throws ArgumentError when blockId is whitespace only', () async {
|
||||||
|
final adsgram = Adsgram.instance;
|
||||||
|
bool errorCallbackCalled = false;
|
||||||
|
|
||||||
|
final adConfig = AdsgramAd(
|
||||||
|
blockId: ' ',
|
||||||
|
rewardAmount: 1,
|
||||||
|
onError: (error) {
|
||||||
|
errorCallbackCalled = true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
() => adsgram.showRewardedAd(adConfig),
|
||||||
|
throwsA(isA<ArgumentError>()),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('showRewardedAd validates blockId before checking SDK', () async {
|
||||||
|
final adsgram = Adsgram.instance;
|
||||||
|
|
||||||
|
// Empty blockId should throw ArgumentError even if SDK is unavailable
|
||||||
|
final adConfig = AdsgramAd(
|
||||||
|
blockId: '',
|
||||||
|
rewardAmount: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
() => adsgram.showRewardedAd(adConfig),
|
||||||
|
throwsA(isA<ArgumentError>()),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('showRewardedAd calls error callback when SDK unavailable', () async {
|
||||||
|
final adsgram = Adsgram.instance;
|
||||||
|
bool errorCallbackCalled = false;
|
||||||
|
String? errorMessage;
|
||||||
|
|
||||||
|
final adConfig = AdsgramAd(
|
||||||
|
blockId: '12345',
|
||||||
|
rewardAmount: 1,
|
||||||
|
onError: (error) {
|
||||||
|
errorCallbackCalled = true;
|
||||||
|
errorMessage = error;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await adsgram.showRewardedAd(adConfig);
|
||||||
|
fail('Expected Exception to be thrown');
|
||||||
|
} catch (e) {
|
||||||
|
expect(e, isA<Exception>());
|
||||||
|
// Note: In test environment, callbacks may not be called synchronously
|
||||||
|
// because JavaScript interop is not available
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('showRewardedAd calls error callback when blockId is invalid', () async {
|
||||||
|
final adsgram = Adsgram.instance;
|
||||||
|
bool errorCallbackCalled = false;
|
||||||
|
String? errorMessage;
|
||||||
|
|
||||||
|
final adConfig = AdsgramAd(
|
||||||
|
blockId: '',
|
||||||
|
rewardAmount: 1,
|
||||||
|
onError: (error) {
|
||||||
|
errorCallbackCalled = true;
|
||||||
|
errorMessage = error;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await adsgram.showRewardedAd(adConfig);
|
||||||
|
fail('Expected ArgumentError to be thrown');
|
||||||
|
} catch (e) {
|
||||||
|
expect(e, isA<ArgumentError>());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('showRewardedAd handles missing error callback gracefully', () async {
|
||||||
|
final adsgram = Adsgram.instance;
|
||||||
|
|
||||||
|
const adConfig = AdsgramAd(
|
||||||
|
blockId: '',
|
||||||
|
rewardAmount: 1,
|
||||||
|
onError: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Should not throw when error callback is null
|
||||||
|
expect(
|
||||||
|
() => adsgram.showRewardedAd(adConfig),
|
||||||
|
throwsA(isA<ArgumentError>()),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('showAdWithBlockId throws Exception when SDK not available', () async {
|
||||||
final adsgram = Adsgram.instance;
|
final adsgram = Adsgram.instance;
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
() => adsgram.showAdWithBlockId('12345'),
|
() => adsgram.showAdWithBlockId('12345'),
|
||||||
throwsException,
|
throwsA(isA<Exception>()),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('showAdWithBlockId throws when blockId is empty', () async {
|
test('showAdWithBlockId throws Exception when blockId is empty', () async {
|
||||||
final adsgram = Adsgram.instance;
|
final adsgram = Adsgram.instance;
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
() => adsgram.showAdWithBlockId(''),
|
() => adsgram.showAdWithBlockId(''),
|
||||||
throwsException,
|
throwsA(isA<Exception>()),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Adsgram instance is singleton', () {
|
||||||
|
final instance1 = Adsgram.instance;
|
||||||
|
final instance2 = Adsgram.instance;
|
||||||
|
|
||||||
|
expect(instance1, same(instance2));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('showRewardedAd validates JavaScript bridge functions exist', () async {
|
||||||
|
final adsgram = Adsgram.instance;
|
||||||
|
|
||||||
|
// In test environment, JavaScript bridge won't be available
|
||||||
|
// This tests that we check for bridge functions before using them
|
||||||
|
final adConfig = AdsgramAd(
|
||||||
|
blockId: '12345',
|
||||||
|
rewardAmount: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Should throw Exception when bridge functions are missing
|
||||||
|
expect(
|
||||||
|
() => adsgram.showRewardedAd(adConfig),
|
||||||
|
throwsA(isA<Exception>()),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,28 @@
|
||||||
// Adsgram SDK integration for rewarded ads
|
// Adsgram SDK integration for rewarded ads
|
||||||
// This file provides a bridge between Dart code and the Adsgram JavaScript SDK
|
// This file provides a bridge between Dart code and the Adsgram JavaScript SDK
|
||||||
|
|
||||||
// Check if Adsgram SDK is loaded
|
// Wait for SDK to load if it's not immediately available
|
||||||
if (typeof window.Adsgram === 'undefined') {
|
(function() {
|
||||||
console.error('Adsgram SDK not loaded. Make sure sad.min.js is included in index.html');
|
let sdkCheckAttempts = 0;
|
||||||
}
|
const maxCheckAttempts = 50; // Check for up to 5 seconds (50 * 100ms)
|
||||||
|
|
||||||
|
function checkSDK() {
|
||||||
|
if (typeof window.Adsgram !== 'undefined') {
|
||||||
|
console.log('Adsgram SDK loaded successfully');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdkCheckAttempts++;
|
||||||
|
if (sdkCheckAttempts < maxCheckAttempts) {
|
||||||
|
setTimeout(checkSDK, 100);
|
||||||
|
} else {
|
||||||
|
console.warn('Adsgram SDK not loaded after timeout. Make sure sad.min.js is included in index.html');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start checking after a short delay to allow script to load
|
||||||
|
setTimeout(checkSDK, 100);
|
||||||
|
})();
|
||||||
|
|
||||||
// Store callbacks for ad lifecycle events
|
// Store callbacks for ad lifecycle events
|
||||||
let rewardCallback = null;
|
let rewardCallback = null;
|
||||||
|
|
@ -18,17 +36,31 @@ const DEFAULT_BLOCK_ID = "16505";
|
||||||
* Initialize Adsgram ad controller with a specific block ID
|
* Initialize Adsgram ad controller with a specific block ID
|
||||||
* @param {string} blockId - The Adsgram block ID
|
* @param {string} blockId - The Adsgram block ID
|
||||||
* @returns {object} Adsgram ad controller instance
|
* @returns {object} Adsgram ad controller instance
|
||||||
|
* @throws {Error} If SDK is not available or initialization fails
|
||||||
*/
|
*/
|
||||||
function initAdController(blockId) {
|
function initAdController(blockId) {
|
||||||
if (typeof window.Adsgram === 'undefined') {
|
if (typeof window.Adsgram === 'undefined') {
|
||||||
throw new Error('Adsgram SDK not available');
|
const error = 'Adsgram SDK not available. Make sure sad.min.js is loaded.';
|
||||||
|
console.error(error);
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!blockId || typeof blockId !== 'string' || blockId.trim() === '') {
|
||||||
|
const error = 'Invalid block ID provided';
|
||||||
|
console.error(error);
|
||||||
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return window.Adsgram.init({ blockId: blockId });
|
const controller = window.Adsgram.init({ blockId: blockId });
|
||||||
|
if (!controller) {
|
||||||
|
throw new Error('Failed to initialize Adsgram controller: init returned null');
|
||||||
|
}
|
||||||
|
return controller;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to initialize Adsgram controller:', error);
|
const errorMessage = error?.message || error?.toString() || 'Unknown initialization error';
|
||||||
throw error;
|
console.error('Failed to initialize Adsgram controller:', errorMessage);
|
||||||
|
throw new Error(`Failed to initialize Adsgram controller: ${errorMessage}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,11 +80,30 @@ function showAd() {
|
||||||
* @returns {Promise} Promise that resolves when ad completes or rejects on error
|
* @returns {Promise} Promise that resolves when ad completes or rejects on error
|
||||||
*/
|
*/
|
||||||
function showAdWithBlockId(blockId) {
|
function showAdWithBlockId(blockId) {
|
||||||
if (!blockId || typeof blockId !== 'string') {
|
// Validate block ID
|
||||||
|
if (!blockId || typeof blockId !== 'string' || blockId.trim() === '') {
|
||||||
const error = 'Invalid block ID provided';
|
const error = 'Invalid block ID provided';
|
||||||
console.error(error);
|
console.error(error);
|
||||||
if (errorCallback && typeof errorCallback === 'function') {
|
if (errorCallback && typeof errorCallback === 'function') {
|
||||||
errorCallback(error);
|
try {
|
||||||
|
errorCallback(error);
|
||||||
|
} catch (callbackError) {
|
||||||
|
console.error('Error in error callback:', callbackError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check SDK availability
|
||||||
|
if (typeof window.Adsgram === 'undefined') {
|
||||||
|
const error = 'Adsgram SDK not available. Make sure sad.min.js is loaded.';
|
||||||
|
console.error(error);
|
||||||
|
if (errorCallback && typeof errorCallback === 'function') {
|
||||||
|
try {
|
||||||
|
errorCallback(error);
|
||||||
|
} catch (callbackError) {
|
||||||
|
console.error('Error in error callback:', callbackError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Promise.reject(new Error(error));
|
return Promise.reject(new Error(error));
|
||||||
}
|
}
|
||||||
|
|
@ -61,6 +112,19 @@ function showAdWithBlockId(blockId) {
|
||||||
// Initialize controller for this specific block
|
// Initialize controller for this specific block
|
||||||
currentAdController = initAdController(blockId);
|
currentAdController = initAdController(blockId);
|
||||||
|
|
||||||
|
if (!currentAdController || typeof currentAdController.show !== 'function') {
|
||||||
|
const error = 'Invalid ad controller: show method not available';
|
||||||
|
console.error(error);
|
||||||
|
if (errorCallback && typeof errorCallback === 'function') {
|
||||||
|
try {
|
||||||
|
errorCallback(error);
|
||||||
|
} catch (callbackError) {
|
||||||
|
console.error('Error in error callback:', callbackError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(error));
|
||||||
|
}
|
||||||
|
|
||||||
// Show the ad
|
// Show the ad
|
||||||
return currentAdController.show().then((result) => {
|
return currentAdController.show().then((result) => {
|
||||||
// Ad completed successfully - user watched till the end
|
// Ad completed successfully - user watched till the end
|
||||||
|
|
@ -72,6 +136,7 @@ function showAdWithBlockId(blockId) {
|
||||||
rewardCallback();
|
rewardCallback();
|
||||||
} catch (callbackError) {
|
} catch (callbackError) {
|
||||||
console.error('Error in reward callback:', callbackError);
|
console.error('Error in reward callback:', callbackError);
|
||||||
|
// Don't fail the promise if callback has an error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,14 +147,20 @@ function showAdWithBlockId(blockId) {
|
||||||
|
|
||||||
// Format error message
|
// Format error message
|
||||||
let errorMessage = 'Ad failed';
|
let errorMessage = 'Ad failed';
|
||||||
if (error && typeof error === 'object') {
|
if (error) {
|
||||||
try {
|
if (typeof error === 'object') {
|
||||||
errorMessage = JSON.stringify(error);
|
if (error.message) {
|
||||||
} catch (e) {
|
errorMessage = error.message;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
errorMessage = JSON.stringify(error);
|
||||||
|
} catch (e) {
|
||||||
|
errorMessage = error.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
errorMessage = error.toString();
|
errorMessage = error.toString();
|
||||||
}
|
}
|
||||||
} else if (error) {
|
|
||||||
errorMessage = error.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call error callback if set
|
// Call error callback if set
|
||||||
|
|
@ -105,7 +176,14 @@ function showAdWithBlockId(blockId) {
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Initialization or show() call failed
|
// Initialization or show() call failed
|
||||||
const errorMessage = error ? error.toString() : 'Failed to show ad';
|
let errorMessage = 'Failed to show ad';
|
||||||
|
if (error) {
|
||||||
|
if (error.message) {
|
||||||
|
errorMessage = error.message;
|
||||||
|
} else {
|
||||||
|
errorMessage = error.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
console.error('Failed to show ad:', errorMessage);
|
console.error('Failed to show ad:', errorMessage);
|
||||||
|
|
||||||
if (errorCallback && typeof errorCallback === 'function') {
|
if (errorCallback && typeof errorCallback === 'function') {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,5 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
|
||||||
<script src="https://telegram.org/js/telegram-web-app.js" defer=""></script>
|
|
||||||
<script src="https://sad.adsgram.ai/js/sad.min.js"></script>
|
|
||||||
<script src="foos.js"></script>
|
|
||||||
</head>
|
|
||||||
<head>
|
<head>
|
||||||
<!--
|
<!--
|
||||||
If you are serving your web app in a path other than the root, change the
|
If you are serving your web app in a path other than the root, change the
|
||||||
|
|
@ -37,6 +32,16 @@
|
||||||
|
|
||||||
<title>mnemo_cards_web_v2</title>
|
<title>mnemo_cards_web_v2</title>
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
|
|
||||||
|
<!-- External SDKs -->
|
||||||
|
<!-- Telegram Web App SDK -->
|
||||||
|
<script src="https://telegram.org/js/telegram-web-app.js" defer></script>
|
||||||
|
|
||||||
|
<!-- Adsgram SDK for rewarded ads - must load before foos.js -->
|
||||||
|
<script src="https://sad.adsgram.ai/js/sad.min.js"></script>
|
||||||
|
|
||||||
|
<!-- JavaScript bridge for Adsgram SDK integration -->
|
||||||
|
<script src="foos.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="flutter_bootstrap.js" async></script>
|
<script src="flutter_bootstrap.js" async></script>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue