Internationalization


PFLogInViewController in simplified Chinese

The iOS App Store is available in 150 countries. For an app developer, this means that if you put in the hard work to localize your app to different markets, you could be rewarded with increased sales from overseas.

At Parse, a lot of our developers are from Europe, China, Japan, and Israel. Frequently they ask us for internationalization support of the Parse framework, especially the UI components including PFLogInViewController, PFSignUpViewController and PFQueryTableViewController.

Today, we are annoucing the internationalization of Parse. This enables developers to localize all resource strings in the Parse framework.

Say, for example, you would like to localize the loading message in the HUD of PFSignUpViewController that says “Loading…” to simplified Chinese. Assume you have followed the Apple localization guide and set up Localizable.strings in the zh-Hans.lproj directory. In Localizable.strings, you can then enter:

"Loading..." = "进行中";

That is all you need to do to localize the string to “进行中”. The key on the left is the original string you want to localize, and the value on the right is the localized value.

More documentation is available here.

Andrew Wang
July 31, 2012

Anypic: A Photo Sharing App With Tutorial

Yesterday we unveiled the Parse App Gallery showcasing apps built on top of Parse. Today, we’re adding one of our own apps to the list. Anypic is a photo sharing app for iOS and the web built entirely using Parse.

Anypic includes functionality such as logging in with Facebook, sending push notifications, storing photos using Parse’s file storage, executing relational queries, and securing objects with ACLs. You can download Anypic from the App Store and start sharing pictures with your friends today!

We’ve shared the source code for Anypic and published a tutorial that shows you how to build it from scratch, joining Anywall in our list of sample apps. You can build your own version of Anypic by following the directions to create an app and add your keys to the Xcode project.

We hope that Anypic serves as a base for your own photo sharing apps, and that it inspires you to build many great apps on top of Parse.

Héctor Ramos
July 26, 2012

The Parse App Gallery

At Parse, we’re proud of our platform. But, we’re even more proud of the apps that developers have built on top of Parse. Ever since our beta launch, we’ve been surprised, impressed, and astounded by the apps that the Parse community has created.

Today, we’re launching the Parse App Gallery, which showcases apps that are powered by Parse. Developers have spent a lot of time and effort in building these apps, so in turn, we’ve designed a beautiful place to show them off.

If you have an app powered by Parse that you’d like to show off, submit it now! We’ll be adding to this gallery as developers launch their apps.

We’ve come a long way from our launch a little over a year ago. Back then, I remember celebrating the first few Parse apps that launched. Today, we have over 25,000 apps being developed across iOS, Android, HTML5, and countless other platforms enabled by our third party REST libraries. These include apps across all genres: games, utilities, social networking apps, enterprise apps, and much more.

James Yu
July 25, 2012

Simple And Safe In-App Purchase Using Parse

In iOS development, setting up in-app purchases (IAPs) can be a challenge. If the IAP requires downloading associated content, developers have to build a backend that can deliver these content files securely. The backend should only make the content available to the user after the purchase has been validated by the server. If your server skips this important validation step, the content will be susceptible to digital theft. This can be a lot of work.

At Parse, we have heard a lot about the difficulties of integrating IAPs from our developer community. Today, we are introducing Parse’s IAP solution, which addresses the problems and is simpler to use than Store Kit. Let’s say you want to sell a product named “Pro” that gets rid of all the ads in the app:

// First, register a handler for the product
[PFPurchase addObserverForProduct:@"Pro" block:^(SKPaymentTransaction *transaction) {
    // Write business logic that should run once this product is purchased.
    isPro = YES;
}];

// ... Later, when the user is purchasing the product:
[PFPurchase buyProduct:@"Pro" block:^(NSError *error) { ... }];

Parse can host your digital downloads and deliver them securely. Using the data browser, you can upload the content files to the Product class on Parse. To download the file in the app:

[PFPurchase addObserverForProduct:@"Pro" block:^(SKPaymentTransaction *transaction) {
    [PFPurchase downloadAssetForTransaction:transaction completion:
            ^(NSString *filePath, NSError *error) { ... }];
}];

// ... Later, when the user is purchasing the product:
[PFPurchase buyProduct:@"Pro" block:^(NSError *error) { ... }];

The call to +[PFPurchase downloadAssetForTransaction:completion:] will tell Parse to validate the transaction with Apple before making the download available. Parse makes it easy for you to work with in-app purchases in a way that safeguards your digital downloads.

More information can be found in our documentation. And as always, your feedback is welcome.

Andrew Wang
July 24, 2012

Targeting Pushes from a Device

You may have noticed the we recently introduced advanced push targeting for iOS push notifications sent through our REST API. We’re continuing to expand our push targeting by enabling the same advanced targeting for pushes which are sent from iOS devices, starting with iOS SDK v1.0.61.

You can read the push targeting blog post for inspiration on the myriad ways for targeting pushes, but let’s step through a simple example which is specific to pushing from a device: sending a notification that doesn’t get delivered to the sending device.

// Build a target query: everyone in the chat room except for this device.
PFQuery *query = [PFInstallation query];
NSString *installationId = [PFInstallation currentInstallation].installationId;
[query whereKey:@"channels" equalTo:chatRoomName];
[query whereKey:@"installationId" notEqualTo:installationId];

// Send the notification.
PFPush *push = [[PFPush alloc] init];
[push setQuery:query];
[push setMessage:@"Hi everyone!"];
[push sendPushInBackground];

You’ll need to enable client push for this sample code to work. Also note that queries constructed with [PFInstallation query] can only be used for targeting push notifications, and cannot be used to retrieve installation data. We hope you enjoy cooking up some awesome query-targeted pushes!

Brian Jacokes
July 23, 2012

Badge Management for iOS

Automatic badge management

Today we’re excited to announce the release of automatic badge management in iOS. The heart of this feature is the
PFInstallation class, which lets you persist badge numbers to Parse for use in auto-badged push notifications.

Let’s take a walk through a typical example. Say you are building a group messaging app, and want to push a message from one sender to a set of receiving devices that will increment each device’s badge. The tricky thing is that the badge numbers could be different among the receiving devices, and the sender doesn’t know what those badge numbers are. Parse will take care of it for you, though, if the sending device creates a push like this:

NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:
    messageContent, @"alert",
    @"Increment", @"badge",
    nil];
PFPush *push = [[PFPush alloc] init];
[push setChannel:chatRoomName];
[push setData:data];
[push sendPushInBackground];

The special "Increment" badge value will tell Parse that the badge
field for each matching Installation should be incremented and the
new value used in the push payload. If you were to specify a numerical
value for the badge, that value will be written in the badge field of
each matching Installation before the push is sent. The badges can
be left the same by simply omitting the badge key from your push data.

Of course, badges eventually need to be cleared, and a good time is
usually when your app is opened. Setting the badge property on the
current installation will update the application icon badge number
and ensure that the latest badge value will be persisted to the server
on the next save, so all you need to do is:

- (void)applicationDidBecomeActive:(UIApplication *)application {
  PFInstallation *currentInstallation = [PFInstallation currentInstallation];
  if (currentInstallation.badge != 0) {
    currentInstallation.badge = 0;
    [currentInstallation saveEventually];
  }
  // ...
}

The UIApplicationDelegate documentation contains more information on hooks into an app’s life cycle; the ones which are most relevant for resetting the badge count are applicationDidBecomeActive:, application:didFinishLaunchingWithOptions:, and application:didReceiveRemoteNotification:.

We hope you find this feature useful in managing badges for your app!

Brian Jacokes
July 18, 2012

Remote Images In A Table View Controller

A few years ago when I was writing my first iOS app, I was stunned by how much code I had to write in order to display remote images in a table view. It is a common problem many developers face, yet it is so difficult that Apple had to publish a tutorial to show how it is done. Even with the guide published, how to load web images in a table view controller remains one of the most asked iOS questions on StackOverflow.

A lot of developers on Parse store their images using the PFFile API. They often ask us how to display these images in a table view, and in the past we have been providing code samples to guide them. However, we always feel strongly that this level of complexity should be hidden away so that application developers need not worry about when and how to load remote images. Developers should simply tell the table view controller which remote images to load, and everything else is taken care of for them.

Yesterday, we announced the introduction of PFImageView which makes remote image loading in a UIImageView really simple. Today, we are announcing an API that makes image loading in a UITableViewController a joy. PFQueryTableViewController just became more powerful:

@interface SimpleTableViewController : PFQueryTableViewController
@end
@implementation SimpleTableViewController

- (UITableViewCell *)tableView:(UITableView *)tableView 
    cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
    static NSString *identifier = @"Cell";
    PFTableViewCell *cell = 
        [tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        cell = [[PFTableViewCell alloc] 
                    initWithStyle:UITableViewCellStyleDefault
                    reuseIdentifier:identifier];
    }
    PFFile *thumbnail = [object objectForKey:@"thumbnail"];
    cell.imageView.image = [UIImage imageNamed:@"placeholder.jpg"];
    cell.imageView.file = thumbnail;
    return cell;
}
@end

All developers need to do is to subclass PFQueryTableViewController and override tableView:cellForRowAtIndexPath:object: to return a PFTableViewCell with its imageView‘s file property specified. If you would like to display a placeholder image to be shown before the remote image is loaded, assign the placeholder image to the image property of the imageView.

The downloading and lazy loading of images are managed by the PFQueryTableViewController. As the user scrolls through the table, the images in the currently visible cells are automatically downloaded, without any work from the developers.

More information can be found in our documentation. And as always, your feedback is welcome.

Andrew Wang
July 12, 2012

Loading Images Stored on Parse

Parse developers love using our framework to store images. Be it photos taken by app users, or static asset pictures too big to ship with the app, a large number of images are uploaded to Parse daily using the PFFile API.

Displaying a remote image in an iOS app, however, is far from a walk in the park. Lots of boilerplate code is needed to first download the image, cache it on disk and in memory, and then decode and display it in an image view. Moreover, the developer needs to be careful about dispatching work to the background thread or the main thread, to keep the UI responsive. This is a lot of work.

Today, we are introducing a new class that makes downloading and displaying these images really easy. Introducing PFImageView:

PFImageView *creature = [[PFImageView alloc] init];
creature.image = [UIImage imageNamed:@"1.jpg"]; // placeholder image
creature.file = (PFFile *)file;
[creature loadInBackground];

The PFImageView class inherits from UIImageView, and is simple to use. You assign a placeholder image to its image property, so that the placeholder is displayed before the remote image is downloaded. Then you assign a PFFile object, which is the remote image stored on Parse, to its file property. When you are ready to load the image, call loadInBackground to initiate the download. That’s it. When the download finishes, Parse does the work to update the image view and display the remote image.

Since Parse does both memory and disk caching, you get the benefit of both without doing any extra work. For example, if you are loading from the same PFFile twice, Parse is going to look for it in memory and in the disk cache first before attempting to download the file.

More information can be found in our documentation. And as always, your feedback is welcome.

Andrew Wang
July 11, 2012

REST Examples in Python

The only thing better than writing code is having it written for you. That’s why we’ve just launched a new feature in our REST API guide. You have always been able to use the REST API from the language of your choice. Now, in addition to curl commands, we give you the REST examples in the language of your choice, too. Just pick on from the drop-down menu next to the example. We’ve started with Python.

REST examples in python

We’ll be adding more languages over time. Which ones would you like to see?

Shyam Jayaraman
July 9, 2012

Pushing to Queries in iOS


We’ve seen developers get a lot of mileage out of our push-to-channel model at Parse. We’ve had channels named after users, sports matchups, and geographical locations in order to target different groups of devices. It’s great that channels have gotten so much use, but it has also become clear that there’s a need for a more powerful model for targeting push notifications.

A couple of months ago, we moved push subscription data into the special Installation class to allow developers to more easily access and modify this information. Each installation object represents an instance of your app being installed on a device, and contains an array of channel subscriptions along with identifiers needed to send a push to the app. Starting with this week’s release of our iOS SDK v1.0.56, there is a PFInstallation class which lets you directly access the current installation object from within your app. In addition, installation objects now have flexible schemas so that you can add arbitrary fields beyond the built-in identifier and channel fields.

Because of these changes, our REST API now supports powerful push targeting for iOS devices using push-to-query. You can specify a where clause in your REST push request which acts like a normal object query over the Installation class, except that the results are used as the target of the push notification instead of being returned. For example, if you store a preferred language and app version in your app’s installation objects, you can target an upgrade reminder with:

curl -X POST 
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" 
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" 
  -H "Content-Type: application/json" 
  -d '{
        "where": {
          "language": "en",
          "version": { "$lt": 1.2 }
        },
        "data": {
          "alert": "Version 1.2 is now available in the app store!"
        }
      }' 

https://api.parse.com/1/push

There are several other uses for push targeting:

  • To target all installations, just send a push with where={}.
  • To target a certain User, you can add a relation from each Installation to the currently logged-in User and push to a simple relational query.
  • To subscribe devices to updates about a sports team, you can add a relation from each Installation to its favorite Team objects. Using relational queries, you can push to devices that are interested in individual teams, as well as more complicated queries like “devices interested in teams that are playing tonight”.
  • To target users who are near a certain location, you can store the current location in each Installation object and push to a geo query.

We hope you enjoy this new functionality, and we’re looking forward to adding these features to Android in the near future!

Brian Jacokes
July 6, 2012

Archives

Categories

RSS Feed Follow us Like us