SDK do Flutter - Acompanhamento de receitas de anúncios

Documento

Atribuição de receitas de anúncios

Acompanhe as receitas de anúncios das plataformas de mediação e atribua-as a campanhas de marketing específicas que trouxeram utilizadores à sua aplicação, permitindo uma análise abrangente do ROI.

O Ad Revenue Attribution liga as receitas de anúncios de aplicações móveis às campanhas de marketing que geraram utilizadores, combinando o custo da campanha, as receitas in-app e as receitas de anúncios num relatório unificado. Esses dados também retornam às redes de anúncios para otimizar o desempenho da campanha.

Saiba mais: Consulte as FAQs da Singular Ad Revenue Attribution para obter informações detalhadas sobre a metodologia de atribuição e as plataformas de mediação suportadas.


Como funciona a atribuição de receita de anúncios

Fluxo de atribuição

A sua plataforma de mediação reporta dados de receita ao nível da impressão ou do utilizador através de callbacks, que valida e encaminha para a Singular para análise de atribuição.

  • Atribuição de campanha: Vincula a receita de anúncios às campanhas específicas que adquiriram cada usuário, mostrando o verdadeiro ROI por campanha
  • Fontes de dados: Os dados de receita são provenientes de sua plataforma de mediação, tanto em nível de usuário quanto em nível de impressão
  • Otimização da rede: A Singular passa os dados de receita de volta para as redes de anúncios para melhorar as estratégias de segmentação e licitação

Requisitos de implementação

Assegurar a exatidão dos dados antes de implementar o rastreio de receitas de anúncios, uma vez que os dados de receitas incorrectos não podem ser corrigidos após a transmissão.

Requisitos críticos:

  • Códigos de moeda: Utilizar códigos ISO 4217 de três letras (USD, EUR, INR). A maioria das plataformas de mediação utiliza USD por defeito
  • Validação de dados: Sempre valide se os valores de receita são positivos e se os códigos de moeda não estão vazios antes de enviar para a Singular
  • Conversão de unidades: Algumas plataformas informam a receita em micros (1.000.000 = US$ 1,00). Converta para dólares antes de enviar para a Singular

Etapas de configuração

Siga estas etapas para implementar a atribuição de receita de anúncios com sua plataforma de mediação.

  1. Atualizar SDK: Certifique-se de que está a executar a versão mais recente do Singular SDK do Flutter
  2. Configurar plataforma: Habilite o relatório de receita de anúncios no painel da sua plataforma de mediação (AdMob, AppLovin, etc.)
  3. Implementar retornos de chamada: Adicione ouvintes de eventos de receita do SDK de mediação para capturar dados de impressão
  4. Validar dados: Verificar se a receita é > 0 e se a moeda é válida antes de encaminhar para o Singular
  5. Testar integração: Verificar se os dados de receita aparecem nos relatórios do Singular em 24 horas

Integração com o AdMob

Pré-requisitos

Habilite o relatório de receita de anúncios na sua conta AdMob e implemente o SDK do Google Mobile Ads para Flutter antes de integrar com o Singular.

  • Configuração do AdMob: Ative a receita de anúncios no nível da impressão no painel do AdMob. Consulte Suporte do AdMob
  • Pacote Flutter: Instale o pacote google_mobile_ads. Consulte o Guia de introdução

Diferenças de plataforma: A AdMob reporta a receita de forma diferente por plataforma. O Android retorna a receita em micros (5000 = US$ 0,005), enquanto o iOS retorna valores decimais (0,005 = US$ 0,005). Converta os valores do Android dividindo-os por 1.000.000 antes de enviá-los para o Singular.


Etapas de implementação

Configure o retorno de chamada onPaidEvent ao carregar anúncios para capturar dados de receita de impressões de anúncios bem-sucedidas.

  1. Carregar anúncio: Criar e carregar um bloco de anúncios (Recompensado, Intersticial, Banner, etc.)
  2. Definir retorno de chamada: Atribua a chamada de retorno onPaidEvent para capturar AdValue quando o anúncio gerar receita
  3. Converter unidades: Dividir valueMicros por 1.000.000 para converter em dólares
  4. Validar: Verificar se a receita é superior a 0 e se a moeda não está vazia
  5. Enviar para Singular: Ligar para Singular.adRevenue() com dados validados

Exemplo de anúncio recompensado

Capture a receita de anúncios em vídeo recompensados definindo a chamada de retorno onPaidEvent após a conclusão do carregamento do anúncio.

Dart
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:singular_flutter_sdk/singular.dart';

const String adUnitId = 'YOUR_AD_UNIT_ID';

class AdManager {
  RewardedAd? _rewardedAd;

  void loadRewardedAd() {
    RewardedAd.load(
      adUnitId: adUnitId,
      request: AdRequest(),
      rewardedAdLoadCallback: RewardedAdLoadCallback(
        onAdLoaded: (RewardedAd ad) {
          _rewardedAd = ad;
          print('Rewarded ad loaded successfully');

          // Set up full screen content callback
          _rewardedAd?.fullScreenContentCallback = FullScreenContentCallback(
            onAdShowedFullScreenContent: () {
              print('Rewarded ad displayed');
            },
            onAdFailedToShowFullScreenContent: (AdError adError) {
              print('Rewarded ad failed to show: ${adError.message}');
            },
            onAdDismissedFullScreenContent: () {
              print('Rewarded ad dismissed');
              _rewardedAd = null;
            },
          );

          // Set up paid event callback for revenue tracking
          _rewardedAd?.onPaidEvent = (AdValue adValue) {
            // Convert revenue from micros to dollars
            double revenue = adValue.valueMicros / 1_000_000.0;
            String? currency = adValue.currencyCode;

            // Validate revenue and currency before sending
            if (revenue > 0 && currency != null && currency.isNotEmpty) {
              final adData = {
                'adPlatform': 'AdMob',
                'currency': currency,
                'revenue': revenue,
              };

              // Send ad revenue data to Singular
              Singular.adRevenue(adData);

              // Log for debugging
              print('Ad Revenue reported: $revenue $currency');
            } else {
              print('Invalid ad revenue: revenue=$revenue, currency=$currency');
            }
          };
        },
        onAdFailedToLoad: (LoadAdError loadAdError) {
          print('Rewarded ad failed to load: ${loadAdError.message}');
        },
      ),
    );
  }

  void showRewardedAd() {
    if (_rewardedAd != null) {
      _rewardedAd!.show(
        onUserEarnedReward: (AdWithoutView ad, RewardItem reward) {
          print('User earned reward: ${reward.amount} ${reward.type}');
        },
      );
    } else {
      print('Rewarded ad not ready');
    }
  }
}

Exemplo de anúncio intersticial

Monitorize as receitas dos anúncios intersticiais utilizando o mesmo padrão onPaidEvent.

Dart
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:singular_flutter_sdk/singular.dart';

const String interstitialAdUnitId = 'YOUR_INTERSTITIAL_AD_UNIT_ID';

class InterstitialAdManager {
  InterstitialAd? _interstitialAd;

  void loadInterstitialAd() {
    InterstitialAd.load(
      adUnitId: interstitialAdUnitId,
      request: AdRequest(),
      adLoadCallback: InterstitialAdLoadCallback(
        onAdLoaded: (InterstitialAd ad) {
          _interstitialAd = ad;
          print('Interstitial ad loaded');

          // Set paid event callback
          _interstitialAd?.onPaidEvent = (AdValue adValue) {
            double revenue = adValue.valueMicros / 1_000_000.0;
            String? currency = adValue.currencyCode;

            if (revenue > 0 && currency != null && currency.isNotEmpty) {
              Singular.adRevenue({
                'adPlatform': 'AdMob',
                'currency': currency,
                'revenue': revenue,
              });
              
              print('Interstitial revenue: $revenue $currency');
            }
          };

          // Set full screen callback
          _interstitialAd?.fullScreenContentCallback = FullScreenContentCallback(
            onAdDismissedFullScreenContent: () {
              _interstitialAd = null;
              loadInterstitialAd(); // Load next ad
            },
          );
        },
        onAdFailedToLoad: (LoadAdError error) {
          print('Interstitial ad failed to load: ${error.message}');
        },
      ),
    );
  }

  void showInterstitialAd() {
    _interstitialAd?.show();
  }
}

Exemplo de anúncio de banner

Acompanhe a receita de anúncios de banner exibidos na interface do usuário do Flutter.

Dart
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:singular_flutter_sdk/singular.dart';

const String bannerAdUnitId = 'YOUR_BANNER_AD_UNIT_ID';

class BannerAdWidget extends StatefulWidget {
  @override
  _BannerAdWidgetState createState() => _BannerAdWidgetState();
}

class _BannerAdWidgetState extends State<BannerAdWidget> {
  BannerAd? _bannerAd;
  bool _isBannerAdReady = false;

  @override
  void initState() {
    super.initState();
    _loadBannerAd();
  }

  void _loadBannerAd() {
    _bannerAd = BannerAd(
      adUnitId: bannerAdUnitId,
      size: AdSize.banner,
      request: AdRequest(),
      listener: BannerAdListener(
        onAdLoaded: (Ad ad) {
          setState(() {
            _isBannerAdReady = true;
          });
          print('Banner ad loaded');

          // Set paid event callback
          (ad as BannerAd).onPaidEvent = (AdValue adValue) {
            double revenue = adValue.valueMicros / 1_000_000.0;
            String? currency = adValue.currencyCode;

            if (revenue > 0 && currency != null && currency.isNotEmpty) {
              Singular.adRevenue({
                'adPlatform': 'AdMob',
                'currency': currency,
                'revenue': revenue,
              });
              
              print('Banner revenue: $revenue $currency');
            }
          };
        },
        onAdFailedToLoad: (Ad ad, LoadAdError error) {
          ad.dispose();
          print('Banner ad failed to load: ${error.message}');
        },
      ),
    );

    _bannerAd?.load();
  }

  @override
  void dispose() {
    _bannerAd?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (_isBannerAdReady && _bannerAd != null) {
      return Container(
        alignment: Alignment.center,
        width: _bannerAd!.size.width.toDouble(),
        height: _bannerAd!.size.height.toDouble(),
        child: AdWidget(ad: _bannerAd!),
      );
    }
    return SizedBox.shrink();
  }
}

Integração do AppLovin MAX

Pré-requisitos

Implemente o plug-in AppLovin MAX Flutter e configure o rastreamento de receita no nível de impressão antes de integrar com o Singular.

  • Configuração MAX: Configure seu aplicativo no painel do AppLovin MAX
  • Plugin Flutter: Instalar o pacote applovin_max. Consulte o Guia de Introdução
  • API de receita: Ativar a API de receita do utilizador ao nível da impressão nas definições do painel MAX

Visão geral da implementação

Configure onAdRevenuePaidCallback listeners para cada formato de anúncio para capturar a receita quando as impressões geram ganhos.

  1. Inicializar o MAX: Configurar o AppLovin MAX SDK com a sua chave SDK
  2. Definir ouvintes: Adicionar onAdRevenuePaidCallback para cada formato de anúncio
  3. Extrair receita: Obter receita da propriedade ad.revenue
  4. Tratamento de moeda: O AppLovin normalmente reporta em USD, mas verifique com ad.currency
  5. Encaminhar para o Singular: Enviar dados validados para Singular.adRevenue()

Implementação completa do MAX

Capture a receita de todos os formatos de anúncio MAX (Rewarded, Interstitial, Banner, MREC) usando um manipulador unificado.

Dart
import 'package:flutter/material.dart';
import 'package:applovin_max/applovin_max.dart';
import 'package:singular_flutter_sdk/singular.dart';

class AppLovinMaxManager extends StatefulWidget {
  @override
  _AppLovinMaxManagerState createState() => _AppLovinMaxManagerState();
}

class _AppLovinMaxManagerState extends State<AppLovinMaxManager> {
  @override
  void initState() {
    super.initState();
    _initializeAppLovinMax();
  }

  Future<void> _initializeAppLovinMax() async {
    // Initialize AppLovin MAX SDK
    await AppLovinMAX.initialize('YOUR_SDK_KEY');

    // Set up revenue listeners for all ad formats
    _setupRewardedAdListeners();
    _setupInterstitialAdListeners();
    _setupBannerAdListeners();
    _setupMRecAdListeners();

    print('AppLovin MAX initialized with revenue tracking');
  }

  void _setupRewardedAdListeners() {
    AppLovinMAX.setRewardedAdListener(RewardedAdListener(
      onAdRevenuePaidCallback: (ad) {
        _handleAdRevenuePaid(ad, 'Rewarded');
      },
      onAdLoadedCallback: (ad) {
        print('Rewarded ad loaded');
      },
      onAdLoadFailedCallback: (adUnitId, error) {
        print('Rewarded ad failed to load: $error');
      },
    ));
  }

  void _setupInterstitialAdListeners() {
    AppLovinMAX.setInterstitialListener(InterstitialListener(
      onAdRevenuePaidCallback: (ad) {
        _handleAdRevenuePaid(ad, 'Interstitial');
      },
      onAdLoadedCallback: (ad) {
        print('Interstitial ad loaded');
      },
      onAdLoadFailedCallback: (adUnitId, error) {
        print('Interstitial ad failed to load: $error');
      },
    ));
  }

  void _setupBannerAdListeners() {
    AppLovinMAX.setBannerListener(AdViewAdListener(
      onAdRevenuePaidCallback: (ad) {
        _handleAdRevenuePaid(ad, 'Banner');
      },
      onAdLoadedCallback: (ad) {
        print('Banner ad loaded');
      },
      onAdLoadFailedCallback: (adUnitId, error) {
        print('Banner ad failed to load: $error');
      },
    ));
  }

  void _setupMRecAdListeners() {
    AppLovinMAX.setMRecListener(AdViewAdListener(
      onAdRevenuePaidCallback: (ad) {
        _handleAdRevenuePaid(ad, 'MREC');
      },
      onAdLoadedCallback: (ad) {
        print('MREC ad loaded');
      },
      onAdLoadFailedCallback: (adUnitId, error) {
        print('MREC ad failed to load: $error');
      },
    ));
  }

  void _handleAdRevenuePaid(Ad ad, String adType) {
    // Extract revenue and currency from ad object
    final double revenueValue = ad.revenue ?? 0.0;
    final String currency = ad.revenueCurrency ?? 'USD';

    // Validate revenue before sending
    if (revenueValue > 0) {
      final adData = {
        'adPlatform': 'AppLovin',
        'currency': currency,
        'revenue': revenueValue,
      };

      // Send ad revenue to Singular
      Singular.adRevenue(adData);

      // Log for debugging
      print('[$adType] Revenue: $revenueValue $currency');
    } else {
      print('[$adType] Invalid revenue: $revenueValue');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('AppLovin MAX Revenue Tracking'),
      ),
      body: Center(
        child: Text('MAX revenue tracking active'),
      ),
    );
  }
}

Melhores práticas: Configurar ouvintes de receitas de anúncios durante a inicialização da aplicação, antes de carregar quaisquer anúncios, para garantir que não se perdem impressões.


Integração do IronSource (Unity LevelPlay)

Pré-requisitos

Ative o Impression Level Revenue (ILR) no painel do IronSource e implemente o plug-in IronSource Flutter antes de integrar com o Singular.

  • Configuração do IronSource: Ativar o sinalizador ARM SDK Postbacks no painel do IronSource
  • Plugin Flutter: Instalar o pacote ironsource_mediation. Consulte o Guia de Introdução
  • API ILR: Configurar o rastreamento de receita no nível de impressão para seu aplicativo

Exemplo de implementação

Use o callback onImpressionDataSuccess para capturar dados de receita no nível de impressão da mediação IronSource.

Dart
import 'package:ironsource_mediation/ironsource_mediation.dart';
import 'package:singular_flutter_sdk/singular.dart';

void setupIronSourceRevenueTracking() {
  // Set up impression data listener
  IronSource.setImpressionDataListener((ISImpressionData? impressionData) {
    onImpressionDataSuccess(impressionData);
  });
}

void onImpressionDataSuccess(ISImpressionData? impressionData) {
  // Ensure impression data is not null
  if (impressionData == null) {
    print('No impression data available');
    return;
  }

  // Extract and validate revenue
  final revenue = impressionData.revenue?.toDouble() ?? 0.0;
  
  if (revenue <= 0) {
    print('Invalid revenue value: $revenue');
    return;
  }

  // Create ad revenue data for Singular
  final adData = {
    'adPlatform': 'IronSource',
    'currency': 'USD',
    'revenue': revenue,
  };

  // Send to Singular
  Singular.adRevenue(adData);

  // Log for debugging
  print('IronSource Revenue: $revenue USD');
}

Integração do TradPlus

Pré-requisitos

Configure o delegado de impressão do TradPlus para capturar dados eCPM quando os anúncios geram receita.

  • Configuração do TradPlus: Configure seu aplicativo no painel do TradPlus
  • Delegado de impressão: Ativar o rastreamento no nível de impressão nas configurações do TradPlus

Conversão de eCPM: O TradPlus normalmente reporta o eCPM em mili-unidades. Divida por 1000.0 para converter em dólares antes de enviar para a Singular.


Exemplo de implementação

Use o ouvinte de impressão global para capturar dados de receita de todos os formatos de anúncio do TradPlus.

Dart
import 'package:singular_flutter_sdk/singular.dart';

void setupTradPlusImpressionListener() {
  // Set up global impression listener
  TradPlusSdk.setGlobalImpressionListener((tpAdInfo) {
    if (tpAdInfo == null) {
      print('AdInfo is null');
      return;
    }

    // Ensure eCPM is available
    if (tpAdInfo.ecpm == null) {
      print('eCPM value is null');
      return;
    }

    // Convert eCPM from milli-units to dollars
    double revenue = tpAdInfo.ecpm! / 1000.0;

    // Validate revenue
    if (revenue <= 0) {
      print('Invalid revenue: $revenue');
      return;
    }

    // Create ad revenue data
    final adData = {
      'adPlatform': 'TradPlus',
      'currency': 'USD',
      'revenue': revenue,
    };

    // Send to Singular
    Singular.adRevenue(adData);

    // Log for debugging
    print('TradPlus Revenue: $revenue USD');
  });
}

void main() {
  // Initialize TradPlus SDK
  setupTradPlusImpressionListener();
  
  runApp(MyApp());
}

Integração genérica (outras plataformas)

Implementação personalizada

Para plataformas de mediação não explicitamente cobertas acima, implemente um gerenciador de receita personalizado usando o método de receita de anúncios da Singular.

Dart
import 'package:singular_flutter_sdk/singular.dart';

/// Generic function to report ad revenue to Singular
/// Use this for any mediation platform not explicitly supported above
void reportAdRevenue({
  required String adPlatform,
  required String currency,
  required double revenue,
}) {
  // Validate revenue value
  if (revenue <= 0) {
    print('Invalid revenue value: $revenue');
    return;
  }

  // Validate currency code
  if (currency.isEmpty) {
    print('Currency code is empty');
    return;
  }

  // Create ad revenue data
  final adData = {
    'adPlatform': adPlatform,
    'currency': currency,
    'revenue': revenue,
  };

  // Send to Singular
  Singular.adRevenue(adData);

  // Log for debugging
  print('Ad Revenue reported: $revenue $currency from $adPlatform');
}

// Example usage with a custom mediation platform
void onCustomAdImpression(Map<String, dynamic> impressionData) {
  reportAdRevenue(
    adPlatform: 'CustomNetwork',
    currency: impressionData['currency'] ?? 'USD',
    revenue: impressionData['revenue'] ?? 0.0,
  );
}

Melhores práticas e solução de problemas

Validação de dados

  • Sempre validar: verifique se a receita é maior que 0 e se a moeda não está vazia antes de enviar para o Singular
  • Conversão de unidades: Verifique se sua plataforma reporta em micros ou dólares e converta de acordo
  • Códigos de moeda: Utilize códigos de três letras ISO 4217 (USD, EUR, JPY) de forma consistente
  • Teste minucioso: Verificar se os dados de receita aparecem nos relatórios da Singular antes do lançamento em produção

Problemas comuns

  • Falta de receita: Certifique-se de que a receita no nível de impressão esteja ativada no painel da plataforma de mediação
  • Valores incorretos: Verifique a conversão de unidades (micros vs dólares) para sua plataforma específica
  • Ausência de dados nos relatórios: Aguarde de 24 a 48 horas para que os dados apareçam nos relatórios do Singular após a implementação
  • Receita nula: Verificar se os callbacks do anúncio estão corretamente definidos antes da conclusão do carregamento do anúncio

Importante: os dados de receita de anúncios não podem ser corrigidos após a transmissão. Valide sempre a exatidão dos dados antes de ligar para Singular.adRevenue().