2
0
mirror of synced 2025-02-02 09:34:45 +00:00

[js][ios][android][messaging] full implementation of upstream send including RemoteMessage builder

This commit is contained in:
Salakar 2017-03-30 16:25:27 +01:00
parent 48e57d2065
commit 91e9263965
5 changed files with 129 additions and 70 deletions

View File

@ -156,35 +156,30 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule implements L
} }
@ReactMethod @ReactMethod
public void send(String senderId, ReadableMap payload) throws Exception { public void send(ReadableMap remoteMessage) {
FirebaseMessaging fm = FirebaseMessaging.getInstance(); FirebaseMessaging fm = FirebaseMessaging.getInstance();
RemoteMessage.Builder message = new RemoteMessage.Builder(senderId + "@gcm.googleapis.com") RemoteMessage.Builder message = new RemoteMessage.Builder(remoteMessage.getString("sender"));
.setMessageId(UUID.randomUUID().toString());
ReadableMapKeySetIterator iterator = payload.keySetIterator(); message.setTtl(remoteMessage.getInt("ttl"));
message.setMessageId(remoteMessage.getString("id"));
message.setMessageType(remoteMessage.getString("type"));
if (remoteMessage.hasKey("collapseKey")) {
message.setCollapseKey(remoteMessage.getString("collapseKey"));
}
// get data keys and values and add to builder
// js side ensures all data values are strings
// so no need to check types
ReadableMap data = remoteMessage.getMap("data");
ReadableMapKeySetIterator iterator = data.keySetIterator();
while (iterator.hasNextKey()) { while (iterator.hasNextKey()) {
String key = iterator.nextKey(); String key = iterator.nextKey();
String value = getStringFromReadableMap(payload, key); String value = data.getString(key);
message.addData(key, value); message.addData(key, value);
} }
fm.send(message.build());
}
private String getStringFromReadableMap(ReadableMap map, String key) throws Exception { fm.send(message.build());
switch (map.getType(key)) {
case String:
return map.getString(key);
case Number:
try {
return String.valueOf(map.getInt(key));
} catch (Exception e) {
return String.valueOf(map.getDouble(key));
}
case Boolean:
return String.valueOf(map.getBoolean(key));
default:
throw new Exception("Unknown data type: " + map.getType(key).name() + " for message key " + key);
}
} }
private void registerMessageHandler() { private void registerMessageHandler() {

View File

@ -278,7 +278,7 @@ RCT_EXPORT_METHOD(requestPermissions:(RCTPromiseResolveBlock)resolve rejecter:(R
[[UNUserNotificationCenter currentNotificationCenter] [[UNUserNotificationCenter currentNotificationCenter]
requestAuthorizationWithOptions:authOptions requestAuthorizationWithOptions:authOptions
completionHandler:^(BOOL granted, NSError * _Nullable error) { completionHandler:^(BOOL granted, NSError * _Nullable error) {
resolve(@{@"granted":@(granted)}); resolve(@{@"granted":@(granted)});
} }
]; ];
#endif #endif
@ -408,23 +408,12 @@ RCT_EXPORT_METHOD(getBadgeNumber: (RCTPromiseResolveBlock)resolve rejecter:(RCTP
resolve(@([RCTSharedApplication() applicationIconBadgeNumber])); resolve(@([RCTSharedApplication() applicationIconBadgeNumber]));
} }
RCT_EXPORT_METHOD(send:(NSString*)senderId withPayload:(NSDictionary *)message) RCT_EXPORT_METHOD(send:(NSDictionary *)remoteMessage) {
{ int64_t ttl = @([[remoteMessage valueForKey:@"ttl"] intValue]).doubleValue;
NSMutableDictionary * mMessage = [message mutableCopy]; NSString * mId = [[remoteMessage valueForKey:@"id"] stringValue];
NSMutableDictionary * upstreamMessage = [[NSMutableDictionary alloc] init]; NSString * receiver = [[remoteMessage valueForKey:@"senderId"] stringValue];
for (NSString* key in mMessage) { NSDictionary * data = [[remoteMessage valueForKey:@"data"] dictionaryRepresentation];
upstreamMessage[key] = [NSString stringWithFormat:@"%@", [mMessage valueForKey:key]]; [[FIRMessaging messaging]sendMessage:data to:receiver withMessageID:mId timeToLive:ttl];
}
NSDictionary *imMessage = [NSDictionary dictionaryWithDictionary:upstreamMessage];
int64_t ttl = 3600;
NSString * receiver = [NSString stringWithFormat:@"%@@gcm.googleapis.com", senderId];
NSUUID *uuid = [NSUUID UUID];
NSString * messageID = [uuid UUIDString];
[[FIRMessaging messaging]sendMessage:imMessage to:receiver withMessageID:messageID timeToLive:ttl];
} }
RCT_EXPORT_METHOD(finishRemoteNotification: (NSString *)completionHandlerId fetchResult:(UIBackgroundFetchResult)result){ RCT_EXPORT_METHOD(finishRemoteNotification: (NSString *)completionHandlerId fetchResult:(UIBackgroundFetchResult)result){

View File

@ -11,7 +11,7 @@ import { isObject } from './utils';
import Auth, { statics as AuthStatics } from './modules/auth'; import Auth, { statics as AuthStatics } from './modules/auth';
import Storage, { statics as StorageStatics } from './modules/storage'; import Storage, { statics as StorageStatics } from './modules/storage';
import Database, { statics as DatabaseStatics } from './modules/database'; import Database, { statics as DatabaseStatics } from './modules/database';
import Messaging from './modules/messaging'; import Messaging, { statics as MessagingStatics } from './modules/messaging';
import Analytics from './modules/analytics'; import Analytics from './modules/analytics';
import Crash from './modules/crash'; import Crash from './modules/crash';
@ -49,16 +49,16 @@ export default class Firebase {
this._log = new Log('firebase'); this._log = new Log('firebase');
this._auth = new Auth(this, this.options);
if (this.options.errorOnMissingPlayServices && !this.googleApiAvailability.isAvailable) { if (this.options.errorOnMissingPlayServices && !this.googleApiAvailability.isAvailable) {
throw new Error(`Google Play Services is required to run this application but no valid installation was found (Code ${this.googleApiAvailability.status}).`); throw new Error(`Google Play Services is required to run this application but no valid installation was found (Code ${this.googleApiAvailability.status}).`);
} }
this.auth = this._staticsOrInstance('auth', StorageStatics, Auth); this.auth = this._staticsOrInstance('auth', AuthStatics, Auth);
this.storage = this._staticsOrInstance('storage', StorageStatics, Storage); this.storage = this._staticsOrInstance('storage', StorageStatics, Storage);
this.database = this._staticsOrInstance('database', DatabaseStatics, Database); this.database = this._staticsOrInstance('database', DatabaseStatics, Database);
this.messaging = this._staticsOrInstance('messaging', MessagingStatics, Messaging);
// init auth to stat listeners // init auth to start listeners
this.auth(); this.auth();
} }
@ -92,13 +92,6 @@ export default class Firebase {
return this._analytics; return this._analytics;
} }
messaging() {
if (!this._messaging) {
this._messaging = new Messaging(this);
}
return this._messaging;
}
crash() { crash() {
if (!this._crash) { if (!this._crash) {
this._crash = new Crash(this); this._crash = new Crash(this);
@ -146,7 +139,6 @@ export default class Firebase {
}; };
Object.assign(getInstance, statics || {}); Object.assign(getInstance, statics || {});
return getInstance; return getInstance;
} }
} }

View File

@ -0,0 +1,80 @@
import { isObject, generatePushID } from './../../utils';
export default class RemoteMessage {
constructor(sender: String) {
this.properties = {
id: generatePushID(),
ttl: 3600,
// add the googleapis sender id part if not already added.
sender: sender.includes('@') ? sender : `${sender}@gcm.googleapis.com`,
type: 'remote',
data: {},
};
}
/**
*
* @param ttl
* @returns {RemoteMessage}
*/
setTtl(ttl: Number): RemoteMessage {
this.properties.ttl = ttl;
return this;
}
/**
*
* @param id
*/
setId(id: string): RemoteMessage {
this.properties.id = id;
return this;
}
/**
*
* @param type
* @returns {RemoteMessage}
*/
setType(type: string): RemoteMessage {
this.properties.type = type;
return this;
}
/**
*
* @param key
* @returns {RemoteMessage}
*/
setCollapseKey(key: string): RemoteMessage {
this.properties.collapseKey = key;
return this;
}
/**
*
* @param data
* @returns {RemoteMessage}
*/
setData(data: Object = {}) {
if (!isObject(data)) {
throw new Error(`RemoteMessage:setData expects an object as the first parameter but got type '${typeof data}'.`);
}
const props = Object.keys(data);
// coerce all property values to strings as
// remote message data only supports strings
for (let i = 0, len = props.length; i < len; i++) {
const prop = props[i];
this.properties.data[prop] = `${data[prop]}`;
}
return this;
}
toJSON() {
return Object.assign({}, this.properties);
}
}

View File

@ -1,40 +1,32 @@
import { NativeModules, DeviceEventEmitter, Platform } from 'react-native'; import { NativeModules, DeviceEventEmitter, Platform } from 'react-native';
import { Base } from './../base'; import { Base } from './../base';
import RemoteMessage from './RemoteMessage';
const FirebaseMessaging = NativeModules.RNFirebaseMessaging; const FirebaseMessaging = NativeModules.RNFirebaseMessaging;
export const EVENT_TYPE = { const EVENT_TYPE = {
RefreshToken: 'FCMTokenRefreshed', RefreshToken: 'FCMTokenRefreshed',
Notification: 'FCMNotificationReceived', Notification: 'FCMNotificationReceived',
}; };
export const NOTIFICATION_TYPE = { const NOTIFICATION_TYPE = {
Remote: 'remote_notification', Remote: 'remote_notification',
NotificationResponse: 'notification_response', NotificationResponse: 'notification_response',
WillPresent: 'will_present_notification', WillPresent: 'will_present_notification',
Local: 'local_notification', Local: 'local_notification',
}; };
export const REMOTE_NOTIFICATION_RESULT = { const REMOTE_NOTIFICATION_RESULT = {
NewData: 'UIBackgroundFetchResultNewData', NewData: 'UIBackgroundFetchResultNewData',
NoData: 'UIBackgroundFetchResultNoData', NoData: 'UIBackgroundFetchResultNoData',
ResultFailed: 'UIBackgroundFetchResultFailed', ResultFailed: 'UIBackgroundFetchResultFailed',
}; };
export const WILL_PRESENT_RESULT = { const WILL_PRESENT_RESULT = {
All: 'UNNotificationPresentationOptionAll', All: 'UNNotificationPresentationOptionAll',
None: 'UNNotificationPresentationOptionNone', None: 'UNNotificationPresentationOptionNone',
}; };
type RemoteMessage = {
id: string,
type: string,
ttl?: number,
sender: string,
collapseKey?: string,
data: Object,
};
/** /**
* IOS only finish function * IOS only finish function
* @param data * @param data
@ -246,10 +238,21 @@ export default class Messaging extends Base {
/** /**
* Send an upstream message * Send an upstream message
* @param senderId * @param remoteMessage
* @param payload
*/ */
send(senderId, payload: RemoteMessage) { send(remoteMessage: RemoteMessage) {
return FirebaseMessaging.send(senderId, payload); if (!(remoteMessage instanceof RemoteMessage)) {
throw new Error('messaging().send requires an instance of RemoteMessage as the first argument.');
}
return FirebaseMessaging.send(remoteMessage.toJSON());
} }
} }
export const statics = {
EVENT_TYPE,
NOTIFICATION_TYPE,
REMOTE_NOTIFICATION_RESULT,
WILL_PRESENT_RESULT,
RemoteMessage,
};