├── .gitignore ├── LICENSE ├── RCTRealtimeMessagingAndroid.js ├── README.md ├── package.json └── reactnativemessagingandroid ├── build.gradle ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml ├── java └── co │ └── realtime │ └── reactnativemessagingandroid │ ├── GcmReceiver.java │ ├── RealtimeMessagingAndroid.java │ ├── RealtimeMessagingPackage.java │ └── RealtimePushNotificationActivity.java └── res └── values └── strings.xml /.gitignore: -------------------------------------------------------------------------------- 1 | reactnativemessagingandroid/.idea/.name 2 | reactnativemessagingandroid/.idea/compiler.xml 3 | reactnativemessagingandroid/.idea/encodings.xml 4 | reactnativemessagingandroid/.idea/gradle.xml 5 | reactnativemessagingandroid/.idea/misc.xml 6 | reactnativemessagingandroid/.idea/modules.xml 7 | .idea/.name 8 | .idea/compiler.xml 9 | .idea/encodings.xml 10 | .idea/misc.xml 11 | .idea/modules.xml 12 | .idea/RCTRealtimeMessagingAndroid.iml 13 | .idea/vcs.xml 14 | reactnativemessagingandroid/.gitignore 15 | reactnativemessagingandroid/reactnativemessagingandroid.iml 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Realtime Framework 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /RCTRealtimeMessagingAndroid.js: -------------------------------------------------------------------------------- 1 | // Created by Joao Caixinha on 02/04/15. 2 | // Copyright (c) 2015 Realtime. All rights reserved. 3 | // 4 | 5 | /** 6 | * @providesModule RCTRealtimeMessagingAndroid 7 | * @flow 8 | */ 9 | 10 | 'use strict'; 11 | 12 | import React, { Component } from 'react'; 13 | import { NativeModules } from 'react-native'; 14 | var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); 15 | var ortcClient = NativeModules.RealtimeMessagingAndroid; 16 | var RTEvents = {}; 17 | var instances = 0; 18 | 19 | class RCTRealtimeMessagingAndroid extends React.Component { 20 | id: String; 21 | 22 | RCTRealtimeMessagingAndroid(){ 23 | this.id = instances++; 24 | } 25 | constructor(props) { 26 | super(props); 27 | this.id = instances++; 28 | } 29 | 30 | RTConnect(config){ 31 | ortcClient.connect(config, this.id); 32 | } 33 | 34 | RTDisconnect(){ 35 | ortcClient.disconnect(this.id); 36 | } 37 | 38 | RTSubscribe(channel, subscribeOnReconnect: boolean){ 39 | ortcClient.subscribe(channel, subscribeOnReconnect, this.id); 40 | } 41 | 42 | RTSubscribeWithFilter(channel, subscribeOnReconnect: boolean, filter){ 43 | ortcClient.subscribeWithFilter(channel, subscribeOnReconnect, filter, this.id); 44 | } 45 | 46 | RTSubscribeWithBuffer(channel, subscriberId){ 47 | ortcClient.subscribeWithBuffer(channel, subscriberId, this.id); 48 | } 49 | 50 | RTSubscribeWithOptions(options){ 51 | ortcClient.subscribeWithOptions(options, this.id); 52 | } 53 | 54 | RTSubscribeWithNotifications(channel, subscribeOnReconnect: boolean){ 55 | ortcClient.subscribeWithNotifications(channel, subscribeOnReconnect, this.id); 56 | } 57 | 58 | RTUnsubscribe(channel){ 59 | ortcClient.unsubscribe(channel, this.id); 60 | } 61 | 62 | RTPublishMessage(channel, message, ttl, callBack){ 63 | ortcClient.publish(channel, message, ttl, this.id, callBack); 64 | } 65 | 66 | RTSendMessage(message, channel){ 67 | ortcClient.sendMessage(message, channel, this.id); 68 | } 69 | 70 | RTEnablePresence(aPrivateKey, channel, aMetadata:boolean){ 71 | ortcClient.enablePresence(aPrivateKey, channel, aMetadata, this.id); 72 | } 73 | 74 | RTDisablePresence(aPrivateKey, channel){ 75 | ortcClient.disablePresence(aPrivateKey, channel, this.id); 76 | } 77 | 78 | RTPresence(channel){ 79 | ortcClient.presence(channel, this.id); 80 | } 81 | 82 | RTIsSubscribed(channel, callBack: Function){ 83 | ortcClient.isSubscribed(channel, this.id, callBack); 84 | } 85 | 86 | // RTSaveAuthentication(url, isCluster, authenticationToken, authenticationTokenIsPrivate, applicationKey, timeToLive, privateKey, permissions, callBack: Function){ 87 | // ortcClient.saveAuthentication(url, isCluster, authenticationToken, authenticationTokenIsPrivate, applicationKey, timeToLive, privateKey, permissions, this.id, callBack); 88 | // } 89 | 90 | RTGetHeartbeatTime(callBack: Function){ 91 | ortcClient.getHeartbeatTime(this.id, callBack); 92 | } 93 | 94 | RTSetHeartbeatTime(newHeartbeatTime){ 95 | ortcClient.setHeartbeatTime(newHeartbeatTime, this.id); 96 | } 97 | 98 | RTGetHeartbeatFails(callBack: Function){ 99 | ortcClient.getHeartbeatFails(this.id, callBack); 100 | } 101 | 102 | RTSetHeartbeatFails(newHeartbeatFails){ 103 | ortcClient.setHeartbeatFails(newHeartbeatFails, this.id); 104 | } 105 | 106 | RTIsHeartbeatActive(callBack: Function){ 107 | ortcClient.isHeartbeatActive(this.id, callBack); 108 | } 109 | 110 | RTEnableHeartbeat(){ 111 | ortcClient.enableHeartbeat(this.id); 112 | } 113 | 114 | RTDisableHeartbeat(){ 115 | ortcClient.disableHeartbeat(this.id); 116 | } 117 | 118 | /* 119 | Events list 120 | - onConnected 121 | - onDisconnect 122 | - onReconnect 123 | - onReconnecting 124 | - onSubscribed 125 | - onUnSubscribed 126 | - onExcption 127 | - onMessage 128 | - onPresence 129 | - onDisablePresence 130 | - onEnablePresence 131 | */ 132 | 133 | RTPushNotificationListener(callBack: Function){ 134 | require('RCTDeviceEventEmitter').addListener( 135 | 'onPushNotification', 136 | callBack 137 | ); 138 | ortcClient.checkForNotifications(); 139 | }; 140 | 141 | 142 | RTEventListener(notification, callBack: Function){ 143 | var modNotification = String(this.id) + '-' + notification; 144 | var channelExists = RTEvents[modNotification]; 145 | if (channelExists){ 146 | this.RTRemoveEventListener(notification); 147 | } 148 | 149 | RTEvents[modNotification] = ( 150 | require('RCTDeviceEventEmitter').addListener( 151 | modNotification, 152 | callBack 153 | ) 154 | ); 155 | }; 156 | 157 | RTRemoveEventListener(notification) 158 | { 159 | var modNotification = String(this.id) + '-' + notification; 160 | RTEvents[modNotification].remove(), 161 | delete RTEvents[modNotification]; 162 | }; 163 | } 164 | 165 | module.exports = RCTRealtimeMessagingAndroid; 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Realtime Messaging SDK for React-Native Android 2 | 3 | [Realtime Cloud Messaging](http://framework.realtime.co/messaging) is a highly-scalable pub/sub message broker, allowing you to broadcast messages to millions of users, reliably and securely. It's all in the cloud so you don't need to manage servers. 4 | 5 | [React Native](http://facebook.github.io/react-native/) enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. 6 | 7 | 8 | More information can be found on the 9 | [Realtime native Android SDK reference documentation](http://messaging-public.realtime.co/documentation/android/2.1.0/index.html?ibt/ortc/api/Ortc.html). 10 | 11 | 12 | ## Installation 13 | 14 | * Create a new react-native project. [Check react-native getting started](http://facebook.github.io/react-native/docs/getting-started.html#content) 15 | 16 | * Execute 17 | 18 | npm install --save react-native-realtimemessaging-android 19 | 20 | * In `android/settings.gradle` 21 | 22 | ... 23 | include ':react-native-realtime-messaging-android' 24 | project(':react-native-realtime-messaging-android').projectDir = new File(settingsDir,'../node_modules/react-native-realtimemessaging-android/reactnativemessagingandroid') 25 | 26 | * In `android/app/build.gradle` 27 | 28 | ... 29 | dependencies { 30 | ... 31 | compile project(':react-native-realtime-messaging-android') 32 | } 33 | 34 | * Add `new RealtimeMessagingPackage()` to the `getPackages()` method return list in `MainApplication.java`. 35 | 36 | import co.realtime.reactnativemessagingandroid.RealtimeMessagingPackage; //<-- import 37 | 38 | public class MainApplication extends Application implements ReactApplication { 39 | 40 | ... 41 | 42 | @Override 43 | protected List getPackages() { 44 | return Arrays.asList( 45 | new MainReactPackage(), 46 | new RealtimeMessagingPackage() // <-- add RealtimeMessagingPackage object 47 | ); 48 | } 49 | 50 | ... 51 | 52 | 53 | 54 | 55 | * Drag `PROJECT_DIR/node_modules/react-native-realtimemessaging-android/RCTRealtimeMessagingAndroid.js` to the root of your project. 56 | 57 | * **If you want to use push notifications**, set `MainActivity` extending `RealtimePushNotificationActivity`. 58 | 59 | import co.realtime.reactnativemessagingandroid.RealtimePushNotificationActivity; 60 | 61 | public class MainActivity extends RealtimePushNotificationActivity { 62 | ... 63 | } 64 | 65 | You are ready to go. 66 | 67 | --- 68 | 69 | 70 | 71 | ## RealtimeMessagingAndroid class reference 72 | 73 | ### Import RealtimeMessaging to your project 74 | 75 | import realtime from './RCTRealtimeMessagingAndroid'; 76 | var RCTRealtimeMessaging = new realtime(); 77 | 78 | ### Event handling 79 | 80 | In order to get event notifications from the native SDK, the JavaScript interface has two methods for adding and removing event registration. 81 | 82 | **RTEventListener(notification, callBack: Function)**
83 | 84 | RTEventListener registers a given event name on the ***notification*** field and a given ***callback function*** to be fired when the event occurs. 85 | 86 | ***Example:*** 87 | 88 | import realtime from './RCTRealtimeMessagingAndroid'; 89 | var RCTRealtimeMessaging = new realtime(); 90 | 91 | RCTRealtimeMessaging.RTEventListener("onConnected",this._onConnected), 92 | 93 | **RTRemoveEventListener(notification)** 94 | 95 | RTRemoveEventListener removes an event registration. After this method when the event occurs the ***callback*** will not be fired. 96 | 97 | ***Example:*** 98 | 99 | import realtime from './RCTRealtimeMessagingAndroid'; 100 | var RCTRealtimeMessaging = new realtime(); 101 | 102 | RCTRealtimeMessaging.RTEventListener("onConnected",this._onConnected), 103 | RCTRealtimeMessaging.RTRemoveEventListener("onConnected"), 104 | 105 | 106 | 107 | ***Complete event list:*** 108 | 109 | * onConnected - Occurs when the client connects 110 | 111 | * onDisconnect - Occurs when the client disconnects 112 | 113 | * onReconnect - Occurs when the client reconnects 114 | 115 | * onReconnecting - Occurs when the client is attempting to reconnect 116 | 117 | * onSubscribed - Occurs when the client has successfully subscribed a channel. The event notification data is `{"channel":channel}` 118 | 119 | * onUnSubscribed - Occurs when the client has successfully unsubscribed a channel. The event notification data is `{"channel":channel}` 120 | 121 | * onException - Occurs when there is an exception. The event notification data is `{"error":error.localizedDescription}` 122 | 123 | * onMessage - Occurs when a message is received. The event notification data is `{"message": message,"channel": channel}` 124 | 125 | * onMessageWithFilter - Occurs when a message is received using `RTSubscribeWithFilter`. The event notification data is `{"message": message,"channel": channel, "filtered":true}`, where the filtered property indicates wheter the server was able to successfully filter the message. 126 | 127 | * onMessageWithBuffer - Fired when a message was received in the specified channel subscribed with the `RTSubscribeWithBuffer`. 128 | - channel - The channel where the message was received 129 | - seqId - The message sequence id 130 | - message - The message received 131 | 132 | * onMessageWithOptions - Fired when a message was received in the specified channel subscribed with the `RTSubscribeWithOptions` 133 | - msgOptions - Dictionary where the message data was received 134 | 135 | - 136 | msgOptions = { 137 | channel, // Channel where the message was received 138 | seqId, // The message sequence id property 139 | filtered, // Indicates if server has filtered the message 140 | message // Content of the received message 141 | } 142 | 143 | 144 | * onPresence - Gets the subscriptions in the specified channel and if active the first 100 unique connection metadata: 145 | - On success -> `{"result": result}` 146 | - On error -> `{"error": error}` 147 | 148 | * onEnablePresence - Enables presence for the specified channel with the first 100 unique connection metadata: 149 | - On success -> `{"result": result}` 150 | - On error -> `{"error": error}` 151 | 152 | * onDisablePresence - Disables presence for the specified channel: 153 | - On success -> `{"result": result}` 154 | - On error -> `{"error": error}` 155 | 156 | ### Push notification handling 157 | 158 | #### Configure your project for push notifications handling 159 | 160 | To configure your react-native project to receive push notifications you must follow [this guide](http://messaging-public.realtime.co/documentation/starting-guide/mobilePushGCM.html) for the Android platform. 161 | 162 | 163 | #### Handling push notifications through javascript 164 | 165 | For handling push notifications ( sent using the Realtime mobile push notifications REST API) we added the following event listener: 166 | 167 | * RTPushNotificationListener(callBack: Function) 168 | 169 | ***Example:*** 170 | 171 | componentDidMount: function(){ 172 | RCTRealtimeMessaging.RTCPushNotificationListener(this._onNotification); 173 | }, 174 | 175 | _onNotification: function(data) 176 | { 177 | this._log("Received notification: " + JSON.stringify(data)); 178 | }, 179 | 180 | ---------- 181 | 182 | ### Methods 183 | 184 | ##### RTConnect(config) 185 | 186 | Connects the client to Realtime server with the given configuration. 187 | 188 | **Parameters** 189 | 190 | * appkey - Realtime application key 191 | * token - Authentication token 192 | * connectionMetadata - Connection metadata string 193 | * clusterUrl or url - The Realtime Messaging cluster or server URL 194 | * projectId - The GCM project number, only required for push notifications usage 195 | 196 | ***Example:*** 197 | 198 | RCTRealtimeMessaging.RTEventListener("onConnected",function(){ 199 | console.log('Connected to Realtime Messaging'); 200 | }), 201 | 202 | RCTRealtimeMessaging.RTConnect( 203 | { 204 | appKey:this.state.appKey, 205 | token:this.state.token, 206 | connectionMetadata:this.state.connectionMetadata, 207 | clusterUrl:this.state.clusterUrl 208 | }); 209 | 210 | 211 | ---------- 212 | 213 | ##### RTDisconnect() 214 | 215 | Disconnects the client from the Realtime server. 216 | 217 | ***Example:*** 218 | 219 | RCTRealtimeMessaging.RTEventListener("onDisconnect", function(){ 220 | console.log('Disconnected from Realtime Messaging'); 221 | }), 222 | 223 | RCTRealtimeMessaging.RTDisconnect(); 224 | 225 | ---------- 226 | 227 | ##### RTSubscribe(channel, subscribeOnReconnect: boolean) 228 | 229 | Subscribes a pub/sub channel to receive messages. 230 | 231 | **Parameters** 232 | 233 | * channel - Channel name 234 | 235 | * subscribeOnReconnected - 236 | Indicates whether the client should subscribe the channel when reconnected (if it was previously subscribed when connected). 237 | 238 | ***Example:*** 239 | 240 | RCTRealtimeMessaging.RTEventListener("onSubscribed", function(subscribedEvent){ 241 | console.log('Subscribed channel: ' + subscribedEvent.channel); 242 | }), 243 | 244 | RCTRealtimeMessaging.RTSubscribe("MyChannel", true); 245 | 246 | ---------- 247 | 248 | ##### RTSubscribeWithFilter(channel, subscribeOnReconnect: boolean, filter) 249 | 250 | Subscribes a channel using a filter, to receive only messages that validate the filter. 251 | 252 | **Parameters** 253 | 254 | * channel - Channel name 255 | 256 | * subscribeOnReconnected - 257 | Indicates whether the client should subscribe to the channel when reconnected (if it was previously subscribed when connected). 258 | 259 | * filter - Filter to apply to messages 260 | 261 | ***Example:*** 262 | 263 | RCTRealtimeMessaging.RTSubscribeWithFilter("MyChannel", true, "message.a = 1"); 264 | 265 | ---------- 266 | 267 | ##### RTSubscribeWithOptions(options) 268 | 269 | Subscribes to a channel to receive messages sent to it with given options. 270 | 271 | **Parameters** 272 | 273 | * options - The subscription options dictionary, EX: 274 | options = { 275 | channel, 276 | subscribeOnReconnected, // optional, default = true, 277 | withNotifications (Bool), // optional, default = false, use push notifications as in subscribeWithNotifications 278 | filter, // optional, default = "", the subscription filter as in subscribeWithFilter 279 | subscriberId // optional, default = "", the subscriberId as in subscribeWithBuffer 280 | } 281 | 282 | ***Example:*** 283 | 284 | var options = { 285 | "channel":"YOUR_CHANNEL_NAME", 286 | "subscriberId":"CLIENT_SUBSCRIBER_ID", 287 | "filter":"MESSAGE_FILTER" 288 | } 289 | RCTRealtimeMessaging.RTSubscribeWithOptions(options); 290 | 291 | ---------- 292 | 293 | ##### RTSubscribeWithBuffer(channel, subscriberId) 294 | 295 | Subscribes to a channel to receive messages published to it. 296 | 297 | **Parameters** 298 | 299 | * channel - The channel name. 300 | * subscriberId - The subscriberId associated to the channel. 301 | 302 | ***Example:*** 303 | 304 | RCTRealtimeMessaging.RTSubscribeWithBuffer("MyChannel", "CLIENT_SUBSCRIBER_ID"); 305 | 306 | ---------- 307 | 308 | ##### RTSubscribeWithNotifications(channel, subscribeOnReconnect: boolean) 309 | 310 | Subscribes a pub/sub channel with Push Notifications Service, to receive messages even if the app is not running. 311 | 312 | **Parameters** 313 | 314 | * channel - Channel name 315 | 316 | * subscribeOnReconnected - 317 | Indicates whether the client should subscribe to the channel when reconnected (if it was previously subscribed when connected). 318 | 319 | ***Example:*** 320 | 321 | RCTRealtimeMessaging.RTSubscribeWithNotifications("MyChannel", true); 322 | 323 | ---------- 324 | 325 | ##### RTUnsubscribe(channel) 326 | 327 | Unsubscribes a channel. 328 | 329 | **Parameters** 330 | 331 | * channel - Channel name. 332 | 333 | ***Example:*** 334 | 335 | RCTRealtimeMessaging.RTUnsubscribe("MyChannel"); 336 | 337 | ---------- 338 | 339 | ##### RTSendMessage(message, channel) 340 | 341 | Sends a message to a pub/sub channel. 342 | 343 | **Parameters** 344 | 345 | * channel - Channel name 346 | 347 | * message - The message to send (a string/stringified JSON object) 348 | 349 | ***Example:*** 350 | 351 | RCTRealtimeMessaging.RTSendMessage("Hello World","MyChannel"); 352 | 353 | ---------- 354 | 355 | ##### RTPublishMessage(channel, message, ttl, onPublishResultCallback) 356 | 357 | Publish a message to a channel. 358 | 359 | **Parameters** 360 | 361 | * channel - The channel name. 362 | * message - The message to publish. 363 | * ttl - The message expiration time in seconds (0 for maximum allowed ttl). 364 | * onPublishResultCallback - callback returns error if message publish was not successful or published message unique id (seqId) if sucessfully published 365 | 366 | ***Example:*** 367 | 368 | RCTRealtimeMessaging.RTPublishMessage("MyChannel", "Hello World", ttl, function(error, seqId){ 369 | 370 | }); 371 | 372 | ---------- 373 | 374 | ##### RTEnablePresence(aPrivateKey, channel, aMetadata:boolean) 375 | 376 | Enables presence for the specified channel with first 100 unique connection metadata. 377 | 378 | **Parameters** 379 | 380 | * privateKey - The Realtime application private key 381 | 382 | * channel - Channel to enable presence 383 | 384 | * metadata - Sets to return metadata info 385 | 386 | 387 | ***Example:*** 388 | 389 | RCTRealtimeMessaging.RTEventListener("onEnablePresence", function(event){ 390 | if(event.result){ 391 | console.log('Realtime enablePresence result: ' + event.result); 392 | }else{ 393 | console.log('Realtime enablePresence error: ' + event.error); 394 | } 395 | }), 396 | 397 | RCTRealtimeMessaging.RTEnablePresence(aPrivateKey, channel, aMetadata); 398 | 399 | 400 | ---------- 401 | 402 | ##### RTDisablePresence(aPrivateKey, channel) 403 | 404 | Disables presence for the specified channel. 405 | 406 | **Parameters** 407 | 408 | * privateKey - The Realtime application private key 409 | 410 | * channel - Channel to disable presence 411 | 412 | ***Example:*** 413 | 414 | RCTRealtimeMessaging.RTEventListener("onDisablePresence", function(event){ 415 | if(event.result){ 416 | console.log('Realtime disablePresence result: ' + event.result); 417 | }else{ 418 | console.log('Realtime disablePresence error: ' + event.error); 419 | } 420 | }), 421 | 422 | RCTRealtimeMessaging.RTDisablePresence(aPrivateKey, channel); 423 | 424 | ---------- 425 | 426 | ##### RTPresence(channel) 427 | 428 | Gets a dictionary with the total number of subscriptions in the specified channel and if active the first 100 unique connection metadata of the subscribers. 429 | 430 | **Parameters** 431 | 432 | * channel - Channel with presence data active 433 | 434 | ***Example:*** 435 | 436 | RCTRealtimeMessaging.RTEventListener("onPresence", function(event){ 437 | if(event.result){ 438 | console.log('Realtime presence result: ' + JSON.stringify(event.result)); 439 | }else{ 440 | console.log('Realtime presence error: ' + event.error); 441 | } 442 | }), 443 | 444 | RCTRealtimeMessaging.RTPresence(channel); 445 | 446 | ---------- 447 | 448 | ##### RTIsSubscribed(channel, callBack: function) 449 | 450 | Indicates whether a given channel is currently subscribed. 451 | 452 | **Parameters** 453 | 454 | * channel - Channel name. 455 | 456 | * callback - Callback function to be called with the result (true or false). 457 | 458 | ***Example:*** 459 | 460 | RCTRealtimeMessaging.RTIsSubscribed("MyChannel", function(result){ 461 | if(result == true){ 462 | console.log('channel is subscribed'); 463 | }else{ 464 | console.log('channel is not subscribed'); 465 | } 466 | }); 467 | 468 | ---------- 469 | 470 | ##### RTGetHeartbeatTime(callBack: function) 471 | 472 | Get the client heartbeat interval. 473 | 474 | **Parameters** 475 | 476 | * callback - 477 | Callback function with the heartbeat interval value 478 | 479 | ***Example:*** 480 | 481 | RCTRealtimeMessaging.RTGetHeartbeatTime(function(result){ 482 | console.log('HeartbeatTime for this client is: ' + result); 483 | }); 484 | 485 | ---------- 486 | 487 | ##### RTSetHeartbeatTime(newHeartbeatTime) 488 | 489 | Sets the client heartbeat interval. 490 | 491 | **Parameters** 492 | 493 | * newHeartbeatTime - The new heartbeat interval 494 | 495 | ***Example:*** 496 | 497 | RCTRealtimeMessaging.RTSetHeartbeatTime(10); 498 | 499 | ---------- 500 | 501 | ##### RTGetHeartbeatFails(callBack: function) 502 | 503 | Number of times the heartbeat can fail before the connection is reconnected 504 | 505 | **Parameters** 506 | 507 | * callBack - The callback function to get the HeartbeatFails value 508 | 509 | ***Example:*** 510 | 511 | RCTRealtimeMessaging.RTGetHeartbeatFails(function(result){ 512 | console.log('HeartbeatFails Time for this client is: ' + result); 513 | }); 514 | 515 | ---------- 516 | 517 | ##### RTSetHeartbeatFails(newHeartbeatFails) 518 | 519 | Sets the number of times the heartbeat can fail before the connection is reconnected 520 | 521 | **Parameters** 522 | 523 | * newHeartbeatFails - The new heartbeat fails value 524 | 525 | ***Example:*** 526 | 527 | RCTRealtimeMessaging.RTSetHeartbeatFails(3); 528 | 529 | ---------- 530 | 531 | ##### RTIsHeartbeatActive(callBack: function) 532 | 533 | Indicates whether the client heartbeat is active or not. 534 | 535 | **Parameters** 536 | 537 | * callBack - The callback function with the result 538 | 539 | ***Example:*** 540 | 541 | RCTRealtimeMessaging.RTIsHeartbeatActive(function(result){ 542 | if(result == true){ 543 | console.log('heartbeat active'); 544 | }else{ 545 | console.log('heartbeat inactive'); 546 | } 547 | }); 548 | 549 | ---------- 550 | 551 | ##### RTEnableHeartbeat() 552 | 553 | Enables the client heartbeat. 554 | 555 | ***Example:*** 556 | 557 | RCTRealtimeMessaging.RTEnableHeartbeat() 558 | 559 | ---------- 560 | 561 | ##### RTDisableHeartbeat() 562 | 563 | Disables the client heartbeat. 564 | 565 | ***Example:*** 566 | 567 | RCTRealtimeMessaging.RTDisableHeartbeat() 568 | 569 | 570 | 571 | ## Full example ( index.android.js ) 572 | 573 | 'use strict'; 574 | 575 | import React, { Component } from 'react'; 576 | import realtime from './RCTRealtimeMessagingAndroid'; 577 | var RCTRealtimeMessaging = new realtime(); 578 | 579 | var messages = []; 580 | 581 | import { 582 | AppRegistry, 583 | Image, 584 | StyleSheet, 585 | Text, 586 | Navigator, 587 | TextInput, 588 | ScrollView, 589 | TouchableHighlight, 590 | ListView, 591 | View 592 | } from 'react-native'; 593 | 594 | 595 | var RealtimeRCT = React.createClass({ 596 | 597 | doConnect: function(){ 598 | this._log('Trying to connect!'); 599 | 600 | RCTRealtimeMessaging.RTEventListener("onConnected",this._onConnected), 601 | RCTRealtimeMessaging.RTEventListener("onDisconnected",this._onDisconnected), 602 | RCTRealtimeMessaging.RTEventListener("onSubscribed",this._onSubscribed), 603 | RCTRealtimeMessaging.RTEventListener("onUnSubscribed",this._onUnSubscribed), 604 | RCTRealtimeMessaging.RTEventListener("onException",this._onException), 605 | RCTRealtimeMessaging.RTEventListener("onMessage",this._onMessage), 606 | RCTRealtimeMessaging.RTEventListener("onPresence",this._onPresence); 607 | 608 | RCTRealtimeMessaging.RTConnect( 609 | { 610 | appKey:this.state.appKey, 611 | token:this.state.token, 612 | connectionMetadata:this.state.connectionMetadata, 613 | clusterUrl:this.state.clusterUrl, 614 | projectId:'' 615 | }); 616 | }, 617 | 618 | componentDidMount: function(){ 619 | RCTRealtimeMessaging.RTPushNotificationListener(this._onNotification); 620 | }, 621 | 622 | _onNotification: function(data) { 623 | this._log("Received push notification: " + JSON.stringify(data)); 624 | }, 625 | 626 | componentWillUnmount: function() { 627 | RCTRealtimeMessaging.RTDisconnect(); 628 | }, 629 | 630 | doDisconnect:function(){ 631 | RCTRealtimeMessaging.RTDisconnect(); 632 | }, 633 | 634 | doSubscribe: function(){ 635 | RCTRealtimeMessaging.RTSubscribe(this.state.channel, true); 636 | // To subscribe using push notifications use the RTSubscribeWithNotifications method 637 | }, 638 | 639 | doUnSubscribe: function(){ 640 | RCTRealtimeMessaging.RTUnsubscribe(this.state.channel); 641 | }, 642 | 643 | doSendMessage: function(){ 644 | RCTRealtimeMessaging.RTSendMessage(this.state.message, this.state.channel); 645 | }, 646 | 647 | doPresence: function(){ 648 | RCTRealtimeMessaging.RTPresence( 649 | this.state.channel 650 | ); 651 | }, 652 | 653 | 654 | _onException: function(exceptionEvent){ 655 | this._log("Exception:" + exceptionEvent.error); 656 | }, 657 | 658 | _onConnected: function() 659 | { 660 | this._log("connected"); 661 | }, 662 | 663 | 664 | _onDisconnected: function(){ 665 | this._log("disconnected"); 666 | }, 667 | 668 | _onSubscribed: function(subscribedEvent) 669 | { 670 | this._log("subscribed channel " + subscribedEvent.channel); 671 | }, 672 | 673 | _onUnSubscribed: function(unSubscribedEvent) 674 | { 675 | this._log("unsubscribed channel " + unSubscribedEvent.channel); 676 | }, 677 | 678 | _onMessage: function(messageEvent) 679 | { 680 | this._log("received message: ["+messageEvent.message+"] on channel [" + messageEvent.channel+"]"); 681 | }, 682 | 683 | _onPresence: function(presenceEvent){ 684 | if (presenceEvent.error) { 685 | this._log("Error getting presence: " + presenceEvent.error); 686 | }else 687 | { 688 | this._log("Presence data: " + JSON.stringify(presenceEvent.result)); 689 | }; 690 | }, 691 | 692 | 693 | getInitialState: function() { 694 | return { 695 | clusterUrl: "http://ortc-developers.realtime.co/server/2.1/", 696 | token: "SomeAuthenticatedToken", 697 | appKey: "YOUR_APP_KEY", 698 | channel: "yellow", 699 | connectionMetadata: "clientConnMeta", 700 | message: "some message", 701 | dataSource: new ListView.DataSource({ 702 | rowHasChanged: (row1, row2) => row1 !== row2, 703 | }), 704 | }; 705 | }, 706 | 707 | _renderRow: function(rowData: string, sectionID: number, rowID: number) { 708 | return ( 709 | 710 | 711 | 712 | 713 | {rowData} 714 | 715 | 716 | 717 | 718 | 719 | ); 720 | }, 721 | 722 | _log: function(message: string) 723 | { 724 | var time = this.getFormattedDate(); 725 | time += " - " + message 726 | var temp = []; 727 | temp[0] = time; 728 | 729 | for (var i = 0; i < messages.length; i++) { 730 | temp[i+1] = messages[i]; 731 | }; 732 | messages = temp; 733 | 734 | this.setState({ 735 | dataSource: this.getDataSource(messages) 736 | }); 737 | }, 738 | 739 | getFormattedDate: function() { 740 | var date = new Date(); 741 | var str = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds(); 742 | return str; 743 | }, 744 | 745 | getDataSource: function(messages: Array): ListView.DataSource { 746 | return this.state.dataSource.cloneWithRows(messages); 747 | }, 748 | 749 | render: function() { 750 | return ( 751 | 752 | 753 | 754 | clusterUrl: 755 | 756 | this.setState({server: text})} 760 | /> 761 | 762 | 763 | 764 | 765 | Authentication Token: 766 | 767 | this.setState({token: text})} 771 | /> 772 | 773 | 774 | Application Key: 775 | 776 | this.setState({appKey: text})} 780 | /> 781 | 782 | 783 | 784 | 785 | Channel: 786 | 787 | this.setState({channel: text})} 791 | /> 792 | 793 | 794 | Connection Metadata: 795 | 796 | this.setState({connectionMetadata: text})} 800 | /> 801 | 802 | 803 | 804 | 805 | Message: 806 | 807 | this.setState({message: text})} 811 | /> 812 | 813 | 814 | 815 | 816 | 817 | 818 | Connect 819 | 820 | 821 | 822 | 823 | 824 | Disconnect 825 | 826 | 827 | 828 | 829 | 830 | Subscribe 831 | 832 | 833 | 834 | 835 | 836 | Unsubscribe 837 | 838 | 839 | 840 | 841 | 842 | Send 843 | 844 | 845 | 846 | 847 | 848 | Presence 849 | 850 | 851 | 852 | 853 | 858 | 859 | 860 | )} 861 | }); 862 | 863 | var styles = StyleSheet.create({ 864 | container: { 865 | marginTop: 30, 866 | margin: 5, 867 | backgroundColor: '#FFFFFF', 868 | }, 869 | list: { 870 | flexDirection: 'column', 871 | backgroundColor: '#F6F6F6', 872 | height:150, 873 | }, 874 | rowView:{ 875 | alignItems: 'stretch', 876 | flexDirection: 'row', 877 | flexWrap: 'wrap', 878 | justifyContent:'center', 879 | }, 880 | button:{ 881 | margin: 5, 882 | }, 883 | margin:{ 884 | 885 | }, 886 | custom:{ 887 | flexDirection: 'row', 888 | flexWrap: 'wrap', 889 | justifyContent:'space-between', 890 | }, 891 | textInput:{ 892 | height: 30, 893 | borderColor: 'gray', 894 | borderWidth: 1, 895 | borderRadius: 4, 896 | padding: 5, 897 | fontSize: 15, 898 | }, 899 | 900 | halfTextInput:{ 901 | height: 30, 902 | borderColor: 'gray', 903 | borderWidth: 1, 904 | borderRadius: 4, 905 | padding: 5, 906 | fontSize: 15, 907 | width: 153, 908 | }, 909 | tryAgain: { 910 | backgroundColor: '#336699', 911 | padding: 13, 912 | borderRadius: 5, 913 | }, 914 | tryAgainText: { 915 | color: '#ffffff', 916 | fontSize: 14, 917 | fontWeight: '500', 918 | }, 919 | welcome: { 920 | fontSize: 20, 921 | textAlign: 'center', 922 | margin: 10, 923 | }, 924 | instructions: { 925 | textAlign: 'center', 926 | color: '#333333', 927 | }, 928 | row: { 929 | flexDirection: 'row', 930 | justifyContent: 'center', 931 | padding: 10, 932 | backgroundColor: '#F6F6F6', 933 | }, 934 | separator: { 935 | height: 1, 936 | backgroundColor: '#CCCCCC', 937 | }, 938 | thumb: { 939 | width: 64, 940 | height: 64, 941 | }, 942 | text: { 943 | flex: 1, 944 | fontSize: 13, 945 | }, 946 | }); 947 | 948 | AppRegistry.registerComponent('RealtimeRCT', () => RealtimeRCT); 949 | 950 | ## Example 951 | Checkout the example at [https://github.com/realtime-framework/RealtimeMessaging-ReactNativeAndroidExample](https://github.com/realtime-framework/RealtimeMessaging-ReactNativeAndroidExample) 952 | ## Authors 953 | Realtime.co 954 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-realtimemessaging-android", 3 | "version": "1.1.7", 4 | "description": "The Realtime Framework Cloud Messaging Pub/Sub client for React-Native Android", 5 | "main": "RCTRealtimeMessagingAndroid.js", 6 | "scripts": { 7 | "start": "exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/realtime-framework/RCTRealtimeMessagingAndroid.git" 12 | }, 13 | "keywords": [ 14 | "react-component", 15 | "reactnative", 16 | "react-native", 17 | "RealtimeMessaging", 18 | "Realtime", 19 | "Android" 20 | ], 21 | "author": "Realtime", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/realtime-framework/RCTRealtimeMessagingAndroid/issues" 25 | }, 26 | "homepage": "https://github.com/realtime-framework/RCTRealtimeMessagingAndroid" 27 | } 28 | -------------------------------------------------------------------------------- /reactnativemessagingandroid/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | minSdkVersion 16 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile "com.facebook.react:react-native:+" 23 | compile 'co.realtime:messaging-android:2.1.+' 24 | } 25 | -------------------------------------------------------------------------------- /reactnativemessagingandroid/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/admin/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /reactnativemessagingandroid/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /reactnativemessagingandroid/src/main/java/co/realtime/reactnativemessagingandroid/GcmReceiver.java: -------------------------------------------------------------------------------- 1 | package co.realtime.reactnativemessagingandroid; 2 | 3 | import android.app.Notification; 4 | import android.app.NotificationManager; 5 | import android.app.PendingIntent; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.os.Bundle; 9 | import android.support.v4.app.NotificationCompat; 10 | import android.util.Log; 11 | 12 | import java.util.Random; 13 | 14 | import ibt.ortc.extensibility.GcmOrtcBroadcastReceiver; 15 | 16 | public class GcmReceiver extends GcmOrtcBroadcastReceiver { 17 | 18 | private static final String TAG = "GcmReceiver"; 19 | 20 | public GcmReceiver() { 21 | } 22 | 23 | @Override 24 | public void onReceive(Context context, Intent intent) { 25 | // Extract the payload from the message 26 | Bundle extras = intent.getExtras(); 27 | if (extras != null) { 28 | // if we are in the foreground, just surface the payload, else post it to the statusbar 29 | if (RealtimeMessagingAndroid.isOnForeground()) { 30 | extras.putBoolean("foreground", true); 31 | RealtimeMessagingAndroid.sendExtras(extras); 32 | } else { 33 | extras.putBoolean("foreground", false); 34 | // Send a notification if there is a message 35 | if (extras.getString("M") != null && extras.getString("M").length() != 0) { 36 | createNotification(context, extras); 37 | } 38 | } 39 | 40 | } 41 | } 42 | 43 | public void createNotification(Context context, Bundle extras) 44 | { 45 | NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 46 | String appName = getAppName(context); 47 | 48 | String packageName = context.getPackageName(); 49 | Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName); 50 | Class className = launchIntent.getComponent().getClass(); 51 | 52 | Intent notificationIntent = context.getPackageManager().getLaunchIntentForPackage(packageName); 53 | notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); 54 | notificationIntent.putExtra("pushBundle", extras); 55 | 56 | PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); 57 | 58 | int defaults = Notification.DEFAULT_ALL; 59 | 60 | if (extras.getString("defaults") != null) { 61 | try { 62 | defaults = Integer.parseInt(extras.getString("defaults")); 63 | } catch (NumberFormatException e) {} 64 | } 65 | 66 | String channel = extras.getString("C"); 67 | String message = extras.getString("message"); 68 | 69 | NotificationCompat.Builder mBuilder = 70 | new NotificationCompat.Builder(context) 71 | .setDefaults(defaults) 72 | .setSmallIcon(context.getApplicationInfo().icon) 73 | .setWhen(System.currentTimeMillis()) 74 | .setContentTitle(context.getString(context.getApplicationInfo().labelRes)) 75 | .setContentIntent(contentIntent) 76 | .setAutoCancel(true); 77 | 78 | 79 | if (message != null) { 80 | mBuilder.setContentText(message); 81 | } else { 82 | mBuilder.setContentText(""); 83 | } 84 | 85 | int notId = 0; 86 | 87 | try { 88 | notId = new Random().nextInt(); 89 | } 90 | catch(NumberFormatException e) { 91 | Log.e(TAG, "Number format exception - Error parsing Notification ID: " + e.getMessage()); 92 | } 93 | catch(Exception e) { 94 | Log.e(TAG, "Number format exception - Error parsing Notification ID" + e.getMessage()); 95 | } 96 | 97 | mNotificationManager.notify(appName, notId, mBuilder.build()); 98 | } 99 | 100 | private static String getAppName(Context context) 101 | { 102 | CharSequence appName = 103 | context 104 | .getPackageManager() 105 | .getApplicationLabel(context.getApplicationInfo()); 106 | 107 | return (String)appName; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /reactnativemessagingandroid/src/main/java/co/realtime/reactnativemessagingandroid/RealtimeMessagingAndroid.java: -------------------------------------------------------------------------------- 1 | package co.realtime.reactnativemessagingandroid; /** 2 | * Created by jcaixinha on 15/09/15. 3 | */ 4 | 5 | import android.annotation.TargetApi; 6 | import android.os.Build; 7 | import android.os.Bundle; 8 | import android.support.annotation.Nullable; 9 | import android.util.Log; 10 | 11 | import com.facebook.react.bridge.Callback; 12 | import com.facebook.react.bridge.ReactApplicationContext; 13 | import com.facebook.react.bridge.ReactContext; 14 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 15 | import com.facebook.react.bridge.ReactMethod; 16 | import com.facebook.react.bridge.ReadableArray; 17 | import com.facebook.react.bridge.ReadableMap; 18 | import com.facebook.react.bridge.ReadableMapKeySetIterator; 19 | import com.facebook.react.bridge.ReadableType; 20 | import com.facebook.react.bridge.WritableMap; 21 | import com.facebook.react.bridge.WritableNativeMap; 22 | import com.facebook.react.modules.core.DeviceEventManagerModule; 23 | 24 | import org.json.JSONException; 25 | import org.json.JSONObject; 26 | 27 | import java.util.ArrayList; 28 | import java.util.HashMap; 29 | import java.util.Iterator; 30 | import java.util.List; 31 | import java.util.Map; 32 | import java.util.Objects; 33 | 34 | import ibt.ortc.api.OnDisablePresence; 35 | import ibt.ortc.api.OnEnablePresence; 36 | import ibt.ortc.api.OnPresence; 37 | import ibt.ortc.api.Ortc; 38 | import ibt.ortc.api.Presence; 39 | import ibt.ortc.extensibility.OnConnected; 40 | import ibt.ortc.extensibility.OnDisconnected; 41 | import ibt.ortc.extensibility.OnException; 42 | import ibt.ortc.extensibility.OnMessage; 43 | import ibt.ortc.extensibility.OnMessageWithBuffer; 44 | import ibt.ortc.extensibility.OnMessageWithFilter; 45 | import ibt.ortc.extensibility.OnMessageWithOptions; 46 | import ibt.ortc.extensibility.OnPublishResult; 47 | import ibt.ortc.extensibility.OnReconnected; 48 | import ibt.ortc.extensibility.OnReconnecting; 49 | import ibt.ortc.extensibility.OnSubscribed; 50 | import ibt.ortc.extensibility.OnUnsubscribed; 51 | import ibt.ortc.extensibility.OrtcClient; 52 | import ibt.ortc.extensibility.OrtcFactory; 53 | import ibt.ortc.extensibility.exception.OrtcNotConnectedException; 54 | 55 | 56 | public class RealtimeMessagingAndroid extends ReactContextBaseJavaModule 57 | { 58 | 59 | private static final String TAG = "" ; 60 | private static Bundle gCachedExtras; 61 | private OrtcClient client; 62 | private HashMap queue; 63 | private ReadableMap config; 64 | private static boolean isOnForeground; 65 | private static RealtimeMessagingAndroid instance; 66 | 67 | public static RealtimeMessagingAndroid instance(){ 68 | return instance; 69 | } 70 | 71 | public static void setIsOnForeground(boolean isOnForeground){ 72 | RealtimeMessagingAndroid.isOnForeground = isOnForeground; 73 | } 74 | 75 | public static boolean isOnForeground(){ 76 | return RealtimeMessagingAndroid.isOnForeground; 77 | } 78 | 79 | 80 | 81 | public RealtimeMessagingAndroid(ReactApplicationContext reactContext){ 82 | super(reactContext); 83 | RealtimeMessagingAndroid.instance = this; 84 | queue = new HashMap(); 85 | } 86 | 87 | @Override 88 | public String getName() { 89 | return "RealtimeMessagingAndroid"; 90 | } 91 | 92 | private void sendEvent(ReactContext reactContext, 93 | String eventName, 94 | @Nullable Object params) { 95 | reactContext 96 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) 97 | .emit(eventName, params); 98 | } 99 | 100 | @TargetApi(Build.VERSION_CODES.KITKAT) 101 | public static Integer getKeyByValue(Map map, OrtcClient value) { 102 | for (Map.Entry entry : map.entrySet()) { 103 | if (Objects.equals(value, entry.getValue())) { 104 | return entry.getKey(); 105 | } 106 | } 107 | return null; 108 | } 109 | 110 | 111 | @ReactMethod 112 | public void connect(ReadableMap config, Integer id){ 113 | this.config = config; 114 | if (this.queue == null) 115 | queue = new HashMap(); 116 | 117 | if (queue.containsKey(id)) 118 | { 119 | client = (OrtcClient)queue.get(id); 120 | }else { 121 | Ortc api = new Ortc(); 122 | OrtcFactory factory = null; 123 | 124 | try { 125 | factory = api.loadOrtcFactory("IbtRealtimeSJ"); 126 | } catch (InstantiationException e) { 127 | e.printStackTrace(); 128 | } catch (IllegalAccessException e) { 129 | e.printStackTrace(); 130 | } catch (ClassNotFoundException e) { 131 | e.printStackTrace(); 132 | } 133 | 134 | client = factory.createClient(); 135 | queue.put(id, client); 136 | } 137 | 138 | client.setApplicationContext(this.getReactApplicationContext()); 139 | 140 | if (this.config.hasKey("projectId")) 141 | client.setGoogleProjectId(this.config.getString("projectId")); 142 | 143 | if (this.config.hasKey("connectionMetadata")) 144 | client.setConnectionMetadata(this.config.getString("connectionMetadata")); 145 | 146 | if(this.config.hasKey("clusterUrl")){ 147 | client.setClusterUrl(this.config.getString("clusterUrl")); 148 | } else if(this.config.hasKey("url")){ 149 | client.setUrl(this.config.getString("url")); 150 | } 151 | 152 | client.onConnected = new OnConnected() { 153 | @Override 154 | public void run(OrtcClient ortcClient) { 155 | String thisId = ""+RealtimeMessagingAndroid.getKeyByValue(queue, ortcClient); 156 | sendEvent(getReactApplicationContext(), thisId + "-onConnected", null); 157 | } 158 | }; 159 | 160 | client.onDisconnected = new OnDisconnected() { 161 | @Override 162 | public void run(OrtcClient ortcClient) { 163 | String thisId = ""+RealtimeMessagingAndroid.getKeyByValue(queue, ortcClient); 164 | sendEvent(getReactApplicationContext(), thisId + "-onDisconnected", null); 165 | } 166 | }; 167 | 168 | client.onException = new OnException() { 169 | @Override 170 | public void run(OrtcClient ortcClient, Exception e) { 171 | WritableMap params = new WritableNativeMap(); 172 | params.putString("error", e.toString()); 173 | String thisId = ""+RealtimeMessagingAndroid.getKeyByValue(queue, ortcClient); 174 | sendEvent(getReactApplicationContext(), thisId + "-onException", params); 175 | } 176 | }; 177 | 178 | client.onSubscribed = new OnSubscribed() { 179 | @Override 180 | public void run(OrtcClient ortcClient, String s) { 181 | checkForNotifications(); 182 | WritableMap params = new WritableNativeMap(); 183 | params.putString("channel", s); 184 | String thisId = ""+RealtimeMessagingAndroid.getKeyByValue(queue, ortcClient); 185 | sendEvent(getReactApplicationContext(), thisId + "-onSubscribed", params); 186 | } 187 | }; 188 | 189 | client.onUnsubscribed = new OnUnsubscribed() { 190 | @Override 191 | public void run(OrtcClient ortcClient, String s) { 192 | WritableMap params = new WritableNativeMap(); 193 | params.putString("channel", s); 194 | String thisId = ""+RealtimeMessagingAndroid.getKeyByValue(queue, ortcClient); 195 | sendEvent(getReactApplicationContext(), thisId + "-onUnsubscribed", params); 196 | } 197 | }; 198 | 199 | client.onReconnected = new OnReconnected() { 200 | @Override 201 | public void run(OrtcClient ortcClient) { 202 | String thisId = ""+RealtimeMessagingAndroid.getKeyByValue(queue, ortcClient); 203 | sendEvent(getReactApplicationContext(), thisId + "-onReconnected", null); 204 | } 205 | }; 206 | 207 | client.onReconnecting = new OnReconnecting() { 208 | @Override 209 | public void run(OrtcClient ortcClient) { 210 | String thisId = ""+RealtimeMessagingAndroid.getKeyByValue(queue, ortcClient); 211 | sendEvent(getReactApplicationContext(), thisId + "-onReconnecting", null); 212 | } 213 | }; 214 | 215 | client.connect(this.config.getString("appKey"), this.config.getString("token")); 216 | 217 | } 218 | 219 | @ReactMethod 220 | public void disconnect(Integer id){ 221 | OrtcClient client = null; 222 | if (queue.containsKey(id)) { 223 | client = queue.get(id); 224 | client.disconnect(); 225 | } 226 | } 227 | 228 | private Map recursivelyDeconstructReadableMap(ReadableMap readableMap) { 229 | ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); 230 | Map deconstructedMap = new HashMap<>(); 231 | while (iterator.hasNextKey()) { 232 | String key = iterator.nextKey(); 233 | ReadableType type = readableMap.getType(key); 234 | switch (type) { 235 | case Null: 236 | deconstructedMap.put(key, null); 237 | break; 238 | case Boolean: 239 | deconstructedMap.put(key, readableMap.getBoolean(key)); 240 | break; 241 | case Number: 242 | deconstructedMap.put(key, readableMap.getDouble(key)); 243 | break; 244 | case String: 245 | deconstructedMap.put(key, readableMap.getString(key)); 246 | break; 247 | case Map: 248 | deconstructedMap.put(key, recursivelyDeconstructReadableMap(readableMap.getMap(key))); 249 | break; 250 | case Array: 251 | deconstructedMap.put(key, recursivelyDeconstructReadableArray(readableMap.getArray(key))); 252 | break; 253 | default: 254 | throw new IllegalArgumentException("Could not convert object with key: " + key + "."); 255 | } 256 | 257 | } 258 | return deconstructedMap; 259 | } 260 | 261 | private List recursivelyDeconstructReadableArray(ReadableArray readableArray) { 262 | List deconstructedList = new ArrayList<>(readableArray.size()); 263 | for (int i = 0; i < readableArray.size(); i++) { 264 | ReadableType indexType = readableArray.getType(i); 265 | switch(indexType) { 266 | case Null: 267 | deconstructedList.add(i, null); 268 | break; 269 | case Boolean: 270 | deconstructedList.add(i, readableArray.getBoolean(i)); 271 | break; 272 | case Number: 273 | deconstructedList.add(i, readableArray.getDouble(i)); 274 | break; 275 | case String: 276 | deconstructedList.add(i, readableArray.getString(i)); 277 | break; 278 | case Map: 279 | deconstructedList.add(i, recursivelyDeconstructReadableMap(readableArray.getMap(i))); 280 | break; 281 | case Array: 282 | deconstructedList.add(i, recursivelyDeconstructReadableArray(readableArray.getArray(i))); 283 | break; 284 | default: 285 | throw new IllegalArgumentException("Could not convert object at index " + i + "."); 286 | } 287 | } 288 | return deconstructedList; 289 | } 290 | 291 | 292 | @ReactMethod 293 | public void subscribeWithOptions(ReadableMap options, Integer id){ 294 | Map newOptions = recursivelyDeconstructReadableMap(options); 295 | OrtcClient client = null; 296 | if (queue.containsKey(id)) { 297 | client = queue.get(id); 298 | client.subscribeWithOptions(newOptions, new OnMessageWithOptions() { 299 | @Override 300 | public void run(OrtcClient sender, Map msgOptions) { 301 | String thisId = "" + RealtimeMessagingAndroid.getKeyByValue(queue, sender); 302 | WritableMap params = new WritableNativeMap(); 303 | params.putString("channel", (String)msgOptions.get("channel")); 304 | params.putString("message", (String)msgOptions.get("message")); 305 | if (msgOptions.containsKey("filtered")) 306 | params.putBoolean("filtered", (Boolean) msgOptions.get("filtered")); 307 | if (msgOptions.containsKey("seqId")) 308 | params.putString("seqId", (String) msgOptions.get("seqId")); 309 | 310 | sendEvent(getReactApplicationContext(), thisId + "-onMessageWithOptions", params); 311 | } 312 | }); 313 | } 314 | } 315 | 316 | @ReactMethod 317 | public void subscribeWithBuffer(String channel, String subscriberId, Integer id){ 318 | OrtcClient client = null; 319 | if (queue.containsKey(id)) { 320 | client = queue.get(id); 321 | client.subscribeWithBuffer(channel, subscriberId, new OnMessageWithBuffer() { 322 | @Override 323 | public void run(OrtcClient sender, String channel, String seqId, String message) { 324 | String thisId = "" + RealtimeMessagingAndroid.getKeyByValue(queue, sender); 325 | WritableMap params = new WritableNativeMap(); 326 | params.putString("channel", channel); 327 | params.putString("message", message); 328 | params.putString("seqId", seqId); 329 | sendEvent(getReactApplicationContext(), thisId + "-onMessageWithBuffer", params); 330 | } 331 | }); 332 | } 333 | } 334 | 335 | @ReactMethod 336 | public void publish(String channel, String message, Integer ttl, Integer id, final Callback callBack){ 337 | if (queue.containsKey(id)) { 338 | final OrtcClient client = queue.get(id); 339 | client.publish(channel, message, ttl, new OnPublishResult() { 340 | @Override 341 | public void run(String error, String seqId) { 342 | String pError = ""; 343 | String pSeqId = ""; 344 | if (error != null) 345 | pError = error; 346 | if (seqId != null) 347 | pSeqId = seqId; 348 | callBack.invoke(pError, pSeqId); 349 | } 350 | }); 351 | } 352 | } 353 | 354 | 355 | @ReactMethod 356 | public void subscribeWithFilter(String channel, Boolean subscribeOnReconnect, String filter, Integer id){ 357 | OrtcClient client = null; 358 | if (queue.containsKey(id)) { 359 | client = queue.get(id); 360 | client.subscribeWithFilter(channel, subscribeOnReconnect, filter, new OnMessageWithFilter() { 361 | @Override 362 | public void run(OrtcClient ortcClient, String s, boolean filtered, String s1) { 363 | WritableMap params = new WritableNativeMap(); 364 | params.putString("channel", s); 365 | params.putString("message", s1); 366 | params.putBoolean("filtered", filtered); 367 | String thisId = "" + RealtimeMessagingAndroid.getKeyByValue(queue, ortcClient); 368 | sendEvent(getReactApplicationContext(), thisId + "-onMessageWithFilter", params); 369 | } 370 | }); 371 | } 372 | } 373 | 374 | @ReactMethod 375 | public void subscribe(String channel, Boolean subscribeOnReconnect, Integer id){ 376 | OrtcClient client = null; 377 | if (queue.containsKey(id)) { 378 | client = queue.get(id); 379 | client.subscribe(channel, subscribeOnReconnect, new OnMessage() { 380 | @Override 381 | public void run(OrtcClient ortcClient, String s, String s1) { 382 | WritableMap params = new WritableNativeMap(); 383 | params.putString("channel", s); 384 | params.putString("message", s1); 385 | String thisId = "" + RealtimeMessagingAndroid.getKeyByValue(queue, ortcClient); 386 | sendEvent(getReactApplicationContext(), thisId + "-onMessage", params); 387 | } 388 | }); 389 | } 390 | } 391 | 392 | @ReactMethod 393 | public void subscribeWithNotifications(String channel, Boolean subscribeOnReconnect, Integer id){ 394 | OrtcClient client = null; 395 | if (queue.containsKey(id)) { 396 | client = queue.get(id); 397 | client.subscribeWithNotifications(channel, subscribeOnReconnect, new OnMessage() { 398 | @Override 399 | public void run(OrtcClient ortcClient, String s, String s1) { 400 | WritableMap params = new WritableNativeMap(); 401 | params.putString("channel", s); 402 | params.putString("message", s1); 403 | String thisId = "" + RealtimeMessagingAndroid.getKeyByValue(queue, ortcClient); 404 | sendEvent(getReactApplicationContext(), thisId + "-onMessage", params); 405 | } 406 | }); 407 | } 408 | } 409 | 410 | @ReactMethod 411 | public void unsubscribe(String channel, Integer id){ 412 | OrtcClient client = null; 413 | if (queue.containsKey(id)) { 414 | client = queue.get(id); 415 | client.unsubscribe(channel); 416 | } 417 | } 418 | 419 | @ReactMethod 420 | public void sendMessage(String message, String channel, Integer id){ 421 | OrtcClient client = null; 422 | if (queue.containsKey(id)) { 423 | client = queue.get(id); 424 | client.send(channel, message); 425 | } 426 | } 427 | 428 | @ReactMethod 429 | public void enablePresence(String aPrivateKey, String channel, boolean aMetadata, final Integer id){ 430 | OrtcClient client = null; 431 | if (queue.containsKey(id)) { 432 | client = queue.get(id); 433 | try { 434 | client.enablePresence(aPrivateKey, channel, aMetadata, new OnEnablePresence() { 435 | @Override 436 | public void run(Exception e, String s) { 437 | if (e != null){ 438 | WritableMap params = new WritableNativeMap(); 439 | params.putString("error", e.toString()); 440 | sendEvent(getReactApplicationContext(), id + "-onEnablePresence", params); 441 | }else{ 442 | WritableMap params = new WritableNativeMap(); 443 | params.putString("result", s); 444 | sendEvent(getReactApplicationContext(), id + "-onEnablePresence", params); 445 | } 446 | } 447 | }); 448 | } catch (OrtcNotConnectedException e) { 449 | e.printStackTrace(); 450 | } 451 | } 452 | } 453 | 454 | @ReactMethod 455 | public void disablePresence(String aPrivateKey, String channel, final Integer id){ 456 | OrtcClient client = null; 457 | if (queue.containsKey(id)) { 458 | client = queue.get(id); 459 | try { 460 | client.disablePresence(aPrivateKey, channel, new OnDisablePresence() { 461 | @Override 462 | public void run(Exception e, String s) { 463 | if (e != null) { 464 | WritableMap params = new WritableNativeMap(); 465 | params.putString("error", e.toString()); 466 | sendEvent(getReactApplicationContext(), id + "-onDisablePresence", params); 467 | } else { 468 | WritableMap params = new WritableNativeMap(); 469 | params.putString("result", s); 470 | sendEvent(getReactApplicationContext(), id + "-onDisablePresence", params); 471 | } 472 | } 473 | }); 474 | } catch (OrtcNotConnectedException e) { 475 | e.printStackTrace(); 476 | } 477 | } 478 | } 479 | 480 | @ReactMethod 481 | public void presence(String channel, final Integer id){ 482 | OrtcClient client = null; 483 | if (queue.containsKey(id)) { 484 | client = queue.get(id); 485 | try { 486 | client.presence(channel, new OnPresence() { 487 | @Override 488 | public void run(Exception e, Presence presence) { 489 | if (e != null) { 490 | WritableMap params = new WritableNativeMap(); 491 | params.putString("error", e.toString()); 492 | sendEvent(getReactApplicationContext(), id + "-onPresence", params); 493 | } else { 494 | WritableMap params = new WritableNativeMap(); 495 | params.putString("result", presence.toString()); 496 | sendEvent(getReactApplicationContext(), id + "-onPresence", params); 497 | } 498 | } 499 | }); 500 | } catch (OrtcNotConnectedException e) { 501 | e.printStackTrace(); 502 | } 503 | } 504 | } 505 | 506 | 507 | @ReactMethod 508 | public void isSubscribed(String channel, Integer id, Callback callBack){ 509 | OrtcClient client = null; 510 | if (queue.containsKey(id)) { 511 | client = queue.get(id); 512 | callBack.invoke(client.isSubscribed(channel)); 513 | } 514 | } 515 | 516 | @ReactMethod 517 | public void getHeartbeatTime(Integer id, Callback callBack){ 518 | OrtcClient client = null; 519 | if (queue.containsKey(id)) { 520 | client = queue.get(id); 521 | callBack.invoke(client.getHeartbeatTime()); 522 | } 523 | } 524 | 525 | @ReactMethod 526 | public void setHeartbeatTime(Integer newTime, Integer id){ 527 | OrtcClient client = null; 528 | if (queue.containsKey(id)) { 529 | client = queue.get(id); 530 | client.setHeartbeatTime(newTime); 531 | } 532 | } 533 | 534 | 535 | @ReactMethod 536 | public void getHeartbeatFails(Integer id, Callback callBack){ 537 | OrtcClient client = null; 538 | if (queue.containsKey(id)) { 539 | client = queue.get(id); 540 | callBack.invoke(client.getHeartbeatFails()); 541 | } 542 | } 543 | 544 | @ReactMethod 545 | public void setHeartbeatTimeFails(Integer newTime, Integer id){ 546 | OrtcClient client = null; 547 | if (queue.containsKey(id)) { 548 | client = queue.get(id); 549 | client.setHeartbeatFails(newTime); 550 | } 551 | } 552 | 553 | @ReactMethod 554 | public void enableHeartbeat(Integer id){ 555 | OrtcClient client = null; 556 | if (queue.containsKey(id)) { 557 | client = queue.get(id); 558 | client.setHeartbeatActive(true); 559 | } 560 | } 561 | 562 | @ReactMethod 563 | public void disableHeartbeat(Integer id){ 564 | OrtcClient client = null; 565 | if (queue.containsKey(id)) { 566 | client = queue.get(id); 567 | client.setHeartbeatActive(false); 568 | } 569 | } 570 | 571 | @ReactMethod 572 | public void checkForNotifications(){ 573 | if (gCachedExtras != null){ 574 | sendExtras(gCachedExtras); 575 | gCachedExtras = null; 576 | } 577 | } 578 | 579 | public static void sendExtras(Bundle extras) { 580 | if (extras != null) { 581 | gCachedExtras = extras; 582 | if (RealtimeMessagingAndroid.instance != null && RealtimePushNotificationActivity.getMainParent() != null) { 583 | RealtimeMessagingAndroid.instance.sendJavascript(convertBundleToJson(extras)); 584 | } 585 | } 586 | } 587 | 588 | 589 | private static JSONObject convertBundleToJson(Bundle extras) 590 | { 591 | JSONObject json = new JSONObject(); 592 | try { 593 | if (extras.containsKey("P")){ 594 | json = new JSONObject(); 595 | json.put("payload", extras.getString("P")); 596 | } 597 | else{ 598 | String message = extras.getString("M"); 599 | if (message.charAt(0) == '#'){ 600 | String seqId = message.substring(message.indexOf("#") + 1,message.indexOf(":")); 601 | json.put("seqId", seqId); 602 | } 603 | String newMsg = message.substring(message.indexOf("_", message.indexOf("_") + 1) + 1); 604 | json.put("message", newMsg); 605 | } 606 | 607 | if (extras.containsKey("C")){ 608 | json.put("channel", extras.getString("C")); 609 | } 610 | 611 | Log.v(TAG, "extrasToJSON: " + json.toString()); 612 | } catch (JSONException e) { 613 | e.printStackTrace(); 614 | } 615 | return json; 616 | 617 | } 618 | 619 | 620 | public void sendJavascript(JSONObject json) { 621 | try { 622 | String send = ""; 623 | String channel = json.getString("channel"); 624 | try { 625 | 626 | WritableMap params = new WritableNativeMap(); 627 | 628 | JSONObject temp = new JSONObject(json.getString("payload")); 629 | Iterator iter = temp.keys(); 630 | while (iter.hasNext()) { 631 | String key = iter.next(); 632 | try { 633 | params.putString(key, temp.getString(key)); 634 | } catch (JSONException e) { 635 | // Something went wrong! 636 | } 637 | } 638 | WritableMap toSend = new WritableNativeMap(); 639 | toSend.putMap("payload", params); 640 | sendEvent(getReactApplicationContext(), "onPushNotification", toSend); 641 | gCachedExtras = null; 642 | } catch (JSONException ex) { 643 | WritableMap params = new WritableNativeMap(); 644 | 645 | Iterator iter = json.keys(); 646 | while (iter.hasNext()) { 647 | String key = iter.next(); 648 | try { 649 | params.putString(key, json.getString(key)); 650 | } catch (JSONException e) { 651 | // Something went wrong! 652 | } 653 | } 654 | 655 | if (queue != null){ 656 | for (int id : this.queue.keySet()){ 657 | OrtcClient cl = queue.get(id); 658 | if (cl != null && (cl.getIsConnected() && cl.isSubscribed(channel))) 659 | { 660 | gCachedExtras = null; 661 | } 662 | } 663 | } 664 | if (gCachedExtras != null){ 665 | sendEvent(getReactApplicationContext(), "onPushNotification", params); 666 | gCachedExtras = null; 667 | } 668 | 669 | } 670 | Log.i(TAG, "sendJavascript: " + send); 671 | 672 | } catch (Exception e) { 673 | Log.e(TAG, "sendJavascript: JSON exception"); 674 | } 675 | } 676 | 677 | 678 | } 679 | -------------------------------------------------------------------------------- /reactnativemessagingandroid/src/main/java/co/realtime/reactnativemessagingandroid/RealtimeMessagingPackage.java: -------------------------------------------------------------------------------- 1 | package co.realtime.reactnativemessagingandroid; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.JavaScriptModule; 5 | import com.facebook.react.bridge.NativeModule; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.uimanager.ViewManager; 8 | 9 | import java.util.Arrays; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by jcaixinha on 15/09/15. 15 | */ 16 | public class RealtimeMessagingPackage implements ReactPackage { 17 | @Override 18 | public List createNativeModules(ReactApplicationContext reactContext) { 19 | return Arrays.asList(new NativeModule[]{new RealtimeMessagingAndroid(reactContext)}); 20 | } 21 | 22 | public List> createJSModules() { 23 | return Collections.emptyList(); 24 | } 25 | 26 | @Override 27 | public List createViewManagers(ReactApplicationContext reactContext) { 28 | return Collections.emptyList(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /reactnativemessagingandroid/src/main/java/co/realtime/reactnativemessagingandroid/RealtimePushNotificationActivity.java: -------------------------------------------------------------------------------- 1 | package co.realtime.reactnativemessagingandroid; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | import com.facebook.react.ReactActivity; 7 | 8 | /** 9 | * Created by jcaixinha on 16/09/15. 10 | */ 11 | public class RealtimePushNotificationActivity extends ReactActivity { 12 | private static Activity mainParent; 13 | 14 | 15 | public static Activity getMainParent(){ 16 | return mainParent; 17 | } 18 | 19 | @Override 20 | protected String getMainComponentName() { 21 | return null; 22 | } 23 | 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | mainParent = this; 28 | super.onCreate(savedInstanceState); 29 | this.processPushBundle(); 30 | } 31 | 32 | 33 | private void processPushBundle() 34 | { 35 | Bundle extras = getIntent().getExtras(); 36 | 37 | if (extras != null) { 38 | Bundle originalExtras = extras.getBundle("pushBundle"); 39 | 40 | if(originalExtras != null){ 41 | originalExtras.putBoolean("foreground", false); 42 | RealtimeMessagingAndroid.sendExtras(originalExtras); 43 | } 44 | } 45 | } 46 | 47 | @Override 48 | protected void onPause() { 49 | super.onPause(); 50 | 51 | if (RealtimeMessagingAndroid.isOnForeground() == true) { 52 | RealtimeMessagingAndroid.setIsOnForeground(false); 53 | } 54 | } 55 | 56 | @Override 57 | protected void onResume() { 58 | super.onResume(); 59 | 60 | if (RealtimeMessagingAndroid.isOnForeground() == false) { 61 | RealtimeMessagingAndroid.setIsOnForeground(true); 62 | //this.processPushBundle(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /reactnativemessagingandroid/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ReactNativeMessagingAndroid 3 | 4 | --------------------------------------------------------------------------------