본문 바로가기

💻 내 소개 안녕하세요 엄청짱 프로그래머 손다빈 입니다.
  • 나이 : 96년생
  • 특이사항 : MZ세대, INFJ, 오른손잡이, 아이폰 유저
  • 좋아하는 음식 : 햄버거피자치킨솥뚜껑삼겹살떡볶이오튀김밥
  • 취미 : 개발, Programming, 코딩, 프로그래밍, Coding

🥷기술
Unity
Godot
Cpp
Javascript
D3
Vue

🐱 우리집 고양이 소개
츄르 먹은 후 츄르 먹기 전
  • 이름 : 콜라
  • 나이 : 8살
  • 종 : Nado moreum

📱 개인 프로젝트
🏢 참여한 프로젝트
빌런즈 Life is Pair 도씨어부키우기 직장상사혼내주기 서바이벌빙고 SlitherCoin

🌱 내 잔디밭

cocos2d-x | Admob [2] 보상형광고 호출하기 본문

글 묶음/거를때가 된 Cocos2d-x

cocos2d-x | Admob [2] 보상형광고 호출하기

초긍정 개발자 다빈맨 2019. 2. 14. 00:04

| 코코스2dx + 파이어베이스 + 애드몹(보상형 광고)



코코스2d-x 프로젝트에서 보상형 광고(동영상 광고)를 호출할 수 있도록 작업해봅시다.
배너광고와 마찬가지로 파이어베이스 SDK를 사용하기 때문에 반드시 파이어베이스와 연결이 되어있어야 합니다. 그 방법은 이전에 https://mynameisdabin.tistory.com/2 에서 설명하였습니다.




| 보상형 광고(Rewarded Video)



보상형 광고는 보상을 받을 수 있는 동영상 광고를 의미하는데 앱의 이용자가 동영상 광고가 끝난 후 보상을 받을 수 있도록 유도해서 악랄한 개발자가 개이득을 챙길 수 있게 합니다.


기존에는 애드몹 외에도 UnityAds, Vungle 과 같은 광고 플랫폼을 사용했지만 구글 애드몹에서도 최근부터 보상형 광고를 지원합니다.

그리고 구글 애드몹의 보상형 광고의 경우 노출 수 제한이 없기 때문에 여러가지 광고 플랫폼을 혼용해서 사용할 이유가 없어졌습니다.




| 애드몹 콘솔에서 광고단위 추가하기


애드몹 콘솔에서 광고를 추가하고자 하는 앱의 광고 단위  탭에 들어갑니다.



기존에 앱에 광고 단위를 추가한적이 없다면 시작하기  를 눌러 광고 단위를 만듭니다.



만약 위와 같이 이미 광고 단위가 1개 이상 존재하더라도 광고 단위 추가 버튼을 눌러서 추가하면 됩니다.



리워드 전면 광고 를 선택합니다.



입맛대로 설정을 선택하시고 저장 을 누르면 이때 입력한 리워드 수량과 리워드 상품(이름) 정보는 광고를 시청후 호출되는 콜백 함수로 데이터를 전달받을 수 있게 됩니다.



마지막 단계에서 앱 ID와 광고 단위 ID를 알려주는데 광고 호출시 이 두가지 정보를 요구하기 때문에 따로 복사해 둡니다.




| 안드로이드 스튜디오에서 구현


보상형광고를 호출할때 요구하는 정보는 애드몹 앱 id와 애드몹 광고 id입니다.

프로젝트 안에서 이 두가지 정보를 가져다 쓸 수 있도록 <project>/res/values/strings.xml 에 추가합니다.


<resources>

    <string name="app_name">SampleProject</string>

    <string name="google_admob_app_id">ca-app-pub-1010101010101010~1234512345</string>

    <string name="google_rewarded_ad_id">ca-app-pub-1010101010101010/1234512345</string>

</resources>


위에서 따로 복사해둔 정보를 각각 넣어주면 되는데 깜빡하고 복사해두지 않았더라도 애드몹 콘솔에서 확인이 가능합니다.


그리고 <project>/src/org/cocos2dx/cpp/AppActivity.java에 몇가지 변수와 함수를 선언하고 시작합시다.

package org.cocos2dx.cpp;

import android.os.Bundle;

import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.reward.RewardedVideoAd;

import org.cocos2dx.lib.Cocos2dxActivity;

import app.hello.sample.R;

public class AppActivity extends Cocos2dxActivity {
    public static AppActivity appActivity;
    private RewardedVideoAd mVideoAd;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        appActivity = this;

        MobileAds.initialize(getApplicationContext(), getResources().getString(R.string.google_admob_app_id));
        initRewardedVideoAd();
    }

    @Override
    public void onResume() {
        mVideoAd.resume(this);
        super.onResume();
    }

    @Override
    public void onPause() {
        mVideoAd.pause(this);
        super.onPause();
    }

    @Override
    public void onDestroy() {
        mVideoAd.destroy(this);
        super.onDestroy();
    }

    public void initRewardedVideoAd() {

    }

    public void loadRewardedVideoAd() {

    }

    public void showRewardedVideoAd() {

    }

    public static void Native_ShowRewardedVideoAd() {

    }

    private static native void nativeCallBackSuccessRewardedVideoAd(String type, int amount);
}

mVideoAd 인스턴스를 통해 광고를 제어할 수 있고 onCreate 시점에서 광고의 초기화를 끝내며 showRewardedVideoAd() 함수가 호출되는 시점에서 광고가 나오도록 구현하면 됩니다.


onResume 과 onPause, onDestroy의 구현된 내용은 mVideoAd 인스턴스가 액티비티의 라이프사이클을 정확히 인지할 수 있도록 도와주는데, 비디오광고가 노출되는 도중에 앱이 백그라운드 상태로 들어가거나 종료되더라도 mVideoAd가 그걸 알고 있어야 한다는걸 의미합니다.


마지막 라인의 nativeCallBackSuccessRewardedVideoAd 함수의 경우는 광고를 성공적으로 시청 후 C++에서 아이템 정보를 전달 받기 위해 선언한 Jni 네이티브 함수입니다.


※ 참고로 위 경고가 나오더라도 무시하세요! 컴파일 단계에서 해결 될 문제에요.


먼저 initRewardedVideoAd는 다음과 같이 구현합니다.

public void initRewardedVideoAd() {
        mVideoAd = MobileAds.getRewardedVideoAdInstance(this);
        mVideoAd.setRewardedVideoAdListener(new RewardedVideoAdListener() {
            @Override
            public void onRewardedVideoAdLoaded() {
                //광고를 성공적으로 불러올 경우 호출되는 코드.
            }
            @Override
            public void onRewardedVideoAdOpened() {
                //광고가 화면상에 나타날때 호출되는 코드. onRewardedVideoStarted 보다 빠르게 호출된다.
            }
            @Override
            public void onRewardedVideoStarted() {
                //광고가 시작할때 호출되는 코드.
            }
            @Override
            public void onRewardedVideoAdClosed() {
                //광고를 닫아버리면 호출되는 코드. 광고를 소진했기 때문에 다음 광고를 미리 불러온다.
                loadRewardedVideoAd();
            }
            @Override
            public void onRewarded(RewardItem rewardItem) {
                //성공적으로 광고가 끝날 경우 호출. 보상정보가 rewardItem 에 묶여서 전달된다.
                nativeCallBackSuccessRewardedVideoAd(rewardItem.getType(), rewardItem.getAmount());
            }
            @Override
            public void onRewardedVideoAdLeftApplication() {
                //광고시청 도중에 앱을 종료할 경우 호출되는 코드.
            }
            @Override
            public void onRewardedVideoAdFailedToLoad(int i) {
                //동영상광고를 불러올 수 없을때 호출되는 코드.
            }
        });

       loadRewardedVideoAd();
    }

loadRewardedVideoAd 다음과 같이 구현.

public void loadRewardedVideoAd() {
        //addTestDevice 로 테스트할 기기의 디바이스 ID 를 추가해줘야 한다.
        //테스트 단계에서 실제 동영상을 계속해서 호출할 경우 애드몹으로부터 불이익을 당할 수 있다.
        //자신이 사용하고있는 디바이스의 ID 는 USB 디버깅을 할 때 로그캣을 확인하면 된다.
        mVideoAd.loadAd(getResources().getString(R.string.google_rewarded_ad_id), new AdRequest.Builder().
                addTestDevice(AdRequest.DEVICE_ID_EMULATOR).
                build());
    }

showRewardedVideoAd 다음과 같이 구현.

public void showRewardedVideoAd() {
        if (mVideoAd.isLoaded())
            mVideoAd.show();
    }

Native_ShowRewardedVideoAd 다음과 같이 구현.

public static void Native_ShowRewardedVideoAd() {
        appActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                appActivity.showRewardedVideoAd();
            }
        });
    }

안드로이드 스튜디오에서의 작업은 이걸로 끝납니다.




| C++에서의 구현


이제 C++코드 상에서 AppActivity.Java에 선언해놓은 함수를 호출 가능하도록 하고 자바에서 보상정보를 네이티브 콜백함수로 반환하면 C++코드 상에서 보상 정보를 얻도록 해야합니다.


HelloWorldScene.h 에 두개의 함수를 선언해 줍니다.

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#define COCOS2D_DEBUG 1

#include "cocos2d.h"

class HelloWorld : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();

    virtual bool init();

    //보상형광고 호출 함수
    void showRewardedVideoAd();

    //보상형광고 콜백 함수
    static void callBackSuccessRewardedVideoAd(std::string type, int amount);

    // a selector callback
    void menuCloseCallback(cocos2d::Ref* pSender);
    
    // implement the "static create()" method manually
    CREATE_FUNC(HelloWorld);
};

#endif // __HELLOWORLD_SCENE_H__

여기서는 편의를 위해서 코코스 기본 프로젝트에서 위와같이 함수를 정의하지만 별도의 클래스를 설계해서 관리할 수 있도록 하세요. 


HelloWorldScene.cpp 에서 함수를 구현합니다.

//<-- 추가
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "platform/android/jni/JniHelper.h"
#endif
//-->

...중략..

void HelloWorld::showRewardedVideoAd()
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
	JniMethodInfo mInfo;

	if (JniHelper::getStaticMethodInfo(mInfo
		, "org/cocos2dx/cpp/AppActivity"
		, "Native_ShowRewardedVideoAd"
		, "()V"))
	{
		mInfo.env->CallStaticVoidMethod(mInfo.classID, mInfo.methodID);
		mInfo.env->DeleteLocalRef(mInfo.classID);
	}
#endif
}

void HelloWorld::callBackSuccessRewardedVideoAd(std::string type, int amount)
{  
	//여기서 type과 amount 값을 가지고 적당히 보상을 지급하면 된다.

	Director::getInstance()->end();
}

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

extern "C"
{
	JNIEXPORT void JNICALL Java_org_cocos2dx_cpp_AppActivity_nativeCallBackSuccessRewardedVideoAd(JNIEnv* env, jobject thiz, jstring type, int amount)
	{
		const char *nativeString = env->GetStringUTFChars(type, nullptr);
		std::string _type = std::string(nativeString);
		env->ReleaseStringUTFChars(type, nativeString);

		HelloWorld::callBackSuccessRewardedVideoAd(_type, amount);
	}
};

#endif

위 예제에선 콜백으로 받은 수치로 적절한 보상을 지급하지 않고 바로 앱을 종료시킵니다. 이렇게 한 이유는 가시적으로 위 콜백이 제대로 호출하는지 확인하기 위해서 입니다. 실제 여러분들이 사용하게 될 땐 적당히 보상을 지급하는 코드를 넣으시면 됩니다.


showRewardedVideoAd()를 호출하면 Java 코드상의 Native_ShowRewardedVideoAd()가 호출되고, 보상형광고의 보상이 지급될 때 네이티브 함수 인 Java_org_cocos2dx_cpp_AppActivity_nativeCallBackSuccessRewardedVideoAd()가 호출됩니다.


마지막으로 기존 게임종료 버튼의 콜백함수인 menuCloseCallback 의 내부를 비워두고 동영상광고를 호출하도록 수정하였습니다.

void HelloWorld::menuCloseCallback(Ref* pSender)
{
	showRewardedVideoAd();
}





Java_org_cocos2dx_cpp_AppActivity_nativeCallBackSuccessRewardedVideoAd 는 JNI 특성상 내부에서 static 함수밖에 호출하지 못합니다. 때문에 여기서는 편의를 위해 callBackSuccessRewardedVideoAd 함수를 static 으로 선언했는데, 상당히 나쁜 방법입니다. 여러분은 싱글톤 클래스를 따로 설계해서 콜백을 함수포인터로 전달하는 방식으로 수정해서 사용하세요. 제발.


AppActivity.java

strings.xml

HelloWorldScene.cpp

HelloWorldScene.h