guru_sdk/guru_app/lib/ads/ads_manager.dart

727 lines
25 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:ui';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:guru_app/account/model/user.dart';
import 'package:guru_app/ads/applovin/banner/applovin_banner_ads.dart';
import 'package:guru_app/ads/core/ads.dart';
import 'package:guru_app/ads/core/ads_config.dart';
import 'package:guru_app/ads/core/ads_impression.dart';
import 'package:guru_app/ads/core/strategy/interstitial/max_strategy_interstitial_ads.dart';
import 'package:guru_app/financial/asset/assets_model.dart';
import 'package:guru_app/financial/asset/assets_store.dart';
import 'package:guru_app/financial/iap/iap_manager.dart';
import 'package:guru_app/financial/iap/iap_model.dart';
import 'package:guru_app/firebase/remoteconfig/remote_config_manager.dart';
import 'package:guru_app/guru_app.dart';
import 'package:guru_utils/lifecycle/lifecycle_manager.dart';
import 'package:guru_app/property/app_property.dart';
import 'package:guru_app/property/property_keys.dart';
import 'package:guru_app/property/settings/guru_settings.dart';
import 'package:guru_applovin_flutter/guru_applovin_flutter.dart';
import 'package:guru_utils/datetime/datetime_utils.dart';
import 'package:guru_utils/extensions/extensions.dart';
import 'package:guru_utils/network/network_utils.dart';
import 'package:guru_utils/tuple/tuple.dart';
import 'package:guru_utils/ads/ads.dart';
import 'applovin/interstitial/applovin_interstitial_ads.dart';
import 'applovin/rewarded/applovin_rewarded_ads.dart';
import 'utils/ads_exception.dart';
import 'package:device_info_plus/device_info_plus.dart';
part 'ads_global_property.dart';
/// Created by Haoyi on 2022/3/2
class AdsManager extends AdsManagerDelegate {
static final AdsManager _instance = AdsManager._();
static AdsManager get instance => _instance;
AdsManager._();
final Map<AdUnitId, Ads> interstitialAds = {};
final Map<AdUnitId, ApplovinRewardedAds> rewardsAds = {};
final AdImpressionController adImpressionController =
AdImpressionController();
final BehaviorSubject<AdsConfig> _adsConfigSubject =
BehaviorSubject.seeded(AdsConfig.defaultAdsConfig);
final BehaviorSubject<AdsProfile> _adsProfileSubject =
BehaviorSubject.seeded(GuruApp.instance.adsProfile);
final BehaviorSubject<bool> _initializedSubject =
BehaviorSubject.seeded(false);
final BehaviorSubject<bool> noBannerAndInterstitialAdsSubject =
BehaviorSubject.seeded(false);
final Map<String, dynamic> adsGlobalProperties = <String, dynamic>{};
static const Set<String> _reservedKeywords = {
"app_version",
"lt",
"paid",
"blv",
"os_version",
"connection"
};
static const List<int> ltSamples = [
0,
1,
2,
3,
4,
5,
6,
14,
30,
60,
90,
120,
180
];
@override
Stream<bool> get observableInitialized => _initializedSubject.stream;
ConnectivityResult get connectivityStatus => NetworkUtils.currentConnectivityStatus;
Stream<ConnectivityResult> get observableConnectivityStatus =>
NetworkUtils.observableConnectivityStatus;
@override
Stream<bool> get observableNoAds => noBannerAndInterstitialAdsSubject.stream;
final CompositeSubscription subscriptions = CompositeSubscription();
AdsProfile get adsProfile => _adsProfileSubject.value;
AdsConfig get adsConfig => _adsConfigSubject.value;
bool get hasAmazonBannerAds => adsConfig.bannerConfig.amazonEnable;
bool get hasAmazonInterstitialAds =>
adsConfig.interstitialConfig.amazonEnable;
bool get hasAmazonAds => hasAmazonBannerAds || hasAmazonInterstitialAds;
final BehaviorSubject<Map<String, String>> keywordsSubject =
BehaviorSubject.seeded({});
Stream<Map<String, String>> get observableKeywords => keywordsSubject.stream;
Map<String, String> get adsKeywords => keywordsSubject.value;
String? consentTestDeviceId;
int? consentDebugGeography;
static final RegExp _nonAlphaNumeric = RegExp('[^a-zA-Z0-9_]');
static final RegExp _alpha = RegExp('[a-zA-Z]');
@override
bool get isPurchasedNoAd => noBannerAndInterstitialAdsSubject.value;
void setProperty(String key, String value) {
adsGlobalProperties[key] = value;
}
void setNoAds(bool noAds) {
noBannerAndInterstitialAdsSubject.addIfChanged(noAds);
GuruSettings.instance.isNoAds.set(noAds);
GuruAnalytics.instance
.setUserProperty("user_type", noAds ? "noads" : "default");
setProperty("user_type", noAds ? "noads" : "default");
}
void ensureInitialize() {}
void listenIap() {
final obs = Rx.combineLatest2<bool, AssetsStore<Asset>,
Tuple2<bool, AssetsStore<Asset>>>(
IapManager.instance.observableAvailable,
IapManager.instance.observableAssetStore,
(a, b) => Tuple2(a, b));
subscriptions.add(obs.listen((tuple) {
final available = tuple.item1;
final purchasedStore = tuple.item2;
if (available && purchasedStore.isActive) {
final tempIsNoAds = purchasedStore
.existsAssets(GuruApp.instance.productProfile.noAdsCapIds);
final isNoAds = isPurchasedNoAd;
Log.i(
"purchased store changed active! tempIsNoAds:$tempIsNoAds isNoAds:$isNoAds",
syncFirebase: true);
if (isNoAds != tempIsNoAds) {
if (!tempIsNoAds) {
GuruAnalytics.instance.logException(NoAdsException(
"The payment system is abnormal, it shouldn't appear that the purchased item become unpurchased"));
}
setNoAds(tempIsNoAds);
}
}
}));
}
static bool initializedSdk = false;
Future initialize({SaasUser? saasUser}) async {
_adsProfileSubject.addEx(GuruApp.instance.adsProfile);
await initEnv();
final connected = await NetworkUtils.isNetworkConnected();
Log.d("adsManager initialize connected:$connected", tag: "Ads");
if (connected) {
await initSdk(
saasUser: saasUser,
onInitialized: () {
// loadAds();
adImpressionController.init();
checkAndPreload();
// GuruSettings.instance.totalLevelUp
// .observe()
// .throttleTime(const Duration(seconds: 1))
// .listen((count) {
// checkAndPreload();
// });
Log.i("ADS Initialized", tag: "Ads", syncFirebase: true);
});
} else {
NetworkUtils.observableConnectivityTrack.listen((track) async {
if (track.newResult != ConnectivityResult.none) {
if (!initializedSdk) {
initializedSdk = true;
await initSdk(onInitialized: () {
adImpressionController.init();
checkAndPreload();
Log.i("ADS Initialized", tag: "Ads", syncFirebase: true);
});
}
}
if (track.newResult != track.oldResult) {
Log.i("connectivity result changed! retry ads!", tag: "Ads");
setKeyword("connection", track.newResult.toString());
if (LifecycleManager.instance.isAppForeground()) {
if (track.newResult == ConnectivityResult.none &&
track.oldResult != ConnectivityResult.none) {
Log.i("connectivity changed! retry ads!", tag: "Ads");
retry();
}
}
}
});
}
subscriptions.add(RemoteConfigManager.instance.observeConfig().listen((_) {
refreshAdsConfig();
}, onError: (error, stacktrace) {
Log.i("init config error!",
tag: "Ads", error: error, stackTrace: stacktrace);
}));
listenIap();
}
// void initLifecycleConnectivity() {
// StreamSubscription? streamSubscription;
// LifecycleManager.instance.observableAppLifecycle.listen((foreground) {
// if (foreground) {
// streamSubscription = Connectivity()
// .onConnectivityChanged
// .listen((ConnectivityResult result) {
// Log.i("Connectivity: $result", tag: "Connectivity");
// if (connectivityStatus == ConnectivityResult.none &&
// result != ConnectivityResult.none) {
// Log.i("connectivity changed! retry ads!", tag: "Ads");
// retry();
// }
// final changed = connectivityStatusSubject.addIfChanged(result);
// if (changed) {
// setKeyword("connection", result.toString());
// }
// });
// } else {
// streamSubscription?.cancel();
// streamSubscription = null;
// }
// });
// }
void initAdsProfile() {
final _hasAmazonBannerAds = hasAmazonBannerAds;
final _hasAmazonInterstitialAds = hasAmazonInterstitialAds;
final _hasAmazonAds = _hasAmazonBannerAds || _hasAmazonInterstitialAds;
final defaultAdsProfile = GuruApp.instance.adsProfile;
final strategyInterstitialIds = adsConfig.strategyAdsConfig.interstitialIds;
final newAdsProfile = adsProfile.copyWith(
amazonAppId: _hasAmazonAds ? defaultAdsProfile.amazonAppId : null,
amazonBannerSlotId:
_hasAmazonBannerAds ? defaultAdsProfile.amazonBannerSlotId : null,
amazonInterstitialSlotId: _hasAmazonInterstitialAds
? defaultAdsProfile.amazonInterstitialSlotId
: null,
strategyInterstitialIds: strategyInterstitialIds);
_adsProfileSubject.addEx(newAdsProfile);
}
Future initEnv() async {
final adsPropertyBundle =
await AppProperty.getInstance().loadValuesByTag(PropertyTags.ads);
final isNoAds = adsPropertyBundle.getBool(PropertyKeys.isNoAds) ?? false;
consentTestDeviceId =
adsPropertyBundle.getString(PropertyKeys.admobConsentTestDeviceId);
consentDebugGeography =
adsPropertyBundle.getInt(PropertyKeys.admobConsentDebugGeography);
noBannerAndInterstitialAdsSubject.addIfChanged(isNoAds);
GuruAnalytics.instance
.setUserProperty("user_type", isNoAds ? "noads" : "default");
setProperty("user_type", isNoAds ? "noads" : "default");
final result = await Connectivity().checkConnectivity().catchError((error) {
Log.w("checkConnectivity error! $error");
});
// connectivityStatusSubject.addEx(result);
setProperty("connectivityStatus", result.toString());
refreshAdsConfig();
initAdsProfile();
}
Future initSdk(
{SaasUser? saasUser,
required VoidCallback onInitialized,
Duration retryPeriod = const Duration(seconds: 15)}) async {
final _adsProfile = adsProfile;
bool initializeResult = false;
if (GuruApp.instance.appSpec.deployment.adsCompliantInitialization &&
adsConfig.commonAdsConfig.compliantInitialization &&
Platform.isAndroid) {
initializeResult = await GuruApplovinFlutter.instance
.gatherConsentAndInitialize(
userId: saasUser?.uid,
amazonAppId: _adsProfile.amazonAppId?.id,
pubmaticStoreUrl: adsProfile.pubmaticAppStoreUrl,
testDeviceId: consentTestDeviceId,
debugGeography: consentDebugGeography)
.catchError((err) => false) ??
false;
} else {
initializeResult = await GuruApplovinFlutter.instance
.initialize(
userId: saasUser?.uid,
amazonAppId: _adsProfile.amazonAppId?.id,
pubmaticStoreUrl: adsProfile.pubmaticAppStoreUrl)
.catchError((err) => false) ??
false;
}
_initializedSubject.addEx(initializeResult);
Log.d("MAX sdk initialize result: $initializeResult");
if (initializeResult) {
try {
await initKeywords();
} catch (error, stacktrace) {
Log.e("initKeywords error! $error $stacktrace", tag: "Ads");
}
onInitialized.call();
} else {
Future.delayed(retryPeriod, () {
initSdk(onInitialized: onInitialized, retryPeriod: retryPeriod);
});
Log.w("Ads Initialize error! retry", tag: "Ads", syncFirebase: true);
}
return initializeResult;
}
void checkAndPreload(
{AdsValidator? rewardedValidator,
AdsValidator? interstitialValidator}) async {
final canPreloadReward =
await adsConfig.rewardedConfig.canPreload(validator: rewardedValidator);
if (canPreloadReward) {
Log.d("preload reward canPreload!");
final reward = await getRewardsAds();
if (reward.loadCount <= 0) {
reward.preload();
}
}
final canPreloadInterstitial = await adsConfig.interstitialConfig
.canPreload(validator: interstitialValidator);
if (!isPurchasedNoAd && canPreloadInterstitial) {
Log.d("preload interstitial canPreload!");
final interstitial = await getInterstitialAds();
if (interstitial is AdsAudit && interstitial.loadCount <= 0) {
interstitial.preload();
}
}
}
void retry() async {
final canPreloadReward = await adsConfig.rewardedConfig.canPreload();
if (canPreloadReward) {
final reward = await getRewardsAds();
reward.retry();
}
final canPreload = await adsConfig.interstitialConfig.canPreload();
if (canPreload) {
Log.d("preload interstitial canPreload!");
final interstitial = await getInterstitialAds();
interstitial.retry();
}
}
static int _nearestLt(int low, int high, int lt) {
if (low > high) {
return -low;
}
while (low <= high) {
final int mid = (low + high) >> 1;
if (lt == ltSamples[mid]) {
return mid;
} else if (lt < ltSamples[mid]) {
return _nearestLt(low, mid - 1, lt);
} else {
return _nearestLt(mid + 1, high, lt);
}
}
return -low;
}
Future<int> getKeywordLt() async {
final latestLtDate = await AppProperty.getInstance().getLatestLtDate();
final dateNum = DateTimeUtils.yyyyMMddUtcNum;
int lt = await AppProperty.getInstance().getLtDays();
if (dateNum != latestLtDate) {
if (dateNum > latestLtDate) {
lt = lt + 1;
await AppProperty.getInstance().setLtDays(lt);
}
await AppProperty.getInstance().setLatestLtDate(dateNum);
}
final idx = _nearestLt(0, ltSamples.lastIndex, lt)
.abs()
.clamp(0, ltSamples.lastIndex);
Log.d(
"getKeywordLt: installTime:$latestLtDate now:$dateNum lt:$lt keywordLt:${ltSamples[idx]}");
return ltSamples[idx];
}
Future<String> getOSVersion() async {
try {
final deviceInfo = DeviceInfoPlugin();
if (Platform.isAndroid) {
final info = await deviceInfo.androidInfo;
return info.version.release;
} else if (Platform.isIOS) {
final info = await deviceInfo.iosInfo;
return info.systemVersion;
}
} catch (error, stacktrace) {
Log.w("getOSVersion error! $error");
}
return "unknown";
}
Future<String> getConnection() async {
try {
final connectivity = await Connectivity().checkConnectivity();
return connectivity.toString();
} catch (error, stacktrace) {
Log.w("getConnection error! $error");
}
return "unknown";
}
Future initKeywords() async {
final paidUser = await AppProperty.getInstance().isPaidUser();
final version = Settings.get().version.get();
final lt = await getKeywordLt();
final osVersion = await getOSVersion();
final connection = await getConnection();
final keywords = <String, String>{
"app_version": version,
"paid": paidUser ? "true" : "false",
"lt": lt.toString(),
"os_version": osVersion,
"connection": connection
};
keywordsSubject.stream.listen((keywords) {
if (keywords.isNotEmpty) {
Log.i("invoke setKeywords: $keywords", tag: "Ads");
GuruApplovinFlutter.instance.setKeywords(keywords);
}
});
keywordsSubject.addEx(keywords);
}
Future restoreKeywords(Map<String, String> keywords) async {
if (GuruSettings.instance.debugMode.get()) {
final newKeywords = Map.of(keywords);
keywordsSubject.addEx(newKeywords);
}
}
void setKeyword(String key, String value, {bool debugForce = false}) {
if (!GuruSettings.instance.debugMode.get() || !debugForce) {
if (_reservedKeywords.contains(key)) {
Log.w("setKeyword error! the key($key) is reserved and cannot be used!",
tag: "Ads");
return;
}
if (key.isEmpty ||
key.length > 36 ||
key.indexOf(_alpha) != 0 ||
key.contains(_nonAlphaNumeric)) {
Log.w(
"setKeyword error! the key($key) must contain 1 to 36 alphanumeric characters.",
tag: "Ads");
return;
}
}
final newKeywords = Map.of(keywordsSubject.value);
newKeywords[key] = value;
keywordsSubject.addEx(newKeywords);
}
void removeKeyword(String key, {bool debugForce = false}) {
if (!GuruSettings.instance.debugMode.get() || !debugForce) {
if (_reservedKeywords.contains(key)) {
Log.w(
"removeKeyword error! the key($key) is reserved and cannot be used!",
tag: "Ads");
return;
}
if (key.isEmpty ||
key.length > 36 ||
key.indexOf(_alpha) != 0 ||
key.contains(_nonAlphaNumeric)) {
Log.w(
"removeKeyword error! the key($key) must contain 1 to 36 alphanumeric characters.",
tag: "Ads");
return;
}
}
final newKeywords = Map.of(keywordsSubject.value);
newKeywords.remove(key);
keywordsSubject.addEx(newKeywords);
}
Future<int> checkConsentDialogStatus() async {
return await GuruApplovinFlutter.instance.checkConsentDialogStatus();
}
Future<bool> afterAcceptPrivacy(bool consentResult) async {
return await GuruApplovinFlutter.instance.afterAcceptPrivacy(consentResult);
}
bool testParseAdsDefaultConfig() {
final iadsConfigString =
RemoteConfigReservedConstants.getDefaultConfigString(
RemoteConfigReservedConstants.iadsConfig) ??
"";
final radsConfigString =
RemoteConfigReservedConstants.getDefaultConfigString(
RemoteConfigReservedConstants.radsConfig) ??
"";
final badsConfigString =
RemoteConfigReservedConstants.getDefaultConfigString(
RemoteConfigReservedConstants.badsConfig) ??
"";
final iosAttConfigString =
RemoteConfigReservedConstants.getDefaultConfigString(
RemoteConfigReservedConstants.iosAttConfig) ??
"";
try {
final adInterstitial =
AdInterstitialConfig.fromJson(json.decode(iadsConfigString));
final adBanner = AdBannerConfig.fromJson(json.decode(badsConfigString));
final iosAttConfig =
IOSAttConfig.fromJson(json.decode(iosAttConfigString));
Log.d("==== ADS AdsConfig ====");
Log.d(" ---> [INTERSTITIAL]: $iadsConfigString");
Log.d(" ---> [BANNER]: $badsConfigString");
Log.d(" ---> [IOSATT]: $iosAttConfigString");
Log.d("=======================");
_adsConfigSubject.addEx(AdsConfig.build(
interstitialConfig: adInterstitial,
bannerConfig: adBanner,
iosAttConfig: iosAttConfig));
return true;
} catch (error, stacktrace) {
Log.e("refreshAdsConfig error $error $stacktrace");
rethrow;
}
}
bool refreshAdsConfig() {
try {
final commonAdsConfig = RemoteConfigManager.instance.getCommonAdsConfig();
final adInterstitial = RemoteConfigManager.instance.getIadsConfig();
final adReward = RemoteConfigManager.instance.getRadsConfig();
final adBanner = RemoteConfigManager.instance.getBadsConfig();
final strategyAdsConfig =
RemoteConfigManager.instance.getStrategyAdsConfig();
final iosAttConfig = RemoteConfigManager.instance.getIOSAttConfig();
Log.d("==== ADS AdsConfig ====", tag: PropertyTags.ads);
Log.d(" ---> [COMMON]: ${commonAdsConfig.toJson()}",
tag: PropertyTags.ads);
Log.d(" ---> [INTERSTITIAL]: ${adInterstitial.toJson()}",
tag: PropertyTags.ads);
Log.d(" ---> [REWARD]: ${adReward.toJson()}", tag: PropertyTags.ads);
Log.d(" ---> [BANNER]: ${adBanner.toJson()}", tag: PropertyTags.ads);
Log.d(" ---> [STRATEGY]: ${strategyAdsConfig.toJson()}",
tag: PropertyTags.ads);
Log.d(" ---> [IOSATT]: ${iosAttConfig.toJson()}", tag: PropertyTags.ads);
Log.d("=======================", tag: PropertyTags.ads);
_adsConfigSubject.addEx(AdsConfig.build(
commonAdsConfig: commonAdsConfig,
interstitialConfig: adInterstitial,
rewardedConfig: adReward,
bannerConfig: adBanner,
strategyAdsConfig: strategyAdsConfig,
iosAttConfig: iosAttConfig));
return true;
} catch (error, stacktrace) {
Log.e("refreshAdsConfig error $error $stacktrace");
rethrow;
}
}
@override
Future<Ads> getInterstitialAds() async {
final _adsProfile = adsProfile;
final strategyInterstitialIds = adsProfile.strategyInterstitialIds ?? [];
Ads? ad;
if (strategyInterstitialIds.isNotEmpty) {
if (strategyInterstitialIds.length > 1) {
ad = interstitialAds[strategyInterstitialIds.first.adUnitId] ??=
MaxStrategyInterstitialAds.create(strategyInterstitialIds)..init();
} else {
ad = interstitialAds[strategyInterstitialIds.first.adUnitId] ??=
ApplovinInterstitialAds.create(
strategyInterstitialIds.first.adUnitId,
strategyInterstitialIds.first.amazonAdSlotId)
..init();
}
} else {
ad = interstitialAds[_adsProfile.interstitialId] ??=
ApplovinInterstitialAds.create(
_adsProfile.interstitialId, _adsProfile.amazonInterstitialSlotId)
..init();
}
return ad;
}
@override
Future<ApplovinRewardedAds> getRewardsAds() async {
final _adsProfile = adsProfile;
ApplovinRewardedAds? ad = rewardsAds[_adsProfile.rewardsId];
if (ad == null) {
ad = ApplovinRewardedAds.create(_adsProfile.rewardsId,
adAmazonSlotId: _adsProfile.amazonRewardedSlotId)
..init();
rewardsAds[_adsProfile.rewardsId] = ad;
}
return ad;
}
Future<int> requestGdpr({int? debugGeography, String? testDeviceId}) async {
Log.d(
"requestGdpr! debugGeography:$debugGeography testDeviceId:$testDeviceId",
tag: "Ads");
// adb logcat -s UserMessagingPlatform
// Use new ConsentDebugSettings.Builder().addTestDeviceHashedId("xxxx") to set this as a debug device.
final result = await GuruApplovinFlutter.instance.requestGdpr(
debugGeography: debugGeography, testDeviceId: testDeviceId);
final consentResult = await GuruAnalytics.instance.refreshConsents();
Log.d("requestGdpr result:$result consentResult:$consentResult");
return result;
}
Future<bool> resetGdpr() {
return GuruApplovinFlutter.instance.resetGdpr();
}
Future<bool> updateOrientation(int orientation) async {
final result =
await GuruApplovinFlutter.instance.updateOrientation(orientation);
return result == true;
}
@override
Future<ApplovinBannerAds> createBannerAds(
{String? scene, AdsLifecycleObserver? observer}) async {
final _adsProfile = adsProfile;
return ApplovinBannerAds.create(
_adsProfile.bannerId, _adsProfile.amazonBannerSlotId,
scene: scene, observer: observer);
}
AdCause canShowInterstitial(String scene) {
if (isPurchasedNoAd) {
return AdCause.noAds;
}
final hiddenAt = AdsManager.instance.latestFullscreenAdsHiddenTimestamps;
final now = DateTimeUtils.currentTimeInMillis();
final impGapInMillis = AdsManager.instance.adsConfig.interstitialConfig
.getSceneImpGapInSeconds(scene) *
1000;
Log.d(
"canShowInterstitial($scene): now:$now latestFullscreenAdsHiddenTimestamps:$latestFullscreenAdsHiddenTimestamps hiddenAt:$hiddenAt impGapInMillis:$impGapInMillis",
tag: "Ads");
if ((now - hiddenAt) < impGapInMillis) {
Log.d("show ads too frequency", syncFirebase: true);
return AdCause.tooFrequent;
}
return AdCause.success;
}
@override
Future<AdCause> validateInterstitial(String? scene,
{AdsValidator? validator}) {
final interstitialConfig = adsConfig.interstitialConfig;
return interstitialConfig.check(scene ?? "", validator: validator);
}
@override
Future<AdCause> validateRewards(String? scene, {AdsValidator? validator}) {
final rewardedConfig = adsConfig.rewardedConfig;
return rewardedConfig.check(scene ?? "", validator: validator);
}
@override
Future<AdCause> validateBanner(String? scene, {AdsValidator? validator}) {
final rewardedConfig = adsConfig.bannerConfig;
return rewardedConfig.check(scene ?? "", validator: validator);
}
@override
dynamic getConfig(String type) {
switch (type) {
case "bannerAutoDisposeInterval":
return adsConfig.bannerConfig.autoDisposeIntervalInMinutes;
case "allowInterstitialAsAlternativeReward":
return GuruApp
.instance.appSpec.deployment.allowInterstitialAsAlternativeReward;
case "showInternalAdsWhenBannerUnavailable":
return GuruApp
.instance.appSpec.deployment.showInternalAdsWhenBannerUnavailable;
}
}
}