import { createCommands } from '@jolibox/common'; import { canIUseNative, createSyncAPI, registerCanIUse } from './base'; import { createToast } from '@jolibox/ui'; import '../rewards'; import { notifyCustomEvent } from '@/common/utils'; const commands = createCommands(); // import { IAdsInitParams, JoliboxAdsImpl, IAdConfigParams, IAdBreakParams, IAdUnitParams } from '@/common/ads'; import { JoliboxAdsForGame, type IAdsInitParams, type IAdsContext, type IAdConfigParams, type IAdBreakParams, type IAdUnitParams } from '@jolibox/ads'; import { track } from '../report'; import { context } from '@/common/context'; import { innerFetch as fetch } from '../network'; import { invokeNative } from '@jolibox/native-bridge'; import { rewardsHelper, createAdsRewardHandler, createJolicoinRewardHandler, createJolicoinOnlyRewardHandler, createGemRewardHandler, createGemOnlyRewardHandler, warmupGemBalanceCache, warmupBalanceCache, createSubscriptionRewardHandler } from '@/common/rewards'; import { adEventEmitter } from '@/common/ads'; import { warmupRewardCache } from '@/common/rewards/fetch-reward'; const checkNetworkStatus = () => { const { data } = invokeNative('getNetworkStatusSync'); return !!data?.isConnected; }; const httpClient = { get: (url: string, options?: any) => fetch(url, { method: 'GET', responseType: 'json', appendHostCookie: true, ...options }).then((res) => res.response.data as T), post: (url: string, options?: any) => fetch(url, { method: 'POST', responseType: 'json', appendHostCookie: true, ...options }).then((res) => res.response.data as T) }; const adsContext: IAdsContext<'GAME'> = { httpClient, checkNetwork: checkNetworkStatus, track, eventEmitter: adEventEmitter, // TODO: @Deng Xue getWindowInfo: () => ({ width: window.innerWidth * window.devicePixelRatio, height: window.innerHeight * window.devicePixelRatio, statusBarHeight: 30 }), handleLinkClicked: (link) => { window.open(link, '_blank'); }, getContextInfo: () => { return { hostAppId: context.hostInfo?.aid ?? '1', deviceId: context.deviceInfo.did ?? '', adId: context.deviceInfo.adId ?? '', sessionId: context.sessionId ?? '', userId: context.hostUserInfo?.uid ?? '', objectType: 'GAME', objectId: context.mpId, testAdsMode: context.testAdsMode, channel: context.joliSource ?? '', deviceBrand: context.deviceInfo.brand, deviceModel: context.deviceInfo.model, osType: context.platform === 'android' ? 'ANDROID' : context.platform === 'ios' ? 'IOS' : 'PC', runtimeType: 'APP', platform: 1000, // WebSDK joliSource: context.joliSource ?? '', deviceInfo: { platform: context.platform, nativeSDKVersionCode: context.sdkInfo.nativeSDKVersionCode ?? 0 } }; } }; const ads = new JoliboxAdsForGame(adsContext); rewardsHelper.getRewardFrequencyConfig(httpClient).then((config) => { console.log('getRewardFrequencyConfig', config); }); rewardsHelper.registerRewardHandler('ADS', createAdsRewardHandler(ads)); rewardsHelper.registerRewardHandler( 'JOLI_COIN', createJolicoinRewardHandler(httpClient, { onUnlockSuccess: (params) => { showUnlockSuccessToast(params); track('jolicoin_unlock_success', { quantity: params.quantity }); }, onUnlockFailed: () => { console.log('onUnlockFailed'); }, hasSubscription: () => canIUseNative('invokeSubscriptionPanelSync') }) as unknown as (params?: unknown) => Promise ); rewardsHelper.registerRewardHandler( 'JOLI_COIN_ONLY', createJolicoinOnlyRewardHandler(httpClient, { onUnlockSuccess: (params) => { showUnlockSuccessToast(params); track('jolicoin_unlock_success', { quantity: params.quantity, isOnly: true }); }, onUnlockFailed: () => { console.log('onUnlockFailed'); }, hasSubscription: () => canIUseNative('invokeSubscriptionPanelSync') }) as unknown as (params?: unknown) => Promise ); // gem rewardsHelper.registerRewardHandler( 'JOLI_GEM', createGemRewardHandler(httpClient, { onUnlockSuccess: (params) => { showGemSuccessToast(params); track('gem_unlock_success', { quantity: params.quantity }); }, hasSubscription: () => canIUseNative('invokeSubscriptionPanelSync') }) as unknown as (params?: unknown) => Promise ); rewardsHelper.registerRewardHandler( 'JOLI_GEM_ONLY', createGemOnlyRewardHandler(httpClient, { onUnlockSuccess: (params) => { showGemSuccessToast(params); track('gem_unlock_success', { quantity: params.quantity, isOnly: true }); }, hasSubscription: () => canIUseNative('invokeSubscriptionPanelSync') }) as unknown as (params?: unknown) => Promise ); const handleUnlockWithSubscriptionSuccess = () => { track('subscription_unlock_success', {}); }; rewardsHelper.registerRewardHandler( 'SUBSCRIPTION', createSubscriptionRewardHandler(httpClient, { onSubSuccess: handleUnlockWithSubscriptionSuccess.bind(this), hasSubscription: () => canIUseNative('invokeSubscriptionPanelSync') }) as unknown as (params?: unknown) => Promise ); const showUnlockSuccessToast = (params: { quantity: number; balance: number }) => { const { quantity } = params; const toastTemplate = `{slot-coin} ${quantity} {slot-i18n-jolicoin.coinUsed}`; createToast(toastTemplate, { customStyle: { mark: { marginRight: '8px' }, base: { with: 'auto' } }, i18nParams: { text: 'Jolicoin Used' } }); }; warmupRewardCache(httpClient); warmupGemBalanceCache(httpClient); adEventEmitter.on('isAdShowing', (isAdShowing) => { notifyCustomEvent('JOLIBOX_ADS_EVENT', { isAdShowing }); }); export const showGemSuccessToast = (params: { quantity: number; balance: number }) => { const { quantity } = params; const toastTemplate = `{slot-correct} ${quantity * -1} {slot-gem}`; createToast(toastTemplate, { customStyle: { mark: { marginRight: '8px' }, base: { 'font-size': '25px', 'font-weight': '700', 'line-height': '18px' }, span: { width: 'auto', minWidth: 'fit-content', maxWidth: '60px', textAlign: 'center', padding: '0 2px', lineHeight: '25px' }, gem: { transform: 'translateY(-2px)', width: '28px', height: '28px' } } }); }; const adInit = createSyncAPI('adInit', { implement: (config?: IAdsInitParams) => { ads.init(config); } }); const adConfig = createSyncAPI('adConfig', { implement: (params: IAdConfigParams) => { ads.adConfig(params); } }); let rewardLocked = false; const wrapAdBreadDoneViewed = (params: IAdBreakParams) => { params.adBreakDone?.({ breakType: params.type, breakName: 'name' in params ? params.name ?? '' : '', breakFormat: params.type === 'reward' ? 'reward' : 'interstitial', breakStatus: 'viewed' }); if ('adViewed' in params) { params.adViewed?.(); } }; const adBreak = createSyncAPI('adBreak', { implement: (params: IAdBreakParams) => { // check is sub user const isSubUser = context.hostUserInfo?.isSubUser; if (isSubUser) { wrapAdBreadDoneViewed(params); return; } if (params.type === 'reward') { if (rewardLocked) { return; } rewardLocked = true; rewardsHelper.getRewardsTypes(httpClient).then((rewardsTypes) => { rewardsHelper .handleReward(rewardsTypes, params) .catch((e) => { console.info('handleReward failed in native', e); params.adBreakDone?.({ breakType: params.type, breakFormat: params.type === 'reward' ? 'reward' : 'interstitial', breakStatus: 'noAdPreloaded' }); }) .finally(() => { rewardLocked = false; }); }); } else { ads.adBreak(params); } } }); const adUnit = createSyncAPI('adUnit', { implement: (params: IAdUnitParams) => { ads.adUnit(params); } }); commands.registerCommand('AdsSDK.init', adInit); commands.registerCommand('AdsSDK.adConfig', adConfig); commands.registerCommand('AdsSDK.adBreak', adBreak); commands.registerCommand('AdsSDK.adUnit', adUnit); registerCanIUse('AdsSDK.init', { version: '1.0.0' }); registerCanIUse('AdsSDK.adConfig', { version: '1.0.0' }); registerCanIUse('AdsSDK.adBreak', { version: '1.0.0' }); registerCanIUse('AdsSDK.adUnit', { version: '1.0.0' });