메인 콘텐츠로 건너뛰기

개요

배너 광고는 화면의 일부 영역에 표시되는 직사각형 광고입니다. AdropBannerView 위젯을 사용하여 손쉽게 구현할 수 있습니다.

주요 특징

  • 화면 상단, 하단 또는 중간에 고정 배치 가능
  • 이미지 및 동영상 광고 지원
  • 콜백을 통한 광고 이벤트 처리
  • 광고 메타데이터 제공 (크리에이티브 ID, 캠페인 ID 등)
개발 환경에서는 테스트 유닛 ID를 사용하세요: PUBLIC_TEST_UNIT_ID_320_100

AdropBannerView

생성자

AdropBannerView({
  required String unitId,
  AdropBannerListener? listener,
})
파라미터
파라미터타입필수설명
unitIdStringY애드컨트롤 콘솔에서 생성한 유닛 ID
listenerAdropBannerListenerN광고 이벤트 리스너

속성

속성타입설명
creativeSizeCreativeSize?광고 크리에이티브 크기
adSizeSize?배너 뷰의 크기 설정

메서드

메서드반환 타입설명
load()Future<void>광고를 로드합니다
dispose()Future<void>리소스를 해제합니다

기본 사용법

import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';

class BannerExample extends StatefulWidget {
  const BannerExample({super.key});

  @override
  State<BannerExample> createState() => _BannerExampleState();
}

class _BannerExampleState extends State<BannerExample> {
  bool isLoaded = false;
  late AdropBannerView bannerView;

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

    bannerView = AdropBannerView(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (unitId, metadata) {
          debugPrint('배너 광고 수신 성공: $unitId');
          setState(() {
            isLoaded = true;
          });
        },
        onAdClicked: (unitId, metadata) {
          debugPrint('배너 광고 클릭: $unitId');
        },
        onAdImpression: (unitId, metadata) {
          debugPrint('배너 광고 노출: $unitId');
        },
        onAdFailedToReceive: (unitId, errorCode) {
          debugPrint('배너 광고 수신 실패: $unitId, $errorCode');
          setState(() {
            isLoaded = false;
          });
        },
      ),
    );

    // 광고 로드
    bannerView.load();
  }

  @override
  void dispose() {
    bannerView.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('배너 광고 예제')),
      body: Column(
        children: [
          // 메인 콘텐츠
          Expanded(
            child: Center(
              child: const Text('메인 콘텐츠'),
            ),
          ),
          // 배너 광고
          if (isLoaded)
            SizedBox(
              width: MediaQuery.of(context).size.width,
              height: 80,
              child: bannerView,
            ),
        ],
      ),
    );
  }
}

AdropBannerListener

배너 광고 이벤트를 처리하는 리스너입니다.

콜백 함수

AdropBannerListener(
  onAdReceived: (String unitId, Map<String, dynamic>? metadata) {
    // 광고 수신 성공
  },
  onAdClicked: (String unitId, Map<String, dynamic>? metadata) {
    // 광고 클릭
  },
  onAdImpression: (String unitId, Map<String, dynamic>? metadata) {
    // 광고 노출
  },
  onAdFailedToReceive: (String unitId, AdropErrorCode errorCode) {
    // 광고 수신 실패
  },
)

콜백 설명

콜백설명
onAdReceived광고 수신 성공 시 호출
onAdClicked광고 클릭 시 호출
onAdImpression광고 노출 시 호출
onAdFailedToReceive광고 수신 실패 시 호출

메타데이터

onAdReceived, onAdClicked, onAdImpression 콜백에서 메타데이터를 받을 수 있습니다.
onAdReceived: (unitId, metadata) {
  debugPrint('크리에이티브 ID: ${metadata?['creativeId']}');
  debugPrint('트랜잭션 ID: ${metadata?['txId']}');
  debugPrint('캠페인 ID: ${metadata?['campaignId']}');
  debugPrint('목적지 URL: ${metadata?['destinationURL']}');
  debugPrint('크리에이티브 너비: ${metadata?['creativeSizeWidth']}');
  debugPrint('크리에이티브 높이: ${metadata?['creativeSizeHeight']}');
}
필드타입설명
creativeIdString크리에이티브 ID
txIdString트랜잭션 ID
campaignIdString캠페인 ID
destinationURLString목적지 URL
creativeSizeWidthdouble크리에이티브 너비
creativeSizeHeightdouble크리에이티브 높이

광고 크기

배너 광고는 유닛에 설정한 크기에 맞춰 컨테이너 크기를 지정해야 합니다.

일반적인 배너 크기

크기테스트 유닛 ID용도
320 x 50PUBLIC_TEST_UNIT_ID_320_50소형 배너
320 x 100PUBLIC_TEST_UNIT_ID_320_100중형 배너

고정 크기 사용

SizedBox(
  width: 320,
  height: 100,
  child: bannerView,
)

화면 너비에 맞추기

SizedBox(
  width: MediaQuery.of(context).size.width,
  height: 80,
  child: bannerView,
)

크기 설정

adSize 속성을 사용하여 배너 뷰의 크기를 명시적으로 설정할 수 있습니다.
@override
void initState() {
  super.initState();

  bannerView = AdropBannerView(
    unitId: 'YOUR_UNIT_ID',
    listener: AdropBannerListener(
      onAdReceived: (unitId, metadata) {
        setState(() {
          isLoaded = true;
        });
      },
    ),
  );

  // 컨텍스트가 준비된 후 크기 설정
  WidgetsBinding.instance.addPostFrameCallback((_) {
    bannerView.adSize = Size(
      MediaQuery.of(context).size.width,
      80,
    );
  });
}

에러 처리

광고 로드 실패 시 적절한 에러 처리를 구현하세요.
class _BannerExampleState extends State<BannerExample> {
  bool isLoaded = false;
  AdropErrorCode? errorCode;
  late AdropBannerView bannerView;

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

    bannerView = AdropBannerView(
      unitId: 'YOUR_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (unitId, metadata) {
          setState(() {
            isLoaded = true;
            errorCode = null;
          });
        },
        onAdFailedToReceive: (unitId, error) {
          setState(() {
            isLoaded = false;
            errorCode = error;
          });
        },
      ),
    );

    bannerView.load();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        if (isLoaded)
          SizedBox(
            width: MediaQuery.of(context).size.width,
            height: 80,
            child: bannerView,
          )
        else if (errorCode != null)
          Text('광고 로드 실패: ${errorCode?.code}'),
      ],
    );
  }

  @override
  void dispose() {
    bannerView.dispose();
    super.dispose();
  }
}

베스트 프랙티스

1. 리소스 해제

배너 뷰가 더 이상 필요하지 않을 때 반드시 dispose()를 호출하세요.
@override
void dispose() {
  bannerView.dispose();
  super.dispose();
}

2. 광고 새로고침

필요에 따라 광고를 새로고침할 수 있습니다.
void refreshAd() {
  setState(() {
    isLoaded = false;
  });
  bannerView.load();
}

3. 조건부 렌더링

광고가 로드될 때까지 배너 영역을 숨기거나 플레이스홀더를 표시하세요.
Widget buildBanner() {
  if (isLoaded) {
    return SizedBox(
      width: MediaQuery.of(context).size.width,
      height: 80,
      child: bannerView,
    );
  } else if (isLoading) {
    return const SizedBox(
      height: 80,
      child: Center(child: CircularProgressIndicator()),
    );
  } else {
    return const SizedBox.shrink();
  }
}

4. 여러 배너 관리

여러 배너를 사용할 때는 각각의 상태를 관리하세요.
class _MultiBannerState extends State<MultiBanner> {
  late AdropBannerView topBanner;
  late AdropBannerView bottomBanner;
  bool isTopLoaded = false;
  bool isBottomLoaded = false;

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

    topBanner = AdropBannerView(
      unitId: 'TOP_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (_, __) => setState(() => isTopLoaded = true),
      ),
    );

    bottomBanner = AdropBannerView(
      unitId: 'BOTTOM_UNIT_ID',
      listener: AdropBannerListener(
        onAdReceived: (_, __) => setState(() => isBottomLoaded = true),
      ),
    );

    topBanner.load();
    bottomBanner.load();
  }

  @override
  void dispose() {
    topBanner.dispose();
    bottomBanner.dispose();
    super.dispose();
  }

  // ...
}

전체 예제

import 'package:flutter/material.dart';
import 'package:adrop_ads_flutter/adrop_ads_flutter.dart';

class BannerAdPage extends StatefulWidget {
  const BannerAdPage({super.key});

  @override
  State<BannerAdPage> createState() => _BannerAdPageState();
}

class _BannerAdPageState extends State<BannerAdPage> {
  static const double bannerHeight = 80;
  bool isLoaded = false;
  bool isLoading = false;
  AdropErrorCode? errorCode;
  late AdropBannerView bannerView;

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

    bannerView = AdropBannerView(
      unitId: 'PUBLIC_TEST_UNIT_ID_320_100', // 테스트 유닛 ID
      listener: AdropBannerListener(
        onAdReceived: (unitId, metadata) {
          debugPrint('광고 수신 성공');
          debugPrint('크리에이티브 ID: ${metadata?['creativeId']}');
          debugPrint('캠페인 ID: ${metadata?['campaignId']}');
          debugPrint('크리에이티브 크기: ${bannerView.creativeSize?.width}x${bannerView.creativeSize?.height}');
          setState(() {
            isLoaded = true;
            isLoading = false;
            errorCode = null;
          });
        },
        onAdClicked: (unitId, metadata) {
          debugPrint('광고 클릭: ${metadata?['destinationURL']}');
        },
        onAdImpression: (unitId, metadata) {
          debugPrint('광고 노출: ${metadata?['creativeId']}');
        },
        onAdFailedToReceive: (unitId, error) {
          debugPrint('광고 수신 실패: $error');
          setState(() {
            isLoaded = false;
            isLoading = false;
            errorCode = error;
          });
        },
      ),
    );

    WidgetsBinding.instance.addPostFrameCallback((_) {
      bannerView.adSize = Size(
        MediaQuery.of(context).size.width,
        bannerHeight,
      );
    });
  }

  void loadAd() {
    setState(() {
      isLoading = true;
      errorCode = null;
    });
    bannerView.load();
  }

  @override
  void dispose() {
    bannerView.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('배너 광고 예제'),
      ),
      body: SafeArea(
        child: Column(
          children: [
            // 로드 버튼
            Padding(
              padding: const EdgeInsets.all(16),
              child: ElevatedButton(
                onPressed: isLoading ? null : loadAd,
                child: Text(isLoading ? '로딩 중...' : '배너 광고 로드'),
              ),
            ),

            // 상태 표시
            if (errorCode != null)
              Padding(
                padding: const EdgeInsets.all(16),
                child: Text(
                  '에러: ${errorCode?.code}',
                  style: const TextStyle(color: Colors.red),
                ),
              ),

            // 메인 콘텐츠
            const Expanded(
              child: Center(
                child: Text('메인 콘텐츠 영역'),
              ),
            ),

            // 배너 광고
            Container(
              width: MediaQuery.of(context).size.width,
              height: bannerHeight,
              color: Colors.grey[200],
              child: isLoaded
                  ? bannerView
                  : isLoading
                      ? const Center(child: CircularProgressIndicator())
                      : const Center(child: Text('광고 영역')),
            ),
          ],
        ),
      ),
    );
  }
}

다음 단계