프레임워크/Flutter
[flutter] Google AdMob Native Ads 적용하기-플랫폼별 설정(Android편)
연어바케트
2025. 1. 16. 20:48
반응형
- 네이티브 템플릿: Dart API로 스타일이 지정된 사전 정의된 네이티브 템플릿입니다.
- 플랫폼 설정: Android 및 iOS 레이아웃 도구를 사용하여 정의된 맞춤 플랫폼별 레이아웃입니다
1. settings.gradle 설정
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withInputStream { stream -> plugins.load(stream) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
2. native_ad.xml 설정
native에서 보여질 화면이 xml 형식으로 봐어 있어 이를 앱 디자인에 맞게 표현할 수 있도록 할 디자인을 설정한다.
아래 코드는 공식문서에서 제공하는 기본 코드이다.
android -> app -> src -> main -> res -> layout 에 아래 코드를 위치 시켰다.
<com.google.android.gms.ads.nativead.NativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#FFFFFF"
android:minHeight="50dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="3dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/ad_app_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:adjustViewBounds="true"
android:paddingBottom="5dp"
android:paddingEnd="5dp"
android:paddingRight="5dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/ad_headline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#0000FF"
android:textSize="16sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/ad_advertiser"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="bottom"
android:textSize="14sp"
android:textStyle="bold"/>
<RatingBar
android:id="@+id/ad_stars"
style="?android:attr/ratingBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:isIndicator="true"
android:numStars="5"
android:stepSize="0.5" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/ad_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:layout_marginEnd="20dp"
android:textSize="12sp" />
<com.google.android.gms.ads.nativead.MediaView
android:id="@+id/ad_media"
android:layout_gravity="center_horizontal"
android:layout_width="250dp"
android:layout_height="175dp"
android:layout_marginTop="5dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingTop="10dp">
<TextView
android:id="@+id/ad_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingStart="5dp"
android:paddingRight="5dp"
android:paddingEnd="5dp"
android:textSize="12sp" />
<TextView
android:id="@+id/ad_store"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingStart="5dp"
android:paddingRight="5dp"
android:paddingEnd="5dp"
android:textSize="12sp" />
<Button
android:id="@+id/ad_call_to_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
3. NativeAdFactory 구현
공식 문서 예제 코드를 바탕으로 코틀린으로 NativeAdFactory를 구현하였다.
NativeAdFactory.kt는 MainActivity.kt와 같은 패키지에 위치 시켰다.
class SawangNativeAdFactory(private val layoutInflater: LayoutInflater) : NativeAdFactory {
override fun createNativeAd(nativeAd: NativeAd, customOptions: Map<String, Any>?): NativeAdView {
val adView = layoutInflater.inflate(R.layout.native_ad_layout, null) as NativeAdView
//XML레이아웃에서 정의한 각UI요소를 adView에 연결
adView.mediaView = adView.findViewById(R.id.ad_media)
adView.headlineView = adView.findViewById(R.id.ad_headline)
adView.bodyView = adView.findViewById(R.id.ad_body)
adView.callToActionView = adView.findViewById(R.id.ad_call_to_action)
adView.iconView = adView.findViewById(R.id.ad_app_icon)
adView.priceView = adView.findViewById(R.id.ad_price)
adView.starRatingView = adView.findViewById(R.id.ad_stars)
adView.storeView = adView.findViewById(R.id.ad_store)
adView.advertiserView = adView.findViewById(R.id.ad_advertiser)
//광고 데이터를 연결된 UI요소에 설정
(adView.headlineView as TextView).text = nativeAd.headline
adView.mediaView?.mediaContent = nativeAd.mediaContent
if (nativeAd.body == null) {
adView.bodyView?.visibility = View.INVISIBLE
} else {
adView.bodyView?.visibility = View.VISIBLE
(adView.bodyView as TextView).text = nativeAd.body
}
if (nativeAd.callToAction == null) {
adView.callToActionView?.visibility = View.INVISIBLE
} else {
adView.callToActionView?.visibility = View.VISIBLE
(adView.callToActionView as Button).text = nativeAd.callToAction
}
if (nativeAd.icon == null) {
adView.iconView?.visibility = View.GONE
} else {
(adView.iconView as ImageView).setImageDrawable(nativeAd.icon?.drawable)
adView.iconView?.visibility = View.VISIBLE
}
if (nativeAd.price == null) {
adView.priceView?.visibility = View.INVISIBLE
} else {
adView.priceView?.visibility = View.VISIBLE
(adView.priceView as TextView).text = nativeAd.price
}
if (nativeAd.store == null) {
adView.storeView?.visibility = View.INVISIBLE
} else {
adView.storeView?.visibility = View.VISIBLE
(adView.storeView as TextView).text = nativeAd.store
}
if (nativeAd.starRating == null) {
adView.starRatingView?.visibility = View.INVISIBLE
} else {
(adView.starRatingView as RatingBar).rating = nativeAd.starRating?.toFloat() ?: 0f
adView.starRatingView?.visibility = View.VISIBLE
}
if (nativeAd.advertiser == null) {
adView.advertiserView?.visibility = View.INVISIBLE
} else {
adView.advertiserView?.visibility = View.VISIBLE
(adView.advertiserView as TextView).text = nativeAd.advertiser
}
//adView에 nativeAd 연결
adView.setNativeAd(nativeAd)
return adView
}
}
4. NativeAdFactory 등록
이제 Main Activity에 NativeAdFactory를 호출 할 수 있는 factoryId를 등록해야한다. 등록되어야 Flutter 코드에서 factoryId로 인스터스화하여 사용할 수 있다. String 식별자를 사용하여 등록하면 된다. 아래는 코틀린 코드로 제작되었다.
class MainActivity : FlutterFragmentActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GoogleMobileAdsPlugin.registerNativeAdFactory(
flutterEngine,
"NativeAdFactory",
NativeAdFactory(layoutInflater)
)
}
override fun cleanUpFlutterEngine(flutterEngine: FlutterEngine) {
super.cleanUpFlutterEngine(flutterEngine)
GoogleMobileAdsPlugin.unregisterNativeAdFactory(flutterEngine, "NativeAdFactory")
}
}
5. AdMobController
필자는 Getx를 사용하고 있어 Getx 형식으로 AdmobController을 만들어 주었다.
class AdMobController extends GetxController {
NativeAd? nativeAd;
bool isAdLoaded = false;
@override
void onInit() {
super.onInit();
loadNativeAd();
}
void loadNativeAd() {
nativeAd = NativeAd(
adUnitId: 'ca-app-pub-3940256099942544/2247696110',
factoryId: 'sawangNativeAdFactory',
listener: NativeAdListener(
onAdLoaded: (ad) {
isAdLoaded = true;
},
onAdFailedToLoad: (ad, error) {
ad.dispose();
if (kDebugMode) {
print(error);
}
},
),
request: AdRequest(),
)..load();
}
@override
void onClose() {
nativeAd?.dispose();
super.onClose();
}
}
6. AdWidget
AdMobController을 호출하여 광고를 띄워줄 위젯을 아래와 같이 만들었다.
class AdmobNativeWidget extends GetWidget<AdMobController> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: controller.isAdLoaded
? SizedBox(
width: 500,
height: 500,
child: AdWidget(ad: controller.nativeAd!),
)
: Container(),
);
}
}
6. 결과화면
무척 잘 나오는것을 볼 수 있다.
이제 XML을 수정해서 앱 디자인에 맞게 수정을 진행하면 끝!
반응형