AdMob Rewarded Videos – ShiVa Engine

AdMob Rewarded Videos

This guide shows you how to implement Admob Rewarded Videos in Android games using hooks and callbacks. It was written with ShiVa 2.0 and and Android Studio 3.3.2 in mind.

ShiVa Setup

You will need a User AIModel which handles your Lua code, and a HUD.
   

HUD

The HUD requires a button with a click action that connects to your AIModel. The AdMob Video will be shown when you click the button, assuming the video has loaded.
   

AIModel

The AIModel requires 3 handlers and one member string:

onInit() simply invokes the HUD:

function Main.onInit (  )
	hud.newTemplateInstance ( this.getUser ( ), "HUD", "HUD" )
end

onAdmobReceive() will reward the user. It also controls the button by changing its text as soon as the video is loaded:

function Main.onAdmobReceive ( sVar0, sVar1 )
	local hComponent = hud.getComponent ( this.getUser ( ), "HUD.Button" )
    if hComponent ~= nil then
        if sVar0 == "sAdmobRewardedVideoStatus" then
            this.sAdMobRewardedVideoStatus ( sVar1 )
        elseif sVar0 == "sAdmobReward" then
            local tTable = table.newInstance ( )
            string.explode ( sVar1, tTable, "###" )
            -- Reward Type and Amount are specified in your AdMob account:
            local sRewardType = table.getAt ( tTable, 0 )
            local sRewardAmount = table.getAt ( tTable, 1 )
            -- reward you user here
            -- ...
        end
        if this.sAdMobRewardedVideoStatus ( ) == "loaded" then
            hud.setButtonText ( hComponent, "Show Video" )
        else
            hud.setButtonText ( hComponent, "" )
        end
    end
end

onAdmbobSend() remains empty, as this is the point where the Java code will hook in later.

Export to Android Studio

Select the Android target in ShiVa’s Authoring panel and choose to build an Android Studio project (ZIP).

Android Studio Hooks & Callbacks

Once ShiVa has finished the export, unzip the project archive, then open your Android Studio and select Import project (Gradle, Eclipse ADT, etc.). We will have to make changes to the files build.gradle, AndroidManifest.xml, S3DClient.cpp and S3DEngine.java.

AdMob IDs

For testing, we will use the following AdMob IDs. It goes without saying that you will have to replace them with your own before distributing your app.

ca-app-pub-3940256099942544~3347511713 - TEST Admob App ID
ca-app-pub-3940256099942544/5224354917 - TEST Admob Ad ID

build.gradle

Add the Google Play Service Ads to the bottom of the dependencies block:

...
dependencies {
	implementation fileTree(dir: 'src/main/libs', include: ['*.jar'])
	implementation 'com.google.android.gms:play-services-ads:17.2.0'
}
...

AndroidManifest.xml

Add the (test) AdMob AppID to the bottom of the application section:

...
<manifest ... >
	...
	<application>
		...
		<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-3940256099942544~3347511713"/>
	</application>
	...
</manifest>

S3DClient.cpp

Hook into the empty onAdmobSend() function with C++. Don’t forget to change pEnv->FindClass ( “com/mycompany/myproduct/S3DEngine” ); and Java_com_mycompany_myproduct_S3DEngine_getNativeString:

...
//----------------------------------------------------------------------
// @@BEGIN_JNI_INSTALL_EVENT_HOOKS@@
//----------------------------------------------------------------------
S3DClient_InstallCurrentUserEventHook ( "Main", "onAdMobSend", onAdMobSendCallback, NULL );
//----------------------------------------------------------------------
// @@END_JNI_INSTALL_EVENT_HOOKS@@
//----------------------------------------------------------------------
...
//----------------------------------------------------------------------
// @@BEGIN_JNI_CALLBACKS@@
//----------------------------------------------------------------------
void onAdMobSendCallback ( unsigned char _iArgumentCount, const void *_pArguments, void *_pUserData ) {
	if ( pJavaVM ) {
		JNIEnv *pEnv ;
		if ( pJavaVM->GetEnv ( (void**) &pEnv, JNI_VERSION_1_4 ) >= 0 ) {
			jclass pClass = pEnv->FindClass ( "com/mycompany/myproduct/S3DEngine" );
			if ( pClass != 0 ) {
				jmethodID pMethod = pEnv->GetStaticMethodID ( pClass, "CPPtoJAVAshowAdd", "()I");
				if ( pMethod ) {
					int nNumber = pEnv->CallStaticIntMethod ( pClass, pMethod );
				}
			}
		}
	}
}
...
//----------------------------------------------------------------------
// @@END_JNI_CALLBACKS@@
//----------------------------------------------------------------------
JNIEXPORT jstring JNICALL Java_com_mycompany_myproduct_S3DEngine_getNativeString(JNIEnv *env, jobject obj, jstring aa, jstring bb) {
	const char *cc = env->GetStringUTFChars( aa , NULL );
	const char *dd = env->GetStringUTFChars( bb , NULL );
	S3DX::AIVariable variables[2];
	variables[0] = cc;
	variables[1] = dd;
	S3DClient_SendEventToCurrentUser ( "Main", "onAdMobReceive", 2, &variables );
	return env->NewStringUTF("OK");
}
...

S3DEngine.java

Finally, edit ShiVa’s main Java file to import the AdMob dependencies, initialize ads, and implement the necessary overrides. Don’t forget to replace the ca-app-pub… IDs before publishing.

...
import android.os.CountDownTimer;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.reward.RewardedVideoAd;
import com.google.android.gms.ads.reward.RewardItem;
import com.google.android.gms.ads.reward.RewardedVideoAdListener;
//----------------------------------------------------------------------
public class S3DEngine extends Application implements RewardedVideoAdListener {
	private RewardedVideoAd mRewardedVideoAd;
	private static boolean bShowAd = false;
	private static int nLoadAd = 0;
	private native String getNativeString(String aa, String bb);
	//------------------------------------------------------------------
	// Application overrides
	//
	@Override
	public void onCreate ( ) {
		// Register it to the S3DX Android tools
		S3DXAndroidTools.setMainApplication ( this ) ;
		// Call parent constructor
		super.onCreate ( ) ;
		MobileAds.initialize(this, "ca-app-pub-3940256099942544~3347511713");
		mRewardedVideoAd = MobileAds.getRewardedVideoAdInstance(this);
		mRewardedVideoAd.setRewardedVideoAdListener(this);
		loadRewardedVideoAd();
		new CountDownTimer(360000000, 1000) {
			public void onTick(long millisUntilFinished) {
				if (mRewardedVideoAd.isLoaded()) {
					getNativeString("sAdMobRewardedVideoStatus", "loaded");
				} else {
					getNativeString("sAdMobRewardedVideoStatus", "notloaded");
					nLoadAd++;
					if (nLoadAd > 10) {
						loadRewardedVideoAd();
					}
				}
				if (bShowAd) {
					bShowAd = false;
					showRewardedVideoAd();
				}
			}
			public void onFinish() {}
		}.start();
	}
	public static int CPPtoJAVAshowAdd( ) {
		bShowAd = true;
		return 0;
	}
	private void loadRewardedVideoAd() {
		nLoadAd = 0;
		mRewardedVideoAd.loadAd("ca-app-pub-3940256099942544/5224354917",
		new AdRequest.Builder().build());
	}
	public void showRewardedVideoAd() {
		if (mRewardedVideoAd.isLoaded()) {
			nLoadAd = -30;
			mRewardedVideoAd.show();
		}
	}
	@Override
	public void onRewarded(RewardItem reward) {
		getNativeString("sAdMobReward", "" + reward.getType() + "###" + reward.getAmount());
	}
	@Override
	public void onRewardedVideoAdLeftApplication() {}
	@Override
	public void onRewardedVideoAdClosed() {
		loadRewardedVideoAd();
	}
	@Override
	public void onRewardedVideoAdFailedToLoad(int errorCode) {}
	@Override
	public void onRewardedVideoAdLoaded() {
		getNativeString("sAdMobRewardedVideoStatus", "loaded");
	}
	@Override
	public void onRewardedVideoAdOpened() {}
	@Override
	public void onRewardedVideoStarted() {}
	@Override
	public void onRewardedVideoCompleted() {}
	//------------------------------------------------------------------
	@Override
	public void onTerminate ( ) {
	//Log.d ( "S3DENGINE MAIN", "### onTerminate" ) ;
		super.onTerminate ( ) ;
	}
	//------------------------------------------------------------------
	@Override
	public void onConfigurationChanged ( Configuration newConfig ) {
		//Log.d ( "S3DENGINE MAIN", "### onConfigurationChanged : " + newConfig.orientation ) ;
		//super.onConfigurationChanged ( newConfig ) ;
	}
}



Need more answers?

  • slackBanner