네이티브 고급 광고

플랫폼 선택: Android iOS

네이티브 광고가 로드되면 Google 모바일 광고 SDK가 해당 광고 형식의 리스너를 실행합니다. 그러면 앱이 광고를 표시합니다(즉시 표시하지 않을 수 있음). 시스템에 정의된 광고 형식을 보다 쉽게 표시할 수 있도록 아래와 같은 유용한 리소스를 SDK에서 제공합니다.

NativeAdView 클래스 정의

NativeAdView 클래스를 정의하세요. 이 클래스는 ViewGroup 클래스이며 NativeAdView 클래스의 최상위 컨테이너입니다. 각 네이티브 광고 뷰에는 MediaView 뷰 요소 또는 Title 뷰 요소와 같은 네이티브 광고 확장 소재가 포함되며, 이는 NativeAdView 객체의 하위 요소여야 합니다.

XML 레이아웃

프로젝트에 XML NativeAdView를 추가합니다.

<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
    android:orientation="vertical">
        <LinearLayout
        android:orientation="horizontal">
          <ImageView
          android:id="@+id/ad_app_icon" />
          <TextView
            android:id="@+id/ad_headline" />
        </LinearLayout>
        <!--Add remaining assets such as the image and media view.-->
    </LinearLayout>
</com.google.android.gms.ads.nativead.NativeAdView>

Jetpack Compose

NativeAdView 및 확장 소재를 구성하는 도우미가 포함된 JetpackComposeDemo/compose-util 모듈을 포함합니다.

compose-util 모듈을 사용하여 NativeAdView를 구성합니다.

  import com.google.android.gms.compose_util.NativeAdAttribution
  import com.google.android.gms.compose_util.NativeAdView

  @Composable
  /** Display a native ad with a user defined template. */
  fun DisplayNativeAdView(nativeAd: NativeAd) {
      NativeAdView {
          // Display the ad attribution.
          NativeAdAttribution(text = context.getString("Ad"))
          // Add remaining assets such as the image and media view.
        }
    }

로드된 네이티브 광고 처리

네이티브 광고가 로드되면 콜백 이벤트를 처리하고 네이티브 광고 뷰를 확장하고 이 뷰를 뷰 계층 구조에 추가합니다.

Java

AdLoader.Builder builder = new AdLoader.Builder(this, "ca-app-pub-3940256099942544/2247696110")
    .forNativeAd(new NativeAd.OnNativeAdLoadedListener() {
        @Override
        public void onNativeAdLoaded(NativeAd nativeAd) {
            // Assumes you have a placeholder FrameLayout in your View layout
            // (with ID fl_adplaceholder) where the ad is to be placed.
            FrameLayout frameLayout =
                findViewById(R.id.fl_adplaceholder);
            // Assumes that your ad layout is in a file call native_ad_layout.xml
            // in the res/layout folder
            NativeAdView adView = (NativeAdView) getLayoutInflater()
                .inflate(R.layout.native_ad_layout, null);
            // This method sets the assets into the ad view.
            displayNativeAd(nativeAd, adView);
            frameLayout.removeAllViews();
            frameLayout.addView(adView);
        }
});

Kotlin

val builder = AdLoader.Builder(this, "ca-app-pub-3940256099942544/2247696110")
    .forNativeAd { nativeAd ->
        // Assumes you have a placeholder FrameLayout in your View layout
        // (with ID fl_adplaceholder) where the ad is to be placed.
        val frameLayout: FrameLayout = findViewById(R.id.fl_adplaceholder)
        // Assumes that your ad layout is in a file call native_ad_layout.xml
        // in the res/layout folder
        val adView = layoutInflater
                .inflate(R.layout.native_ad_layout, null) as NativeAdView
        // This method sets the assets into the ad view.
        displayNativeAd(nativeAd, adView)
        frameLayout.removeAllViews()
        frameLayout.addView(adView)
    }

Jetpack Compose

@Composable
/** Load and display a native ad. */
fun NativeScreen() {
  var nativeAd by remember { mutableStateOf<NativeAd?>(null) }
  val context = LocalContext.current
  var isDisposed by remember { mutableStateOf(false) }

  DisposableEffect(Unit) {
    // Load the native ad when we launch this screen
    loadNativeAd(
      context = context,
      onAdLoaded = { ad ->
        // Handle the native ad being loaded.
        if (!isDisposed) {
          nativeAd = ad
        } else {
          // Destroy the native ad if loaded after the screen is disposed.
          ad.destroy()
        }
      },
    )
    // Destroy the native ad to prevent memory leaks when we dispose of this screen.
    onDispose {
      isDisposed = true
      nativeAd?.destroy()
      nativeAd = null
    }
  }

  // Display the native ad view with a user defined template.
  nativeAd?.let { adValue -> DisplayNativeAdView(adValue) }
}

fun loadNativeAd(context: Context, onAdLoaded: (NativeAd) -> Unit) {
  val adLoader =
    AdLoader.Builder(context, NATIVE_AD_UNIT_ID)
      .forNativeAd { nativeAd -> onAdLoaded(nativeAd) }
      .withAdListener(
        object : AdListener() {
          override fun onAdFailedToLoad(error: LoadAdError) {
            Log.e(TAG, "Native ad failed to load: ${error.message}")
          }

          override fun onAdLoaded() {
            Log.d(TAG, "Native ad was loaded.")
          }

          override fun onAdImpression() {
            Log.d(TAG, "Native ad recorded an impression.")
          }

          override fun onAdClicked() {
            Log.d(TAG, "Native ad was clicked.")
          }
        }
      )
      .build()
  adLoader.loadAd(AdRequest.Builder().build())
}

네이티브 광고의 모든 확장 소재는 NativeAdView 레이아웃 내에서 렌더링해야 합니다. 네이티브 확장 소재가 네이티브 광고 뷰 레이아웃 외부에 렌더링되면 Google 모바일 광고 SDK가 경고를 로그하려고 시도합니다.

광고 뷰 클래스에서도 개별 확장 소재에 사용되는 뷰를 등록하는 메서드 여러 개와 NativeAd 객체 자체를 등록하는 메서드 1개를 제공합니다. 이 방법으로 뷰를 등록하면 다음과 같은 작업을 SDK가 자동으로 처리할 수 있습니다.

  • 클릭수 기록
  • 첫 픽셀이 화면에 표시되는 시점에 노출 기록
  • AdChoices 오버레이 표시

네이티브 광고 표시

다음 예에서는 네이티브 광고를 표시하는 방법을 보여줍니다.

Java

private void displayNativeAd(ViewGroup parent, NativeAd ad) {

  // Inflate a layout and add it to the parent ViewGroup.
  LayoutInflater inflater = (LayoutInflater) parent.getContext()
          .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  NativeAdView adView = (NativeAdView) inflater
          .inflate(R.layout.ad_layout_file, parent);

  // Locate the view that will hold the headline, set its text, and call the
  // NativeAdView's setHeadlineView method to register it.
  TextView headlineView = adView.findViewById<TextView>(R.id.ad_headline);
  headlineView.setText(ad.getHeadline());
  adView.setHeadlineView(headlineView);

  // Repeat the process for the other assets in the NativeAd
  // using additional view objects (Buttons, ImageViews, etc).

  // If you use a MediaView, call theNativeAdView.setMediaView() method
  // before calling the NativeAdView.setNativeAd() method.
  MediaView mediaView = (MediaView) adView.findViewById(R.id.ad_media);
  adView.setMediaView(mediaView);

  // Register the native ad with its ad view.
  adView.setNativeAd(ad);

  // Ensure that the parent view doesn't already contain an ad view.
  parent.removeAllViews();

  // Place the AdView into the parent.
  parent.addView(adView);
}

Kotlin

fun displayNativeAd(parent: ViewGroup, ad: NativeAd) {

  // Inflate a layout and add it to the parent ViewGroup.
  val inflater = parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)
          as LayoutInflater
  val adView = inflater.inflate(R.layout.ad_layout_file, parent) as NativeAdView

  // Locate the view that will hold the headline, set its text, and use the
  // NativeAdView's headlineView property to register it.
  val headlineView = adView.findViewById<TextView>(R.id.ad_headline)
  headlineView.text = ad.headline
  adView.headlineView = headlineView

  // Repeat the process for the other assets in the NativeAd using
  // additional view objects (Buttons, ImageViews, etc).

  val mediaView = adView.findViewById<MediaView>(R.id.ad_media)
  adView.mediaView = mediaView

  // Call the NativeAdView's setNativeAd method to register the
  // NativeAdObject.
  adView.setNativeAd(ad)

  // Ensure that the parent view doesn't already contain an ad view.
  parent.removeAllViews()

  // Place the AdView into the parent.
  parent.addView(adView)
}

Jetpack Compose

@Composable
/** Display a native ad with a user defined template. */
fun DisplayNativeAdView(nativeAd: NativeAd) {
  val context = LocalContext.current
  Box(modifier = Modifier.padding(8.dp).wrapContentHeight(Alignment.Top)) {
    // Call the NativeAdView composable to display the native ad.
    NativeAdView(nativeAd) {
      // Inside the NativeAdView composable, display the native ad assets.
      Column(Modifier.align(Alignment.TopStart).wrapContentHeight(Alignment.Top)) {
        // Display the ad attribution.
        NativeAdAttribution(text = context.getString(R.string.attribution))
        Row {
          // If available, display the icon asset.
          nativeAd.icon?.let { icon ->
            NativeAdIconView(Modifier.padding(5.dp)) {
              icon.drawable?.toBitmap()?.let { bitmap ->
                Image(bitmap = bitmap.asImageBitmap(), "Icon")
              }
            }
          }
          Column {
            // If available, display the headline asset.
            nativeAd.headline?.let {
              NativeAdHeadlineView {
                Text(text = it, style = MaterialTheme.typography.headlineLarge)
              }
            }
            // If available, display the star rating asset.
            nativeAd.starRating?.let {
              NativeAdStarRatingView {
                Text(text = "Rated $it", style = MaterialTheme.typography.labelMedium)
              }
            }
          }
        }

        // If available, display the body asset.
        nativeAd.body?.let { NativeAdBodyView { Text(text = it) } }
        // Display the media asset.
        NativeAdMediaView(Modifier.fillMaxWidth().height(500.dp).fillMaxHeight())

        Row(Modifier.align(Alignment.End).padding(5.dp)) {
          // If available, display the price asset.
          nativeAd.price?.let {
            NativeAdPriceView(Modifier.padding(5.dp).align(Alignment.CenterVertically)) {
              Text(text = it)
            }
          }
          // If available, display the store asset.
          nativeAd.store?.let {
            NativeAdStoreView(Modifier.padding(5.dp).align(Alignment.CenterVertically)) {
              Text(text = it)
            }
          }
          // If available, display the call to action asset.
          // Note: The Jetpack Compose button implements a click handler which overrides the native
          // ad click handler, causing issues. Use the NativeAdButton which does not implement a
          // click handler. To handle native ad clicks, use the NativeAd AdListener onAdClicked
          // callback.
          nativeAd.callToAction?.let { callToAction ->
            NativeAdCallToActionView(Modifier.padding(5.dp)) { NativeAdButton(text = callToAction) }
          }
        }
      }
    }
  }
}

AdChoices 오버레이

SDK가 각 광고 뷰에 AdChoices 오버레이를 추가합니다. 네이티브 광고 뷰에서 원하는 모서리 부분에 AdChoices 로고가 자동으로 삽입될 공간을 남겨두세요. 또한 AdChoices 오버레이가 눈에 잘 띄도록 배경색과 이미지를 적절히 선택하세요. 오버레이의 모양과 기능에 대해 자세히 알아보려면 네이티브 광고 필드에 대한 설명을 참고하세요.

광고 표시

뷰가 광고임을 나타내는 광고 표시를 사용해야 합니다. 정책 가이드 라인에서 자세히 알아보세요.

클릭 처리

네이티브 광고 뷰의 위 또는 안에 맞춤 클릭 핸들러를 구현하지 마세요. 올바르게 애셋 뷰를 적용하고 등록하면 SDK가 광고 뷰 애셋의 클릭을 처리합니다.

클릭을 수신 대기하려면 Google 모바일 광고 SDK 클릭 콜백을 구현하세요.

Java

AdLoader adLoader = new AdLoader.Builder(context, "ca-app-pub-3940256099942544/2247696110")
    // ...
    .withAdListener(new AdListener() {
        @Override
        public void onAdFailedToLoad(LoadAdError adError) {
            // Handle the failure by logging.
        }
        @Override
        public void onAdClicked() {
            // Log the click event or other custom behavior.
        }
    })
    .build();

Kotlin

val adLoader = AdLoader.Builder(this, "ca-app-pub-3940256099942544/2247696110")
    // ...
    .withAdListener(object : AdListener() {
        override fun onAdFailedToLoad(adError: LoadAdError) {
            // Handle the failure.
        }
        override fun onAdClicked() {
            // Log the click event or other custom behavior.
        }
    })
    .build()

ImageScaleType

이미지를 표시할 때 MediaView 클래스에는 ImageScaleType 속성이 있습니다. MediaView에서 이미지의 크기가 조정되는 방식을 변경하려면 MediaViewsetImageScaleType() 메서드를 사용하여 해당하는 ImageView.ScaleType을 설정하세요.

Java

mediaView.setImageScaleType(ImageView.ScaleType.CENTER_CROP);

Kotlin

mediaView.imageScaleType = ImageView.ScaleType.CENTER_CROP

MediaContent

MediaContent 클래스에는 MediaView 클래스를 사용하여 표시되는 네이티브 광고의 미디어 콘텐츠와 관련된 데이터가 포함됩니다. MediaView mediaContent 속성이 MediaContent 인스턴스와 함께 설정된 경우:

  • 사용할 수 있는 동영상 애셋은 버퍼링 후 MediaView 안에서 재생되기 시작합니다. hasVideoContent()를 확인하면 동영상 애셋을 사용할 수 있는지 알 수 있습니다.

  • 광고에 동영상 애셋이 없으면 mainImage 애셋이 대신 다운로드되어 MediaView에 배치됩니다.

광고 소멸시키기

네이티브 광고를 표시한 후 소멸시킵니다. 다음 예를 참고하세요.

Java

nativeAd.destroy();

Kotlin

nativeAd.destroy()

GitHub의 예

완전한 네이티브 광고 구현의 예는 다음과 같습니다.

Java Kotlin JetpackCompose

다음 단계

다음 주제를 살펴보세요.