Introducing Bolts for Parse SDKs

Bolts Framework

Earlier this year we introduced the Bolts Framework, a set of low-level libraries to make developing mobile apps easier and faster. One of the core components of Bolts is Tasks. Tasks brings the programming model of JavaScript Promises to iOS and Android.

Today, we are proud to open an entirely new set of public APIs with the new versions of our iOS, OS X and Android SDKs. Inside this release you will find that every method that was once intended to be asynchronous now has a Tasks-based counterpart. Organizing complex asynchronous code is now much more manageable in addition to being easier and faster to implement.

For example, here’s how you can find posts, mark them all as published, and update the UI on iOS:

PFQuery *query = [PFQuery queryWithClassName:@"Post"];
[query whereKey:@"published" notEqualTo:@YES];
[[query findObjectsInBackground] continueWithSuccessBlock:^id(BFTask *task) {
  NSArray *results = task.result;

  NSMutableArray *saveTasks = [NSMutableArray arrayWithCapacity:[results count]];
  for (PFObject *post in results) {
    post[@"published"] = @YES;
    [saveTasks addObject:[post saveInBackground]];
  }
  return [BFTask taskForCompletionOfAllTasks:saveTasks];
}] continueWithExecutor:[BFExecutor mainThreadExecutor] withSuccessBlock:^id(BFTask *task) {
  _postStatusLabel.text = @"All Posts Published!";
  return task;
}];

And here’s how it looks on Android:

ParseQuery<ParseObject> query = ParseQuery.getQuery("Post");
query.whereNotEqualTo("published", true);
query.findInBackground().onSuccessTask(new Continuation<List<ParseObject>, Task<Void>>() {
  @Override
  public Task<Void> then(Task<List<ParseObject>> task) throws Exception {
    List<ParseObject> results = task.getResult();
        
    List<Task<Void>> saveTasks = new ArrayList<Task<Void>>();
    for (final ParseObject post : results) {
      post.put("published", true);
      saveTasks.add(post.saveInBackground());
    }
    return Task.whenAll(saveTasks);
  }
}).onSuccess(new Continuation<Void, Void>() {
  @Override
  public Void then(final Task<Void> task) {
    mPostStatusTextView.setText(String.format("All Posts Published!"));
    return null;
  }
}, Task.UI_THREAD_EXECUTOR);

As you can see, there’s a lot of advantages to this approach when it comes to branching, chaining tasks, parallelizing across multiple threads, and handling complex errors.

We are really excited about this release and would love to hear your feedback. Let us know what you think!

Nikita Lutsenko
October 15, 2014

Android Push Gets Major Refresh

We’re excited to announce today that the Android Push API is getting its biggest facelift since inception. We’ve rethought the API to bring Parse Push better in line with both other Parse APIs and traditional Android development. The new API simplifies developer setup, provides better reliability, and is much more easily extended or customized to override default push behavior.

With the new API, we’ve decoupled the concepts of registration and reaction; the icon and activity which you want push to use are no longer statically bound to a channel. You can replace all calls to

PushService.subscribe(myApplicationContext, "channel", MyActivity.class, intIconID);

with

ParsePush.subscribeInBackground("channel");

Notice the InBackground suffix in the new APIs on ParsePush? The Android API now exposes when the Parse servers have accepted a subscription change in addition to any reason why the request may have failed. When the new API receives a push, it fires the com.parse.push.intent.RECEIVE Intent. We’ve provided a BroadcastReceiver implementation that automatically handles the vast majority of our developer’s needs. You can register it with the following additions to your manifest:

<receiver android:name="com.parse.ParsePushBroadcastReceiver"
  android:exported="false">
  <intent-filter>
    <action android:name="com.parse.push.intent.RECEIVE" />
    <action android:name="com.parse.push.intent.DELETE" />
    <action android:name="com.parse.push.intent.OPEN" />
  </intent-filter>
</receiver>

This BroadcastReceiver will suit most developers needs without any additional configuration. Your pushes will show your application’s default icon and launch your application’s main activity when touched. To provide a different icon, specify it with the com.parse.push.notification_icon meta-data in your AndroidManifest.xml. You no longer need to add push open tracking calls throughout your activities; we do it automatically in the BroadcastReceiver. If the contents of your push are too long for the normal UI, we’ll automatically create the expanded layout available in Android 4.1 JellyBean (API 16) and up.

We’re also introducing a new special field for Android pushes too! If you specify the uri push option, the Notification created will navigate to that URI rather than launching the default Activity. For example, the sending the following push from Cloud Code would create a notification that sends users to the Parse blog.

Parse.Push.send({
  where: new Parse.Query(Parse.Installation), // Everyone
  data: {
    alert: "Android Push Gets Major Refresh",
    uri: "http://blog.parse.com",
  }
})

When the user clicks ‘back’, they will be sent to your launcher Activity (overridden with getActivity). As a security precaution, the uri option may not be used when a push is sent from a client.

If your app has more sophisticated needs, you can easily subclass ParsePushBroadcastReceiver to tweak the behavior of your application without foregoing all of the built-in features. Subclass our BroadcastReceiver and put your new class in the manifest instead of ours. You can react to push notification events by overriding any of onPushReceived, onPushOpen, or onPushDismiss. If you need to customize the Notification that we create, you can override getNotification.

We’re very excited for this new API. If you’re not ready to adopt the new API quite yet, the old push APIs are deprecated but still work exactly as they did before. We hope you are excited for the new approach. It’s now easier than ever to get started and to transition from turn-key implementations to much more sophisticated ones.

Thomas Bouldin
September 30, 2014

Parse SDK for iOS 8, Performance, and Security

Parse SDK for iOS 8

We’re excited that the big day is finally here — iOS 8 is finally available to everyone! We spent the last few weeks waiting patiently and getting ready. Today we’re rolling out a new version of the Parse SDK for iOS with support for iOS 8 as well as a bunch of other performance and security improvements.

Parse and iOS 8

We updated our SDK to make sure it runs smoothly on iOS 8 and benefits from all the new APIs available. Just to name a couple, we’ve updated how [PFGeoPoint geoPointForCurrentLocationInBackground:] works to be smarter about requesting the appropriate permissions depending on the state of the app, and we’ve updated our push notification integration everywhere to use the new permissions style and support the category key.

Performance Improvements for Parse Files

Parse Files let you easily store application files in the cloud that would otherwise be too large or cumbersome to fit into a regular database-style Parse Object. This release of the iOS (and OS X) SDK brings greatly improved performance for Parse Files. Uploading is now up to 3 times faster and downloading is up to 35% faster. We’re also using fewer system resources which leads to better battery usage for file-heavy apps.

Improved Security for Account Data

The Parse SDK now uses the System Keychain on both iOS and OS X to store sensitive user information tied to PFUser. All of this happens automatically and under the hood so you don’t need to make any changes on your end.

Try It Out

The latest iOS SDK is now available for download here. Send us your feedback! We hope you’re as excited as we are about the new features and possibilities that iOS 8 brings.

Nikita Lutsenko
September 18, 2014

Ready for iOS 8? So is Parse Push

In this year’s WWDC, Apple announced some great changes to iOS Notifications. First, Apple has increased the maximum payload size to two kilobytes rather than 256 bytes. This new limit is retroactive and works with all existing devices! The more subtle changes to push notifications involve security and interaction with notifications.

“Silent” pushes are push notifications that don’t create UI; they instead tell your app to fetch or react to new content available online. In iOS 8, Apple has separated out the permissions for UI and push. The push permission is auto-accepted by default too! This means your iOS 8 apps will be able to much more reliably depend on the ability to receive silent notifications in iOS 8. To migrate your app, change the following code:

// Before iOS 8:
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert |
                                                                      UIRemoteNotificationTypeBadge |
                                                                      UIRemoteNotificationTypeSound];

to

// For iOS 8:
UIUserNotificationSettings *settings =
    [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert |
                                                 UIUserNotificationTypeBadge |
                                                 UIUserNotificationTypeSound
                                      categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
Even if the user declines permission for creating UI, the permission to send (silent) pushes is auto-accepted for most users.

Notice the nil param for categories above? Categories unlock a whole new dimension to push notifications in iOS 8. Categories describe “actions” that should be presented in your notification in various views. Actions provide custom buttons your users can use when interacting with your push notification; your action can launch the app into the foreground or even trigger a background action, such as accepting or declining a calendar invite. To enable this feature, you must define a UIUserNotificationCategory. These categories have an identifier string and a map of UIUserNotificationActionContext to many UIUserNotificationActions. A UIUserNotificationActionContext comes in two flavors: default and minimal. The default context specifies which actions should be presented when the notification has an alert UI and supports a maximum of four actions; the minimal context specifies which actions should be presented when the notification has a banner UI or is on the lock screen and supports a maximum of two actions.  Once you’ve registered notification categories with your application, sending them via Parse Push is easy: simply pass the category identifier as the category option in your push. This feature is supported retroactively on all Parse SDKs, you don’t even need to upgrade! You may, however, want to check out the new UIApplicationDelegate method application:handleActionWithIdentifier:forRemoteNotification:completionHandler:

iOS 8 allows developers to define actions an end user can take when responding to a notification.

We look forward to seeing the great things you build with Parse and iOS 8!

Thomas Bouldin
September 15, 2014

The Dangerous World of Client Push

Push Notifications are one of the most effective ways for apps to increase user engagement and retention, notify customers of important information like sales and new products, or allow users communicate with each other. A messaging app, for example, could use push notifications to alert users to an incoming message from their friend in the app. But be careful, because the most obvious way to do this can expose you to a security risk.

One easy way to send push notifications to particular users from within an app is to send the pushes directly from the client code, for example by using PFPush on iOS. This is tempting, because you have all the information you need to send the push straight from within iOS, and the code to send the push is very simple. But as Bryan mentioned in his security series, clients can’t be trusted to send push notifications directly. Some nefarious hacker could modify the client code, changing the Objective-C or Java code to modify the push’s alert text, or to send pushes to people they shouldn’t be able to. The hacker could steal your app’s keys and send pushes himself without even using the app.

Sounds scary! Luckily, there is a simple way around this security vulnerability. In your app’s settings, under “Push Notifications”, there is a toggle that lets you disable “Client Push.” We highly recommend that you set this switch to “OFF,” and instead of sending the push notifications from the client, you should write Cloud Code functions that validate the user and the data to be pushed before sending them. Client Push is disabled by default, but this feature can still be useful for initial prototyping if you want to hook up push notifications without diving into Cloud Code as you iterate. But as you scale to a production app, you really should not have Client Push enabled.

Here is one example of how to port your pushes from the client into Cloud Code, starting with an example Client Push to a single user, stored in userObject. Here’s the old iOS code:

// WRONG WAY TO SEND PUSH - INSECURE!
PFQuery *pushQuery = [PFInstallation query];
[pushQuery whereKey:@"user" equalTo:userObject];
PFUser *user = [PFUser currentUser];
NSString *message = [NSString stringWithFormat:@"%@ says Hi!", user[@"name"]];

PFPush *push = [[PFPush alloc] init];
[push setQuery:pushQuery]; // Set our Installation query
[push setMessage:message];
[push sendPushInBackground];

And on Android:

// WRONG WAY TO SEND PUSH - INSECURE!
ParseQuery pushQuery = ParseInstallation.getQuery();
pushQuery.whereEqualTo("user", userObject);
ParseUser currentUser = ParseUser.getCurrentUser();
String message = currentUser.getString("name") + " says Hi!";

ParsePush push = new ParsePush();
push.setQuery(pushQuery); // Set our Installation query
push.setMessage(message);
push.sendInBackground();

To move these push calls to Cloud Code, first we would write a Cloud function, sendPushToUser, to verify that the user sending the push is allowed to send it and that the alert text is what it should be.

Parse.Cloud.define("sendPushToUser", function(request, response) {
  var senderUser = request.user;
  var recipientUserId = request.params.recipientId;
  var message = request.params.message;

  // Validate that the sender is allowed to send to the recipient.
  // For example each user has an array of objectIds of friends
  if (senderUser.get("friendIds").indexOf(recipientUserId) === -1) {
    response.error("The recipient is not the sender's friend, cannot send push.");
  }

  // Validate the message text.
  // For example make sure it is under 140 characters
  if (message.length > 140) {
  // Truncate and add a ...
    message = message.substring(0, 137) + "...";
  }

  // Send the push.
  // Find devices associated with the recipient user
  var recipientUser = new Parse.User();
  recipientUser.id = recipientUserId;
  var pushQuery = new Parse.Query(Parse.Installation);
  pushQuery.equalTo("user", recipientUser);
 
  // Send the push notification to results of the query
  Parse.Push.send({
    where: pushQuery,
    data: {
      alert: message
    }
  }).then(function() {
      response.success("Push was sent successfully.")
  }, function(error) {
      response.error("Push failed to send with error: " + error.message);
  });
});

 After you deploy this Cloud function, you can call the code from iOS like this:

[PFCloud callFunctionInBackground:@"sendPushToUser"
                   withParameters:@{@"recipientId": userObject.id, @"message": message}
                            block:^(NSString *success, NSError *error) {
  if (!error) {
     // Push sent successfully
  }
}];

And on Android:

HashMap<String, Object> params = new HashMap<String, Object>();
params.put("recipientId", userObject.getObjectId());
params.put("message", message);
ParseCloud.callFunctionInBackground("sendPushToUser", params, new FunctionCallback<String>() {
   void done(String success, ParseException e) {
       if (e == null) {
          // Push sent successfully
       }
   }
});

Now that you have moved the Push logic into Cloud Code, you can disable Client Push in your app settings, and spoil the hacker’s evil plan! We hope you learned how to use Cloud Code to secure your app’s push notifications, and that you will think twice before enabling Client Push for your app. As always, feel free to ask questions or let us know what you think on our new Help page.

Jamie
September 3, 2014

Open Sourcing the f8 Conference Apps

f8 App

 

As part of the f8 conference experience, we launched iOS and Android apps built entirely on Parse. The app enabled conference attendees to stay up-to-date with upcoming talks, get to know the speakers, and receive push notifications on talks they had marked as favorites.

This app grew out of the Parse Developer Day apps, and was thoroughly customized to match the f8 experience. Using Parse to build these apps was a fun experience, and it took one iOS and Android developer around two weeks to deliver the apps. Parse Data was used to store all the conference data and much of the User Interface (UI) customizations and assets, enabling quick iteration on design changes across iOS and Android. Even after the app was shipped, last minute updates were possible without touching code, simply by using the Data Browser. And, as talks were in session, the Push Console was used for ad hoc messaging to conference attendees–it’s vitally important to know when to pick up those T-shirts.

Today, we are releasing the source code for these apps so you can peek under the hood and see how they were built. The source code is available on GitHub. We hope they will serve as good guidance for how to build apps on Parse. We also hope others find them useful as a starting point for their own conference apps. We can’t wait to see what you do with them!

Christine Abernathy
August 28, 2014

Parse for PHP: A Fractal of Rad Design

Parse for PHP

Today we are very happy to release the Parse PHP SDK, which will enable Parse integration for a whole new class of apps and different use cases. This is our first SDK for a server-side language, and the first to be truly open-source.

PHP is an incredibly popular programming language and has consistently been in the top 10 on the TIOBE index for the past 15 years. Some metrics report that it is still serving the vast majority of websites on the internet. Until now, if you wanted to access Parse from PHP, the REST API was the only option. A few Parse API wrapper libraries have been released by third parties on GitHub. While we think this is awesome, many developers requested better PHP support and we decided to build a first-party SDK.

Earlier this year at Facebook’s f8 developer conference, we launched the completely re-invented Facebook SDK for PHP. In the 3 months since it was released there have been over 160 commits, with good solid contributions and enhancements from 20 passionate developers who use and care about the product. It has been a lot of fun managing the process for the Facebook SDK, and I’m looking forward to working together with the community on this Parse SDK.

For a fast overview of the SDK, check out the README file. We’ve also updated our documentation with a new PHP guide, and added a PHP Quickstart with installation instructions. We encourage you to report any issues and requests on GitHub.

Go build something awesome with Parse + PHP!

Fosco Marotto
August 5, 2014

Parse Security VI – Quiz Time

In Part VI of our five-part series on how to secure your Parse app, let’s take a quiz and see how well you know your stuff. If you can’t handle having Part VI in a five-part series, then maybe you should go read up on buffer overflow exploits. ;-)

Part I   Part II   Part III   Part IV   Part V

Bryan Klimt
August 4, 2014

Parse Security V – How to Make Friends

In the first four parts of this five-part series on how to secure your Parse app, we’ve taken a look at all of the different features that Parse has to help you secure your app and your users’ data. In Part V, let’s put it all together and take a look at a real example of how you can use these features to solve a complex use case.

Most classes in your app will fall into one of a couple of easy-to-secure categories. For fully public data, you can use class-level permissions to lock down the table to put publicly readable and writeable by no one. For fully private data, you can use ACLs to make sure that only the user who owns the data can read it. But occasionally, you’ll run into situations where you don’t want data that’s fully public or fully private. For example, you may have a social app, where you have data for a user that should be readable only to friends whom they’ve approved. For this you’ll need to use ACLs, roles, and Cloud Code together to enable exactly the sharing rules you desire.

If you aren’t clear on those features, go back and read Parts II – IV of this series. Once you’re clear on what ACLs, roles, and Cloud Code are, let’s dig into some code. The first thing you’ll need to do is set up a place for the user’s social data to live. Let’s assume you want to create a “FriendData” object for each user that stores the data that should be visible to their friends. To create this object for each new user, you can use an afterSave handler.

Parse.Cloud.afterSave(Parse.User, function(request, response) {
    var user = request.object;
    if (user.existed()) { return; }
    var roleName = "friendsOf_" + user.id;
    var friendRole = new Parse.Role(roleName, new Parse.ACL(user));
    return friendRole.save().then(function(friendRole) {
        var acl = new Parse.ACL();
        acl.setReadAccess(friendRole, true);
        acl.setReadAccess(user, true);
        acl.setWriteAccess(user, true);
        var friendData = new Parse.Object("FriendData", {
          user: user,
          ACL: acl,
          profile: "my friend profile"
        });
        return friendData.save();
    });
});

The first couple of lines just set up the request. On line 3, we check to see if the user already existed. If so, then we’ve already completed this setup, and there’s no reason to do it again. On lines 4-6, we create a new role. This role will represent the friends of the user being created. We generate a unique name for the role. The role is created with an ACL that only allows this user to read or write it. In other words, only the user themselves can decide who their friends are.

Once the role is created, lines 7-10 create an ACL that grants read permission to friends of the user. And of course the user receives read and write permission for their own social data. Once the ACL is set up, lines 11-16 actually create the object. The user is set on the object so that it can be found with a query later. The profile field is set as an example of data that will be readable only to the users friends.

So, that’s everything you need to set up an object for every user that will be readable only to people in their special friends role. Of course, that’s worthless without any way for people to get added to your friends list, so we need to address that with another function. Technically, this function could be written in any client and be secure, but for the sake of consistency, let’s make another Cloud Code function. This function will be called “friend.”  It will take one parameter: the objectId of the person to friend. This person will then be added to the friends role of the current user.

Parse.Cloud.define("friend", function(request, response) {
    var userToFriend = new Parse.User();
    userToFriend.id = request.params.friendId;

    var roleName = "friendsOf_" + request.user.id;
    var roleQuery = new Parse.Query("_Role");
    roleQuery.equalTo("name", roleName);
    roleQuery.first().then(function(role) {
        role.getUsers().add(userToFriend);
        return role.save();

    }).then(function() {
        response.success("Success!");    
    });
});

Lines 1-3 just set up the function and create a User object to represent the person being added to the friend role. Lines 5-8 fetch the Role object using its name. A Role is just a special kind of Parse object, so we need to fetch it before we can modify it. Once the role has been fetched, we add this user to it on line 9, and save it on line 10. That’s all there is to it! Now we have an easy way to store data that’s only accessible to a user’s friends.

Over the course of this five-part series on how to secure your Parse app, we’ve looked at a lot of features. You know the about the various keys used to access your app. We’ve looked at the permissions you can set to lock down a whole class. You’ve learned about ACLs and how they can secure per-user data. And we’ve even dived deep into a particular example of how you can use Cloud Code to tackle even the trickiest data models.

We hope that you’ll use these tools to do everything you can to keep your app’s data and your users’ data secure. Together, we can make the web a safer place.

Part I   Part II   Part III   Part IV

Bryan Klimt
July 28, 2014

Parse Security IV – Ahead in the Cloud

In our first three posts on how to secure your Parse app, we looked at your app’s keys, class-level permissions, and object-level ACLs. For many apps, that’s all you need to keep your app and your users’ data safe. But sometimes you’ll run into an edge case where they aren’t quite enough. For everything else, there’s Cloud Code.

With Cloud Code, you can upload JavaScript to Parse’s servers, where we will run it for you. Unlike client code running on users’ devices that may have been tampered with, Cloud Code is guaranteed to be the code that you’ve written, so it can be trusted with more responsibility. For example, if you need to validate the data that a user has entered, you should do it in Cloud Code so that you know a malicious client won’t be able to bypass the validation logic. Specifically to help you validate data, Cloud Code has beforeSave triggers. These triggers are run whenever an object is saved, and allow you to modify the object, or completely reject a save. For example, this is how you create a Cloud Code trigger to make sure every user has an email address set:

Parse.Cloud.beforeSave(Parse.User, function(request, response) {
  var user = request.object;
  if (!user.get("email")) {
    response.error("Every user must have an email address.");
  } else {
    response.success();
  }
});

To upload this trigger, follow the instructions in our guide for setting up the Parse command line tool.

You can also use your master key in Cloud Code to bypass the normal security mechanism for trusted code. For example, if you want to allow a user to “like” a “Post” object without giving them full write permissions on the object, you can do so with a Cloud Code function. Every API function in the Cloud Code JavaScript SDK that talks to Parse allows passing in a useMasterKey option. By providing this option, you will use the master key for that one request.

Parse.Cloud.define("like", function(request, response) {
  var post = new Parse.Object("Post");
  post.id = request.params.postId;
  post.increment("likes");
  post.save(null, { useMasterKey: true }).then(function() {
    response.success();
  }, function(error) {
    response.error(error);
  });
});

One very common use case for Cloud Code is sending push notifications to particular users. In general, clients can’t be trusted to send push notifications directly, because they could modify the alert text, or push to people they shouldn’t be able to. Your app’s settings will allow you to set whether “client push” is enabled or not; we recommend that you make sure it’s disabled. Instead, you should write Cloud Code functions that validate the data to be pushed before sending a push.

In this post, we’ve looked at how you can use Cloud Code to write trusted code, to keep your data secure in cases where class-level permissions and ACLs aren’t enough. In Part V, we’ll dive into a particular example of how to use ACLs, Roles, and Cloud Code to let users have data that is shared only to their friends.

Part I   Part II   Part III   Part V

Bryan Klimt
July 21, 2014