2017-07-26 236 views

回答

1

我已经使用FCM的通知发送给用户。我使用了Mongodb,Nodejs和fcm-push节点模块。

请参阅代码,希望它能帮助你。

deviceModel.js:

var mongoose = require('mongoose'); 
var Schema = require('mongoose').Schema; 

var schema = new Schema({ 
    userId: { type: Schema.Types.ObjectId }, 
    userType: { type: String }, 
    deviceType: { type: String, required: true, enum: ['apn', 'gcm'] }, 
    deviceId: { type: String, required: true }, 
    timestamp: { type: Date, default: Date.now } 
}); 

module.exports = mongoose.model('Device', schema); 

push.js:

var pushModule = require('./push'); 
var DeviceModel = require('./DeviceModel'); 
var highland = require('highland'); 
var FCM = require('fcm-push'); 
var serverKey = config.get('fcmServerKey'); 
var fcm = new FCM(serverKey); 
var _ = require('lodash'); 


/** 
* Handle fcm push results and updates/invalidates device ids. 
* 
* @param {String[]} deviceIds - array of device ids used in send. 
* @param {Object} fcmResponse - fcm send response. 
*/ 
function handleFcmSendResult(deviceIds, fcmResponse) { 

    // fcm results 
    var results = fcmResponse.results; 

    // changes for deviceIds 
    var fcmUpdated = []; 
    var fcmDeleted = []; 

    // process results 
    for (var i = 0; i < results.length; i++) { 

     var oldId = deviceIds[i]; 
     var deviceResult = results[i]; 
     var msgId = deviceResult.message_id; 
     var newId = deviceResult.registration_id; 

     if (_.isString(msgId) && _.isString(newId)) { 
      // If registration_id is set, replace the original ID with the new value 
      fcmUpdated.push({ oldId: oldId, newId: newId }); 
     } else { 
      // Otherwise, get the value of error 
      var e = deviceResult.error; 

      if (e === 'Unavailable') { 
       winston.warn('Push: FCM: Feedback: device unavailable: %s.', oldId); 
      } else if (e === 'NotRegistered' || e === 'InvalidRegistration') { 
       // delete invalid devices 
       fcmDeleted.push(oldId); 
      } 
     } 
    } 

    // apply changes, in bulk 
    var bulkOp = DeviceModel.collection.initializeUnorderedBulkOp(); 


    if (fcmUpdated.length > 0) { 
     fcmUpdated.forEach(function (upd) { 
      bulkOp.find({ deviceId: upd.oldId }).update({ deviceId: upd.newId, timestamp: Date.now() }); 
     }); 

     // those old ids that are updated, need not be deleted 
     fcmDeleted = _.difference(fcmDeleted, _.map(fcmUpdated, _.property('oldId'))); 
    } 

    if (fcmDeleted.length > 0) { 
     bulkOp.find({ deviceId: { '$in': fcmDeleted } }).remove(); 
    } 

    console.log(bulkOp); 
    // run bulk op 
    bulkOp.execute(); 
} 


/** 
* Dispatch FCM push to device ids. 
* 
* @param {String[]} deviceIds - array of apn device ids. 
* @param {String} eventName - event name. 
* @param {*} eventData - event data. 
*/ 
function sendFcm(deviceIds, eventName, eventData) { 
    // payload 
    var msgOpts = { 
     priority: 'high', 
     registration_ids: deviceIds, 
     data: _.set(eventData, 'eventName', eventName), 
     notification: eventData, 
     content_available: true, 
     mutable_content: true 
    }; 

    fcm.send(msgOpts) 
     .then(function (response) { 
      console.log("SENT :",response); 
      // handleFcmSendResult(deviceIds, JSON.parse(response)); 
     }) 
     .catch(function (err) { 
      winston.error('Push: FCM: Error sending push.', err); 
     }) 
} 


/** 
* Sends push notifications to Device docs emitted from stream. 
* 
* @param {Stream.Readable} docStream - Stream of device docs. 
* @param {String} eventName - event name. 
* @param {*} eventData - event data. 
*/ 
function streamSend(docStream, eventName, eventData) { 
    // stream for fcm 
    var fcmStream = highland(); 

    // batch device ids from sub stream and sent to gcm 
    fcmStream.batch(1000).each(function (fcmIds) { 
     sendFcm(fcmIds, eventName, eventData); 
    }); 

    // split source to sub streams 
    highland(docStream).each(function (doc) { 
     fcmStream.write(doc.deviceId); 
    }).done(function() { 
     // end sub streams when doc source is done 
     fcmStream.end(); 
    }); 

} 



/** 
* Sends the event via push to all registered devices. 
* @param {String} eventName - event name. 
* @param {Object} eventData - event data. Can contain a "notification" object with: title, description and icon. 
*/ 
var pushToPublic = function (eventName, eventData) { 
    var str = DeviceModel.find().cursor(); 
    streamSend(str, eventName, eventData); 
} 

/** 
* Sends the event via push to devices that are mapped to given user ids. 
* @param {ObjectId[]} userIds - array of user ids. 
* @param {String} eventName - event name. 
* @param {Object} eventData - event data. Can contain a "notification" object with: title, description and icon. 
*/ 
var pushToUserIds = function (userIds, eventName, eventData) { 
    var str = DeviceModel.find({ userId: { '$in': userIds } }).cursor(); 
    streamSend(str, eventName, eventData); 
} 


// Send notification test function 
var sendNotification = function() { 
    var payload = { 
     "updatedAt": "2017-06-17T06:12:42.975Z", 
     "message": "this is notification message", 
     "typeId": "591452ecad4c6b71bed61089", 
     "userId": "5912d45f29945b6d649f287e", 
     "_id": "5913f90d08b4d213f1ded021", 
     "isRead": false, 
     "isPublic": true, 

     // ORDER DELIVERD 
     "type": "order", 
     "title_loc_key": "title_order_delivered", 
     "title_loc_args": ["OrderValue"], 
     "body_loc_key": "body_order_delivered", 
     "body_loc_args": ["reminderValue"], 
    }; 

    // pushToPublic("testEvent", payload); 
    pushToUserIds(['59562201a544614d47845eef'], "testEvent", payload) 
} 

sendNotification(); 

结果:

SENT:{ "multicast_id":1234567891234567890, 
     "success":1, 
     "failure":0, 
     "canonical_ids":0, 
     "results":[{ 
        "message_id": "0:12345678912345678912345678912345678" 
       }] 
    }