Skip to content

Commit 1108901

Browse files
committed
add cloud messaging for android
1 parent 291f6a2 commit 1108901

File tree

8 files changed

+442
-13
lines changed

8 files changed

+442
-13
lines changed

README.md

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public class MainApplication extends Application implements ReactApplication {
127127
protected List<ReactPackage> getPackages() {
128128
return Arrays.<ReactPackage>asList(
129129
new MainReactPackage(),
130-
new FirestackPackage()
130+
new FirestackPackage(getApplicationContext())
131131
);
132132
}
133133
};
@@ -143,6 +143,22 @@ dependencies {
143143
}
144144
```
145145

146+
Add to `AndroidManifest.xml` file
147+
```diff
148+
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
149+
+ <service android:name="io.fullstack.firestack.FirestackMessagingService">
150+
+ <intent-filter>
151+
+ <action android:name="com.google.firebase.MESSAGING_EVENT"/>
152+
+ </intent-filter>
153+
+ </service>
154+
155+
+ <service android:name="io.fullstack.firestack.FirestackInstanceIdService" android:exported="false">
156+
+ <intent-filter>
157+
+ <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
158+
+ </intent-filter>
159+
+ </service>
160+
```
161+
146162
## Firebase setup
147163

148164
The Firestack library is intended on making it easy to work with [Firebase](https://firebase.google.com/) and provides a small native shim to the Firebase native code.
@@ -667,6 +683,58 @@ Firebase provides some static values based upon the server. We can use the `Serv
667683
const timestamp = firestack.ServerValue.TIMESTAMP
668684
```
669685

686+
### Cloud Messaging
687+
688+
Access the device registration token
689+
690+
```javascript
691+
firestack.cloudMessaging.getToken().then(function (token) {
692+
console.log('device token', token);
693+
});
694+
```
695+
696+
Monitor token generation
697+
698+
```javascript
699+
// add listener
700+
firestack.cloudMessaging.listenForTokenRefresh(function (token) {
701+
console.log('refresh device token', token);
702+
});
703+
704+
// remove listener
705+
firestack.cloudMessaging.unlistenForTokenRefresh();
706+
```
707+
708+
Subscribe to topic
709+
710+
```javascript
711+
firestack.cloudMessaging.subscribeToTopic("topic_name").then(function (topic) {
712+
console.log('Subscribe:'+topic);
713+
}).catch(function(err){
714+
console.error(err);
715+
});
716+
```
717+
718+
Unsubscribe from topic
719+
720+
```javascript
721+
firestack.cloudMessaging.unsubscribeFromTopic("topic_name").then(function (topic) {
722+
console.log('unsubscribe:'+topic);
723+
}).catch(function(err){
724+
console.error(err);
725+
});
726+
```
727+
728+
Receive Messages
729+
730+
```javascript
731+
firestack.cloudMessaging.listenForReceiveNotification((msg) =>{
732+
console.log('Receive Messages:'+msg.data);
733+
console.log('Receive Messages:'+msg.notification);
734+
735+
});
736+
```
737+
670738
### Events
671739

672740
#### on()

android/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ dependencies {
2424
compile 'com.google.firebase:firebase-analytics:9.4.0'
2525
compile 'com.google.firebase:firebase-database:9.4.0'
2626
compile 'com.google.firebase:firebase-storage:9.4.0'
27+
compile 'com.google.firebase:firebase-messaging:9.4.0'
2728
}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
package io.fullstack.firestack;
2+
3+
import java.util.Map;
4+
5+
import android.content.Context;
6+
import android.content.IntentFilter;
7+
import android.content.Intent;
8+
import android.content.BroadcastReceiver;
9+
import android.util.Log;
10+
11+
import com.facebook.react.bridge.Arguments;
12+
import com.facebook.react.bridge.Callback;
13+
import com.facebook.react.bridge.ReactApplicationContext;
14+
import com.facebook.react.bridge.ReactContext;
15+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
16+
import com.facebook.react.bridge.Promise;
17+
import com.facebook.react.bridge.ReactMethod;
18+
import com.facebook.react.bridge.ReadableMap;
19+
import com.facebook.react.bridge.ReadableMapKeySetIterator;
20+
import com.facebook.react.bridge.ReadableType;
21+
import com.facebook.react.bridge.WritableMap;
22+
23+
import com.google.firebase.iid.FirebaseInstanceId;
24+
import com.google.firebase.messaging.FirebaseMessaging;
25+
import com.google.firebase.messaging.RemoteMessage;
26+
27+
/**
28+
* Created by nori on 2016/09/12.
29+
*/
30+
public class FirestackCloudMessaging extends ReactContextBaseJavaModule {
31+
32+
private static final String TAG = "FirestackCloudMessaging";
33+
private static final String EVENT_NAME_TOKEN = "FirestackRefreshToken";
34+
private static final String EVENT_NAME_NOTIFICATION = "FirestackReceiveNotification";
35+
private static final String EVENT_NAME_SEND = "FirestackUpstreamSend";
36+
37+
public static final String INTENT_NAME_TOKEN = "io.fullstack.firestack.refreshToken";
38+
public static final String INTENT_NAME_NOTIFICATION = "io.fullstack.firestack.ReceiveNotification";
39+
public static final String INTENT_NAME_SEND = "io.fullstack.firestack.Upstream";
40+
41+
private ReactContext mReactContext;
42+
private IntentFilter mRefreshTokenIntentFilter;
43+
private IntentFilter mReceiveNotificationIntentFilter;
44+
private IntentFilter mReceiveSendIntentFilter;
45+
46+
public FirestackCloudMessaging(ReactApplicationContext reactContext) {
47+
super(reactContext);
48+
mReactContext = reactContext;
49+
mRefreshTokenIntentFilter = new IntentFilter(INTENT_NAME_TOKEN);
50+
mReceiveNotificationIntentFilter = new IntentFilter(INTENT_NAME_NOTIFICATION);
51+
mReceiveSendIntentFilter = new IntentFilter(INTENT_NAME_SEND);
52+
initRefreshTokenHandler();
53+
initMessageHandler();
54+
initSendHandler();
55+
Log.d(TAG, "New instance");
56+
}
57+
58+
@Override
59+
public String getName() {
60+
return TAG;
61+
}
62+
63+
@ReactMethod
64+
public void getToken(final Callback callback) {
65+
66+
try {
67+
String token = FirebaseInstanceId.getInstance().getToken();
68+
Log.d(TAG, "Firebase token: " + token);
69+
callback.invoke(null, token);
70+
} catch (Exception e) {
71+
WritableMap error = Arguments.createMap();
72+
error.putString("message", e.getMessage());
73+
callback.invoke(error);
74+
}
75+
}
76+
77+
/**
78+
*
79+
*/
80+
private void initRefreshTokenHandler() {
81+
getReactApplicationContext().registerReceiver(new BroadcastReceiver() {
82+
@Override
83+
public void onReceive(Context context, Intent intent) {
84+
WritableMap params = Arguments.createMap();
85+
params.putString("token", intent.getStringExtra("token"));
86+
FirestackUtils.sendEvent(mReactContext, EVENT_NAME_TOKEN, params);
87+
88+
}
89+
90+
;
91+
}, mRefreshTokenIntentFilter);
92+
}
93+
94+
@ReactMethod
95+
public void subscribeToTopic(String topic, final Callback callback) {
96+
try {
97+
FirebaseMessaging.getInstance().subscribeToTopic(topic);
98+
callback.invoke(null,topic);
99+
} catch (Exception e) {
100+
e.printStackTrace();
101+
Log.d(TAG, "Firebase token: " + e);
102+
WritableMap error = Arguments.createMap();
103+
error.putString("message", e.getMessage());
104+
callback.invoke(error);
105+
106+
}
107+
}
108+
109+
@ReactMethod
110+
public void unsubscribeFromTopic(String topic, final Callback callback) {
111+
try {
112+
FirebaseMessaging.getInstance().unsubscribeFromTopic(topic);
113+
callback.invoke(null,topic);
114+
} catch (Exception e) {
115+
WritableMap error = Arguments.createMap();
116+
error.putString("message", e.getMessage());
117+
callback.invoke(error);
118+
}
119+
}
120+
121+
private void initMessageHandler() {
122+
getReactApplicationContext().registerReceiver(new BroadcastReceiver() {
123+
@Override
124+
public void onReceive(Context context, Intent intent) {
125+
RemoteMessage remoteMessage = intent.getParcelableExtra("data");
126+
Log.d(TAG, "Firebase onReceive: " + remoteMessage);
127+
WritableMap params = Arguments.createMap();
128+
if (remoteMessage.getData().size() != 0) {
129+
WritableMap dataMap = Arguments.createMap();
130+
Map<String, String> data = remoteMessage.getData();
131+
//Set<String> keysIterator = data.keySet();
132+
for (String key : data.keySet()) {
133+
dataMap.putString(key, data.get(key));
134+
}
135+
params.putMap("data", dataMap);
136+
} else {
137+
params.putNull("data");
138+
}
139+
if (remoteMessage.getNotification() != null) {
140+
WritableMap notificationMap = Arguments.createMap();
141+
RemoteMessage.Notification notification = remoteMessage.getNotification();
142+
notificationMap.putString("title", notification.getTitle());
143+
notificationMap.putString("body", notification.getBody());
144+
notificationMap.putString("icon", notification.getIcon());
145+
notificationMap.putString("sound", notification.getSound());
146+
notificationMap.putString("tag", notification.getTag());
147+
params.putMap("notification", notificationMap);
148+
} else {
149+
params.putNull("notification");
150+
}
151+
FirestackUtils.sendEvent(mReactContext, EVENT_NAME_NOTIFICATION, params);
152+
}
153+
}, mReceiveNotificationIntentFilter);
154+
}
155+
156+
@ReactMethod
157+
public void send(String senderId, Integer messageId, String messageType, ReadableMap params) {
158+
FirebaseMessaging fm = FirebaseMessaging.getInstance();
159+
RemoteMessage.Builder remoteMessage = new RemoteMessage.Builder(senderId);
160+
remoteMessage.setMessageId(messageId.toString());
161+
remoteMessage.setMessageType(messageType);
162+
ReadableMapKeySetIterator iterator = params.keySetIterator();
163+
while (iterator.hasNextKey()) {
164+
String key = iterator.nextKey();
165+
ReadableType type = params.getType(key);
166+
if (type == ReadableType.String) {
167+
remoteMessage.addData(key, params.getString(key));
168+
Log.d(TAG, "Firebase send: " + key);
169+
Log.d(TAG, "Firebase send: " + params.getString(key));
170+
}
171+
}
172+
fm.send(remoteMessage.build());
173+
}
174+
175+
private void initSendHandler() {
176+
getReactApplicationContext().registerReceiver(new BroadcastReceiver() {
177+
@Override
178+
public void onReceive(Context context, Intent intent) {
179+
WritableMap params = Arguments.createMap();
180+
if (intent.getBooleanExtra("hasError", false)) {
181+
WritableMap error = Arguments.createMap();
182+
error.putInt("code", intent.getIntExtra("errCode", 0));
183+
error.putString("message", intent.getStringExtra("errorMessage"));
184+
params.putMap("err", error);
185+
} else {
186+
params.putNull("err");
187+
}
188+
FirestackUtils.sendEvent(mReactContext, EVENT_NAME_SEND, params);
189+
}
190+
}, mReceiveSendIntentFilter);
191+
}
192+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.fullstack.firestack;
2+
3+
/**
4+
* Created by nori on 2016/09/12.
5+
*/
6+
import android.content.Intent;
7+
import android.os.Bundle;
8+
import android.util.Log;
9+
10+
import com.google.firebase.iid.FirebaseInstanceId;
11+
import com.google.firebase.iid.FirebaseInstanceIdService;
12+
13+
public class FirestackInstanceIdService extends FirebaseInstanceIdService {
14+
15+
private static final String TAG = "FSInstanceIdService";
16+
17+
/**
18+
*
19+
*/
20+
@Override
21+
public void onTokenRefresh() {
22+
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
23+
Log.d(TAG, "Refreshed token: " + refreshedToken);
24+
25+
26+
// send Intent
27+
Intent i = new Intent(FirestackCloudMessaging.INTENT_NAME_TOKEN);
28+
Bundle bundle = new Bundle();
29+
bundle.putString("token", refreshedToken);
30+
i.putExtras(bundle);
31+
sendBroadcast(i);
32+
}
33+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package io.fullstack.firestack;
2+
3+
import android.content.Intent;
4+
import android.util.Log;
5+
6+
import com.google.firebase.messaging.FirebaseMessagingService;
7+
import com.google.firebase.messaging.RemoteMessage;
8+
import com.google.firebase.messaging.SendException;
9+
10+
public class FirestackMessagingService extends FirebaseMessagingService {
11+
12+
private static final String TAG = "FSMessagingService";
13+
14+
@Override
15+
public void onMessageReceived(RemoteMessage remoteMessage) {
16+
Log.d(TAG, "Remote message received");
17+
// debug
18+
Log.d(TAG, "From: " + remoteMessage.getFrom());
19+
if (remoteMessage.getData().size() > 0) {
20+
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
21+
}
22+
if (remoteMessage.getNotification() != null) {
23+
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
24+
}
25+
if (remoteMessage.getNotification() != null) {
26+
27+
}
28+
Intent i = new Intent(FirestackCloudMessaging.INTENT_NAME_NOTIFICATION);
29+
i.putExtra("data", remoteMessage);
30+
sendOrderedBroadcast(i, null);
31+
32+
}
33+
34+
@Override
35+
public void onMessageSent(String msgId) {
36+
// Called when an upstream message has been successfully sent to the GCM connection server.
37+
Log.d(TAG, "upstream message has been successfully sent");
38+
Intent i = new Intent(FirestackCloudMessaging.INTENT_NAME_SEND);
39+
i.putExtra("msgId", msgId);
40+
sendOrderedBroadcast(i, null);
41+
}
42+
43+
@Override
44+
public void onSendError(String msgId, Exception exception) {
45+
// Called when there was an error sending an upstream message.
46+
Log.d(TAG, "error sending an upstream message");
47+
Intent i = new Intent(FirestackCloudMessaging.INTENT_NAME_SEND);
48+
i.putExtra("msgId", msgId);
49+
i.putExtra("hasError", true);
50+
SendException sendException = (SendException) exception;
51+
i.putExtra("errorCode", sendException.getErrorCode());
52+
switch(sendException.getErrorCode()){
53+
case SendException.ERROR_INVALID_PARAMETERS:
54+
i.putExtra("errorMessage", "Message was sent with invalid parameters.");
55+
break;
56+
case SendException.ERROR_SIZE:
57+
i.putExtra("errorMessage", "Message exceeded the maximum payload size.");
58+
break;
59+
case SendException.ERROR_TOO_MANY_MESSAGES:
60+
i.putExtra("errorMessage", "App has too many pending messages so this one was dropped.");
61+
break;
62+
case SendException.ERROR_TTL_EXCEEDED:
63+
i.putExtra("errorMessage", "Message time to live (TTL) was exceeded before the message could be sent.");
64+
break;
65+
case SendException.ERROR_UNKNOWN:
66+
default:
67+
i.putExtra("errorMessage", "Unknown error.");
68+
break;
69+
}
70+
sendOrderedBroadcast(i, null);
71+
}
72+
}

0 commit comments

Comments
 (0)