Merge pull request #131 from invertase/admob

Admob -> v2 Branch
This commit is contained in:
Michael Diarmid
2017-05-27 13:23:37 +01:00
committed by GitHub
18 changed files with 1050 additions and 55 deletions

View File

@@ -0,0 +1,22 @@
export default class AdRequest {
constructor() {
this._props = {
keywords: [],
};
}
build() {
return this._props;
}
addTestDevice() {
this._props.testDevice = true;
return this;
}
addKeyword(word: string) {
this._props.keywords.push(word);
return this;
}
}

View File

@@ -0,0 +1,82 @@
import React, { PropTypes } from 'react';
import { requireNativeComponent, View } from 'react-native';
import { statics } from './';
import { nativeToJSError } from '../../utils';
class Banner extends React.Component {
static propTypes = {
...View.propTypes,
// TODO ehesp: cant init this outside of the component; statics isn't defined
...(() => {
const eventProps = {};
Object.keys(statics.EventTypes).forEach((key) => {
eventProps[key] = PropTypes.func;
});
return eventProps;
}),
size: PropTypes.string,
unitId: PropTypes.string,
testing: PropTypes.bool,
};
static defaultProps = {
size: 'SMART_BANNER',
unitId: 'ca-app-pub-3940256099942544/6300978111', // Testing
testing: true,
};
constructor() {
super();
this.state = {
width: 0,
height: 0,
};
}
/**
* Handle a single banner event and pass to
* any props watching it
* @param nativeEvent
*/
onBannerEvent = ({ nativeEvent }) => {
if (this.props[nativeEvent.type]) {
if (nativeEvent.type === 'onAdFailedToLoad') {
const { code, message } = nativeEvent.payload;
this.props[nativeEvent.type](nativeToJSError(code, message));
} else {
this.props[nativeEvent.type](nativeEvent.payload || {});
}
}
if (nativeEvent.type === 'onSizeChange') this.updateSize(nativeEvent.payload);
};
/**
* Handle a native onSizeChange event
* @param width
* @param height
*/
updateSize = ({ width, height }) => {
this.setState({ width, height });
};
/**
* Render the native component
* @returns {XML}
*/
render() {
return (
<RNFirebaseAdMobBanner
{...this.props}
style={[this.props.style, { ...this.state }]}
bannerEvent={this.onBannerEvent}
/>
);
}
}
const RNFirebaseAdMobBanner = requireNativeComponent('RNFirebaseAdMobBanner', Banner);
export default Banner;

View File

@@ -0,0 +1,82 @@
import { NativeModules } from 'react-native';
import { statics } from './';
import { nativeToJSError } from '../../utils';
const FirebaseAdMob = NativeModules.RNFirebaseAdmob;
export default class Interstitial {
constructor(admob: Object, adunit: string) {
this.admob = admob;
this.adUnit = adunit;
this.loaded = false;
this.admob.on(`interstitial_${adunit}`, this._onInterstitialEvent.bind(this));
}
/**
* Handle a JS emit event
* @param event
* @private
*/
_onInterstitialEvent(event) {
const eventType = `interstitial:${this.adUnit}:${event.type}`;
let emitData = Object.assign({}, event);
switch (event.type) {
case 'onAdLoaded':
this.loaded = true;
break;
case 'onAdFailedToLoad':
emitData = nativeToJSError(event.payload.code, event.payload.message);
emitData.type = event.type;
break;
default:
}
this.admob.emit(eventType, emitData);
this.admob.emit(`interstitial:${this.adUnit}:*`, emitData);
}
/**
* Load an ad with an instance of AdRequest
* @param request
* @returns {*}
*/
loadAd(request: AdRequest) {
return FirebaseAdMob.interstitialLoadAd(this.adUnit, request);
}
/**
* Return a local instance of isLoaded
* @returns {boolean}
*/
isLoaded() {
return this.loaded;
}
/**
* Show the advert - will only show if loaded
* @returns {*}
*/
show() {
if (this.loaded) {
FirebaseAdMob.interstitialShowAd(this.adUnit);
}
}
/**
* Listen to an Ad event
* @param eventType
* @param listenerCb
* @returns {null}
*/
on(eventType, listenerCb) {
if (!statics.EventTypes[eventType]) {
console.warn(`Invalid event type provided, must be one of: ${Object.keys(statics.EventTypes).join(', ')}`);
return null;
}
return this.admob.on(`interstitial:${this.adUnit}:${eventType}`, listenerCb);
}
}

View File

@@ -0,0 +1,56 @@
import { NativeModules, NativeEventEmitter } from 'react-native';
import Interstitial from './Interstitial';
import AdRequest from './AdRequest';
import Banner from './Banner';
import { Base } from './../base';
const FirebaseAdMob = NativeModules.RNFirebaseAdMob;
const FirebaseAdMobEvt = new NativeEventEmitter(FirebaseAdMob);
export default class Admob extends Base {
constructor() {
super();
FirebaseAdMobEvt.addListener('interstitial_event', this._onInterstitialEvent.bind(this));
}
_onInterstitialEvent(event) {
const { adunit } = event;
const jsEventType = `interstitial_${adunit}`;
if (!this.hasListeners(jsEventType)) {
// TODO
}
this.emit(jsEventType, event);
}
interstitial(adUnit: string) {
return new Interstitial(this, adUnit);
}
static get statics() {
return statics;
}
}
export const statics = {
Banner,
AdRequest,
EventTypes: {
onAdLoaded: 'onAdLoaded',
onAdOpened: 'onAdOpened',
onAdLeftApplication: 'onAdLeftApplication',
onAdClosed: 'onAdClosed',
onAdFailedToLoad: 'onAdFailedToLoad',
},
RewardedEventTypes: {
onRewarded: 'onRewarded',
onRewardedVideoAdLeftApplication: 'onRewardedVideoAdLeftApplication',
onRewardedVideoAdClosed: 'onRewardedVideoAdClosed',
onRewardedVideoAdFailedToLoad: 'onRewardedVideoAdFailedToLoad',
onRewardedVideoAdLoaded: 'onRewardedVideoAdLoaded',
onRewardedVideoAdOpened: 'onRewardedVideoAdOpened',
onRewardedVideoStarted: 'onRewardedVideoStarted',
},
};

View File

@@ -1,25 +1,14 @@
/**
* @flow
*/
import { NativeModules, NativeEventEmitter } from 'react-native';
import EventEmitter from 'EventEmitter';
import Log from '../utils/log';
import EventEmitter from './../utils/eventEmitter';
const FirebaseModule = NativeModules.RNFirebase;
const FirebaseModuleEvt = new NativeEventEmitter(FirebaseModule);
const logs = {};
const SharedEventEmitter = new EventEmitter();
type FirebaseOptions = {};
export class Base extends EventEmitter {
constructor(firebase: Object, options: FirebaseOptions = {}) {
super();
this.firebase = firebase;
this.eventHandlers = {};
this.options = Object.assign({}, firebase.options, options);
}
export class Base {
/**
* Return a namespaced instance of Log
@@ -27,52 +16,53 @@ export class Base extends EventEmitter {
*/
get log(): Log {
if (logs[this.namespace]) return logs[this.namespace];
return logs[this.namespace] = new Log(this.namespace, this.firebase._debug);
// todo grab log level from global config provider (still todo);
return logs[this.namespace] = new Log(this.namespace, '*');
}
/**
* app instance
**/
get app(): Object {
return this.firebase.app;
}
/**
* Add a native module event subscription
* @param name
* @param handler
* @param nativeModule
* @returns {*}
* @private
/*
* Proxy functions to shared event emitter instance
* https://github.com/facebook/react-native/blob/master/Libraries/EventEmitter/EventEmitter.js
*/
_on(name, handler, nativeModule) {
let _nativeModule = nativeModule;
if (!_nativeModule) {
_nativeModule = FirebaseModuleEvt;
}
return this.eventHandlers[name] = _nativeModule.addListener(name, handler);
get sharedEventEmitter () {
return SharedEventEmitter;
}
/**
* Remove a native module event subscription
* @param name
* @private
*/
_off(name): void {
const subscription = this.eventHandlers[name];
if (!subscription) return;
get addListener() {
return SharedEventEmitter.addListener.bind(SharedEventEmitter);
}
subscription.remove();
delete this.eventHandlers[name];
get on() {
return SharedEventEmitter.addListener.bind(SharedEventEmitter);
}
get emit() {
return SharedEventEmitter.emit.bind(SharedEventEmitter);
}
get listeners() {
return SharedEventEmitter.listeners.bind(SharedEventEmitter);
}
hasListeners(eventType: string): Boolean {
const subscriptions = SharedEventEmitter._subscriber.getSubscriptionsForType(eventType);
return subscriptions && subscriptions.length;
}
get removeListener() {
return SharedEventEmitter.removeListener.bind(SharedEventEmitter);
}
get removeAllListeners() {
return SharedEventEmitter.removeAllListeners.bind(SharedEventEmitter);
}
}
export class ReferenceBase extends Base {
constructor(firebase: Object, path: string) {
super(firebase);
constructor(path: string) {
super();
this.path = path || '/';
}