AI.

안드로이드 앱 구글 Admob Native in-feed 광고 넣기

From.h 2025. 12. 31. 00:24
728x90
반응형
SMALL

 

 

안드로이드 구글 Admob Native in-feed 광고 넣기

- 본 앱 경우 하단 슬롯에 광고를 넣고자 함.

- 슬롯을 클릭하면 카드 페이지 모달 발생(실제 광고)

- 현재 PWA로 만들어진 상태 (ai studio)

 

 

 

 

 

 

 

 

1. 애드몹 가입 계정생성

- 계정을 만들고, 지불방식(payment 설정 까지 마치면 활성화됨)

https://admob.google.com/

 

Google AdMob: 모바일 앱 수익 창출

인앱 광고를 사용하여 모바일 앱에서 더 많은 수익을 창출하고, 사용이 간편한 도구를 통해 유용한 분석 정보를 얻고 앱을 성장시켜 보세요.

admob.google.com

 

 

 

 

 

 

 

 

2. 애드몹 광고단위 생성

- 이번 경우 인 피드 방식 광고 설정을 위해

- native in-feed 방식을 생성함

 

 

 

 

 

 

 

 

 

3. 애드몹 설치

npm install @capacitor-community/admob

 

 

 

 

 

 

 

 

 

4. nativeAdService.ts 파일 생성

// nativeAdService.ts
import { AdMob, NativeAdOptions } from '@capacitor-community/admob';
import { Capacitor } from '@capacitor/core';

const TEST_NATIVE_AD_ID = 'ca-app-pub-3940256099942544/2247696110';
const PROD_NATIVE_AD_ID = 'ca-app-pub-3933370356899243/6341217418';

const IS_DEV = import.meta.env.DEV;
const NATIVE_AD_ID = IS_DEV ? TEST_NATIVE_AD_ID : PROD_NATIVE_AD_ID;

export interface NativeAdData {
  id: string;
  isAd: true;
  headline: string;
  body: string;
  callToAction: string;
  advertiser: string;
  icon?: string;
  images?: string[];
  price?: string;
  store?: string;
  starRating?: number;
}

// [수정] adCache 변수 자체를 사용하지 않거나 항상 빈 배열로 초기화
let isLoading = false;

export const loadNativeAds = async (count: number = 3): Promise<NativeAdData[]> => {
  if (!Capacitor.isNativePlatform()) {
    return []; // 웹 환경에선 무조건 빈 배열 (목업 차단)
  }

  try {
    await AdMob.initialize();
  } catch (e) {
    console.log("AdMob initialization check:", e);
  }

  if (isLoading) return []; // 로딩 중이면 이전 캐시 대신 빈 배열 반환

  isLoading = true;

  try {
    const options: NativeAdOptions = {
      adId: NATIVE_AD_ID,
    };

    // AdMob 실제 광고 로드
    const result = await AdMob.prepareNativeAd(options);
    
    const nativeAd: NativeAdData = {
      id: `native-ad-${Date.now()}`,
      isAd: true,
      headline: result.headline || '',
      body: result.body || '',
      callToAction: result.callToAction || 'Learn More',
      advertiser: result.advertiser || 'Sponsored',
      icon: result.icon,
      images: result.images || [],
      price: result.price,
      store: result.store,
      starRating: result.starRating,
    };

    return [nativeAd]; // 로드 성공 시 실제 데이터만 반환
    
  } catch (error) {
    console.error('Failed to load native ads:', error);
    return []; // [핵심] 실패 시 절대 getMockAds를 호출하지 않고 빈 배열 반환
  } finally {
    isLoading = false;
  }
};

// [삭제] 기존에 존재하던 getMockAds 함수는 아예 지우거나 아래처럼 비워두세요.
const getMockAds = (count: number): NativeAdData[] => [];

 

 

 

 

 

 

 

 

 

5. PWA 앱 내에서 만든 광고 슬롯 > 안드로이드 적용 가능 확인

- 커서ai 에서 확인함 = 즉, 리액트 컴포넌트로 되어있어 안드로이드에서도 유지된다는 의미

네이티브 광고 데이터 로딩: AdMob.prepareNativeAd()로 네이티브 광고 데이터를 가져옴
React 컴포넌트로 렌더링: 가져온 데이터를 AdSlot 컴포넌트로 표시
인피드 방식: 일정 목록 사이에 광고가 자연스럽게 삽입됨

 

 

 

 

 

 

 

 

 

 

6. 애드몹 기기설정 (테스트를 위한 설정 필요)

- 이미 구글 앱스토어에 등록되어있다면 바로 실제 ID-key를 사용해도 될테지만,

- 난 아직 미등록 상태이며, 내 기기에서 테스트가 필요함.

 

 

 

 

 

 

 

 

 

7. 기기 추가 내용

 

 

 

기기 ID 찾는 방법

- 설정 / google 서비스 / 광고 / 하단

"이 기기의 광고 ID' 아래 코드를 위의 입력란에 넣음.

 

 

 

 

 

 

 

8. 애드몹 ID 입력을 통해 테스트 광고 연결 확인

- 먼저 브라우저에서 확인 (브라우저에서는 빌드한 버전이 아니므로 테스트용 ID가 적용됨)

- 하단에 ad 뱃지가 보이고, 카드 페이지 접근 버튼이 생겼다. 성공!!

 

 

아래 작업을 통해서 최종 구현된 화면임.

component/ AdSlot.tsx 파일 수정! 

import React from 'react';
import { Advertisement, Language } from '../types';

interface Props {ad: Advertisement;
  lang: Language;
  onClick: (ad: Advertisement) => void;
  getRemainingTimeStr: (date: string) => React.ReactNode;
}

const AdSlot: React.FC<Props> = ({ ad, onClick }) => {
  return (
    <div 
      id={`native-ad-container-${ad.id}`}
      onClick={() => onClick(ad)}
      className="native-ad-placeholder flex-shrink-0 w-44 sm:w-60 p-5 sm:p-6 rounded-[1.5rem] sm:rounded-[2.5rem] border border-white/20 bg-white/5 relative overflow-hidden flex flex-col justify-between transition-all hover:border-white/40 cursor-pointer"
    >
      {/* 상단: 배지 및 광고주 정보 */}
      <div className="flex justify-between items-start mb-3">
        <span className="text-[8px] sm:text-[9px] font-black px-2 py-0.5 rounded-full bg-white/10 text-white/50">
          AD
        </span>
        <span className="text-[8px] sm:text-[9px] font-medium text-white/20 truncate max-w-[100px]">
          {ad.advertiser || 'Sponsored'}
        </span>
      </div>

      {/* 중단: 광고 본문 (이미지 + 텍스트) */}
      <div className="flex flex-col flex-grow overflow-hidden">
        {ad.images && ad.images.length > 0 && (
          <div className="w-full h-20 sm:h-24 mb-2 rounded-xl overflow-hidden bg-white/5">
            <img 
              src={ad.images[0]} 
              alt="Ad Media" 
              className="w-full h-full object-cover opacity-80"
            />
          </div>
        )}
        
        <p className="text-sm sm:text-base font-black text-white truncate mb-1">
          {ad.headline}
        </p>
        <p className="text-[10px] sm:text-[11px] text-white/40 line-clamp-2 leading-tight">
          {ad.body}
        </p>
      </div>

      {/* 하단: 행동 유도 버튼 (CTA) */}
      <div className="mt-3">
        <div className="w-full py-2 rounded-xl bg-lime-400/20 border border-lime-400/30 text-center">
          <span className="text-[11px] sm:text-xs font-black text-lime-400">
            {ad.callToAction || 'Learn More'}
          </span>
        </div>
      </div>
    </div>
  );
};

export default AdSlot;

 

 

필요에 따라 nativeAdService.ts 파일 수정

- 주요한 것은 test ID 와 prod ID 를 분리 선언하므로 테스트 확인 및 관리에 용이함.

- 이건 PWA 상태이고, 안드로이드로 넘어가면 AndroidManifest.xml 파일로 넘어가면서 prod ID 만 남게됨.

- 즉 무조건 실제 ID로 접속하게 되므로, 테스트 기기 등록이 반드시 필요함. 그냥 테스트하다가 광고 누르면 계정에 문제 발생 가능!

// nativeAdService.ts
import { AdMob, NativeAdOptions } from '@capacitor-community/admob';
import { Capacitor } from '@capacitor/core';

const TEST_NATIVE_AD_ID = 'ca-app-pub-3940256099942544/2247696110';  // 테스트용 ID
const PROD_NATIVE_AD_ID = 'ca-app-pub-3933370356899243/xxxxxxxxx'; // 내 실제 ID

const IS_DEV = import.meta.env.DEV;
const NATIVE_AD_ID = IS_DEV ? TEST_NATIVE_AD_ID : PROD_NATIVE_AD_ID;

export interface NativeAdData {
  id: string;
  isAd: true;
  headline: string;
  body: string;
  callToAction: string;
  advertiser: string;
  icon?: string;
  images?: string[];
  price?: string;
  store?: string;
  starRating?: number;
}

// [수정] adCache 변수 자체를 사용하지 않거나 항상 빈 배열로 초기화
let isLoading = false;

export const loadNativeAds = async (count: number = 3): Promise<NativeAdData[]> => {
  if (!Capacitor.isNativePlatform()) {
    return []; // 웹 환경에선 무조건 빈 배열 (목업 차단)
  }

  try {
    await AdMob.initialize();
  } catch (e) {
    console.log("AdMob initialization check:", e);
  }

  if (isLoading) return []; // 로딩 중이면 이전 캐시 대신 빈 배열 반환

  isLoading = true;

  try {
    const options: NativeAdOptions = {
      adId: NATIVE_AD_ID, // 자동으로 테스트와 프로덕트를 구분하여 적용
    };

    // AdMob 실제 광고 로드
    const result = await AdMob.prepareNativeAd(options);
    
    const nativeAd: NativeAdData = {
      id: `native-ad-${Date.now()}`,
      isAd: true,
      headline: result.headline || '',
      body: result.body || '',
      callToAction: result.callToAction || 'Learn More',
      advertiser: result.advertiser || 'Sponsored',
      icon: result.icon,
      images: result.images || [],
      price: result.price,
      store: result.store,
      starRating: result.starRating,
    };

    return [nativeAd]; // 로드 성공 시 실제 데이터만 반환
    
  } catch (error) {
    console.error('Failed to load native ads:', error);
    return []; // [핵심] 실패 시 절대 getMockAds를 호출하지 않고 빈 배열 반환
  } finally {
    isLoading = false;
  }
};

// [삭제] 기존에 존재하던 getMockAds 함수는 아예 지우거나 아래처럼 비워두세요.
const getMockAds = (count: number): NativeAdData[] => [];

 

 

 

 

 

 

 

 

9. 기기 연결 안드로이드 확인

- 기기 연결 테스트는 빌드 후에 적용되므로, 테스트ID 적용을 하지 못하게 되어있음. (위에 설명됨)

- 자동으로 프로덕트 ID가 들어가게 되어있음.

- 하지만 애드몹에 기기 등록을 해둔 상태이므로, 테스트 광고가 뜨게 되는 원리

 

- 카드 연결 버튼을 누르면 아래와 같이 미리 세팅해둔 디자인 UI에 맞춰 테스트 광고 레이어 모달을 확인할 수 있음.

 

 

 

 

 

 

 

 

 


!! 중간에 뻘짓하며 배운 내용 요약 

1. 안드로이드 빌드 후 런하면서 버전 문제로 개고생. > 36버전을 낮춰 35로 통일

    compileSdkVersion = 35
    targetSdkVersion = 35

 

2. 그밖에 환경변수 설정 포함 처음 안드로이드 스튜디오 실행으로 생기는 흔한 문제들

 

3. flatDir 구식 방법 찾아서 제거하느라 개고생  > fileTree 방식으로 통일, 

    implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar']) 

    settings.ts 에도 남아있어서 뒤늦게 발견 삭제!!

 

4. 애드몹 네이티브 광고 삽입 문제 개고생 > 안드로이드에서 해결이 안되서, ai studio에서 프롬프트로 해결

  " 광고에는 목업광고를 넣지 않는다. GPT(웹광고)방식 사용안함. 안드로이드앱으로 빌드할 것임. 안드로이드 스튜디오에서 설정 가능하도록 세팅만 해주길 요청" 

   (주: 네이티브 인피드 광고 최소 사이즈는 최소 32x32dp 만 넘으면 되므로 자유로운 사이즈, 위치에 넣을 수 있어 UX에 좋음)

   이렇게 새로 다운로드한 PWA 파일을 빌드한 후 안드로이드 스튜디오 ai 에서 다시 한 번 확인하면서 정리.

   AdSlot.ts 경우 빈 템플릿만 생성되었으므로 안드로이드에서 알려주는 코드로 변경하여 적용하니 원활히 수행됨.

 

 

 

 

 

 

 

 

 

728x90
반응형
LIST