[admob][android] Add admob module to base firebase object
This commit is contained in:
parent
dd1262ca86
commit
0e47c57317
|
@ -0,0 +1,97 @@
|
||||||
|
package io.invertase.firebase.admob;
|
||||||
|
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.Arguments;
|
||||||
|
import com.facebook.react.bridge.Promise;
|
||||||
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||||
|
import com.facebook.react.bridge.ReactMethod;
|
||||||
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
|
import com.facebook.react.bridge.WritableArray;
|
||||||
|
import com.google.android.gms.ads.AdRequest;
|
||||||
|
import com.google.firebase.database.ServerValue;
|
||||||
|
import com.google.firebase.perf.FirebasePerformance;
|
||||||
|
import com.google.firebase.perf.metrics.Trace;
|
||||||
|
import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
|
||||||
|
|
||||||
|
import io.invertase.firebase.Utils;
|
||||||
|
import io.invertase.firebase.admob.RNFirebaseAdmobInterstitial;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class RNFirebaseAdMob extends ReactContextBaseJavaModule {
|
||||||
|
|
||||||
|
private static final String TAG = "RNFirebaseAdmob";
|
||||||
|
|
||||||
|
public ReactApplicationContext getContext() {
|
||||||
|
return getReactApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Activity getActivity() {
|
||||||
|
return getCurrentActivity();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReactApplicationContext context;
|
||||||
|
private HashMap<String, RNFirebaseAdmobInterstitial> interstitials = new HashMap<>();
|
||||||
|
|
||||||
|
public RNFirebaseAdMob(ReactApplicationContext reactContext) {
|
||||||
|
super(reactContext);
|
||||||
|
context = reactContext;
|
||||||
|
Log.d(TAG, "New instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void interstitialLoadAd(String adUnit, ReadableMap request) {
|
||||||
|
RNFirebaseAdmobInterstitial interstitial = getOrCreateInterstitial(adUnit);
|
||||||
|
AdRequest.Builder requestBuilder = new AdRequest.Builder();
|
||||||
|
|
||||||
|
if (request.hasKey("testDevice")) {
|
||||||
|
requestBuilder.addTestDevice(AdRequest.DEVICE_ID_EMULATOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadableArray keywords = request.getArray("keywords");
|
||||||
|
List<Object> keywordsList = Utils.recursivelyDeconstructReadableArray(keywords);
|
||||||
|
|
||||||
|
for (Object word : keywordsList) {
|
||||||
|
requestBuilder.addKeyword((String) word);
|
||||||
|
}
|
||||||
|
|
||||||
|
interstitial.loadAd(requestBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void interstitialShowAd(String adUnit) {
|
||||||
|
RNFirebaseAdmobInterstitial interstitial = getOrCreateInterstitial(adUnit);
|
||||||
|
interstitial.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private RNFirebaseAdmobInterstitial getOrCreateInterstitial(String adUnit) {
|
||||||
|
if (interstitials.containsKey(adUnit)) {
|
||||||
|
return interstitials.get(adUnit);
|
||||||
|
}
|
||||||
|
RNFirebaseAdmobInterstitial interstitial = new RNFirebaseAdmobInterstitial(adUnit, this);
|
||||||
|
interstitials.put(adUnit, interstitial);
|
||||||
|
return interstitial;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getConstants() {
|
||||||
|
final Map<String, Object> constants = new HashMap<>();
|
||||||
|
constants.put("DEVICE_ID_EMULATOR", AdRequest.DEVICE_ID_EMULATOR);
|
||||||
|
return constants;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,303 @@
|
||||||
|
package io.invertase.firebase.admob;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.Arguments;
|
||||||
|
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.MobileAds;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
public class RNFirebaseAdMobBanner extends SimpleViewManager<ReactViewGroup> implements View.OnLayoutChangeListener {
|
||||||
|
|
||||||
|
public static final String REACT_CLASS = "RNFirebaseAdMobBanner";
|
||||||
|
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");
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
|
||||||
|
attachAdViewToViewGroup();
|
||||||
|
|
||||||
|
return viewGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
Log.d("Ads", "onLayoutChange");
|
||||||
|
// 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 unitId
|
||||||
|
*/
|
||||||
|
@ReactProp(name = "unitId")
|
||||||
|
public void setUnitId(final ReactViewGroup view, final String unitId) {
|
||||||
|
Log.d("Ads", "Prop unitId something " + unitId);
|
||||||
|
|
||||||
|
AdView adViewView = (AdView) view.getChildAt(0);
|
||||||
|
adViewView.setAdUnitId(unitId);
|
||||||
|
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 = propToAdSize(size.toUpperCase());
|
||||||
|
Log.d("Ads", "Prop size something " + adSize.toString());
|
||||||
|
|
||||||
|
AdView adViewView = (AdView) view.getChildAt(0);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the AdView and attaches it to the
|
||||||
|
* current ReactViewGroup
|
||||||
|
*/
|
||||||
|
void attachAdViewToViewGroup() {
|
||||||
|
removeAdFromViewGroup();
|
||||||
|
|
||||||
|
final AdView adView = new AdView(context);
|
||||||
|
viewGroup.addView(adView);
|
||||||
|
setAdListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the AdView from the ViewGroup
|
||||||
|
*/
|
||||||
|
void removeAdFromViewGroup() {
|
||||||
|
AdView adView = (AdView) viewGroup.getChildAt(0);
|
||||||
|
viewGroup.removeAllViews();
|
||||||
|
|
||||||
|
if (adView != null) {
|
||||||
|
adView.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a new ad into a viewGroup
|
||||||
|
*/
|
||||||
|
void requestAd() {
|
||||||
|
AdView adView = (AdView) viewGroup.getChildAt(0);
|
||||||
|
|
||||||
|
if (adView.getAdSize() == null || adView.getAdUnitId() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdRequest.Builder adRequestBuilder = new AdRequest.Builder();
|
||||||
|
adRequestBuilder.addTestDevice(AdRequest.DEVICE_ID_EMULATOR);
|
||||||
|
AdRequest adRequest = adRequestBuilder.build();
|
||||||
|
adView.loadAd(adRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen to Ad events
|
||||||
|
*/
|
||||||
|
void setAdListener() {
|
||||||
|
final AdView adView = (AdView) viewGroup.getChildAt(0);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
sendEvent(Events.EVENT_AD_LOADED.toString(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAdFailedToLoad(int errorCode) {
|
||||||
|
WritableMap payload = Arguments.createMap();
|
||||||
|
|
||||||
|
// TODO Error code converter
|
||||||
|
switch (errorCode) {
|
||||||
|
case AdRequest.ERROR_CODE_INTERNAL_ERROR:
|
||||||
|
payload.putString("code", "admob/error-code-internal-error");
|
||||||
|
payload.putString("message", "Something happened internally; for instance, an invalid response was received from the ad server.");
|
||||||
|
break;
|
||||||
|
case AdRequest.ERROR_CODE_INVALID_REQUEST:
|
||||||
|
payload.putString("code", "admob/error-code-invalid-request");
|
||||||
|
payload.putString("message", "The ad request was invalid; for instance, the ad unit ID was incorrect.");
|
||||||
|
break;
|
||||||
|
case AdRequest.ERROR_CODE_NETWORK_ERROR:
|
||||||
|
payload.putString("code", "admob/error-code-network-error");
|
||||||
|
payload.putString("message", "The ad request was unsuccessful due to network connectivity.");
|
||||||
|
break;
|
||||||
|
case AdRequest.ERROR_CODE_NO_FILL:
|
||||||
|
payload.putString("code", "admob/error-code-no-fill");
|
||||||
|
payload.putString("message", "The ad request was successful, but no ad was returned due to lack of ad inventory.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
emitter.receiveEvent(viewGroup.getId(), BANNER_EVENT, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map the size prop to the AdSize
|
||||||
|
* @param prop
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
AdSize propToAdSize(String prop) {
|
||||||
|
switch (prop) {
|
||||||
|
default:
|
||||||
|
case "BANNER":
|
||||||
|
return AdSize.BANNER;
|
||||||
|
case "LARGE_BANNER":
|
||||||
|
return AdSize.LARGE_BANNER;
|
||||||
|
case "MEDIUM_RECTANGLE":
|
||||||
|
return AdSize.MEDIUM_RECTANGLE;
|
||||||
|
case "FULL_BANNER":
|
||||||
|
return AdSize.FULL_BANNER;
|
||||||
|
case "LEADERBOARD":
|
||||||
|
return AdSize.LEADERBOARD;
|
||||||
|
case "SMART_BANNER":
|
||||||
|
return AdSize.SMART_BANNER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package io.invertase.firebase.admob;
|
||||||
|
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
|
import com.google.android.gms.ads.AdRequest;
|
||||||
|
import com.google.android.gms.ads.InterstitialAd;
|
||||||
|
|
||||||
|
class RNFirebaseAdmobInterstitial {
|
||||||
|
|
||||||
|
private InterstitialAd interstitialAd;
|
||||||
|
private RNFirebaseAdMob adMob;
|
||||||
|
|
||||||
|
RNFirebaseAdmobInterstitial(String adUnit, RNFirebaseAdMob adMobInstance) {
|
||||||
|
adMob = adMobInstance;
|
||||||
|
interstitialAd = new InterstitialAd(adMob.getContext());
|
||||||
|
interstitialAd.setAdUnitId(adUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadAd(final AdRequest adRequest) {
|
||||||
|
Activity activity = adMob.getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
interstitialAd.loadAd(adRequest);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void show() {
|
||||||
|
Activity activity = adMob.getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (interstitialAd.isLoaded()) {
|
||||||
|
interstitialAd.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import Analytics from './modules/analytics';
|
||||||
import Crash from './modules/crash';
|
import Crash from './modules/crash';
|
||||||
import RemoteConfig from './modules/config';
|
import RemoteConfig from './modules/config';
|
||||||
import Performance from './modules/perf';
|
import Performance from './modules/perf';
|
||||||
|
import AdMob, { statics as AdMobStatics } from './modules/admob';
|
||||||
|
|
||||||
const instances: Object = { default: null };
|
const instances: Object = { default: null };
|
||||||
const FirebaseModule = NativeModules.RNFirebase;
|
const FirebaseModule = NativeModules.RNFirebase;
|
||||||
|
@ -36,6 +37,7 @@ export default class Firebase {
|
||||||
_config: ?Object;
|
_config: ?Object;
|
||||||
_crash: ?Object;
|
_crash: ?Object;
|
||||||
_perf: ?Object;
|
_perf: ?Object;
|
||||||
|
_admob: ?Object;
|
||||||
|
|
||||||
auth: Function;
|
auth: Function;
|
||||||
crash: Function;
|
crash: Function;
|
||||||
|
@ -45,6 +47,7 @@ export default class Firebase {
|
||||||
messaging: Function;
|
messaging: Function;
|
||||||
config: Function;
|
config: Function;
|
||||||
perf: Function;
|
perf: Function;
|
||||||
|
admob: Function;
|
||||||
|
|
||||||
eventHandlers: Object;
|
eventHandlers: Object;
|
||||||
debug: boolean;
|
debug: boolean;
|
||||||
|
@ -90,6 +93,7 @@ export default class Firebase {
|
||||||
this.crash = this._staticsOrInstance('crash', {}, Crash);
|
this.crash = this._staticsOrInstance('crash', {}, Crash);
|
||||||
this.config = this._staticsOrInstance('config', {}, RemoteConfig);
|
this.config = this._staticsOrInstance('config', {}, RemoteConfig);
|
||||||
this.perf = this._staticsOrInstance('perf', {}, Performance);
|
this.perf = this._staticsOrInstance('perf', {}, Performance);
|
||||||
|
this.admob = this._staticsOrInstance('admob', AdMobStatics, AdMob);
|
||||||
|
|
||||||
// init auth to start listeners
|
// init auth to start listeners
|
||||||
this.auth();
|
this.auth();
|
||||||
|
|
Loading…
Reference in New Issue