배너 광고는 화면의 일부 영역에 표시되는 직사각형 광고입니다. AdropBannerView 위젯을 사용하여 손쉽게 구현할 수 있습니다.
주요 특징
- 화면 상단, 하단 또는 중간에 고정 배치 가능
- 이미지 및 동영상 광고 지원
- 콜백을 통한 광고 이벤트 처리
- 광고 메타데이터 제공 (크리에이티브 ID, 캠페인 ID 등)
개발 환경에서는 테스트 유닛 ID를 사용하세요: PUBLIC_TEST_UNIT_ID_320_100
AdropBannerView
생성자
AdropBannerView({
required String unitId,
AdropBannerListener? listener,
})
파라미터
| 파라미터 | 타입 | 필수 | 설명 |
|---|
unitId | String | Y | 애드컨트롤 콘솔에서 생성한 유닛 ID |
listener | AdropBannerListener | N | 광고 이벤트 리스너 |
| 속성 | 타입 | 설명 |
|---|
creativeSize | CreativeSize? | 광고 크리에이티브 크기 |
adSize | Size? | 배너 뷰의 크기 설정 |
메서드
| 메서드 | 반환 타입 | 설명 |
|---|
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']}');
}
| 필드 | 타입 | 설명 |
|---|
creativeId | String | 크리에이티브 ID |
txId | String | 트랜잭션 ID |
campaignId | String | 캠페인 ID |
destinationURL | String | 목적지 URL |
creativeSizeWidth | double | 크리에이티브 너비 |
creativeSizeHeight | double | 크리에이티브 높이 |
광고 크기
배너 광고는 유닛에 설정한 크기에 맞춰 컨테이너 크기를 지정해야 합니다.
일반적인 배너 크기
| 크기 | 테스트 유닛 ID | 용도 |
|---|
| 320 x 50 | PUBLIC_TEST_UNIT_ID_320_50 | 소형 배너 |
| 320 x 100 | PUBLIC_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('광고 영역')),
),
],
),
),
);
}
}
다음 단계