Exelbid SDK for Flutter
Flutter Plugin 가이드입니다.
목차
Version History
1.1.11
- mediation 초기화 수정
시작하기 전에
- Exelbid에서는 광고 요청에 대한 응답 후 노출까지의 시간(노출 캐시 시간)을 30분 이내로 권장합니다.(IAB 권장)
- 광고 응답 이후 노출 시간 차이가 해당 시간보다 길어지면 광고 캠페인에 따라서 노출이 무효 처리될 수 있습니다.
Plugin 정보
Flutter 3.32.5
SDK 정보
SDK 정보는 아래 링크를 참고해주세요.
시작하기
Flutter Plugin 추가하기
명령어를 이용한 설치
다음 명령어로 종속성 추가 및 설치하세요.
flutter pub add exelbid_plugin
수동으로 설치
pubspec.yaml
파일에 종속성 설정을 해주세요.
dependencies:
exelbid_plugin: any
종속성 설정 후 다음 명령어로 설치하세요.
flutter pub get
Android 설정
AndroidManifest 설정
필수 권한 설정
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
// 구글 정책(2022.03.15 발표)에 따라 대상 API 수준을 32(Android 13)로 업데이트하는 앱은 다음과 같이 매니페스트 파일에서 Google Play 서비스 일반 권한을 선언해야 합니다.(정책 적용 2022년 말 예정)
<uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
권장 권한 설정
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
Google Library 추가
ExelBid Android SDK가 제대로 작동하려면 Google Play Service 4.0 이상의 라이브러리가 필요합니다.
광고 식별자 수집에 대한 Google Play 콘텐츠 가이드라인을 준수하기 위한 것입니다.
1. AndroidManifest.xml파일에 태그 안에 아래 코드를 추가합니다.
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"
/>
2. Google Play Service jar를 dependencies에 추가합니다.
poject structure -> dependencies -> add -> library dependency 에서
com.google.android.gms:play-services
or com.google.android.gms:play-services-ads
를 추가합니다.
* eclipse를 사용하는 경우에는 Google Play Service 라이브러리 프로젝트를 추가합니다.
build.gradle
dependencies {
implementation("com.google.android.gms:play-services-ads-identifier:16.0.0")
}
iOS 설정
Info.plist 설정
광고 식별자 및 HTTP 트래픽 허용을 위한 권한을 설정합니다.
Exelbid에서는 광고 요청등의 Api에 https를 사용하지만 Exelbid에 연결된 많은 광고주 플랫폼사들의 광고 소재 리소스(image, js등)의 원할한 활용을 위해 http사용 허가 설정이 필요합니다.
- Flutter 프로젝트에서 ios/Runner/Info.plist 파일을 엽니다.
- 아래 내용을 추가하세요.
<key>NSUserTrackingUsageDescription</key>
<string>이 앱은 사용자 맞춤 광고를 제공하기 위해 광고 식별자를 사용합니다.</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
광고식별자 권한 요청
사용자로부터 개인정보 보호에 관한 권한을 요청해야 합니다.
앱 설치 후 한번만 요청되며, 사용자가 권한에 대해 응답 후 더 이상 사용자에게 권한 요청을 하지 않습니다.
광고식별자를 수집하지 못하는 경우 광고 요청에 대해 응답이 실패할 수 있습니다.
※ 광고를 호출하기 전에 완료되어야 합니다.
※ 앱이 실행될때 광고식별자 권한 요청을 권장합니다.
- Flutter 프로젝트에서 ios/Runner/AppDelegate.swift 파일을 엽니다.
- 아래 내용을 추가하세요.
import AppTrackingTransparency
...
@main
@objc class AppDelegate: FlutterAppDelegate {
...
override func applicationDidBecomeActive(_ application: UIApplication) {
super.applicationDidBecomeActive(application)
if #available(iOS 14.0, *) {
ATTrackingManager.requestTrackingAuthorization { _ in }
}
}
}
광고 적용하기
-
Exelbid 계정을 생성합니다.
-
Inventory -> App -> Create New App
-
Inventory -> Unit -> Create New Unit
인스턴스 공통 메소드
광고의 효율을 높이기 위해 나이, 성별을 설정하는 것이 좋습니다.
Key | Type | Default | Desc |
---|---|---|---|
adUnitId | String | 광고 아이디를 셋팅 합니다. | |
coppa | bool? | false | 선택사항으로 미국 아동 온라인 사생활 보호법에 따라 13세 미만의 사용자를 설정하면 개인 정보를 제한하여 광고 입찰 처리됩니다. (IP, Device ID, Geo 정보등) |
listener | EBPAdListener? | null | 콜백 이벤트 리스너. |
인스턴스 공통 스타일 클래스
EBViewStyle
EBViewStyle extends EBBaseStyle {
final Color? backgroundColor; // 배경색
final double? borderRadius; // 라운드
}
EBImageStyle
EBImageStyle extends EBBaseStyle {
const EBImageStyle({
super.backgroundColor, // 배경색
super.borderRadius, // 라운드
super.objectFit, // 스케일 설정 (fit, crop)
});
}
EBTextStyle
EBTextStyle extends EBBaseStyle {
const EBTextStyle({
super.color, // 폰트 색상
super.fontSize, // 폰트 크기
super.fontWeight, // 폰트 두께
});
}
EBTextStyle
EBButtonStyle extends EBBaseStyle {
const EBButtonStyle({
super.backgroundColor, // 배경색
super.borderRadius, // 라운드
super.color, // 폰트 색상
super.fontSize, // 폰트 크기
super.fontWeight, // 폰트 두께
});
}
배너 광고
배너 광고 인스턴스
Key | Type | Default | Desc |
---|---|---|---|
isFullWebView | bool? | true | 광고 안에 너비 100%로 웹뷰가 바인딩되게 설정. |
styles | EBViewStyle? | null | 배너 광고의 스타일 설정. |
EBBannerAdView {
final String adUnitId;
final bool? isFullWebView;
final bool? coppa;
final bool? isTest;
final EBViewStyle? styles;
}
예시)
EBBannerAdView(
adUnitId: "<<Ad Unit Id>>",
listener: EBPBannerAdViewListener(
onLoadAd: () {
print("Banner onLoadAd");
}, onFailAd: (String? errorMessage) {
print("Banner onFailAd");
}, onClickAd: () {
print("Banner onClickAd");
}
)
)
배너 광고 이벤트 리스너
EBPBannerAdViewListener {
/// 광고 요청 성공
final Function() onLoadAd;
/// 광고 요청 실패 (광고 없음)
final Function(String? errorMessage) onFailAd;
/// 광고 클릭
final Function()? onClickAd;
}
전면 광고
전면 광고 이벤트 리스너
EBPInterstitialAdViewListener {
/// 광고 요청 성공
final Function() onLoadAd;
/// 광고 요청 실패 (광고 없음)
final Function(String? errorMessage) onFailAd;
/// 광고 클릭
final Function()? onClickAd;
/// 전면 광고가 화면에 표시된 후에 전송됩니다.
final Function()? onInterstitialShow;
/// 전면 광고가 화면에서 해제 된 후 전송됩니다.
final Function()? onInterstitialDismiss;
}
전면 광고 콜백 리스너 설정
예시)
ExelbidPlugin.shared.setInterstitialListener(EBPInterstitialAdViewListener(
onLoadAd: () {
print("Interstitial onLoadAd");
}, onFailAd: (String? errorMessage) {
print("Interstitial onFailAd");
}, onClickAd: () {
print("Interstitial onClickAd");
}, onInterstitialShow: () {
print("onInterstitialShow");
}, onInterstitialDismiss: () {
print("onInterstitialDismiss");
})
);
전면 광고 요청
Future<void> loadInterstitial({
required String adUnitId,
bool? coppa,
bool? isTest
})
예시)
ExelbidPlugin.shared.loadInterstitial(adUnitId: "<<Ad Unit Id>>");
전면 광고 보기
전면 광고 초기화가 이루어진 후 광고 보기를 요청해야 합니다.
ExelbidPlugin.shared.showInterstitial();
네이티브 광고
네이티브 광고 인스턴스
Key | Type | Default | Desc |
---|---|---|---|
nativeAssets | EBNativeAssets? | null | 네이티브 광고 요청 시 필요한 항목들을 요청합니다. |
styles | EBViewStyle? | null | 네이티브 광고의 스타일 설정. |
EBNativeAdView {
final Widget child;
final String adUnitId;
final List<String>? nativeAssets;
final bool? coppa;
final bool? isTest;
final EBPNativeAdViewListener? listener;
};
네이티브 광고 속성
class EBNativeAssets {
// 제목
static const String title = "title";
// 아이콘 이미지
static const String icon = "icon";
// 메인 이미지
static const String main = "main";
// 설명
static const String desc = "desc";
// 클릭 버튼명 (유도문)
static const String ctatext = "ctatext";
}
예시)
EBNativeAdView(
adUnitId: "<<Ad Unit Id>>",
nativeAssets: const [
EBNativeAssets.title,
EBNativeAssets.main,
EBNativeAssets.icon,
EBNativeAssets.ctatext,
],
listener: EBPNativeAdViewListener(
onLoadAd: () {
print("Native onLoadAd");
}, onFailAd: (String? errorMessage) {
print("Native onFailAd");
}, onClickAd: () {
print("Native onClickAd");
}
)
child: "<<Native Ad View UI>>"
)
네이티브 광고 UI
네이티브 광고 뷰 설정 시 아래 내용을 참고하여
asset이 설정될 객체를 포함하여 구형하여야 합니다.
네이티브 제목
EBNativeAdTtitle {
EBTextStyle? styles;
}
네이티브 설명
EBNativeAdDescription {
EBTextStyle? styles;
}
네이티브 메인 이미지
EBNativeAdMainImage {
double? width;
double? height;
EBImageStyle? styles;
}
네이티브 아이콘 이미지
EBNativeAdIconImage{
double? width;
double? height;
EBImageStyle? styles;
}
네이티브 액션 버튼
EBNativeAdCallToAction {
EBButtonStyle? styles;
}
온라인 맞춤형 광고 개인정보보호 가이드라인 아이콘
EBNativeAdPrivacyInformationIconImage {
double? width;
double? height;
EBImageStyle? styles;
}
2017/07 방송통신위원회에서 시행되는 '온라인 맞춤형 광고 개인정보보호 가이드라인' 에 따라서 필수 적용 되어야 합니다.
광고주측에서 제공하는 해당 광고의 타입(맞춤형 광고 여부)에 따라 정보 표시 아이콘(Opt-out)의 노출이 결정됩니다.
※ 광고 정보 표시 아이콘이 노출될 ImageView의 사이즈는 NxN(권장 20x20)으로 설정 되어야 합니다.
예시)
EBNativeAdView(
adUnitId: "<<adUnitId>>",
nativeAssets: const [
EBNativeAssets.title,
EBNativeAssets.main,
EBNativeAssets.icon,
EBNativeAssets.ctatext,
],
styles: const EBViewStyle(
borderRadius: 20,
),
listener: EBPNativeAdViewListener(onLoadAd: () {
print("Native onLoadAd");
}, onFailAd: (String? errorMessage) {
print("Native onFailAd");
}, onClickAd: () {
print("Native onClickAd");
}),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(10),
child: // 상단 이미지 및 텍스트 영역
Row(children: [
SizedBox(
width: 48,
height: 48,
child: Center(
child: EBNativeAdIconImage(
styles: EBImageStyle(
backgroundColor: Colors.grey[300],
borderRadius: 20,
),
),
),
),
const SizedBox(width: 10),
Expanded(
child: SizedBox(
child: EBNativeAdTitle(
styles: const EBTextStyle(
fontWeight: FontWeight.bold,
),
),
),
),
]),
),
const SizedBox(height: 10),
// 메인 이미지 뷰
Expanded(
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: Stack(children: [
Center(
child: EBNativeAdMainImage(
styles: EBImageStyle(
backgroundColor: Colors.grey[300],
borderRadius: 10,
),
),
),
Positioned(
right: 10,
top: 10,
child:
EBNativeAdPrivacyInformationIconImage(
width: 20,
height: 20,
),
),
]),
),
),
const SizedBox(height: 10),
// 버튼 영역
Align(
alignment: Alignment.bottomRight,
child: Container(
padding: const EdgeInsets.only(
top: 10, bottom: 10, right: 10),
child: EBNativeAdCallToAction(
styles: const EBButtonStyle(
color: Colors.white,
backgroundColor: Colors.lightBlue,
borderRadius: 10,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
)
네이티브 광고 이벤트 리스너
EBPNativeAdViewListener {
/// 광고 요청 성공
final Function() onLoadAd;
/// 광고 요청 실패 (광고 없음)
final Function(String? errorMessage) onFailAd;
/// 광고 클릭
final Function()? onClickAd;
}
미디에이션
Exelbid Plugin을 이용한 Mediation 연동의 경우,
각 앱에서 연동하고 있는 광고 SDK들의 최적화 된 호출 순서를 응답한다.
미디에이션 네트워크
네트워크 | 미디에이션 타입 |
---|---|
Exelbid | EBMediationTypes.exelbid |
AdMob | EBMediationTypes.admob |
EBMediationTypes.facebook | |
AdFit | EBMediationTypes.adfit |
DigitalTurbine | EBMediationTypes.digitalturbine |
Pangel | EBMediationTypes.pangle |
TNK | EBMediationTypes.tnk |
AppLovin | EBMediationTypes.applovin |
MPartners | EBMediationTypes.mpartners |
미디에이션 설정 및 요청
미디에이션 인스턴스
EBMediationManager {
final String mediationUnitId;
final List<String> mediationTypes;
final EBPMediationListener listener;
}
미디에이션 인스턴스 초기화
_mediationManager = EBMediationManager(
mediationUnitId: "<<Mediation Unit ID>>",
mediationTypes: [
EBMediationTypes.exelbid,
// 사용할 미디에이션 네트워크 추가
],
listener: EBPMediationListener(
onLoad: () {
// loadMediation() 콜백 함수
// 미디에이션 목록 조회 성공 및 미디에이션 요청
_mediationManager.nextMediation();
},
onError: (EBError error) {
// 미디에이션 에러, 예외 처리 (광고 없음 처리)
},
onEmpty: () {
// 미디에이션 목록이 없거 순회를 완료했을 경우 (광고 없음 처리)
},
onNext: (EBMediation mediation) {
// nextMediation() 콜백 함수
// 사용할 미디에이션 네트워크 체크 후 광고 요청
if (mediation.networkId == EBMediationTypes.exelbid) {
// 전달받은 unitId로 networkId에 맞게 광고 요청
} else {
// 매칭되는 네트워크가 없으면 다음 미디에이션 요청
_mediationManager.nextMediation();
}
},
),
);
미디에이션 콜백 리스너
// 미디에이션 콜백 리스너
class EBPMediationListener {
// 미디에이션 목록 조회 성공
final Function() onLoad;
// 다음 순서 미디에이션 조회
final Function(EBMediation mediation) onNext;
// 미디에이션 목록이 없거 순회를 완료했을 경우 (광고 없음 처리)
final Function() onEmpty;
// 미디에이션 에러, 예외 처리 (광고 없음 처리)
final Function(EBError error) onError;
}
미디에이션 데이터
class EBMediation {
final String networkId;
final String unitId;
}
미디에이션 요청 및 목록 순회
// 미디에이션 목록 조회 (EBPMediationListener -> onLoad)
_mediationManager.loadMediation();
// 미디에이션 정보 조회 (EBPMediationListener -> onNext or onEmpty)
// onLoad 콜백 응답 후 요청해야 합니다.
_mediationManager.nextMediation();
유의 사항
- 타사 광고 요청 후 광고가 없거나 오류가 발생하면 미디에이션 다음 순서를 호출해주세요.
- 미디에이션 목록이 비어있다면 광고없음 처리를 해주세요.
- 광고가 노출될 때까지 전체 과정을 반복해서는 안됩니다.