[admob][android] Add NativeExpress & RewardedVideo classes

This commit is contained in:
Elliot Hesp 2017-05-31 16:40:26 +01:00
parent 35aeef460f
commit ad68ccc9af
2 changed files with 416 additions and 0 deletions

View File

@ -0,0 +1,281 @@
package io.invertase.firebase.admob;
import android.support.annotation.Nullable;
import android.view.View;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.facebook.react.views.view.ReactViewGroup;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.NativeExpressAdView;
import com.google.android.gms.ads.VideoController;
import com.google.android.gms.ads.VideoOptions;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RNFirebaseAdMobNativeExpress extends SimpleViewManager<ReactViewGroup> implements View.OnLayoutChangeListener {
public static final String REACT_CLASS = "RNFirebaseAdMobNativeExpress";
public static final String BANNER_EVENT = "bannerEvent";
public enum Events {
EVENT_AD_SIZE_CHANGE("onSizeChange"),
EVENT_AD_LOADED("onAdLoaded"),
EVENT_AD_FAILED_TO_LOAD("onAdFailedToLoad"),
EVENT_AD_OPENED("onAdOpened"),
EVENT_AD_CLOSED("onAdClosed"),
EVENT_AD_LEFT_APPLICATION("onAdLeftApplication"),
EVENT_AD_VIDEO_END("onVideoEnd"),
EVENT_AD_VIDEO_CONTENT("hasVideoContent");
private final String event;
Events(final String name) {
event = name;
}
@Override
public String toString() {
return event;
}
}
private ThemedReactContext context;
private ReactViewGroup viewGroup;
private RCTEventEmitter emitter;
private AdRequest.Builder request;
private VideoOptions.Builder videoOptions;
private String size;
@Override
public String getName() {
return REACT_CLASS;
}
/**
* Create & return view instance
* @param themedReactContext
* @return
*/
@Override
public ReactViewGroup createViewInstance(ThemedReactContext themedReactContext) {
context = themedReactContext;
viewGroup = new ReactViewGroup(themedReactContext);
emitter = themedReactContext.getJSModule(RCTEventEmitter.class);
NativeExpressAdView adView = new NativeExpressAdView(context);
viewGroup.addView(adView);
setAdListener();
return viewGroup;
}
NativeExpressAdView getAdView() {
return (NativeExpressAdView) viewGroup.getChildAt(0);
}
/**
* Declare custom events
* @return
*/
@Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
MapBuilder.Builder<String, Object> builder = MapBuilder.builder();
builder.put(BANNER_EVENT, MapBuilder.of("registrationName", BANNER_EVENT));
return builder.build();
}
/**
* If the React View changes, reset the Ad size
* @param view
* @param left
* @param top
* @param right
* @param bottom
* @param oldLeft
* @param oldTop
* @param oldRight
* @param oldBottom
*/
@Override
public void onLayoutChange(View view, final int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
// If the view has changed at all, recalculate what banner we need
if (left != oldLeft || right != oldRight || top != oldTop || bottom != oldBottom) {
setSize(viewGroup, null);
}
}
/**
* Handle unitId prop
* @param view
* @param value
*/
@ReactProp(name = "unitId")
public void setUnitId(final ReactViewGroup view, final String value) {
NativeExpressAdView adViewView = getAdView();
adViewView.setAdUnitId(value);
requestAd();
}
/**
* Handle request prop
* @param view
* @param map
*/
@ReactProp(name = "request")
public void setRequest(final ReactViewGroup view, final ReadableMap map) {
request = RNFirebaseAdMobUtils.buildRequest(map);
requestAd();
}
/**
* Handle video prop
* @param view
* @param map
*/
@ReactProp(name = "video")
public void setVideoOptions(final ReactViewGroup view, final ReadableMap map) {
videoOptions = RNFirebaseAdMobUtils.buildVideoOptions(map);
requestAd();
}
/**
* Handle size prop
* @param view
* @param value
*/
@ReactProp(name = "size")
public void setSize(final ReactViewGroup view, final @Nullable String value) {
if (value != null) {
size = value;
}
AdSize adSize = RNFirebaseAdMobUtils.stringToAdSize(size);
NativeExpressAdView adViewView = getAdView();
adViewView.setAdSize(adSize);
// Send the width & height back to the JS
int width;
int height;
WritableMap payload = Arguments.createMap();
if (adSize == AdSize.SMART_BANNER) {
width = (int) PixelUtil.toDIPFromPixel(adSize.getWidthInPixels(context));
height = (int) PixelUtil.toDIPFromPixel(adSize.getHeightInPixels(context));
} else {
width = adSize.getWidth();
height = adSize.getHeight();
}
payload.putDouble("width", width);
payload.putDouble("height", height);
sendEvent(Events.EVENT_AD_SIZE_CHANGE.toString(), payload);
requestAd();
}
/**
* Loads a new ad into a viewGroup
*/
void requestAd() {
NativeExpressAdView adView = getAdView();
if (adView.getAdSize() == null || adView.getAdUnitId() == null || request == null || videoOptions == null) {
return;
}
AdRequest adRequest = request.build();
adView.setVideoOptions(videoOptions.build());
adView.loadAd(adRequest);
}
/**
* Listen to Ad events
*/
void setAdListener() {
final NativeExpressAdView adView = getAdView();
adView.setAdListener(new AdListener() {
@Override
public void onAdLoaded() {
int left = adView.getLeft();
int top = adView.getTop();
int width = adView.getAdSize().getWidthInPixels(context);
int height = adView.getAdSize().getHeightInPixels(context);
adView.measure(width, height);
adView.layout(left, top, left + width, top + height);
VideoController vc = adView.getVideoController();
WritableMap payload = Arguments.createMap();
payload.putBoolean(Events.EVENT_AD_VIDEO_CONTENT.toString(), vc.hasVideoContent());
payload.putInt("width", width);
payload.putInt("height", height);
payload.putInt("left", left);
payload.putInt("top", top);
if (vc.hasVideoContent()) {
vc.setVideoLifecycleCallbacks(new VideoController.VideoLifecycleCallbacks() {
public void onVideoEnd() {
sendEvent(Events.EVENT_AD_VIDEO_END.toString(), null);
}
});
}
sendEvent(Events.EVENT_AD_LOADED.toString(), payload);
}
@Override
public void onAdFailedToLoad(int errorCode) {
WritableMap payload = RNFirebaseAdMobUtils.errorCodeToMap(errorCode);
sendEvent(Events.EVENT_AD_FAILED_TO_LOAD.toString(), payload);
}
@Override
public void onAdOpened() {
sendEvent(Events.EVENT_AD_OPENED.toString(), null);
}
@Override
public void onAdClosed() {
sendEvent(Events.EVENT_AD_CLOSED.toString(), null);
}
@Override
public void onAdLeftApplication() {
sendEvent(Events.EVENT_AD_LEFT_APPLICATION.toString(), null);
}
});
}
/**
* Sends an event back to the JS component to handle
* @param type
* @param payload
*/
void sendEvent(String type, final @Nullable WritableMap payload) {
WritableMap event = Arguments.createMap();
event.putString("type", type);
if (payload != null) {
event.putMap("payload", payload);
}
int id = viewGroup.getId();
emitter.receiveEvent(viewGroup.getId(), BANNER_EVENT, event);
}
}

View File

@ -0,0 +1,135 @@
package io.invertase.firebase.admob;
import android.app.Activity;
import android.support.annotation.Nullable;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.WritableMap;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.reward.RewardItem;
import com.google.android.gms.ads.reward.RewardedVideoAd;
import com.google.android.gms.ads.reward.RewardedVideoAdListener;
import io.invertase.firebase.Utils;
public class RNFirebaseAdMobRewardedVideo implements RewardedVideoAdListener {
private RewardedVideoAd mAd;
private String adUnit;
private RNFirebaseAdMob adMob;
private RewardedVideoAd rewardedVideo;
RNFirebaseAdMobRewardedVideo(final String adUnitString, final RNFirebaseAdMob adMobInstance) {
adUnit = adUnitString;
adMob = adMobInstance;
rewardedVideo = MobileAds.getRewardedVideoAdInstance(adMob.getContext());
Activity activity = adMob.getActivity();
final RNFirebaseAdMobRewardedVideo _this = this;
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
rewardedVideo.setRewardedVideoAdListener(_this);
}
});
}
}
/**
* Load an Ad with a AdRequest instance
*
* @param adRequest
*/
void loadAd(final AdRequest adRequest) {
Activity activity = adMob.getActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
rewardedVideo.loadAd(adUnit, adRequest);
}
});
}
}
/**
* Show the loaded interstitial, if it's loaded
*/
void show() {
Activity activity = adMob.getActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (rewardedVideo.isLoaded()) {
rewardedVideo.show();
}
}
});
}
}
@Override
public void onRewarded(RewardItem reward) {
WritableMap payload = Arguments.createMap();
payload.putInt("amount", reward.getAmount());
payload.putString("type", reward.getType());
sendEvent("onRewarded", payload);
}
@Override
public void onRewardedVideoAdLeftApplication() {
sendEvent("onAdLeftApplication", null);
}
@Override
public void onRewardedVideoAdClosed() {
sendEvent("onAdClosed", null);
}
@Override
public void onRewardedVideoAdFailedToLoad(int errorCode) {
WritableMap payload = RNFirebaseAdMobUtils.errorCodeToMap(errorCode);
sendEvent("onAdFailedToLoad", payload);
}
@Override
public void onRewardedVideoAdLoaded() {
sendEvent("onAdLoaded", null);
}
@Override
public void onRewardedVideoAdOpened() {
sendEvent("onAdOpened", null);
}
@Override
public void onRewardedVideoStarted() {
sendEvent("onRewardedVideoStarted", null);
}
// TODO onResume etc??? https://developers.google.com/admob/android/rewarded-video
/**
* Send a native event over the bridge with a type and optional payload
*
* @param type
* @param payload
*/
void sendEvent(String type, final @Nullable WritableMap payload) {
WritableMap map = Arguments.createMap();
map.putString("type", type);
map.putString("adUnit", adUnit);
if (payload != null) {
map.putMap("payload", payload);
}
Utils.sendEvent(adMob.getContext(), "rewarded_video_event", map);
}
}