├── .gitignore ├── README.md ├── bower.json ├── changelog.md ├── ionic-push.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .*.sw* 2 | node_modules/ 3 | *~ 4 | lib/ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NOTICE: 2 | 3 | This library has been deprecated by the [ionic-platform-web-client](https://github.com/driftyco/ionic-platform-web-client). 4 | 5 | Head over to our [docs](https://docs.ionic.io) to learn more about setting up a project with the Ionic Platform. 6 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-service-push", 3 | "version": "0.1.13", 4 | "homepage": "http://ionic.io", 5 | "authors": [ 6 | "Max Lynch ", 7 | "William Pelrine " 8 | ], 9 | "description": "Ionic Mobile Platform Push Notifications client", 10 | "main": "ionic-push.js", 11 | "license": "Apache2", 12 | "ignore": [ 13 | "**/.*", 14 | "node_modules", 15 | "bower_components", 16 | "test", 17 | "tests" 18 | ], 19 | "dependencies": { 20 | "ionic-service-core": " >= 0.1.9" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | ## 0.1.13 5 | 6 | * Fixed a log typo telling people to set gcm_id instead of gcm_key 7 | 8 | ## 0.1.12 9 | 10 | * Updated dependencies. 11 | 12 | ## 0.1.11 13 | 14 | * Added support for auto-generated $ionicCoreSettings factory, will fall back to $ionicApp.get() if it can't find app ID and API key. 15 | -------------------------------------------------------------------------------- /ionic-push.js: -------------------------------------------------------------------------------- 1 | angular.module('ionic.service.push', ['ngCordova', 'ionic.service.core']) 2 | 3 | /** 4 | * The Ionic Push service client wrapper. 5 | * 6 | * Example: 7 | * 8 | * angular.controller(['$scope', '$ionicPush', function($scope, $ionicPush) { 9 | * }]) 10 | * 11 | */ 12 | .factory('$ionicPush', ['$http', '$cordovaPush','$cordovaLocalNotification', '$ionicApp', '$ionicPushActions', '$ionicUser', '$ionicCoreSettings', '$rootScope', '$log', '$q', 13 | 14 | function($http, $cordovaPush, $cordovaLocalNotification, $ionicApp, $ionicPushActions, $ionicUser, $ionicCoreSettings, $rootScope, $log, $q) { 15 | 16 | // Grab the current app 17 | var app = {} 18 | var oldApp = $ionicApp.getApp(); 19 | if ($ionicCoreSettings.get('app_id') && $ionicCoreSettings.get('api_key')) { 20 | // Get needed values form core settings 21 | app.app_id = $ionicCoreSettings.get('app_id'); 22 | app.api_key = $ionicCoreSettings.get('api_key'); 23 | app.gcm_key = $ionicCoreSettings.get('gcm_key'); 24 | app.dev_push = $ionicCoreSettings.get('dev_push'); 25 | 26 | // Make sure we don't overwrite their old dev_push 27 | if (oldApp.dev_push === false) { 28 | app.dev_push = false; 29 | } 30 | 31 | if (!app.gcm_key) { 32 | console.warn('PUSH: Unable to get GCM project number, run "ionic config set gcm_key your-gcm-id"'); 33 | } 34 | } else { 35 | console.warn('CORE: Unable to load app ID or API key, falling back to $ionicApp.getApp()...'); 36 | app = oldApp; 37 | app.gcm_key = $ionicApp.getGcmId(); 38 | } 39 | 40 | //Check for required credentials 41 | if(!app || !app.app_id) { 42 | console.error('PUSH: Unable to initialize, you must call $ionicAppProvider.identify() first'); 43 | } 44 | 45 | function generateDevGuid() { 46 | // Some crazy bit-twiddling to generate a random guid 47 | return 'DEV-xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 48 | var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); 49 | return v.toString(16); 50 | }); 51 | } 52 | 53 | function init(options) { 54 | var defer = $q.defer(); 55 | 56 | // TODO: This should be part of a config not a direct method 57 | var gcmKey = app.gcm_key; 58 | var api = $ionicApp.getValue('push_api_server'); 59 | 60 | //Default configuration 61 | var config = { 62 | "senderID": gcmKey, 63 | "badge": true, 64 | "sound": true, 65 | "alert": true 66 | }; 67 | 68 | /** 69 | * For testing push notifications, set the dev_push flag in your config to true. 70 | **/ 71 | if (app.dev_push) { 72 | var localNotifications = false; 73 | // If they have the local notification plugin, let them receive notifications with it, otherwise just do alerts 74 | if (window.cordova && window.cordova.plugins && window.cordova.plugins.notification && window.cordova.plugins.notification.local) { 75 | localNotifications = true; 76 | } 77 | 78 | var devToken = generateDevGuid(); 79 | var devHost = api + '/dev/push'; 80 | 81 | var req = { 82 | method: 'POST', 83 | url: devHost, 84 | data: { 85 | "dev_token": devToken 86 | } 87 | }; 88 | 89 | $http(req).success(function(resp){ 90 | console.log('$ionicPush:REGISTERED_DEV_MODE', devToken); 91 | $rootScope.$emit('$cordovaPush:tokenReceived', { 92 | token: devToken, 93 | platform: 'none' 94 | }); 95 | defer.resolve(devToken); 96 | }).error(function(error){ 97 | console.log("$ionicPush: Error connecting dev_push service ", error); 98 | }); 99 | 100 | var checkReq = { 101 | method: 'GET', 102 | url: devHost + '/check', 103 | headers: { 104 | 'Content-Type': 'application/json', 105 | 'X-Ionic-Dev-Token': devToken 106 | } 107 | }; 108 | 109 | // Check for new dev pushes every 5 seconds 110 | var checkPushes = setInterval(function(){ 111 | $http(checkReq).success(function(resp){ 112 | if (resp.messages.length > 0) { 113 | var notification = {}; 114 | notification.alert = resp.messages[0]; 115 | console.warn("Calling onNotification() for a development push. Payload will NOT be available"); 116 | var callbackRet = options.onNotification && options.onNotification(notification); 117 | // If the custom handler returns false, don't handle this at all in our code 118 | if(callbackRet === false) { 119 | return; 120 | } 121 | 122 | if (localNotifications) { 123 | console.log('$ionicPush: Attempting to send local notification.'); 124 | window.cordova.plugins.notification.local.registerPermission(function (granted) { 125 | if (granted) { 126 | window.cordova.plugins.notification.local.schedule({ 127 | title: 'DEVELOPMENT PUSH', 128 | text: resp.messages[0] 129 | }); 130 | } 131 | }); 132 | } else { 133 | console.log('$ionicPush: No device, sending alert instead.'); 134 | alert(resp.messages[0]); 135 | } 136 | } 137 | }).error(function(error){ 138 | console.log("$ionicPush: Error checking for dev pushes ", error); 139 | }); 140 | }, 5000); 141 | 142 | /** 143 | * It's a notmal push, do normal push things 144 | */ 145 | } else { 146 | $cordovaPush.register(config).then(function(token) { 147 | console.log('$ionicPush:REGISTERED', token); 148 | 149 | defer.resolve(token); 150 | 151 | if(token !== 'OK') { 152 | 153 | $rootScope.$emit('$cordovaPush:tokenReceived', { 154 | token: token, 155 | platform: 'ios' 156 | }); 157 | 158 | // Push the token into the user data 159 | try { 160 | $ionicUser.push('_push.ios_tokens', token, true); 161 | } catch(e) { 162 | console.warn('Received push token before user was identified and will not be synced with ionic.io. Make sure to call $ionicUser.identify() before calling $ionicPush.register.'); 163 | } 164 | } 165 | }, function(err) { 166 | console.error('$ionicPush:REGISTER_ERROR', err); 167 | }); 168 | } 169 | 170 | $rootScope.$on('$cordovaPush:notificationReceived', function(event, notification) { 171 | console.log('$ionicPush:RECEIVED', JSON.stringify(notification)); 172 | 173 | var callbackRet = options.onNotification && options.onNotification(notification); 174 | 175 | if (ionic.Platform.isAndroid() && notification.event == "registered") { 176 | /** 177 | * Android handles push notification registration in a callback from the GCM service (whereas 178 | * iOS can be handled in a single call), so we need to check for a special notification type 179 | * here. 180 | */ 181 | console.log('$ionicPush:REGISTERED', notification.regid); 182 | $rootScope.$emit('$cordovaPush:tokenReceived', { 183 | token: notification.regid, 184 | platform: 'android' 185 | }); 186 | androidInit(notification.regid); 187 | } 188 | 189 | // If the custom handler returns false, don't handle this at all in 190 | // our code 191 | if(callbackRet === false) { 192 | return; 193 | } 194 | 195 | // If we have the notification plugin, show this 196 | if(options.canShowAlert && notification.alert) { 197 | if (navigator.notification) { 198 | navigator.notification.alert(notification.alert); 199 | } else { 200 | // Browser version 201 | alert(notification.alert); 202 | } 203 | } 204 | 205 | if(options.canPlaySound) { 206 | if (notification.sound && window.Media) { 207 | var snd = new Media(notification.sound); 208 | snd.play(); 209 | } 210 | } 211 | 212 | if(options.canSetBadge) { 213 | if (notification.badge) { 214 | $cordovaPush.setBadgeNumber(notification.badge).then(function(result) { 215 | // Success! 216 | }, function(err) { 217 | console.log('Could not set badge!', err); 218 | // An error occurred. Show a message to the user 219 | }); 220 | } 221 | } 222 | 223 | // Run any custom notification actions 224 | if(options.canRunActionsOnWake) { 225 | if(notification.foreground == "0" || notification.foreground === false) { 226 | $ionicPushActions.run(notification); 227 | } 228 | } 229 | }); 230 | 231 | 232 | return defer.promise; 233 | } 234 | 235 | function androidInit(token) { 236 | // Push the token into the user data 237 | try { 238 | $ionicUser.push('_push.android_tokens', token, true); 239 | } catch(e) { 240 | console.warn('Received push token before user was identified and will not be synced with ionic.io. Make sure to call $ionicUser.identify() before calling $ionicPush.register.'); 241 | } 242 | } 243 | 244 | return { 245 | /** 246 | * Register for push notifications. 247 | * 248 | * Configure the default notification behavior by using the options param: 249 | * 250 | * { 251 | * // Whether to allow notifications to pop up an alert while in the app. 252 | * // Setting this to false lets you control the push behavior more closely. 253 | * allowAlert: true/false (default: true) 254 | * 255 | * // Whether to allow notifications to update the badge 256 | * allowBadge: true/false (default: true) 257 | * 258 | * // Whether to allow notifications to play a sound 259 | * allowSound: true/false (default: true) 260 | * 261 | * // Whether to run auto actions, like navigating to a state, when a push 262 | * // is opened outside of the app (foreground is false) 263 | * canRunActionsOnWake: true/false (default: true) 264 | * 265 | * // A callback to do some custom task on notification 266 | * onNotification: true/false (default: true) 267 | * } 268 | */ 269 | register: function(options, userdata){ 270 | return $q(function(resolve) { 271 | if (!app) { 272 | return; 273 | } 274 | 275 | options = angular.extend({ 276 | canShowAlert: true, 277 | canSetBadge: true, 278 | canPlaySound: true, 279 | canRunActionsOnWake: true, 280 | onNotification: function () { 281 | return true; 282 | }, 283 | onTokenRecieved: function (token) { } 284 | }, options); 285 | 286 | var user = {}; 287 | 288 | if (userdata) { 289 | if (!userdata.user_id) { 290 | // Set your user_id here, or generate a random one 291 | console.warn("No user ID specified in userdata or existing model, generating generic user ID."); 292 | user.user_id = $ionicUser.generateGUID(); 293 | }; 294 | 295 | angular.extend(user, userdata); 296 | 297 | console.log('$ionicPush: Identifying user', user.user_id); 298 | $ionicUser.identify(user).then(function () { 299 | resolve(init(options)); 300 | }); 301 | } else { 302 | user = $ionicUser.get(); 303 | if (!user.user_id){ 304 | console.log('$ionicPush: Registering anonymous user.'); 305 | $ionicUser.identifyAnonymous().then(function() { 306 | resolve(init(options)); 307 | }); 308 | } else { 309 | resolve(init(options)); 310 | } 311 | } 312 | }); 313 | }, 314 | unregister: function(options) { 315 | return $cordovaPush.unregister(options); 316 | } 317 | } 318 | }]) 319 | 320 | .factory('$ionicPushActions', [ 321 | '$rootElement', 322 | '$injector', 323 | function($rootElement, $injector) { 324 | return { 325 | run: function(notification) { 326 | var state = false; 327 | var stateParams = {}; 328 | if (ionic.Platform.isAndroid()) { 329 | if (notification.payload.payload.$state) { 330 | state = notification.payload.payload.$state; 331 | } 332 | if (notification.payload.payload.$stateParams) { 333 | try { 334 | stateParams = JSON.parse(notification.payload.payload.$stateParams); 335 | } catch(e) {} 336 | } 337 | } else if (ionic.Platform.isIOS()) { 338 | if (notification.$state) { 339 | state = notification.$state; 340 | } 341 | if (notification.$stateParams) { 342 | try { 343 | stateParams = JSON.parse(notification.$stateParams); 344 | } catch(e) {} 345 | } 346 | } 347 | 348 | if (state) { 349 | // Auto navigate to state 350 | var injector = $rootElement.injector(); 351 | $state = injector.get('$state'); 352 | $state.go(state, stateParams); 353 | } 354 | } 355 | } 356 | }]); 357 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ionic-service-push", 3 | "version": "0.1.13", 4 | "description": "Ionic Push Component", 5 | "dependencies": { 6 | "ionic-service-core": ">=0.1.8" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/driftyco/ionic-service-push-client.git" 11 | }, 12 | "keywords": [ 13 | "Ionic", 14 | "push" 15 | ], 16 | "author": "Ionic", 17 | "license": "Apache 2.0", 18 | "bugs": { 19 | "url": "https://github.com/driftyco/ionic-service-push-client/issues" 20 | }, 21 | "homepage": "https://github.com/driftyco/ionic-service-push-client#readme" 22 | } 23 | --------------------------------------------------------------------------------