Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support DFPInterstitial & DFPBanner for AdManager #517

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
64 changes: 64 additions & 0 deletions RNDFPInterstitial.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {
NativeModules,
NativeEventEmitter,
} from 'react-native';

import { createErrorFromErrorData } from './utils';

const RNDFPInterstitial = NativeModules.RNDFPInterstitial;

const eventEmitter = new NativeEventEmitter(RNDFPInterstitial);

const eventMap = {
adLoaded: 'interstitialAdLoaded',
adFailedToLoad: 'interstitialAdFailedToLoad',
adOpened: 'interstitialAdOpened',
adClosed: 'interstitialAdClosed',
adLeftApplication: 'interstitialAdLeftApplication',
};

const _subscriptions = new Map();

const addEventListener = (event, handler) => {
const mappedEvent = eventMap[event];
if (mappedEvent) {
let listener;
if (event === 'adFailedToLoad') {
listener = eventEmitter.addListener(mappedEvent, error => handler(createErrorFromErrorData(error)));
} else {
listener = eventEmitter.addListener(mappedEvent, handler);
}
_subscriptions.set(handler, listener);
return {
remove: () => removeEventListener(event, handler)
};
} else {
console.warn(`Trying to subscribe to unknown event: "${event}"`);
return {
remove: () => { },
};
}
};

const removeEventListener = (type, handler) => {
const listener = _subscriptions.get(handler);
if (!listener) {
return;
}
listener.remove();
_subscriptions.delete(handler);
};

const removeAllListeners = () => {
_subscriptions.forEach((listener, key, map) => {
listener.remove();
map.delete(key);
});
};

export default {
...RNDFPInterstitial,
addEventListener,
removeEventListener,
removeAllListeners,
};
7 changes: 6 additions & 1 deletion RNPublisherBanner.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { arrayOf, func, string } from 'prop-types';
import { arrayOf, func, string, object } from 'prop-types';
import React, { Component } from 'react';
import {
findNodeHandle,
Expand Down Expand Up @@ -88,6 +88,11 @@ PublisherBanner.propTypes = {
*/
adSize: string,

/**
* make it as json?
*/
customTargeting: object,

/**
* Optional array specifying all valid sizes that are appropriate for this slot.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public class RNAdMobPackage implements ReactPackage {
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(
new RNAdMobInterstitialAdModule(reactContext),
new RNAdMobRewardedVideoAdModule(reactContext)
new RNAdMobRewardedVideoAdModule(reactContext),
new RNDFPInterstitialAdModule(reactContext)
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package com.sbugert.rnadmob;

import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
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.ReadableNativeArray;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.doubleclick.PublisherInterstitialAd;
import com.google.android.gms.ads.doubleclick.PublisherAdRequest;

import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class RNDFPInterstitialAdModule extends ReactContextBaseJavaModule {

public static final String REACT_CLASS = "RNDFPInterstitial";

public static final String EVENT_AD_LOADED = "interstitialAdLoaded";
public static final String EVENT_AD_FAILED_TO_LOAD = "interstitialAdFailedToLoad";
public static final String EVENT_AD_OPENED = "interstitialAdOpened";
public static final String EVENT_AD_CLOSED = "interstitialAdClosed";
public static final String EVENT_AD_LEFT_APPLICATION = "interstitialAdLeftApplication";

PublisherInterstitialAd mInterstitialAd;
String[] testDevices;
ReadableMap customTargeting;

private Promise mRequestAdPromise;

@Override
public String getName() {
return REACT_CLASS;
}

public RNDFPInterstitialAdModule(ReactApplicationContext reactContext) {
super(reactContext);
mInterstitialAd = new PublisherInterstitialAd(reactContext);

new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
mInterstitialAd.setAdListener(new AdListener() {
@Override
public void onAdClosed() {
sendEvent(EVENT_AD_CLOSED, null);
}
@Override
public void onAdFailedToLoad(int errorCode) {
String errorString = "ERROR_UNKNOWN";
String errorMessage = "Unknown error";
switch (errorCode) {
case AdRequest.ERROR_CODE_INTERNAL_ERROR:
errorString = "ERROR_CODE_INTERNAL_ERROR";
errorMessage = "Internal error, an invalid response was received from the ad server.";
break;
case AdRequest.ERROR_CODE_INVALID_REQUEST:
errorString = "ERROR_CODE_INVALID_REQUEST";
errorMessage = "Invalid ad request, possibly an incorrect ad unit ID was given.";
break;
case AdRequest.ERROR_CODE_NETWORK_ERROR:
errorString = "ERROR_CODE_NETWORK_ERROR";
errorMessage = "The ad request was unsuccessful due to network connectivity.";
break;
case AdRequest.ERROR_CODE_NO_FILL:
errorString = "ERROR_CODE_NO_FILL";
errorMessage = "The ad request was successful, but no ad was returned due to lack of ad inventory.";
break;
}
WritableMap event = Arguments.createMap();
WritableMap error = Arguments.createMap();
event.putString("message", errorMessage);
sendEvent(EVENT_AD_FAILED_TO_LOAD, event);
mRequestAdPromise.reject(errorString, errorMessage);
}
@Override
public void onAdLeftApplication() {
sendEvent(EVENT_AD_LEFT_APPLICATION, null);
}
@Override
public void onAdLoaded() {
sendEvent(EVENT_AD_LOADED, null);
mRequestAdPromise.resolve(null);
}
@Override
public void onAdOpened() {
sendEvent(EVENT_AD_OPENED, null);
}
});
}
});
}
private void sendEvent(String eventName, @Nullable WritableMap params) {
getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);
}

@ReactMethod
public void setAdUnitID(String adUnitID) {
if (mInterstitialAd.getAdUnitId() == null) {
mInterstitialAd.setAdUnitId(adUnitID);
}
}

@ReactMethod
public void setTestDevices(ReadableArray testDevices) {
ReadableNativeArray nativeArray = (ReadableNativeArray)testDevices;
ArrayList<Object> list = nativeArray.toArrayList();
this.testDevices = list.toArray(new String[list.size()]);
}

@ReactMethod
public void setCustomTargeting(ReadableMap customTargeting) {
this.customTargeting = customTargeting;
}

@ReactMethod
public void requestAd(final Promise promise) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run () {
if (mInterstitialAd.isLoaded() || mInterstitialAd.isLoading()) {
promise.reject("E_AD_ALREADY_LOADED", "Ad is already loaded.");
} else {
mRequestAdPromise = promise;
PublisherAdRequest.Builder adRequestBuilder = new PublisherAdRequest.Builder();
if (testDevices != null) {
for (int i = 0; i < testDevices.length; i++) {
adRequestBuilder.addTestDevice(testDevices[i]);
}
}

if (customTargeting != null) {
ReadableMapKeySetIterator iterator = customTargeting.keySetIterator();
while (iterator.hasNextKey()) {
String key = iterator.nextKey();
ReadableType type = customTargeting.getType(key);
switch (type) {
case String:
adRequestBuilder.addCustomTargeting(key, customTargeting.getString(key));
break;
case Array:
ReadableArray arrayValue = customTargeting.getArray(key);
adRequestBuilder.addCustomTargeting(key, (List<String>) (Object) arrayValue.toArrayList());
break;
case Number:
adRequestBuilder.addCustomTargeting(key, Integer.toString(customTargeting.getInt(key)));
break;
case Boolean:
adRequestBuilder.addCustomTargeting(key, Boolean.toString(customTargeting.getBoolean(key)));
break;
default:
break;
}
}
}
PublisherAdRequest adRequest = adRequestBuilder.build();
mInterstitialAd.loadAd(adRequest);
}
}
});
}

@ReactMethod
public void showAd(final Promise promise) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run () {
if (mInterstitialAd.isLoaded()) {
mInterstitialAd.show();
promise.resolve(null);
} else {
promise.reject("E_AD_NOT_READY", "Ad is not ready.");
}
}
});
}

@ReactMethod
public void isReady(final Callback callback) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run () {
callback.invoke(mInterstitialAd.isLoaded());
}
});
}

@javax.annotation.Nullable
@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put("simulatorId", AdRequest.DEVICE_ID_EMULATOR);
return constants;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.ReadableNativeArray;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.ViewGroupManager;
Expand All @@ -22,6 +25,8 @@
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.doubleclick.PublisherAdView;

import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -34,6 +39,7 @@ class ReactPublisherAdView extends ReactViewGroup implements AppEventListener {
AdSize[] validAdSizes;
String adUnitID;
AdSize adSize;
ReadableMap customTargeting;

public ReactPublisherAdView(final Context context) {
super(context);
Expand Down Expand Up @@ -155,6 +161,32 @@ public void loadBanner() {
adRequestBuilder.addTestDevice(testDevice);
}
}

if (this.customTargeting != null) {
ReadableMapKeySetIterator iterator = this.customTargeting.keySetIterator();
while (iterator.hasNextKey()) {
String key = iterator.nextKey();
ReadableType type = this.customTargeting.getType(key);
switch (type) {
case String:
adRequestBuilder.addCustomTargeting(key, this.customTargeting.getString(key));
break;
case Array:
ReadableArray arrayValue = this.customTargeting.getArray(key);
adRequestBuilder.addCustomTargeting(key, (List<String>) (Object) arrayValue.toArrayList());
break;
case Number:
adRequestBuilder.addCustomTargeting(key, Integer.toString(this.customTargeting.getInt(key)));
break;
case Boolean:
adRequestBuilder.addCustomTargeting(key, Boolean.toString(this.customTargeting.getBoolean(key)));
break;
default:
break;
}
}
}

PublisherAdRequest adRequest = adRequestBuilder.build();
this.adView.loadAd(adRequest);
}
Expand All @@ -181,6 +213,10 @@ public void setValidAdSizes(AdSize[] adSizes) {
this.validAdSizes = adSizes;
}

public void setCustomTargeting(ReadableMap customTargeting) {
this.customTargeting = customTargeting;
}

@Override
public void onAppEvent(String name, String info) {
WritableMap event = Arguments.createMap();
Expand All @@ -198,6 +234,7 @@ public class RNPublisherBannerViewManager extends ViewGroupManager<ReactPublishe
public static final String PROP_VALID_AD_SIZES = "validAdSizes";
public static final String PROP_AD_UNIT_ID = "adUnitID";
public static final String PROP_TEST_DEVICES = "testDevices";
public static final String PROP_CUSTOM_TARGETING = "customTargeting";

public static final String EVENT_SIZE_CHANGE = "onSizeChange";
public static final String EVENT_AD_LOADED = "onAdLoaded";
Expand Down Expand Up @@ -264,6 +301,11 @@ public void setPropValidAdSizes(final ReactPublisherAdView view, final ReadableA
view.setValidAdSizes(adSizes);
}

@ReactProp(name = PROP_CUSTOM_TARGETING)
public void setCustomTargeting(final ReactPublisherAdView view, final ReadableMap customTargeting) {
view.setCustomTargeting(customTargeting);
}

@ReactProp(name = PROP_AD_UNIT_ID)
public void setPropAdUnitID(final ReactPublisherAdView view, final String adUnitID) {
view.setAdUnitID(adUnitID);
Expand Down
Loading