Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CloudKit for sending push notifications through cron jobs?

I'm creating a college dining menu app, in which I need to send push notifications based on the daily menus. Originally, I was planning on storing user data in a database through Heroku and using cron jobs to compare the data in the database with the daily menus and send appropriate notifications to users.

After the news on Cloudkit, however, I thought I could use that instead to manage the server-related part of my code. After closer inspection, though, it seems like Cloudkit is currently capable of storing the data, but does not allow us to write server-side code.

I'm wondering if I interpreted this limitation correctly, or if I can, in fact, schedule a database on CloudKit to compare its data to the online menus each day and send appropriate push notifications.

like image 484
Mahir Avatar asked Oct 01 '22 15:10

Mahir


2 Answers

It seems incredible you wouldn't use or consider Parse.com for something like this ...

(If not Parse, some other bAAs with a similar feature set.)

NOTE - Parse is now at back4app.com.

1) Parse is the easiest possible way to do push with an iOS app

2) the whole idea of Parse is that you have cloud code, and it's incredibly simple,

https://parse.com/docs/cloud_code_guide

you can have cloud code routines, and, you can have "cron" routines that go off regularly. it's why everyone's using Parse!

Note that it is super-easy to call "cloud functions" from iOS, with Parse.

Here's an example,

-(void)tableView:(UITableView *)tableView
        commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
        forRowAtIndexPath:(NSIndexPath *)indexPath
    {
    int thisRow = indexPath.row;
    PFUser *delFriend = [self.theFriends objectAtIndex:thisRow];

    NSLog(@"you wish to delete .. %@", [delFriend fullName] );

    // note, this cloud call is happily is set and forget
    // there's no return either way. life's like that sometimes

    [PFCloud callFunctionInBackground:@"clientRequestFriendRemove"
            withParameters:@{
                            @"removeThisFriendId":delFriend.objectId
                            }
            block:^(NSString *serverResult, NSError *error)
            {
            if (!error)
                {
                NSLog(@"ok, Return (string) %@", serverResult);
                }
            }];

    [self back];    // that simple
    }

Notice I'm calling a cloud function "clientRequestFriendRemove". So that's just a piece of cloud code I wrote and which is on our Parse account, in fact here it is

Parse.Cloud.define("clientRequestHandleInvite", function(request, response)
{
// called from the client, to accept an invite from invitorPerson

var thisUserObj = request.user;
var invitorPersonId = request.params.invitorPersonId;
var theMode = request.params.theMode;

// theMode is likely "accept" or "ignore"

console.log( "clientRequestAcceptInvite called....  invitorPersonId " + invitorPersonId + " By user: " + thisUserObj.id );
console.log( "clientRequestAcceptInvite called....  theMode is " + theMode );

if ( invitorPersonId == undefined || invitorPersonId == "" )
  {
  response.error("Problem in clientRequestAcceptInvite, 'invitorPersonId' missing or blank?");
  return;
  }

var query = new Parse.Query(Parse.User);
query.get(
  invitorPersonId,
    {
    success: function(theInvitorPersonObject)
      {
      console.log("clientRequestFriendRemove ... internal I got the userObj ...('no response' mode)");

      if ( theMode == "accept" )
        {
        createOneNewHaf( thisUserObj, theInvitorPersonObject );
        createOneNewHaf( theInvitorPersonObject, thisUserObj );
        }

      // in both cases "accept" or "ignore", delete the invite in question:
      // and on top of that you have to do it both ways

      deleteFromInvites( theInvitorPersonObject, thisUserObj );
      deleteFromInvites( thisUserObj, theInvitorPersonObject );

      // (those further functions exist in the cloud code)

      // for now we'll just go with the trick of LETTING THOSE RUN
      // so DO NOT this ........... response.success( "removal attempt underway" );
      // it's a huge problem with Parse that (so far, 2014) is poorly handled:
      // READ THIS:
      // parse.com/questions/can-i-use-a-cloud-code-function-within-another-cloud-code-function
      },
    error: function(object,error)
      {
      console.log("clientRequestAcceptInvite ... internal unusual failure: " + error.code + " " + error.message);
      response.error("Problem, internal problem?");
      return;
      }
    }
  );

}
);

(Fuller examples ... https://stackoverflow.com/a/24010828/294884 )

3) it's trivial to make Push happen from the cloud code in Parse, again this is why "everyone uses it"

For example, here's a Parse cloud code fragment that relates to Push ...

function runAPush( ownerQueryForPush, description )
// literally run a push, given an ownerQuery
// (could be 1 to millions of devices pushed to)
    {
    var pushQuery = new Parse.Query(Parse.Installation);
    pushQuery.matchesQuery('owner', ownerQueryForPush);
    Parse.Push.send
        (
        {
        where: pushQuery,
        data:
            {
            swmsg: "reload",
            alert: description,
            badge: "Increment",
            title: "YourClient"
            }
        },
        {
        success: function()
{ console.log("did send push w txt message, to all..."); },
        error: function(error)
{ console.log("problem! sending the push"); }
        }
        );
    }

4) it's unbelievably easy to do everything relating to your food database, on a nosql environment. nothing could be easier than the Parse approach

5) you get the whole back end for free (for adding foods, whatever) - normally months of work

6) finally i guess Parse is quite free (until you have so many users you'd be making a fortune anyway)

So, I can't imagine doing what you say any other way - it would be a nightmare otherwise. Hope it helps

like image 94
Fattie Avatar answered Oct 18 '22 02:10

Fattie


Server-side

As you said CloudKit doesn't allow server-side code.

But.. Welcome to

Subscriptions

Subscriptions concept is that the client registers for specific updates. You can create a record type called Daily for instance and make users register to it. You should check the Apple documentation and WWDC14 videos (even if Subscriptions are not detailed, it's a good start point).

The good thing is push notifications are linked with the subscription concept. So basically you say: Send my a notification for each new CKRecord of type Daily added.

Crons

Now the problem is your users are registers to new posts but you don't want to connect to the iCloud Dashboard everyday in order to perform the push by adding a record. One solution here is to code an app on a mac server (I guess mac mini as server will become more popular with CloudKit) that add a new Daily CKRecord every day.

Limitations

The problem is AFAIK the notification message is written on the client side, so it doesn't depend on data you send.

like image 2
Francescu Avatar answered Oct 18 '22 03:10

Francescu