Quantcast
Channel: Envato Tuts+ Code - Mobile Development
Viewing all 1836 articles
Browse latest View live

Accessing Google Services Using the OAuth 2.0 Protocol

$
0
0

This tutorial will dive into implementing Google Services using the OAuth 2.0 protocol. Read on!


OAuth 2.0 Overview

The OAuth 2.0 protocol provides a simple and secure standard that allows third-party applications to access major service providers like Facebook, G+, and Twitter without compromising user passwords. The whole idea revolves around the existence of an access token, something like a unique key that can identify a user in place of a password. Access tokens are obtained by third-party applications after the user successfully authenticates with a web service. The whole process, known as authorization flow, begins when a user enters his credentials into a login window and finishes when the access token is acquired. The access token is usually refreshed from time to time. With this token, there is no need for any of the user’s personal data or password to be transmitted over the web each time that a client application asks for access on behalf of the user.

If you are not familiar with the OAuth 2.0 protocol you should do some background reading now before continuing this tutorial. Specifically, review the following links:

In general, the OAuth 2.0 authorization flow adheres to the following pattern:

  1. Let users connect to their online account.
  2. Get an authorization code (i.e. authorization token).
  3. Exchange the authorization code for an access token and a refresh token.
  4. Use the access token to interact with a web service or an API.
  5. Use the refresh token to update the access token when needed.

Google and OAuth 2.0

Google is one of the many third-party web service providers that have adopted the OAuth 2.0 protocol. It provides many APIs for accessing almost all of its services (like Calendar, Blogger, etc.) through client applications and provides guidance on how to implement the authorization flow with various programming languages and platforms. Every application that needs to use any of the Google web services must first register with the Google Developer Console, an administration panel where all the client applications developed by a user are managed. When registering an app in the Console, a client id and a client secret are created specifically for this app. These values, along with some others, are used by OAuth to authorize an app and to obtain the access token. After having registered an application, there are a number of available services that can be integrated into projects. These services are accessed through APIs that are provided for each one. Some of them are free of charge while others require a fee before Google will let you use them beyond a courtesy/trial usage limit.

From this point forward, I’ll assume that you are familiar with OAuth 2.0 principles, so it’s time to visit the Using OAuth 2.0 for Installed Applications documentation from Google. This documentation presents the authorization flow supported by Google for client applications implemented for mobile or desktop platforms and is going to be our guide on the project of this tutorial. Also, I would recommend that you surf around a little using the menu options at the top-left side of the window and the links inside the text in order to gain a deeper understanding on Google services and the way the OAuth 2.0 protocol works.


Project Overview

This project will teach you how to create a class that will contain the OAuth 2.0 client-side implementation for accessing Google’s API and services. This class will be part of a simple demo application. The GUI will be really simple, as we only need to test the class, so we are going to spend a great deal of time actually coding. In order to test the OAuth protocol implementation, we will ask for the user profile information from Google, which will be displayed in our app. Also, in order for our work to be as complete as possible, we will add extra checks and error handling messages. After this class is ready, it can be used in real projects for accessing Google services. Of course, it can be improved or be modified by anyone at any time.

Before we begin writing one line of code, we need to register the demo application in the Google Developers Console. To do this, we’ll need the app’s name. For the sake of our project, I’m using the name GoogleOAuthDemo. If you prefer some other name, make sure to use it instead of mine in the steps that follow.

For now, here is a screenshot of the final product:

gt5_final

1. Register the iOS Application

Step 1

Our first step is to register the iOS application in the Google Developer Console because we need to acquire a Client ID and a Client Secret value pair. So, inside a new browser tab/window, visit the Google Developers website. At the top-right side of the window, a Sign In button exists. Click it and the next window will show up.

gt5_2_signin_window

If you have an account in any Google service (like gmail, Google+, Drive, etc.) then you can login using the credentials from this account. If you don’t have one already, or you just want to create a new one, now is the time to do it, simply by clicking on the Sign Up button.

gt5_3_signup_button

In case you are making a new account, enter any required information, create it, and login to the Google Developers website.

Step 2

Once you get connected with the Google Developers account, you might become quite curious about all the stuff this page contains, so go ahead and take a look if you wish. Surely you’ll find some pretty interesting topics. Scroll to the bottom side of the page, until you see the Developer Tools area. Click on the API Console link.

gt5_4_api_console_icon

Step 3

When you create an application in the Developers Console, the information regarding it is grouped all together and it’s called a project. Through it, you can manage all the APIs, users, authorization, and more stuff that you use in your applications. I would advise to look at the Help section (at the top-right side of the webpage) if you want to find detailed information about the console.

Let’s get back on track. When you first look at this webpage, you notice a drop-down menu at the top-left side of the webpage, named API Project. If you expand it, you’ll find some extra options, where by using them you can create new projects, delete them, rename them, and more. We don’t need anything from it, so if you have expanded it, click on it to collapse it. Beneath the drop-down menu, there are four options:

  1. Overview
  2. Services
  3. Team
  4. API Access
gt5_5_dashboard

If you click on the Services option, you’ll see all the services that Google offers with APIs. Next to each service there are some notes indicating which of them require a fee. To use any of them in an application, first you must register your application, then implement the OAuth protocol and finally ask for the appropriate APIs.

Click on the API Access option now. This is the place where we’ll register our new application. Click on the big blue button with the title “Create an OAuth 2.0 client ID…”.

gt5_6_create_oauth_button

In the popup window, add as the Product Name the Google OAuth 2.0 iOS Implementation Demo value and click on Next.

gt5_7_create_client_id_1

In the next step, set the following:

  • Application Type: Installed application
  • Installed Application Type: iOS
  • Bundle ID: com.yourdomain.googleoauthdemo (for example, com.gabrieltheodoropoulos.googleoauthdemo)
gt5_8_create_client_id_2

Click on the Create client ID button now and you are ready. As you can see at the next screenshot, you can easily find the client ID and the client secret values.

gt5_9_client_id_secret

You can find out for yourself that you can edit all the information we just entered using the provided links and buttons in the webpage. The data we are going to use in our demo application is:

  • client ID
  • client secret
  • Redirect URI

At this point, the first part of our mission is over. Our app has been registered in the Google Developers Console and we have all the necessary information we want. The hard part though is coming next, where we are going to actually implement the OAuth 2.0 protocol in code.


2. Create the Demo Project

Time to begin building our app. Launch Xcode and create a new project. At the first step, select the Single View Application option from the provided templates.

gt5_10_project_template

Next, specify the GoogleOAuthDemo in the Product Name field of the project’s options window.

gt5_11_project_options

Lastly, select a place to save your project and click on the Create button.

gt5_12_project_create

3. Create the Interface

Step 1

Click on the ViewController.xib file to launch Interface Builder. Drag-and-drop the next subviews on the default view:

  1. A Table View.
  2. A Toolbar.

Also, apart from the default Bar Button Item that the toolbar contains, add:

  1. A Flexible Space Bar Button Item and
  2. A Bar Button Item

Make sure that the one button is at the left side of toolbar, while the second is at the right side of it. The flexible space should be between them.

Step 2

Let’s now do a couple of settings.

  • Select the View and set its Size to None so it works on 3.5″ iPhone screens as well.
    1. Open the Utilities pane.
    2. Show the Attributes Inspector tab.
    3. In the Simulated Metrics section set the Size to None.
    gt5_13_size_none
  • Set the frame of the Table View to: X: 0, Y: 0, Width: 320, Height: 416.
  • Set the Title of the left Bar Button Item to My Profile.
  • Set the Title of the right Bar Button Item to Revoke access.

That’s all we want from our interface and this is how it should look now:

gt5_14_interface_sample

4. Setup IBOutlets & IBActions

Step 1

Our interface is prepared, but we need an IBOutlet property to connect the Table View. We also need two IBAction methods if we want our buttons to work. So, while we are in Interface Builder, Click on the middle button of the Editor section on the Xcode toolbar to make the Assistant Editor appear.

gt5_15_assistant_editor

Step 2

With the goal of creating the necessary IBOutlet connection, open the Document Outline and perform the following steps:

  1. Control + Click or Right + Click on the Table View.
  2. On the popup menu, click on the New Referencing Outlet.
  3. Drag-and-drop into the Assistant Editor window, just like you see in the next image.
gt5_16_iboutlet_create

Give a name for the Table View and click on the Connect button. I simply named it table.

gt5_17_iboutlet_name

Step 3

Let’s create the two IBAction methods now. Apply the following procedure in both the Bar Button Items.

  1. Control + Click or Right + Click on the left Bar Button item.
  2. Click on the Selector option in the Sent Actions section of the popup menu.
  3. Drag-and-drop into the Assistant Editor window.
gt5_18_ibaction_create

Set the showProfile as the name for the method and create it.

gt5_19_ibaction_name

Give the name revokeAccess to the next IBAction method when you create it. Your ViewController.h file after the IBOutlet property and the IBAction methods should look like this:

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UITableView *table;
- (IBAction)showProfile:(id)sender;
- (IBAction)revokeAccess:(id)sender;
@end

5. Create the OAuth 2.0 Protocol Implementation File

Step 1

Even though we added a Table View in the project, we won’t implement its delegate methods for the time being. This is something that we are going to do when the OAuth 2.0 implementation is over. What we are going to do in this step is to create a new file where we will build the OAuth protocol.

On the Project Navigator, do the following:

  1. Control + Click or Right + Click on the GoogleOAuthDemo group.
  2. Select the New File… option from the menu.
gt5_20_new_file

Step 2

In the window that appears, select the Objective-C class option as the template for the new file:

gt5_21_new_file_template

Next, at the Subclass of field, select the UIWebView option. Our new class is going to be a subclass of the UIWebView class, because we want to show a web view to the users for letting them sign in with their Google account and grant them access to our application. At the Class field, add the GoogleOAuth value:

gt5_22_new_file_options

On the next step, just click on the Create button to get the new files made.

gt5_23_new_file_create

6. The OAuth 2.0 Flow

In this part, I will shortly describe how the OAuth 2.0 flow will be implemented and how all the necessary checking for the existence of the tokens and the validity of the access token is going to take place. First of all, after the access token has been obtained, it should be stored permanently along with any other info that comes with it. It’s up to the developer to choose the way that all this information will be saved. You may store everything into a database, save it to the user defaults, write everything to files, or use more secure methods in order to keep things safe. In this tutorial, I prefer to save all in plain files, inside the Documents directory of the app.

We are going to create two different files. The access token and any other information that comes with it from Google is going to be stored into the first one, except for the refresh token. The refresh token is going to be saved in another file, because we need to keep it for a longer period than everything else and use it when the access token has expired. Every time that the access token is being refreshed, the contents of the first file are overwritten. Besides that, the refresh token itself is not refreshed that often.

So, having said all that, here is a preview of the protocol’s flow and how it is going to be implemented.

gt5_oauth_flow

Even though an image equals a thousand words, I would better describe the whole procedure to make it more clear. To elaborate on the authorization process:

  • In case the file that contains the access token information does not exist…
  1. The URL that we will require an access token from is being formed. All the necessary parameters to authenticate the user are provided. The client ID and client secret values are needed here.
  2. Next, we display a web view inside the app (we don’t call Safari) to let the user sign in to Google. After a successful login, a message from Google with the permissions we ask for is displayed to the user, who should consent if he/she wants to go any further.
  3. An authorization code comes back from Google, which will be exchanged with the access token right after.
  4. A new URL is formed with new parameters. The aim is to exchange the authorization code with the access token.
  5. If the access token is successfully obtained, the caller class is informed via a delegate method. Otherwise, using another delegate method we let the caller class know that the access token was not obtained, so further actions should be taken as needed.
  • In case the file that contains the access token information already exists…
    1. The access token info is loaded from the file.
    2. The access token is checked to see whether it has expired or not.
    3. If the access token is valid, then the caller class simply gets notified through a delegate method that is valid and these steps end here. Otherwise, a refresh is required (next steps).
    4. If the file that contains the refresh token is not found in the Documents directory, then the whole OAuth flow starts over. If it exists, then the refresh token is loaded.
    5. A new access token is requested. If the refresh token is not valid, a kind of error message will be returned from Google and the user is guided to the beginning again. Otherwise the access token is obtained.
    6. So, let’s see everything step-by-step.


      7. Start building

      Step 1

      At first, open the GoogleOAuth.h file and adopt the next two protocols, simply by declaring them in the @interface header line:

      @interface OAuth : UIWebView <UIWebViewDelegate, NSURLConnectionDataDelegate>
      @end

      I am pretty sure that it is quite obvious what these delegates are for.

      Step 2

      Now let’s create an enum type, with the acceptable HTTP method values required for various API calls. For the time being, we’ll create the enum type, but we’ll use it when we’ll implement the API call method.

      So, right above the @interface line at the GoogleOAuth.h file, add the following:

      typedef enum {
          httpMethod_GET,
          httpMethod_POST,
          httpMethod_DELETE,
          httpMethod_PUT
      } HTTP_Method;

      Step 3

      It’s always useful to use constants for things that we don’t want to make any mistakes about, and that is true for the URL endpoints we want to access during the OAuth flow. For that reason, open the GoogleOAuth.m file and declare the following two constants at the top of the file:

      #define authorizationTokenEndpoint  @"https://accounts.google.com/o/oauth2/auth"
      #define accessTokenEndpoint         @"https://accounts.google.com/o/oauth2/token"

      The first URL will be used to access the endpoint for getting the authorization code, which we will exchange then with the access token using the second endpoint. Let’s move on now and let’s declare some private properties that are going to hold some essential data.

      Step 4

      While working in the GoogleOAuth.m file, inside the private part of the interface, add the following properties. There are comments above each property that explain their purpose:

      // The client ID from the Google Developers Console.
      @property (nonatomic, strong) NSString *clientID;
      // The client secret value from the Google Developers Console.
      @property (nonatomic, strong) NSString *clientSecret;
      // The redirect URI after the authorization code gets fetched. For mobile applications it is a standard value.
      @property (nonatomic, strong) NSString *redirectUri;
      // The authorization code that will be exchanged with the access token.
      @property (nonatomic, strong) NSString *authorizationCode;
      // The refresh token.
      @property (nonatomic, strong) NSString *refreshToken;
      // An array for storing all the scopes we want authorization for.
      @property (nonatomic, strong) NSMutableArray *scopes;
      // A NSURLConnection object.
      @property (nonatomic, strong) NSURLConnection *urlConnection;
      // The mutable data object that is used for storing incoming data in each connection.
      @property (nonatomic, strong) NSMutableData *receivedData;
      // The file name of the access token information.
      @property (nonatomic, strong) NSString *accessTokenInfoFile;
      // The file name of the refresh token.
      @property (nonatomic, strong) NSString *refreshTokenFile;
      // A dictionary for keeping all the access token information together.
      @property (nonatomic, strong) NSMutableDictionary *accessTokenInfoDictionary;
      // A flag indicating whether an access token refresh is on the way or not.
      @property (nonatomic) BOOL isRefreshing;
      // The parent view where the webview will be shown on.
      @property (nonatomic, strong) UIView *parentView;

      Note that for the access token there is not a specific NSString property, but we have the accessTokenInfoDictionary NSMutableDictionary for storing all the access token related data in it.

      Step 5

      Time to do some initializations. Go inside the - (id)initWithFrame:(CGRect)frame and add the following code:

      - (id)initWithFrame:(CGRect)frame
      {
          self = [super initWithFrame:frame];
          if (self) {
              // Set the access token and the refresh token file paths.
              NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
              NSString *docDirectory = [paths objectAtIndex:0];
              _accessTokenInfoFile = [[NSString alloc] initWithFormat:@"%@/acctok", docDirectory];
              _refreshTokenFile = [[NSString alloc] initWithFormat:@"%@/reftok", docDirectory];
              // Set the redirect URI.
              // This is taken from the Google Developers Console.
              _redirectUri = @"urn:ietf:wg:oauth:2.0:oob";
              // Make any other required initializations.
              _receivedData = [[NSMutableData alloc] init];
              _urlConnection = [[NSURLConnection alloc] init];
              _refreshToken = nil;
              _isRefreshing = NO;
          }
          return self;
      }

      The rest of the initializations will take place inside the methods that they will be used, so for now we are just fine.


      8. Define a protocol

      Defining a protocol inside a new class is a task that is done usually after most of the class’ functionality has been completed, but in our case it would be nice if we have had the protocol definition prepared before we go any further. What we will actually do is to declare the protocol methods that will be implemented later by the classes that will adopt the protocol. So, inside the GoogleOAuth.h file and above the @interface line, add the next few lines:

      @protocol GoogleOAuthDelegate
      -(void)authorizationWasSuccessful;
      -(void)accessTokenWasRevoked;
      -(void)responseFromServiceWasReceived:(NSString *)responseJSONAsString andResponseJSONAsData:(NSData *)responseJSONAsData;
      -(void)errorOccuredWithShortDescription:(NSString *)errorShortDescription andErrorDetails:(NSString *)errorDetails;
      -(void)errorInResponseWithBody:(NSString *)errorMessage;
      @end

      Here is a short description of the above methods:

    • authorizationWasSuccessful : It will be used after a successful authorization, meaning after having obtained a valid access token.
    • accessTokenWasRevoked : This delegate method will be used when the user revokes all the granted permissions.
    • responseFromServiceWasReceived:andResponseJSONAsData: : This method will be called every time that a response to an API call is received.
    • errorOccuredWithShortDescription:andErrorDetails: : Called when a general error occurs.
    • errorInResponseWithBody: : This delegate method will be called when an error in the HTTP response exists.

    Next, inside the @interface, add the next line:

    @interface OAuth : UIWebView <UIWebViewDelegate, NSURLConnectionDataDelegate>
    @property (nonatomic, strong) id<GoogleOAuthDelegate> gOAuthDelegate;
    @end

    9. Authorization Flow Setup

    Step 1

    Until now, we declared all the private member variables we are going to need and initialized some of them, we defined constants, delegates, and protocol, so it’s now time to begin implementing the actual authorization flow. The best place to begin from is the “entry” point, a public method that the user will call every time that should be authorized or use an API.

    Go to the GoogleOAuth.h file and add the next method declaration:

    @interface GoogleOAuth : UIWebView <UIWebViewDelegate, NSURLConnectionDataDelegate>
    @property (nonatomic, strong) id<GoogleOAuthDelegate> gOAuthDelegate;
    -(void)authorizeUserWithClienID:(NSString *)client_ID andClientSecret:(NSString *)client_Secret
                        andParentView:(UIView *)parent_View andScopes:(NSArray *)scopes;
    @end

    Step 2

    Let’s go to the implementation now. I think it would be better to have the method built first and then discuss it a little bit. Inside the GoogleOAuth.m file add the next snippet:

    -(void)authorizeUserWithClienID:(NSString *)client_ID
                          andClientSecret:(NSString *)client_Secret
                          andParentView:(UIView *)parent_View
                          andScopes:(NSArray *)scopes{
        // Store into the local private properties all the parameter values.
        _clientID = [[NSString alloc] initWithString:client_ID];
        _clientSecret = [[NSString alloc] initWithString:client_Secret];
        _scopes = [[NSMutableArray alloc] initWithArray:scopes copyItems:YES];
        _parentView = parent_View;
        // Check if the access token info file exists or not.
        if ([self checkIfAccessTokenInfoFileExists]) {
            // In case it exists load the access token info and check if the access token is valid.
            [self loadAccessTokenInfo];
            if ([self checkIfShouldRefreshAccessToken]) {
                // If the access token is not valid then refresh it.
                [self refreshAccessToken];
            }
            else{
                // Otherwise tell the caller through the delegate class that the authorization is successful.
                [self.gOAuthDelegate authorizationWasSuccessful];
            }
        }
        else{
            // In case that the access token info file is not found then show the
            // webview to let user sign in and allow access to the app.
            [self showWebviewForUserLogin];
        }
    }

    Let’s talk a little about the way the method that we just wrote works. As you can see, the first thing we do is to store all the values being passed into the method as parameters to the local properties. These are the client ID, the client secret, the scopes array and the UIView that the login webview shall appear within.

    A scope indicates an API that the app requests access for.

    Next, we check if the access token info file exists or not. In case it exists, we load it using the loadAccessTokenInfo method. We check if it’s valid using the checkIfShouldRefreshAccessToken method and if it’s not, we refresh it by using the refreshAccessToken method. In case the access token is valid and it has not yet expired, we just inform the caller class through the authorizationWasSuccessful delegate method. Finally, if the access token info file doesn’t exist, we simply call the showWebviewForUserLogin method to force the webview to appear and let the user sign in.

    All of the methods above will be implemented one by one.


    10. Method Preview & Declaration

    As you can see for yourself in the snippet above, the method almost in its entirety works using other, private methods. Before going on to the next steps, it is a good idea to declare all the private methods that we are going to implement inside the private @interface section.

    In order to make the whole idea easier to understand, I prefer to separate the private methods in two categories:

    1. The first one includes those methods which are part of the authorization flow itself. These are:
      @interface OAuth()
      ...
      ...
      -(void)showWebviewForUserLogin;
      -(void)exchangeAuthorizationCodeForAccessToken;
      -(void)refreshAccessToken;
      @end
    2. The second category includes auxiliary methods whose role is to support the authorization flow by implementing other necessary operations in order the whole procedure properly works. These include:
      @interface OAuth()
      ...
      ...
      -(NSString *)urlEncodeString:(NSString *)stringToURLEncode;
      -(void)storeAccessTokenInfo;
      -(void)loadAccessTokenInfo;
      -(void)loadRefreshToken;
      -(BOOL)checkIfAccessTokenInfoFileExists;
      -(BOOL)checkIfRefreshTokenFileExists;
      -(BOOL)checkIfShouldRefreshAccessToken;
      -(void)makeRequest:(NSMutableURLRequest *)request;
      @end

    Besides all the above, we will implement the following delegate method for the webview:

    -(void)webViewDidFinishLoad:(UIWebView *)webView;

    Using it we will “read” the authorization code.

    Additionally, we will implement the next NSURLConnection delegate methods:

    -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
    -(void)connectionDidFinishLoading:(NSURLConnection *)connection;
    -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
    -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;

    Let’s move on now and let’s see how all these bind together.


    11. Implementing the Authorization Flow

    Step 1

    Let’s continue by writing the -(void)showWebviewForUserLogin method. This method serves two purposes. The first one is to form the URL (with all the required parameters) that our app will use to get the authorization code. The second is to show a webview to the users, through which they will sign in their Google account and grant access permissions to the app. Let’s see the method first.

    -(void)showWebviewForUserLogin{
        // Create a string to concatenate all scopes existing in the _scopes array.
        NSString *scope = @"";
        for (int i=0; i<[_scopes count]; i++) {
            scope = [scope stringByAppendingString:[self urlEncodeString:[_scopes objectAtIndex:i]]];
            // If the current scope is other than the last one, then add the "+" sign to the string to separate the scopes.
            if (i < [_scopes count] - 1) {
                scope = [scope stringByAppendingString:@"+"];
            }
        }
        // Form the URL string.
        NSString *targetURLString = [NSString stringWithFormat:@"%@?scope=%@&amp;redirect_uri=%@&amp;client_id=%@&amp;response_type=code",
                                     authorizationTokenEndpoint,
                                     scope,
                                     _redirectUri,
                                     _clientID];
        // Do some basic webview setup.
        [self setDelegate:self];
        [self setScalesPageToFit:YES];
        [self setAutoresizingMask:_parentView.autoresizingMask];
        // Make the request and add self (webview) to the parent view.
        [self loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:targetURLString]]];
        [_parentView addSubview:self];
    }

    A couple of observations now. At first, all the scopes existing in the _scopes array are getting concatenated into one NSString, after having been URL encoded. This is a must, as every special character that might exist in a scope should be replaced with the equivalent URL encoded character (more on this later). A temporary string is being used for concatenation purposes. Inside the concatenated string the scopes are separated using the plus “+” sign.

    Next, the URL string is formed. Pay special attention to the parameters it accepts.

    We provide:

    • The authorization code endpoint
    • The scopes
    • The redirect URI which is a constant value for installed applications
    • The client ID that we got from the Google Developers Console
    • The response_type value which is set to the standard value of code

    In the second half of the method, we are simply setting up the webview that will appear to the user. There is nothing particular I should point out here, the code is easy enough. Just note that after setting everything up and calling the loadRequest method the webview is added as a subview to the parent view.

    Step 2

    Once the user has signed in and has agreed to provide access to our app, the authorization code is returned from Google. Actually, there are two ways to get it. The first one involves the use of cookies, where the authorization code is stored in a cookie file. Google provides a sample on how to use this way. The second one, which is the way I prefer to use, is to get the authorization code from the web view’s page title. Once we acquire it, we are ready to proceed in obtaining the access token.

    This is what we are going to do in the only one webview delegate method that we are going to implement. Let’s see this in action.

    -(void)webViewDidFinishLoad:(UIWebView *)webView{
        // Get the webpage title.
        NSString *webviewTitle = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
        //NSLog(@"Webview Title = %@", webviewTitle);
        // Check for the "Success token" literal in title.
        if ([webviewTitle rangeOfString:@"Success code"].location != NSNotFound) {
            // The oauth code has been retrieved.
            // Break the title based on the equal sign (=).
            NSArray *titleParts = [webviewTitle componentsSeparatedByString:@"="];
            // The second part is the oauth token.
            _authorizationCode = [[NSString alloc] initWithString:[titleParts objectAtIndex:1]];
            // Show a "Please wait..." message to the webview.
            NSString *html = @"<html><head><title>Please wait</title></head><body><h1>Please wait...</h1></body></html>";
            [self loadHTMLString:html baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
            // Exchange the authorization code for an access code.
            [self exchangeAuthorizationCodeForAccessToken];
        }
        else{
            if ([webviewTitle rangeOfString:@"access_denied"].location != NSNotFound) {
                // In case that the user tapped on the Cancel button instead of the Accept, then just
                // remove the webview from the superview.
                [webView removeFromSuperview];
            }
        }
    }

    The authorization code that is returned is in a form similar to code=4/a5F4r45.... That’t why in the above snippet the title is being broken into parts based on the equal sign “=”. After that, we are ready to exchange it for the access token.

    Step 3

    Now that the authorization token has been obtained, the webview is no longer needed. We will remove it though at the end of the whole process (next step). The NSURLConnection and NSURLRequest classes will be in use from now on. What we have to do in the exchangeAuthorizationCodeForAccessToken method is just to setup all the required parameters that are needed to get the access token and to make a request to the access token endpoint. The most important thing I should point out here is that the POST HTTP method is being used. Here is the method.

    -(void)exchangeAuthorizationCodeForAccessToken{
        // Create a string containing all the post parameters required to exchange the authorization code
        // with the access token.
        NSString *postParams = [NSString stringWithFormat:@"code=%@&amp;client_id=%@&amp;client_secret=%@&amp;redirect_uri=%@&amp;grant_type=authorization_code",
                                _authorizationCode,
                                _clientID,
                                _clientSecret,
                                _redirectUri];
        // Create a mutable request object and set its properties.
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:accessTokenEndpoint]];
        [request setHTTPMethod:@"POST"];
        [request setHTTPBody:[postParams dataUsingEncoding:NSUTF8StringEncoding]];
        [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        // Make the request.
        [self makeRequest:request];
    }

    Notice the use of the authorization code that we acquired in the previous step.

    Step 4

    When making a request and using a NSURLConnection, two things may happen. Either the connection will successfully finish, or it will fail. In our case, when a request fails we only want to inform the caller class through the delegate and that’s all. So, let’s write the first NSURLConnection delegate method.

    -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
        [self.gOAuthDelegate errorOccuredWithShortDescription:@"Connection failed." andErrorDetails:[error localizedDescription]];
    }

    You see how our delegate methods become handy. Let’s go now to the case where the connection is successfully finished and the access token has been received.

    -(void)connectionDidFinishLoading:(NSURLConnection *)connection{
        // This object will be used to store the converted received JSON data to string.
        NSString *responseJSON;
        // This flag indicates whether the response was received after an API call and out of the
        // following cases.
        BOOL isAPIResponse = YES;
        // Convert the received data in NSString format.
        responseJSON = [[NSString alloc] initWithData:(NSData *)_receivedData encoding:NSUTF8StringEncoding];
        // Check for access token.
        if ([responseJSON rangeOfString:@"access_token"].location != NSNotFound) {
            // This is the case where the access token has been fetched.
            [self storeAccessTokenInfo];
            // Remove the webview from the superview.
            [self removeFromSuperview];
            if (_isRefreshing) {
                _isRefreshing = NO;
            }
            // Notify the caller class that the authorization was successful.
            [self.gOAuthDelegate authorizationWasSuccessful];
            isAPIResponse = NO;
        }
    }

    Don’t fool yourself by believing that this is going to be the only content of this delegate method. Actually, it’s going to become somehow big, but you shouldn’t mind about that right now.

    Note: Do you see the isAPIResponse flag? Well, this is useful for knowing when the response regards an API or the authorization process itself. When it comes under any case that has to do with the authorization process, it becomes NO, as you can see in the access token’s case. You’ll completely understand its significance along the way.

    Google returns a JSON object which contains the access token along with other data. The first thing we do is to convert the received data into a string value, so we can easily distinguish what kind of data has been received and properly handle it. By doing so at the beginning of the method, we check whether the access token was received indeed or not, simply by looking for it inside the response string. If it’s there, then…wow, we just obtained the access token! Let’s take care of it now. First, we save it into the file, and we remove the webview from the superview. In case that the access token was obtained during a refresh process, we set the respective flag to NO. Finally, we use our delegate to inform the caller class that the access token has been successfully acquired.

    The JSON that is returned is something similar to this one:

    {"access_token" : "ya29.AHES6ZSpPmQZwz30EcyhWE9mvi_lgvh4DX8gSQ9GpIbkLL5qhP9sYQ","token_type" : "Bearer","expires_in" : 3600,"id_token" : "eyJhbGciOiJSUzI1NiIsImtpZCI6ImUxYzdhM2NkZGFmMzcxOWFlMGNlZGUzOTI4ZmZlZDI1MGFmMmQyODMifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwidG9rZW5faGFzaCI6ImNfWngxMzBaWGQySFlCT0lEWlhiVUEiLCJhdF9oYXNoIjoiY19aeDEzMFpYZDJIWUJPSURaWGJVQSIsImNpZCI6Ijg4ODk5MTE4OTQ4OS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImF6cCI6Ijg4ODk5MTE4OTQ4OS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImF1ZCI6Ijg4ODk5MTE4OTQ4OS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImlkIjoiMTE0MzE1NTUzNzc0OTY1NTIwNTIzIiwic3ViIjoiMTE0MzE1NTUzNzc0OTY1NTIwNTIzIiwiaWF0IjoxMzczMjE5NDYwLCJleHAiOjEzNzMyMjMzNjB9.jM8_m8aqwW56V2YHob5d-Xlb69yTRBrd_FgagJlSSOxEgRcxpn3D6uDDBmbkiI7S_UgvCc07CAis9wmzTGrKvjpp8JR04ka_LlzdvlaWlFlMvCZgs13GNP8fpi_o4jTgpMLeUM47ZZbBtF0C2uU8XCaVAzTW-VOYZkNPT2SjDY4","refresh_token" : "1/xZWny-TMV0jZvDRuHxwMl5tTZSiN8yCGP7gaILbPPxk"
    }

    At this point, add the following code segment above the if ([_responseJSON rangeOfString:@"access_token"].location != NSNotFound) { line. It is required for dealing with any invalid request that may occur. If you wonder why could this happen, just try to play around with the whole authorization or refresh process and you will easily find out.

        if ([responseJSON rangeOfString:@"invalid_request"].location != NSNotFound) {
            NSLog(@"General error occured.");
            // If a refresh was on the way then set the respective flag to NO.
            if (_isRefreshing) {
                _isRefreshing = NO;
            }
            // Notify the caller class through the delegate.
            [self.gOAuthDelegate errorInResponseWithBody:responseJSON];
            isAPIResponse = NO;
        }

    Quite important is the next NSURLConnection delegate method too, if you want the above two to properly work.

    -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
        // Append any new data to the _receivedData object.
        [_receivedData appendData:data];
    }

    The authorization flow is now over. However, there is still a lot of work to be done before we will be ready to say that we have a fully implemented class.


    12. Refreshing the Access Token

    One piece of information that is received along with the access token is the time in seconds that the access token is valid. While the access token is valid, it can be used without any problem when calling APIs. However, when the token expires, a refresh is necessary to take place in the background and a new access token needs to be obtained.

    To check if an access token is still valid or not, we will use the checkIfShouldRefreshAccessToken method. We will implement it a little bit later, along with the rest of the auxiliary private methods. For now, let’s focus on the refresh process.

    The way we refresh an access token is quite similar to the way we exchange the authorization code for the access token. We set the POST parameters and we perform a NSURLRequest so as to get a new access token. Here is the method:

    -(void)refreshAccessToken{
        // Load the refrest token if it's not loaded alredy.
        if (_refreshToken == nil) {
            [self loadRefreshToken];
        }
        // Set the HTTP POST parameters required for refreshing the access token.
        NSString *refreshPostParams = [NSString stringWithFormat:@"refresh_token=%@&client_id=%@&client_secret=%@&grant_type=refresh_token",
                                       _refreshToken,
                                       _clientID,
                                       _clientSecret
                                       ];
        // Indicate that an access token refresh process is on the way.
        _isRefreshing = YES;
        // Create the request object and set its properties.
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:accessTokenEndpoint]];
        [request setHTTPMethod:@"POST"];
        [request setHTTPBody:[refreshPostParams dataUsingEncoding:NSUTF8StringEncoding]];
        [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        // Make the request.
        [self makeRequest:request];
    }

    As you can see, we need only the refresh token that was obtained with the access token, the client ID, the client secret, and the standard value grant_type parameters. Nothing hard or new here.

    There are a couple of things I should underline at this point. First of all, a refresh token lasts a lot longer than an access token. That means that a refresh token is not being received every time a refresh procedure is on the way. A refresh token can be used many times and that fact leads to the need for a more permanent way of storage, while the saving place/way of it should be different from the access token’s. The last one may be re-written many times and if the refresh token resides with it, it will be deleted after the first refresh.

    Secondly, a refresh token can become invalid as well. In that case, and if the access token needs to be updated, the user must be led to enter login information and provide access permissions once again. This is a case we should predict in our code.

    Inside the -(void)connectionDidFinishLoading:(NSURLConnection *)connection delegate method, the case of obtaining an access token from the response already exists. What we also need to add is a new code segment that will check if Google responded that we have an invalid refresh token. So, right before the if ([_responseJSON rangeOfString:@"access_token"].location != NSNotFound) line, add the following:

        // Check for invalid refresh token.
        // In that case guide the user to enter the credentials again.
        if ([responseJSON rangeOfString:@"invalid_grant"].location != NSNotFound) {
            if (_isRefreshing) {
                _isRefreshing = NO;
            }
            [self showWebviewForUserLogin];
            isAPIResponse = NO;
        }

    By calling the showWebviewForUserLogin method, we start the whole procedure over again.


    13. Auxiliary Private Methods

    Time to implement the rest of the auxiliary, private methods that we have already declared.

    Step 1

    Let’s begin with the -(NSString *)urlEncodeString:(NSString *)stringToURLEncode method, which is simply used to transform URL related strings to a URL-encoded form. When sending data over the web, not every character can exist in the URL. It should be replaced by other, special characters that are URL-friendly, and that’s exactly what the next method does:

    -(NSString *)urlEncodeString:(NSString *)stringToURLEncode{
        // URL-encode the parameter string and return it.
        CFStringRef encodedURL = CFURLCreateStringByAddingPercentEscapes(NULL,
                                                                         (CFStringRef) stringToURLEncode,
                                                                         NULL,
                                                                         (CFStringRef)@"!@#$%&*'();:=+,/?[]",
                                                                         kCFStringEncodingUTF8);
        return (NSString *)CFBridgingRelease(encodedURL);
    }

    As you can see, the CFURLCreateStringByAddingPercentEscapes function, which I would advise to read more about it, returns a CFStringRef type object, which is then converted to NSString when it’s returned. It’s not hard to understand the parameters this function accepts. Note that we provide a “list” of characters that should be replaced with percent characters. For example, the ! is converted to %21, the * to %2A, and so on. The last parameter relates to the desired encoding.

    Step 2

    We keep going with the next one:

    -(void)storeAccessTokenInfo{
        NSError *error;
        // Keep the access token info into a dictionary.
        _accessTokenInfoDictionary = [NSJSONSerialization JSONObjectWithData:_receivedData options:NSJSONReadingMutableContainers error:&error];
        // Check if any error occured while converting NSData data to NSDictionary.
        if (error) {
            [self.gOAuthDelegate errorOccuredWithShortDescription:@"An error occured while saving access token info into a NSDictionary."
                                                    andErrorDetails:[error localizedDescription]];
        }
        // Save the dictionary to a file.
        [_accessTokenInfoDictionary writeToFile:_accessTokenInfoFile atomically:YES];
        // If a refresh token is found inside the access token info dictionary then save it separately.
        if ([_accessTokenInfoDictionary objectForKey:@"refresh_token"] != nil) {
            // Extract the refresh token.
            _refreshToken = [[NSString alloc] initWithString:[_accessTokenInfoDictionary objectForKey:@"refresh_token"]];
            // Save the refresh token as data.
            [_refreshToken writeToFile:_refreshTokenFile atomically:YES encoding:NSUTF8StringEncoding error:&error];
            // If an error occurs while saving the refresh token notify the caller class.
            if (error) {
                [self.gOAuthDelegate errorOccuredWithShortDescription:@"An error occured while saving the refresh token."
                                                      andErrorDetails:[error localizedDescription]];
            }
        }
    }

    Things are simple here. At first, the received data containing the access token information is stored in the accessTokenInfoDictionary mutable dictionary, which, in turn, is written to a file. Then, whether a refresh token exists is checked in the returned information. If found, it is extracted and saved to another file. Remember that we need to keep the refresh token separated from the access token file.

    Step 3

    Let’s see the loadAccessTokenInfo method now and then talk about it:

    -(void)loadAccessTokenInfo{
        // Check if the access token info file exists.
        if ([self checkIfAccessTokenInfoFileExists]) {
            // Load the access token info from the file into the dictionary.
            _accessTokenInfoDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:_accessTokenInfoFile];
        }
        else{
            // If the access token info file doesn't exist then inform the caller class through the delegate.
            [self.gOAuthDelegate errorOccuredWithShortDescription:@"Access token info file was not found."
                                                  andErrorDetails:@""];
        }
    }

    First of all, we check if the access token information file exists or not. If it exists, then it's loaded into the accessTokenInfoDictionary. If the file for some reason is not found, then the errorOccuredWithShortDescription:andErrorDetails: delegate method is called to inform the caller class.

    Step 4

    Next, let's see how to load the refresh token as well:

    -(void)loadRefreshToken{
        // Check if the refresh token file exists.
        if ([self checkIfRefreshTokenFileExists]) {
            NSError *error;
            _refreshToken = [[NSString alloc] initWithContentsOfFile:_refreshTokenFile encoding:NSUTF8StringEncoding error:&error];
            // If an error occurs while saving the refresh token notify the caller class.
            if (error) {
                [self.gOAuthDelegate errorOccuredWithShortDescription:@"An error occured while loading the refresh token."
                                                      andErrorDetails:[error localizedDescription]];
            }
        }
    }

    The approach here is the same as previously implemented. We check if the file with the refresh code exists, and if it does we load it into the refreshToken string. Otherwise, we report an error to the caller class through the delegate method.

    Step 5

    The next task is to check if the file with the access token information exists or not.

    -(BOOL)checkIfAccessTokenInfoFileExists
    {
        // If the access token info file exists, return YES, otherwise return NO.
        return (![[NSFileManager defaultManager] fileExistsAtPath:_accessTokenInfoFile]) ? NO : YES;
    }

    Step 6

    Do exactly the same for the refresh token file.

    -(BOOL)checkIfRefreshTokenFileExists
    {
        // If the refresh token file exists then return YES, otherwise return NO.
        return (![[NSFileManager defaultManager] fileExistsAtPath:_refreshTokenFile]) ? NO : YES;
    }

    Pretty simple, right?

    Step 7

    Let's see now how to check if an access token is valid or not. When talking for validity, we mean whether the access token has expired or not. Google returns the time that an access token may keep alive, along with the rest of the returned data. That time is expressed in seconds and it usually is 3,600 seconds or one hour. If an access token expires and we want to exchange data from a Google service, we simply need to refresh it in the background and obtain a new one.

    Our strategy is going to be really simple. We will read the creation time of the file containing the access token info, as well as the time the access token should stay valid. If the time elapsed since the file creation is greater than the time to live, then a refresh is required, otherwise the access token is still valid. Let's see everything in action:

    -(BOOL)checkIfShouldRefreshAccessToken{
        NSError *error = nil;
        // Get the time-to-live (in seconds) value regarding the access token.
        int accessTokenTTL = [[_accessTokenInfoDictionary objectForKey:@"expires_in"] intValue];
        // Get the date that the access token file was created.
        NSDate *accessTokenInfoFileCreated = [[[NSFileManager defaultManager] attributesOfItemAtPath:_accessTokenInfoFile error:&error]
                                              fileCreationDate];
        // Check if any error occured.
        if (error != nil) {
            [self.gOAuthDelegate errorOccuredWithShortDescription:@"Cannot read access token file's creation date."
                                                  andErrorDetails:[error localizedDescription]];
            return YES;
        }
        else{
            // Get the time difference between the file creation date and now.
            NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:accessTokenInfoFileCreated];
            // Check if the interval value is equal or greater than the accessTokenTTL value.
            // If that's the case then the access token should be refreshed.
            if (interval >= accessTokenTTL) {
                // In this case the access token should be refreshed.
                return YES;
            }
            else{
                // Otherwise the access token is valid.
                return NO;
            }
        }
    }

    So, in case the access token should be refreshed we return YES, otherwise we return NO. Everything is self-explained, so I comment no further here.

    Step 8

    There is only one method that has been left out of these steps, the makeRequest. This method has nothing particular or special that I should point out. It exists just to avoid writing the same code every time we want to make NSURLRequest requests. So, as you will see right away, what we do is to empty the receivedData object by setting its length to zero and to make a new request.

    -(void)makeRequest:(NSMutableURLRequest *)request{
        // Set the length of the _receivedData mutableData object to zero.
        [_receivedData setLength:0];
        // Make the request.
        _urlConnection = [NSURLConnection connectionWithRequest:request delegate:self];
    }

    14. NSURLConnection Additions

    Step 1

    There are a few more things that we should add inside the connectionDidFinishLoading: method to make this class more complete. Until now we have added support for dealing with responses regarding:

    • Invalid requests
    • Invalid grants (e.g. an expired refresh token)
    • Access token obtainment

    What we should also add support for is the case of invalid credentials and for any other response that may contain the error word inside it. A response containing an Invalid credentials message arrives when an API is called and the access token is invalid. In our implementation, we always check if the access token is valid or not before doing any requests. However, this remains an edge case that we should predict. For any other general case that the response describes an error, we will call the errorInResponseWithBody delegate method. So, at the end of the connectionDidFinishLoading:, add the next code section:

        // Check for invalid credentials.
        // This checking is useful when an API is called without prior checking whether the
        // access token is valid or not.
        if ([responseJSON rangeOfString:@"Invalid Credentials"].location != NSNotFound ||
            [responseJSON rangeOfString:@"401"].location != NSNotFound) {
            [self refreshAccessToken];
            isAPIResponse = NO;
        }
        // This is the case where any other error message exists in the response.
        if ([responseJSON rangeOfString:@"error"].location != NSNotFound) {
            [self.gOAuthDelegate errorInResponseWithBody:responseJSON];
            isAPIResponse = NO;
        }

    If you look now at the connectionDidFinishLoading: method content, you'll see all the cases that we should take care of regarding the Google responses. For normal usage and for the purpose of this tutorial, almost nothing else needs to be added, except for one thing. The call to the responseFromServiceWasReceived:andResponseJSONAsData: delegate method. This method will be called every time that is retrieved a response about an API call that the caller class should handle it and it doesn't come under any other of the previous cases. Here it is:

        // If execution successfully arrives here then notify the caller class that a response was received.
        if (isAPIResponse) {
            [self.gOAuthDelegate responseFromServiceWasReceived:responseJSON andResponseJSONAsData:_receivedData];
        }

    Step 2

    It would be useful (especially when debugging) to have the next method implemented as well:

    -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        NSLog(@"%d", [httpResponse statusCode]);
    }

    The httpResponse object contains the returned HTTP status code of the request that was made. If everything rolls normally, the value of this code is 200. Search around the web for more information about the HTTP status codes if you'd like.


    15. Access Token Revocation

    There are cases you may want to revoke the access you gave in an app. Google provides a URL in which a request can be made and when access is being revoked.

    Open the GoogleOAuth.h class to declare a new public method, as highlighted next:

    @interface GoogleOAuth : UIWebView <UIWebViewDelegate, NSURLConnectionDataDelegate>
    @property (nonatomic, strong) id<GoogleOAuthDelegate> gOAuthDelegate;
    -(void)authorizeUserWithClienID:(NSString *)client_ID andClientSecret:(NSString *)client_Secret
                      andParentView:(UIView *)parent_View andScopes:(NSArray *)scopes;
    -(void)revokeAccessToken;
    @end

    Now go to the GoogleOAuth.m file to implement it:

    -(void)revokeAccessToken{
        // Set the revoke URL string.
        NSString *revokeURLString = [NSString stringWithFormat:@"https://accounts.google.com/o/oauth2/revoke?token=%@",
                                     [_accessTokenInfoDictionary objectForKey:@"access_token"]
                                     ];
        // Create and make a request based on the URL string.
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:revokeURLString]];
        [self makeRequest:request];
        // Now that the request for revoking the access in Google has been made,
        // all local files regarding the access token should be removed as well.
        NSError *error = nil;
        // If the access token info file exists then delete it.
        if ([self checkIfAccessTokenInfoFileExists]) {
            [[NSFileManager defaultManager] removeItemAtPath:_accessTokenInfoFile error:&error];
            if (error != nil) {
                // If an error occurs while removing the access token info file then notify the caller class through the
                // next delegate method.
                [self.gOAuthDelegate errorOccuredWithShortDescription:@"Unable to delete access token info file."
                                                      andErrorDetails:[error localizedDescription]];
            }
        }
        // Check now if the refresh token file exists and then remove it.
        if ([self checkIfRefreshTokenFileExists]) {
            [[NSFileManager defaultManager] removeItemAtPath:_refreshTokenFile error:&error];
            if (error != nil) {
                // In case of an error while removing the file then notify the caller class through the delegate method.
                [self.gOAuthDelegate errorOccuredWithShortDescription:@"Unable to delete refresh token info file."
                                                      andErrorDetails:[error localizedDescription]];
            }
        }
        if (error == nil) {
            // If no error occured during file removals then use the next delegate method
            // to notify the caller class that the access has been revoked.
            [self.gOAuthDelegate accessTokenWasRevoked];
        }
    }

    At first, we prepare the revoke URL string and make the request. Then, any file related to the access token is deleted, and, finally, the accessTokenWasRevoked delegate method is called.


    16. Calling an API

    Our class is ready and fully functional and if you use it now you will be able to obtain an access token from Google. But, without having implemented a way to call APIs, the only data you can get is your own personal info. Therefore, let's implement our last, public method, a really important and necessary one.

    Go to the GoogleOAuth.h file and declare the next method just like you see it:

    -(void)callAPI:(NSString *)apiURL withHttpMethod:(HTTP_Method)httpMethod
                        postParameterNames:(NSArray *)params postParameterValues:(NSArray *)values;

    Note that any API that requires data to be posted in Google must be in a key-value pair. The parameters for this are:

    • apiURL: The URL string required to make the API call.
    • httpMethod: The desired HTTP method for calling an API. This is where the enum type we created at the beginning is used.
    • params: A NSArray object containing the keys of the key-value pair form parameters.
    • values: A NSArray object containing the values of the key-value pair form parameters.

    Now turn on the GoogleOAuth.m file and implement the method:

    -(void)callAPI:(NSString *)apiURL withHttpMethod:(HTTP_Method)httpMethod
                                postParameterNames:(NSArray *)params
                                postParameterValues:(NSArray *)values{
        // Check if the httpMethod value is valid.
        // If not then notify for error.
        if (httpMethod != httpMethod_GET && httpMethod != httpMethod_POST && httpMethod != httpMethod_DELETE && httpMethod != httpMethod_PUT) {
            [self.gOAuthDelegate errorOccuredWithShortDescription:@"Invalid HTTP Method in API call" andErrorDetails:@""];
        }
        else{
            // Create a string containing the API URL along with the access token.
            NSString *urlString = [NSString stringWithFormat:@"%@?access_token=%@", apiURL, [_accessTokenInfoDictionary objectForKey:@"access_token"]];
            // Create a mutable request.
            NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
            // Depending on the httpMethod value set the respective property of the request object.
            switch (httpMethod) {
                case httpMethod_GET:
                    [request setHTTPMethod:@"GET"];
                    break;
                case httpMethod_POST:
                    [request setHTTPMethod:@"POST"];
                    break;
                case httpMethod_DELETE:
                    [request setHTTPMethod:@"DELETE"];
                    break;
                case httpMethod_PUT:
                    [request setHTTPMethod:@"PUT"];
                    break;
                default:
                    break;
            }
            // In case of POST httpMethod value, set the parameters and any other necessary properties.
            if (httpMethod == httpMethod_POST) {
                // A string with the POST parameters should be built.
                // Create an empty string.
                NSString *postParams = @"";
                // Iterrate through all parameters and append every POST parameter to the postParams string.
                for (int i=0; i<[params count]; i++) {
                    postParams = [postParams stringByAppendingString:[NSString stringWithFormat:@"%@=%@",
                                                                      [params objectAtIndex:i], [values objectAtIndex:i]]];
                    // If the current parameter is not the last one then add the "&" symbol to separate post parameters.
                    if (i < [params count] - 1) {
                        postParams = [postParams stringByAppendingString:@"&"];
                    }
                }
                // Set any other necessary options.
                [request setHTTPBody:[postParams dataUsingEncoding:NSUTF8StringEncoding]];
                [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
            }
            // Make the request.
            [self makeRequest:request];
        }
    }

    There is nothing difficult in this method that needs to be discussed.

    Our class is now ready to be put into action. Let's go forward to our demo app to try it out!


    17. Configure the Demo App

    Step 1

    At the beginning of the implementation of this project, while still working from Interface Builder, we added a table view to our project and now it's time to set it up. So, at first, go to the ViewController.h file and adopt the next protocols, as you see in the highlighted code:

    @interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
    @property (weak, nonatomic) IBOutlet UITableView *table;
    - (IBAction)showProfile:(id)sender;
    - (IBAction)revokeAccess:(id)sender;
    @end

    Besides the above two protocols, we also need to adopt our own protocol regarding our class. So, at the top of the file, import the GoogleOAuth.h file and also adopt the GoogleOAuthDelegate protocol:

    #import <UIKit/UIKit.h>
    #import "GoogleOAuth.h"
    @interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, GoogleOAuthDelegate>
    @property (weak, nonatomic) IBOutlet UITableView *table;
    - (IBAction)showProfile:(id)sender;
    - (IBAction)revokeAccess:(id)sender;
    @end

    Step 2

    Now turn to the ViewController.h file. At the private section of the interface, add these two mutable arrays, as we need them to store the user profile info that will be shown later on within the table view:

    @interface ViewController ()
    @property (nonatomic, strong) NSMutableArray *arrProfileInfo;
    @property (nonatomic, strong) NSMutableArray *arrProfileInfoLabel;
    @end

    Actually, the arrProfileInfoLabel will contain the data that describe each field of the profile information returned by Google. This data will be placed into the detailTextLabel of each cell.

    We also need an object of our newly created class. So, right below the array declarations, add this:

    @interface ViewController ()
    @property (nonatomic, strong) NSMutableArray *arrProfileInfo;
    @property (nonatomic, strong) NSMutableArray *arrProfileInfoLabel;
    @property (nonatomic, strong) GoogleOAuth *googleOAuth;
    @end

    Step 3

    Let's initialize our objects and set our delegates. Go inside the viewDidLoad method to initialize both the two arrays and the googleOAuth object, as well as to set the delegates, including the table view's delegate.

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        [_table setDelegate:self];
        [_table setDataSource:self];
        _arrProfileInfo = [[NSMutableArray alloc] init];
        _arrProfileInfoLabel = [[NSMutableArray alloc] init];
        _googleOAuth = [[GoogleOAuth alloc] initWithFrame:self.view.frame];
        [_googleOAuth setGOAuthDelegate:self];
    }

    Step 4

    Now we must create the table view methods. We will put in action the two arrays we declared previously, even though there is still no data on them. In the next code section I provide all the methods you need completed.

    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
        return 1;
    }
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return [_arrProfileInfo count];
    }
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        static NSString *CellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
            [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
            [cell setAccessoryType:UITableViewCellAccessoryNone];
            [[cell textLabel] setFont:[UIFont fontWithName:@"Trebuchet MS" size:15.0]];
            [[cell textLabel] setShadowOffset:CGSizeMake(1.0, 1.0)];
            [[cell textLabel] setShadowColor:[UIColor whiteColor]];
            [[cell detailTextLabel] setFont:[UIFont fontWithName:@"Trebuchet MS" size:13.0]];
            [[cell detailTextLabel] setTextColor:[UIColor grayColor]];
        }
        [[cell textLabel] setText:[_arrProfileInfo objectAtIndex:[indexPath row]]];
        [[cell detailTextLabel] setText:[_arrProfileInfoLabel objectAtIndex:[indexPath row]]];
        return cell;
    }
    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
        return 60.0;
    }

    Step 5

    Time to use what we've built by implementing the two IBAction methods we created at the beginning of the project. Starting from the showProfile: method, we will call the authorizeUserWithClienID: andClientSecret: andParentView: andScopes: of the GoogleOAuth class, which will fire the authorization flow. Let's implement it:

    - (IBAction)showProfile:(id)sender {
        [_googleOAuth authorizeUserWithClienID:@"YOUR_CLIENT_ID"
                               andClientSecret:@"YOUR_CLIENT_SECRET"
                               andParentView:self.view
                               andScopes:[NSArray arrayWithObjects:@"https://www.googleapis.com/auth/userinfo.profile", nil]
         ];
    }

    Make sure to set your own client ID and client secret values.

    Let's implement the revokeAccess: IBAction method now. It's just a single line of code:

    - (IBAction)revokeAccess:(id)sender {
        [_googleOAuth revokeAccessToken];
    }

    Step 6

    Finally, the only thing we have left is the delegate methods. Using the first IBAction method, we force the authorization flow to begin. Using the delegate methods we will control everything and we will retrieve the data we want. So, let's implement them one by one.

    We begin from the authorizationWasSuccessful: method. This method is called after a new access token is successfully obtained or an existing token is still valid. So, we are ready to proceed with the API call. This one is pretty simple as we just ask for the user profile and there is no data to post.

    -(void)authorizationWasSuccessful{
        [_googleOAuth callAPI:@"https://www.googleapis.com/oauth2/v1/userinfo"
                withHttpMethod:httpMethod_GET
                postParameterNames:nil postParameterValues:nil];
    }

    Continue with the accessTokenWasRevoked: method. We will simply show an alert view to the user and we will empty the arrays and the table contents.

    -(void)accessTokenWasRevoked{
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
                                                        message:@"Your access was revoked!"
                                                       delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
        [alert show];
        [_arrProfileInfo removeAllObjects];
        [_arrProfileInfoLabel removeAllObjects];
        [_table reloadData];
    }

    For the error handling methods we will simply log the error messages and that's all. Here are both of them:

    -(void)errorOccuredWithShortDescription:(NSString *)errorShortDescription andErrorDetails:(NSString *)errorDetails{
        NSLog(@"%@", errorShortDescription);
        NSLog(@"%@", errorDetails);
    }
    -(void)errorInResponseWithBody:(NSString *)errorMessage{
        NSLog(@"%@", errorMessage);
    }

    Finally, the most important delegate method, in which we'll get the Google response with the user profile information and we'll fill our arrays. We check if the family_name field exists in the JSON response to be sure that the user profile info exists in the response.

    -(void)responseFromServiceWasReceived:(NSString *)responseJSONAsString andResponseJSONAsData:(NSData *)responseJSONAsData{
        if ([responseJSONAsString rangeOfString:@"family_name"].location != NSNotFound) {
            NSError *error;
            NSMutableDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:responseJSONAsData
                                                                              options:NSJSONReadingMutableContainers
                                                                                error:&error];
            if (error) {
                NSLog(@"An error occured while converting JSON data to dictionary.");
                return;
            }
            else{
                if (_arrProfileInfoLabel != nil) {
                    _arrProfileInfoLabel = nil;
                    _arrProfileInfo = nil;
                    _arrProfileInfo = [[NSMutableArray alloc] init];
                }
                _arrProfileInfoLabel = [[NSMutableArray alloc] initWithArray:[dictionary allKeys] copyItems:YES];
                for (int i=0; i<[_arrProfileInfoLabel count]; i++) {
                    [_arrProfileInfo addObject:[dictionary objectForKey:[_arrProfileInfoLabel objectAtIndex:i]]];
                }
                [_table reloadData];
            }
        }
    }

    Now we're ready. Let's try it out!


    18. OAuth 2.0 in Action

    Run the project and let the iPhone Simulator appear. Initially, the table view is empty, as no data exists. Click on the My Profile button and enter your credentials to sign into your Google account. In the next window, allow the app to access your profile information and proceed. Once you get back to the table view, you'll see your personal data appear on-screen!

    Stop running the app and start over again. Click again on the My Profile button and notice that no credentials will be asked for this time. Instead, your personal info is being retrieved and will be shown in the table view.

    Next, try to revoke your access and then go to your profile once again. This time, you'll be asked for permissions once more.

    gt5_final

    Conclusion

    Through this tutorial we managed to see how the OAuth 2.0 protocol actually works. A simple, but also fully working custom class has been implemented, which consists of a reusable tool. Hopefully this tool is useful for every programmer's toolkit who wants to explore and use the services that Google provides. Of course, new features and functionalities can be added at any time, and you are most welcome to improve it or change it as you wish.

    In this tutorial, I tried to cover every aspect required to implement Google services with OAuth 2.0. In a future lesson, we will use this class in a real-world example while working with Google calendar. Until then, play around and get a great taste of the OAuth 2.0 protocol philosophy!


    iOS SDK: Working with Google Calendars

    $
    0
    0

    This tutorial will teach you how to build an app that will interact with the Google Calendar web service using OAuth 2.0. Read on!


    Where We Left Off…

    In my last tutorial, I showed you how to implement the OAuth 2.0 protocol in order to access Google services. By the end of that tutorial, we had built a fully functional class for accessing Google Services with OAuth 2.0. In this tutorial, I am going to put this class in action by implementing a demo app. Specifically, I am going to show you how to interact with the Google Calendar web service.


    Project Overview

    The app we’ll build in this tutorial is going to let users get connected to their Google account, download their calendars, and create a new event with a description and a date/time. The new event will be posted to a calendar that the user selects.

    Regarding our app structure, the basic view is going to be a table view that will contain three sections for setting the following data:

    • An event description
    • An event date/time
    • A target calendar

    As far as the event description is concerned, a textfield will appear on the cell when the user edits the description and it will go away when he finishes doing so. For ease of use, an Input Accessory View will appear above the keyboard every time that the textfield is displayed.

    For setting or changing the event date and time, another view (not a view controller) is going to be used. This view will contain a date picker view, from which the user will be able to pick a date. An event can be an all-day event, so no specific time needs to be set. For this case, a button will be used to set the date picker contents. For events occurring at a specific time, the date picker will display both date and time. For all-day events, only the date will be displayed. The view that contains the date picker (and a toolbar with the necessary bar button items as well) will be added as a subview to the view of our view controller when the user taps on the row of the second section of the table view.

    Finally, the calendar section is going to be multi-functional. When the user is not yet signed into their Google account, only one row is going to exist in the section with a message that prompts the user to download their calendars. When the user selects this, the authorization process will be put in action. Once the access token has been obtained, an API call will be made to get the calendar list from Google. After the calendar list has been taken, the first calendar on the list is going to replace the prompting message on the row and become the selected calendar by default.

    In addition to all of the above, a toolbar will exist under the table view and it will contain two bar button items. One button will be for posting the event on the selected calendar and a second button will be used to log out.

    Let’s get started!


    1. Create a New Project

    Step 1

    Launch Xcode and create a new project. Select the Single View Application option and click Next:

    gt6_1_project_template

    In the Product Name field, add the GoogleCalendarPostDemo value. Of course, you may choose another name if you’d like. Also, make sure to check the Use Automatic Reference Counting option and uncheck everything else. After that, keep on going.

    gt6_2_project_options

    Finally, select a directory to store the project and click Create.

    gt6_3_project_create

    Step 2

    Now you need to add the class files that were implemented in the previous tutorial. This class is going to be the mechanism that will do all the work behind the scenes. So, if you have the previous tutorial’s project files, get these two:

    • GoogleOAuth.h
    • GoogleOAuth.m

    Add them into your project. If you don’t have the previous project, then you can download and get them from this post’s download.

    gt6_4_class_files

    2. Building the Interface

    We will use Interface Builder to setup the interface. As you will soon find out, several subviews are going to be added because we want to make the demo app as functional as it can be. Here is a series of steps that describe every subview you should add, along with the properties for each one:

    1. Open the ViewController.xib file to configure the interface and to add all the necessary subviews. First of all, set the view’s Size to None in the Utilities Pane > Attributes Inspector > Simulated Metrics, in order to let the project work properly on iPhones prior to the 5.
      gt6_5_size_none
    2. Set the view’s Background Color to White.
    3. Drag-and-drop a UIToolbar subview into the view. Place it at the bottom of the screen.
    4. Add the following items on the toolbar (ordered left-to-right):
      • Bar Button Item with Title: Sign out
      • Flexible Space Bar Button Item
      • Bar Button Item with Title: Post
    5. Add a UITableView subview on the view and let it occupy all the available space left on the view.
    6. Set the next two properties of the table view:
      • Style: Grouped
      • Background:: Clear Color

    The following is what you should have at this point:

    gt6_6_ib_sample

    Next, we need to have another view that will contain the date picker view. Here are the steps:

    1. Add a new view outside of the default view and set its Size to None (like you did before). Also, set its Height to 460.
    2. Set the view’s Background Color to Scroll View Textured Background Color.
    3. Add a UIDatePicker subview in the view and center it in accordance to the view’s center.
    4. Add a UIToolBar subview at the bottom of the view.
    5. Add the following bar button items to the toolbar:
      • Bar Button Item with Title: Cancel
      • Flexible Space Bar Button Item
      • Bar Button Item with Title: All-day event
      • Flexible Space Bar Button Item
      • Bar Button Item with Title: Okay
    gt6_7_ib_datepicker

    Finally, add the following subviews outside the default view controller’s view and in the second view we just created:

    1. A UIToolBar subview. This is going to be the Input Accessory View for the textfield that will be used to edit the event description. Add the next bar button items to it:
      • Bar Button Item with Title: Cancel
      • Flexible Space Bar Button Item
      • Bar Button Item with Title: Okay
    2. A UIActivityIndicatorView with the following properties:
      • Style: Large White
      • Background: Black Color
    gt6_8_ib_iav
    gt6_9_ib_activityindicator

    3. Setup IBOutlet Properties & IBAction Methods

    Step 1

    We are going to need a few IBOutlet properties connected to our subviews, so we can modify them in code. To connect an IBOutlet property to a subview (as well as to create an IBAction method), you need to have the ViewController.h file shown in the Assistant Editor. So, click on the middle button of the Xcode Editor toolbar to let it show up. Make sure that the contents of the ViewController.h file are displayed there.

    gt6_10_assistant_editor

    I will show you how to create an IBOutlet property for the table view only. Use the same way to create the properties for the subviews I’ll tell you about next.

    Either on the Document Outline pane or directly on the view, do the following:

    1. Right-Click or Control-Click on the table view
    2. On the black popup menu, click on the circle next to the New Referencing Outlet option and keep the mouse button pressed.
    3. Drag-and-drop (and at the same time a blue line will follow your mouse) into the Assistant Editor window.
    gt6_11_iboutlet_create

    On the new window that appears, add the tblPostData as the Name of the property and don’t touch any other options. Click on the Connect button or hit the Return button on your keyboard.

    gt6_12_iboutlet_name

    Here is a list with all the subviews that we need IBOutlet connections created, along with their names. Make sure to follow the same way as before and you’ll be fine.

    • Post bar button item: barItemPost
    • Sign out bar button item: barItemRevokeAccess
    • Input Accessory View Toolbar (the alone toolbar): toolbarInputAccessoryView
    • View container of the date picker: viewDatePicker
    • Date Picker: dpDatePicker
    • All-day bar button item: barItemToggleDatePicker
    • Activity Indicator View: activityIndicatorView

    Step 2

    As you see, we added some bar button items in our views. We require from them to react on our taps, so we need to create IBAction methods to make that happen.

    Creating an IBAction method is almost the same as I previously demonstrated. For the Post bar button item only, here is the procedure in detail:

    1. On either the Document Outline or directly on the view, right-click or control-click on the bar button item.
    2. On the black popup menu, under the Sent Actions section, click on the circle next to the Selector option and keep the mouse button down.
    3. Drag and drop on the Assistant Editor window.
    gt6_13_ibaction_create

    On the new window, add the post in the Name field and leave everything else as it is. Click on Connect or hit the Return button on your keyboard.

    gt6_14_ibaction_name

    Now, follow the same pattern and create the next IBAction methods for the given subviews:

    • Sign out bar button item: revokeAccess
    • Okay bar button item on the Input Accessory View Toolbar: acceptEditingEvent
    • Cancel bar button item on the Input Accessory View Toolbar: cancelEditingEvent
    • Okay bar button item on the Date Picker View Toolbar: acceptSelectedDate
    • Cancel bar button item on the Date Picker View Toolbar: cancelPickingDate
    • All-day bar button item on the Date Picker View Toolbar: toggleDatePicker

    After the addition of all the IBOutlet properties and all the IBAction methods, your ViewController.h file should look like this:

    @interface ViewController : UIViewController
    @property (weak, nonatomic) IBOutlet UITableView *tblPostData;
    @property (weak, nonatomic) IBOutlet UIBarButtonItem *barItemPost;
    @property (weak, nonatomic) IBOutlet UIBarButtonItem *barItemRevokeAccess;
    @property (strong, nonatomic) IBOutlet UIToolbar *toolbarInputAccessoryView;
    @property (strong, nonatomic) IBOutlet UIView *viewDatePicker;
    @property (weak, nonatomic) IBOutlet UIDatePicker *dpDatePicker;
    @property (weak, nonatomic) IBOutlet UIBarButtonItem *barItemToggleDatePicker;
    @property (strong, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
    - (IBAction)post:(id)sender;
    - (IBAction)revokeAccess:(id)sender;
    - (IBAction)acceptEditingEvent:(id)sender;
    - (IBAction)cancelEditingEvent:(id)sender;
    - (IBAction)acceptSelectedDate:(id)sender;
    - (IBAction)cancelPickingDate:(id)sender;
    - (IBAction)toggleDatePicker:(id)sender;
    @end

    4. Adopting Protocols

    Step 1

    Now that the interface has been setup and configured and the IBOutlet properties along with the IBAction methods have been created and connected, it’s time to start writing some code. Previously we added the GoogleOAuth header and implementation files in the project, but that’s not enough to make our class work. We also need to import it in the view controller’s class and adopt its protocol.

    Open the ViewController.h file and import the GoogleOAuth.h file at the top of the file:

    #import <UIKit/UIKit.h>
    #import "GoogleOAuth.h"

    Step 2

    In addition to the GoogleOAuth class’ protocol, we need to adopt the following as well:

    • UITableViewDelegate: the delegate of the table view.
    • UITableViewDatasource: the datasource of the table view.
    • UITextFieldDelegate: the delegate of the textfield that will be used to edit the event description.

    So, while still within the ViewController.h file, modify the @interface statement like this:

    @interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, GoogleOAuthDelegate>

    5. Declaring Private Properties & Methods

    Step 1

    There are some properties and some methods that should be declared at the private section of the class and are required to make everything work smoothly. These properties are mostly going to store application information, but some simple flags will also be used to indicate program state.

    The next code snippet presents all the private data members you should add in your project (copy and paste them if you’d like). The comments explain everything. Don’t forget that we are working now in the ViewController.m file!

    @interface ViewController ()
    // The string that contains the event description.
    // Its value is set every time the event description gets edited and its
    // value is displayed on the table view.
    @property (nonatomic, strong) NSString *strEvent;
    // The string that contains the date of the event.
    // This is the value that is displayed on the table view.
    @property (nonatomic, strong) NSString *strEventDate;
    // This string is composed right before posting the event on the calendar.
    // It's actually the quick-add string and contains the date data as well.
    @property (nonatomic, strong) NSString *strEventTextToPost;
    // The selected event date from the date picker.
    @property (nonatomic, strong) NSDate *dtEvent;
    // The textfield that is appeared on the table view for editing the event description.
    @property (nonatomic, strong) UITextField *txtEvent;
    // This array is one of the most important properties, as it contains
    // all the calendars as NSDictionary objects.
    @property (nonatomic, strong) NSMutableArray *arrGoogleCalendars;
    // This dictionary contains the currently selected calendar.
    // It's the one that appears on the table view when the calendar list
    // is collapsed.
    @property (nonatomic, strong) NSDictionary *dictCurrentCalendar;
    // A GoogleOAuth object that handles everything regarding the Google.
    @property (nonatomic, strong) GoogleOAuth *googleOAuth;
    // This flag indicates whether the event description is being edited or not.
    @property (nonatomic) BOOL isEditingEvent;
    // It indicates whether the event is a full-day one.
    @property (nonatomic) BOOL isFullDayEvent;
    // It simply indicates whether the calendar list is expanded or not on the table view.
    @property (nonatomic) BOOL isCalendarListExpanded;
    @end

    Beyond that, add the next method declarations after the properties and before the @end statement:

    -(void)setupEventTextfield;
    -(NSString *)getStringFromDate:(NSDate *)date;
    -(void)showOrHideActivityIndicatorView;

    Step 2

    After having declared all these properties, let’s do some initialization. This will take place on the viewDidLoad: method. Note that in this method we also set self as the delegate and the datasource of the table view.

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Set self as the delegate and datasource of the table view.
        [_tblPostData setDelegate:self];
        [_tblPostData setDataSource:self];
        // Set the initial values of the following private properties.
        _strEvent = @"";
        _strEventDate = @"Pick a date...";
        _isEditingEvent = NO;
        _isFullDayEvent = NO;
        _isCalendarListExpanded = NO;
        // Initialize the googleOAuth object.
        // Pay attention so as to initialize it with the initWithFrame: method, not just init.
        _googleOAuth = [[GoogleOAuth alloc] initWithFrame:self.view.frame];
        // Set self as the delegate.
        [_googleOAuth setGOAuthDelegate:self];
    }

    6. Table View Datasource & Delegate Methods

    Let’s keep going by writing some datasource and delegate methods related to the table view. For the time being, we’ll add only some standard code. As we move on, we’ll add even more code when it’s required. So, let’s go ahead. As I said at the beginning, there are going to be three sections on the table view:

    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
        return 3;
    }

    Each section is going to contain one row. For the third section, we’ll have as many rows as the calendars support. In this method, you can see how the _isCalendarListExpanded flag is used for first time:

    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        if (section != 2) {
            return 1;
        }
        else{
            // Depending on whether the calendars are listed in the table view,
            // the respective section will have either one row, or as many as the calendars are.
            if (!_isCalendarListExpanded) {
                return 1;
            }
            else{
                return [_arrGoogleCalendars count];
            }
        }
    }

    Let’s add some footer titles, in order to make our demo app more descriptive. Nothing hard here:

    -(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
    {
        // Set the footer title depending on the section value.
        NSString *footerTitle = @"";
        if (section == 0) {
            footerTitle = @"Event short description";
        }
        else if (section == 1){
            footerTitle = @"Event date";
        }
        else{
            footerTitle = @"Google Calendar";
        }
        return footerTitle;
    }

    Set the height of the row for each cell:

    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
        return 50.0;
    }

    Regarding the tableView:cellForRowAtIndexPath: datasource method, this one is going to be built step-by-step while we add more functionalities to the app. For now, let’s write only the basics:

    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        static NSString *CellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
            [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
            [cell setAccessoryType:UITableViewCellAccessoryNone];
            // Set a font for the cell textLabel.
            [[cell textLabel] setFont:[UIFont fontWithName:@"Trebuchet MS" size:15.0]];
        }
        return cell;
    }

    Finally, we have only one delegate method, the well-known tableView:didSelectRowAtIndexPath:. Just like the previous one, this is also going to be built step-by-step. For now, make it only remove the selection from each row that is tapped:

    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        // At first, remove the selection from the tapped cell.
        [[_tblPostData cellForRowAtIndexPath:indexPath] setSelected:NO];
    }

    7. Editing the Event Description

    Step 1

    Until now, I have already said many times that a textfield is going to appear on the table view every time that we want to change the event description. However, when not editing, the textfield should not appear. After we finish editing, we’ll update the event description and make the textfield go away.

    Before we bring this behavior to life, it might be better to implement the private method that we have declared, the setupEventTextfield. In this method, we’ll do the following tasks:

    • We will initialize the textfield by setting a frame related to the cell content view’s frame and set a style too.
    • We’ll set the contents of the strEvent string as its text.
    • Remember the (alone) toolbar we added in the Interface Builder earlier? We’ll set it as the input accessory view of the textfield.
    • We’ll set self as its delegate so we can handle the Return key of the keyboard.

    Let’s see it:

    -(void)setupEventTextfield{
        // Initialize the textfield by setting the following properties.
        // Add or remove properties depending on your demand.
        if (!_txtEvent) {
            _txtEvent = [[UITextField alloc] initWithFrame:CGRectMake(10.0, 10.0,
                                                                      [[_tblPostData cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] contentView].frame.size.width - 20.0,
                                                                      30.0)];
            [_txtEvent setBorderStyle:UITextBorderStyleRoundedRect];
            [_txtEvent setText:_strEvent];
            [_txtEvent setInputAccessoryView:_toolbarInputAccessoryView];
            [_txtEvent setDelegate:self];
        }
    }

    Step 2

    Now that this method is ready and we can call it any time we’d like to initialize the textfield, let’s see how we can implement the behavior we expect from the table view. We want to display the textfield every time that we tap on the row of the first section, so let’s do so.

    Inside the tableView:didSelectRowAtIndexPath: we’ll check if the event is currently being edited. If not, then we’ll call the previously implemented method to initialize the textfield, we’ll change the flag status indicating whether the event is being edited and we’ll show the keyboard.

    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        // At first, remove the selection from the tapped cell.
        [[_tblPostData cellForRowAtIndexPath:indexPath] setSelected:NO];
        if ([indexPath section] == 0) {
            // If the row of the first section is tapped, check whether the event description is being edited or not.
            // If not, then setup and show the textfield on the cell.
            if (!_isEditingEvent) {
                [self setupEventTextfield];
            }
            else{
                return;
            }
            // Change the value of the isEditingEvent flag.
            _isEditingEvent = !_isEditingEvent;
            // Reload the selected row.
            [_tblPostData reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                                withRowAnimation:UITableViewRowAnimationAutomatic];
            // If the textfield has been added as a subview to the cell,
            // then make it the first responder and show the keyboard.
            if (_isEditingEvent) {
                [_txtEvent becomeFirstResponder];
            }
        }
    }

    Step 3

    Now let’s update the tableView:cellForRowAtIndexPath: so it reflects the state of the first section at any given time:

    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        ...
        ...
        ...
        if ([indexPath section] == 0) {
            if (!_isEditingEvent) {
                // If currently the event description is not being edited then just show
                // the value of the strEvent string and let the cell contain a disclosure indicator accessory view.
                // Also, set the gray as the selection style.
                [[cell textLabel] setText:_strEvent];
                [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
                [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
            }
            else{
                // If the event description is being edited, then empty the textLabel text so as to avoid
                // having text behind the textfield.
                // Add the textfield as a subview to the cell's content view and turn the selection style to none.
                [[cell textLabel] setText:@""];
                [[cell contentView] addSubview:_txtEvent];
                [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
            }
        }
    }

    Great! If you run the app now, you’ll notice that the textfield appears on the table view when you tap on the row of the first section. However, you cannot make the textfield vanish and keep the edited value. Why? Because we need to implement the related IBAction methods of the input accessory view bar button items.

    Step 4

    Let’s begin with the acceptEditingEvent: IBAction method. In short, in this method we’ll keep the typed event description on the strEvent string, we’ll change the isEditingEvent flag’s value, we’ll make the keyboard disappear, and we’ll refresh the table view. Here it is:

    - (IBAction)acceptEditingEvent:(id)sender {
        // If the strEvent property is already initialized then set its value to nil
        // as it's going to be re-allocated right after.
        if (_strEvent) {
            _strEvent = nil;
        }
        // Keep the text entered in the textfield.
        _strEvent = [[NSString alloc] initWithString:[_txtEvent text]];
        // Indicate that no longer the event description is being edited.
        _isEditingEvent = NO;
        // Resign the first responder and make the textfield nil.
        [_txtEvent resignFirstResponder];
        [_txtEvent removeFromSuperview];
        _txtEvent = nil;
        // Reload the row of the first section of the table view.
        [_tblPostData reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]]
                            withRowAnimation:UITableViewRowAnimationAutomatic];
    }

    The cancelEditingEvent: is similar.

    - (IBAction)cancelEditingEvent:(id)sender {
        // Indicate that no longer the event description is being edited.
        _isEditingEvent = NO;
        // Resign the first responder.
        [_txtEvent resignFirstResponder];
        [_txtEvent removeFromSuperview];
        _txtEvent = nil;
        // Reload the first row of the first section of the table view.
        [_tblPostData reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]]
                            withRowAnimation:UITableViewRowAnimationAutomatic];
    }

    Step 5

    In order to be perfectly complete regarding the textfield and the event description editing in general, we have one more thing left to do. Namely, we must handle the Return button of the keyboard and make it work just like the acceptEditingEvent: IBAction method. For this reason, implement the following delegate method:

    -(BOOL)textFieldShouldReturn:(UITextField *)textField{
        // In case the Return button on the keyboard is tapped, call the acceptEditingEvent: method
        // to handle it.
        [self acceptEditingEvent:nil];
        return YES;
    }

    As you can see, we simply make a call to the IBAction method and nothing more. Now, we are 100% complete regarding the event editing and the textfield manipulation.


    8. Picking an Event Date

    Step 1

    One part of our demo app is complete. Let’s go ahead now and let’s fully implement the date picking feature. In this case, what we want is when we tap on the row of the second section on the table view, to show the view that contains the date picker and through it to select a date. After that, we want the picked date to be displayed on the table view as well. Special care should be given to the fact that an event can be set for a specific time, but it can also be an all-day event, which means that picking a time has no point at all. We’ll see all this next.

    Let’s begin by showing the date picker container view to the self.view. It’s just a matter of one line, which should be written in the tableView:didSelectRowAtIndexPath: delegate method, under any other content it has until now:

    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        ...
        ...
        else if ([indexPath section] == 1){
            // If the row of the second section is tapped, just show the view that contains the date picker.
            [self.view addSubview:_viewDatePicker];
        }
    }

    Step 2

    Okay, that was the easy part. If you run the app now and you tap on the row of the second section, the date picker container view will be displayed on the screen. You’ll notice that by default, both date and time are represented in the picker. That’s nice if we want to set a specific time for the event. However, we should not let the time appear on the date picker if we are talking about an all-day event. Therefore, we need to implement the toggleDatePicker: IBAction method.

    The way this method is going to work is fairly simple. Depending on the current date picker’s contents, we will set its mode and we’ll also change the respective bar button item’s title. Don’t forget that there is a flag as well, the isFullDayEvent variable, that should be changed accordingly. The following is the implementation:

    - (IBAction)toggleDatePicker:(id)sender {
        if ([_dpDatePicker datePickerMode] == UIDatePickerModeDateAndTime) {
            // If the date picker currently shows both date and time, then set it to show only date
            // and change the title of the barItemToggleDatePicker item.
            // In this case the user selects to make a full-day event.
            [_dpDatePicker setDatePickerMode:UIDatePickerModeDate];
            [_barItemToggleDatePicker setTitle:@"Specific time"];
        }
        else{
            // Otherwise, if only date is shown on the date picker, set it to show time too.
            // The event is no longer a full-day one.
            [_dpDatePicker setDatePickerMode:UIDatePickerModeDateAndTime];
            [_barItemToggleDatePicker setTitle:@"All-day event"];
        }
        // Change the flag that indicates whether is a full-day event or not.
        _isFullDayEvent = !_isFullDayEvent;
    }

    Give it another try now and tap (or click on the Simulator) on the All-day event bar button item. Notice how the contents of the date picker get changed, along with the title of the button.

    Step 3

    Now we know when an event is set as a full-day event, but we are still unable to keep the selected date and to make it appear on the table view. Similarly, we cannot yet cancel the date picking and go back to our view.

    So, let’s work on both of these IBAction methods now.

    In the acceptSelectedDate: IBAction method we need to do only four things: (1) keep the selected date as a string, (2) store the date as a NSDate object, (3) remove the view from the superview, and, finally, (4) reload our table view in order to show the selected date.

    - (IBAction)acceptSelectedDate:(id)sender
    {
        // Keep the selected date as a NSDate object.
        _dtEvent = [_dpDatePicker date];
        // Also, convert it to a string properly formatted depending on whether the event is a full-day one or not
        // by calling the getStringFromDate: method.
        _strEventDate = [[NSString alloc] initWithString:[self getStringFromDate:[_dpDatePicker date]]];
        // Remove the view with the date picker from the self.view.
        [_viewDatePicker removeFromSuperview];
        // Reload the row of the second section of the table view to reflect the selected date.
        [_tblPostData reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:1]]
                            withRowAnimation:UITableViewRowAnimationAutomatic];
    }

    In the cancelPickingDate: IBAction method, we only need to remove the date picker container view from the superview.

    - (IBAction)cancelPickingDate:(id)sender {
        // Just remove the view with the date picker from the superview.
        [_viewDatePicker removeFromSuperview];
    }

    Step 4

    In the acceptSelectedDate: method, we made a call to the getStringFromDate: private method, which is declared but not yet implemented. It’s now time to work with this method. Before I present the code, I should make an observation.

    The purpose of the getStringFromDate: method is to get the date we provide (the selected date in our example) and to return this date as a string and formatted the way we want. However, there are two kind of string formats we need to have, depending on whether the event is a full-day one or not. If the event date has a specific time, we want this time to be present on the string. This means that we’ll have a condition in our method that will determine what the output string format will be. So, having made our intention clear, enter the following code:

    -(NSString *)getStringFromDate:(NSDate *)date{
        // Create a NSDateFormatter object to handle the date.
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        if (!_isFullDayEvent) {
            // If it's not a full-day event, then set the date format in a way that contains the time too.
            [formatter setDateFormat:@"EEE, MMM dd, yyyy, HH:mm"];
        }
        else{
            // Otherwise keep just the date.
            [formatter setDateFormat:@"EEE, MMM dd, yyyy"];
        }
        // Return the formatted date as a string value.
        return [formatter stringFromDate:date];
    }

    The above will give us something like Mon, Aug 12, 2013, 17:32.

    For more information about the date symbols used here and any other symbols that exist, look at the Date Format Patterns.

    Note: Keep in mind that you should change the date symbol order in a real app in order to match the date representation of your own country.

    Step 5

    So far so good: just one thing left to do. Add some code on the tableView:cellForRowAtIndexPath: method so the selected date will be displayed. Under all of the other contents of the method, add the next snippet:

    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        ...
        ...
        ...
        else if ([indexPath section] == 1){
            // In the event date cell just show the strEventDate string which either prompts the user
            // to pick a date, or contains the selected date as a string.
            // Also, add a disclosure indicator view.
            [[cell textLabel] setText:_strEventDate];
            [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
        }
        return cell;
    }

    9. App Authorization

    If you have already run the app, or if you do it now, you’ll notice that the row of the third section on the table view contains the Download calendars… message. Of course, nothing takes place when you tap on this method. What we’d like to do on tap is to make an API call to Google and request the information we need. But, prior to this, we must authorize ourselves against the Google service and obtain an access token that will be used to exchange data. Actually, all of this will be done by the GoogleOAuth class we included early on. All wee need to do is provide this class with the client ID, the client secret, and the scope. So, let’s pay a visit to the Google developers website and get all the values we need.

    Step 1

    Go to the Google Developer website. Click on the Sign In button that exists on the top-right side of the webpage to login.

    gt6_15_sign_in
    gt6_16_sign_in_2

    After you have signed in, scroll down on the page until you locate the API Console icon.

    gt6_17_api_console

    Click on it and you’ll be transferred to your Dashboard, where you handle all of your projects. If you must, create a project now, otherwise select the project you created from the previous tutorial in this series. On the menu at the left side of the webpage, click on the API Access option.

    gt6_18_api_access_option

    Details about the current project will be displayed on the right side of the page. In there, you can track down the client ID and client secret values that you will need. Note them, and let’s move ahead.

    gt6_19_client_info

    Next, we need to tell Google that we want to use the Calendars service. To do so, click on the Services option at the menu on the left side of the webpage. A list of all the provided services will appear. Locate the Calendar API item. Click on the Off button to enable the specific service for the current project.

    gt6_20_services

    Step 2

    What we haven’t located yet is the scope value for getting the calendar info we need. Just to remind you, a scope indicates an API that the app requests access for. The best practice to locate what you want is to use the search engine for the Google developer website. So, go to the homepage of the Google developer site and search for the term Google Calendar API. In the results page, click on the first result.

    gt6_22_search_box

    ake a look around if you want and explore using the menus. For this tutorial, you should go to Reference > Calendar List > list. A new webpage is loaded, containing information about the calendar list API call. Find the Authorization area near the bottom of the page. There you can find the scope we need: https://www.googleapis.com/auth/calendar.

    gt6_21_scopes_calendarlist

    Step 3

    In the previous steps, I showed you how you can enable a service on Google and the best way to find what you need from the developer web site. Now, we can keep building the app.

    Now that we have access to all the data we need from Google, let’s get back to our app and see how to use the information. Append the following code to our project:

    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        ...
        ...
        ...
        else if ([indexPath section] == 2){
            if (_arrGoogleCalendars == nil || [_arrGoogleCalendars count] == 0) {
                // If the arrGoogleCalendars array is nil or contains nothing, then the calendars should be
                // downloaded from Google.
                // So, show the activity indicator view and authorize the user by calling the the next
                // method of our custom-made class.
                [self showOrHideActivityIndicatorView];
                [_googleOAuth authorizeUserWithClienID:@"YOUR_CLIENT_ID"
                                       andClientSecret:@"YOUR_CLIENT_SECRET"
                                         andParentView:self.view
                                             andScopes:[NSArray arrayWithObject:@"https://www.googleapis.com/auth/calendar"]];
            }
    }

    You’ll notice that above we display the indicator view as well. We do this because we don’t know how long it’ll take to obtain authorization. Don’t forget to set your own values for the client ID and the client secret!

    When you use the app for the first time, the embedded web view will appear. You must enter your credentials and sign into your Google account to allow the app to access your calendars. If everything goes okay, you’ll be authorized without a problem.


    10. Downloading Calendar Data

    Step 1

    At this point, we need to implement some of the GoogleOAuth delegate methods. Let’s begin with the authorizationWasSuccessful method, where we’ll handle a successful authorization by making the API call for getting the calendar list.

    However, we need the API URL string if we want to proceed. Navigate to the proper calendar list page in your Google developer account. At the top of the page you’ll find the URL along with the HTTP method that should be used.

    gt6_23_api_calendarlist

    Now we can implement the delegate method:

    -(void)authorizationWasSuccessful{
        // If user authorization is successful, then make an API call to get the calendar list.
        // For more infomation about this API call, visit:
        // https://developers.google.com/google-apps/calendar/v3/reference/calendarList/list
        [_googleOAuth callAPI:@"https://www.googleapis.com/calendar/v3/users/me/calendarList"
               withHttpMethod:httpMethod_GET
           postParameterNames:nil
          postParameterValues:nil];
    }

    Step 2

    If all works according to plan, the responseFromServiceWasReceived:andResponseJSONAsData: delegate method will be called by the GoogleOAuth class. We are responsible to check if Google responded with the desired results, and then to keep only the data that we care about.

    Let’s discuss a bit about what the response contains and how we are going to manage the data. What we should do first is to convert the response JSON data into an NSDictionary object. If you NSLog this dictionary, we’ll see the way the returned data is formed. See the following example:

    {
    etag = "\"AaJWGrGt8CrZSonQa3iAA4QAo_s/oZDiRXBvAIXr3JkNwKQRZZfQzQ4\"";
        items =     (
                    { … }
    		{ … }
    		{ … }
        );
        kind = "calendar#calendarList";
    }

    Inside each curly bracket there is a block containing a bunch of information regarding every calendar you have created in Google Calendars. The items object is equivalent to an array which contains dictionaries as objects. In other words, we will extract the items object as a NSArray and we’ll handle every single object of it as a NSDictionary object.

    Let’s get back on track again. Once we acquire all the items as NSArray objects, we’ll go through a loop to access each calendar’s details and we’ll keep only the values we want for the purposes of this example. Actually, we are going to create key-value pairs with these values with the goal of creating new NSDictionaries, which will be stored in the arrGoogleCalendars array. This array is the calendar list for our app. Also, the dictCurrentCalendar dictionary will be initialized with the contents of the first calendar from the list. Once this has been done, the Post and Logout items will become enabled. We’ll also hide the activity indicator view and we’ll refresh the table to show the selected calendar.

    Here is the code:

    -(void)responseFromServiceWasReceived:(NSString *)responseJSONAsString andResponseJSONAsData:(NSData *)responseJSONAsData{
        NSError *error;
        if ([responseJSONAsString rangeOfString:@"calendarList"].location != NSNotFound) {
            // If the response from Google contains the "calendarList" literal, then the calendar list
            // has been downloaded.
            // Get the JSON data as a dictionary.
            NSDictionary *calendarInfoDict = [NSJSONSerialization JSONObjectWithData:responseJSONAsData options:NSJSONReadingMutableContainers error:&error];
            if (error) {
                // This is the case that an error occured during converting JSON data to dictionary.
                // Simply log the error description.
                NSLog(@"%@", [error localizedDescription]);
            }
            else{
                // Get the calendars info as an array.
                NSArray *calendarsInfo = [calendarInfoDict objectForKey:@"items"];
                // If the arrGoogleCalendars array is nil then initialize it so to store each calendar as a NSDictionary object.
                if (_arrGoogleCalendars == nil) {
                    _arrGoogleCalendars = [[NSMutableArray alloc] init];
                }
                // Make a loop and get the next data of each calendar.
                for (int i=0; i<[calendarsInfo count]; i++) {
                    // Store each calendar in a temporary dictionary.
                    NSDictionary *currentCalDict = [calendarsInfo objectAtIndex:i];
                    // Create an array which contains only the desired data.
                    NSArray *values = [NSArray arrayWithObjects:[currentCalDict objectForKey:@"id"],
                                       [currentCalDict objectForKey:@"summary"],
                                       nil];
                    // Create an array with keys regarding the values on the previous array.
                    NSArray *keys = [NSArray arrayWithObjects:@"id", @"summary", nil];
                    // Add key-value pairs in a dictionary and then add this dictionary into the arrGoogleCalendars array.
                    [_arrGoogleCalendars addObject:
                     [[NSMutableDictionary alloc] initWithObjects:values forKeys:keys]];
                }
                // Set the first calendar as the selected one.
                _dictCurrentCalendar = [[NSDictionary alloc] initWithDictionary:[_arrGoogleCalendars objectAtIndex:0]];
                // Enable the post and the sign out bar button items.
                [_barItemPost setEnabled:YES];
                [_barItemRevokeAccess setEnabled:YES];
                // Stop the activity indicator view.
                [self showOrHideActivityIndicatorView];
                // Reload the table view section.
                [_tblPostData reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:2]]
                                    withRowAnimation:UITableViewRowAnimationAutomatic];
            }
        }
    }

    Step 3

    Now that we’ve done all the above, we want to be able to tap on a calendar name and have the full list expand, allowing us to select another calendar. This will be done in the tableView:didSelectRowAtIndexPath: method. Add the following code snippet:

    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
            ...
            ...
            ...
            else{
                // In this case the calendars exist in the arrGoogleCalendars array.
                if (_isCalendarListExpanded) {
                    // If the calendar list is shown on the table view, then the tapped one shoule become the selected calendar.
                    // Re-initialize the dictCurrentCalendar dictionary so it contains the information regarding the selected one.
                    _dictCurrentCalendar = nil;
                    _dictCurrentCalendar = [[NSDictionary alloc] initWithDictionary:[_arrGoogleCalendars objectAtIndex:[indexPath row]]];
                }
                // Change the value of the isCalendarListExpanded which indicates whether only the selected calendar is shown, or the
                // whole list.
                _isCalendarListExpanded = !_isCalendarListExpanded;
                // Finally, reload the section.
                [_tblPostData reloadSections:[NSIndexSet indexSetWithIndex:2]
                            withRowAnimation:UITableViewRowAnimationAutomatic];
            }
        }
    }

    Step 4

    Finally, we need to update the tableView:cellForRowAtIndexPath: method to display everything we’ve done. Append the following code:

    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        ...
        ...
        ...
        else if ([indexPath section] == 2){
            // This is the case where either the selected calendar is shown, or a list with all of them.
            if (!_isCalendarListExpanded) {
                // If the calendar list is not expanded and only the selected calendar is shown,
                // then if the arrGoogleCalendars array is nil or it doesn't have any contents at all prompt
                // the user to download them now.
                // Otherwise show the summary (title) of the selected calendar along with a disclosure indicator.
                if (![_arrGoogleCalendars count] || [_arrGoogleCalendars count] == 0) {
                    [[cell textLabel] setText:@"Download calendars..."];
                }
                else{
                    [[cell textLabel] setText:[_dictCurrentCalendar objectForKey:@"summary"]];
                }
                [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
            }
            else{
                // This is the case where all the calendars should be listed.
                // Note that each calendar is represented as a NSDictionary which is read from the
                // arrGoogleCalendars array.
                // If the calendar that is shown in the current cell is the already selected one,
                // then add the checkmark accessory type to the cell, otherwise set the accessory type to none.
                NSDictionary *tempDict = [_arrGoogleCalendars objectAtIndex:[indexPath row]];
                [[cell textLabel] setText:[tempDict objectForKey:@"summary"]];
                if ([tempDict isEqual:_dictCurrentCalendar]) {
                    [cell setAccessoryType:UITableViewCellAccessoryCheckmark];
                }
                else{
                    [cell setAccessoryType:UITableViewCellAccessoryNone];
                }
            }
        }
        return cell;
    }

    That’s it. Go and give it a try. Watch your calendars on the Simulator and play around for a while by expanding the calendar list and selecting a calendar!


    11. Posting Calendar Events

    Step 1

    Let’s see how we’ll manage to add an event to a selected calendar. The first thing we should do is make sure that the event description and the event date have been set. To verify this, we’ll check their values and we’ll show an alert if something is wrong.

    Our work will now take place in the post: IBAction method.

    - (IBAction)post:(id)sender {
        // Before posting the event, check if the event description is empty or a date has not been selected.
        if ([_strEvent isEqualToString:@""]) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
                                                            message:@"Please enter an event description."
                                                           delegate:self
                                                  cancelButtonTitle:nil
                                                  otherButtonTitles:@"Okay", nil];
            [alert show];
            return;
        }
        if ([_strEventDate isEqualToString:@"Pick a date..."]) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
                                                            message:@"Please select a date for the event."
                                                           delegate:self
                                                  cancelButtonTitle:nil
                                                  otherButtonTitles:@"Okay", nil];
            [alert show];
            return;
        }
        ...
    }

    You’ll notice that we’ll simply check if the event description string is equal to the empty string and if the event date string is equal to its initial value.

    Step 2

    As I have already said, what we actually do in this project is to implement the Quick-add feature that Google Calendar supports. However, we need to know the format for the event string because there are some rules that apply. For example, there are special ways that the event date and time should be appended at the end of the event description string, so Google will know the exact date/time of the event. Of course, if you have already used the online Quick-Add feature, then you surely know what I am talking about.

    Thankfully, Google provides help and examples regarding this issue. We just have to visit the Quick Add documentation. Go and visit this website and familiarize your self with this feature.

    In our case, if we have a full-day event, we simply have to add the date using slashes at the end of the event description string (for example, “This is an event 08/12/2013″). If we don’t have a full-day event, then we will add the time too, using the “at” between the date and time (for example, “This is an event 08/12/2013 at 21:40″).

    In addition, we need to know the URL of the API we want to call. Just like we with the calendar list, we must find the quick-add related information in the Google Calendar API documentation. If you don’t want to bother looking for it right now, this is where you can find it. We must search for the following information:

    • Request: This is the URL of the API we want to call as it appeared at the top of the page. Also notice that we need to use the POST HTTP method.
    • POST parameters: Here are the parameters we need to send with the POST method. There are only two mandatory params, the ID of the calendar on which we want to add the event and the event text (of course formatted with the date, as I indicated before).
    • Authorization: This is the scope that we should be authorizing. In this case, the scope is equal to the calendar list scope, so we don’t need to care about it. However, if that was a different value, then we should include it in the scope array during authorization.

    So, let’s go back to our method to finish things. Update our code as follows:

    - (IBAction)post:(id)sender {
        ...
        ...
        ...
        // Create the URL string of API needed to quick-add the event into the Google calendar.
        // Note that we specify the id of the selected calendar.
        NSString *apiURLString = [NSString stringWithFormat:@"https://www.googleapis.com/calendar/v3/calendars/%@/events/quickAdd",
                                  [_dictCurrentCalendar objectForKey:@"id"]];
        // Build the event text string, composed by the event description and the date (and time) that should happen.
        // Break the selected date into its components.
        NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
        dateComponents = [[NSCalendar currentCalendar] components:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit
                                                         fromDate:_dtEvent];
        if (_isFullDayEvent) {
            // If a full-day event was selected (meaning without specific time), then add at the end of the string just the date.
            _strEventTextToPost = [NSString stringWithFormat:@"%@ %d/%d/%d", _strEvent, [dateComponents month], [dateComponents day], [dateComponents year]];
        }
        else{
            // Otherwise, append both the date and the time that the event should happen.
            _strEventTextToPost = [NSString stringWithFormat:@"%@ %d/%d/%d at %d.%d", _strEvent, [dateComponents month], [dateComponents day], [dateComponents year], [dateComponents hour], [dateComponents minute]];
        }
        // Show the activity indicator view.
        [self showOrHideActivityIndicatorView];
        // Call the API and post the event on the selected Google calendar.
        // Visit https://developers.google.com/google-apps/calendar/v3/reference/events/quickAdd for more information about the quick-add event API call.
        [_googleOAuth callAPI:apiURLString
               withHttpMethod:httpMethod_POST
           postParameterNames:[NSArray arrayWithObjects:@"calendarId", @"text", nil]
          postParameterValues:[NSArray arrayWithObjects:[_dictCurrentCalendar objectForKey:@"id"], _strEventTextToPost, nil]];
    }

    If you run the app now and you click on the Post button, the event will be posted. You can verify this if you check your calendar from a web browser. However, until we handle the response from Google, we are unable to know if the event was successfully added or not.

    Step 3

    Each time that an event is posted, Google creates a respective object which contains several properties and data. After a successful addition, Google responds with this data, so we can have any information we need regarding the newly created event. In our case, we won’t do something extraordinary. We’ll simply show an alert view that will contain the following values, so we are sure that the event was successfully posted.

    • ID: Each new event gets a unique ID value, which we are going to display on the alert view.
    • Created Date: The date that the event was created.
    • Summary: The event description itself.

    Of course, in a real app, you must handle this event data in a different way. Always regard the app’s needs.

    We are going to work in the responseFromServiceWasReceived:andResponseJSONAsData: method again. Notice that the JSON data is converted again into an NSDictionary object.

    -(void)responseFromServiceWasReceived:(NSString *)responseJSONAsString andResponseJSONAsData:(NSData *)responseJSONAsData{
        NSError *error;
        ...
        ...
        ...
        else if ([responseJSONAsString rangeOfString:@"calendar#event"].location != NSNotFound){
            // If the Google response contains the "calendar#event" literal then the event has been added to the selected calendar
            // and Google returns data related to the new event.
            // Get the response JSON as a dictionary.
            NSDictionary *eventInfoDict = [NSJSONSerialization JSONObjectWithData:responseJSONAsData options:NSJSONReadingMutableContainers error:&error];
            if (error) {
                // This is the case that an error occured during converting JSON data to dictionary.
                // Simply log the error description.
                NSLog(@"%@", [error localizedDescription]);
                return;
            }
            // An alert view with some information regarding the just added event will be shown.
            // Keep only the information that will be shown to the alert view.
            // Look at the https://developers.google.com/google-apps/calendar/v3/reference/events#resource for a complete list of the
            // data fields that Google returns.
            NSString *eventID = [eventInfoDict objectForKey:@"id"];
            NSString *created = [eventInfoDict objectForKey:@"created"];
            NSString *summary = [eventInfoDict objectForKey:@"summary"];
            // Build the alert message.
            NSString *alertMessage = [NSString stringWithFormat:@"ID: %@\n\nCreated:%@\n\nSummary:%@", eventID, created, summary];
            // Stop the activity indicator view.
            [self showOrHideActivityIndicatorView];
            // Show the alert view.
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"New event"
                                                            message:alertMessage
                                                           delegate:self
                                                  cancelButtonTitle:nil
                                                  otherButtonTitles:@"Great", nil];
            [alert show];
        }
    }

    Now, every time you add an event an alert view containing the new event info is displayed.


    12. Signing Out

    Signing out of the Google account is an option that should always be provided to the users, even though it’s recommended to keep them connected for faster access to online services. For our app, it’s only a matter of one single line of code, which we’ll add on the revokeAccess: IBAction method.

    - (IBAction)revokeAccess:(id)sender {
        // Revoke the access token.
        [_googleOAuth revokeAccessToken];
    }

    The revokeAccessToken method will make a call to the accessTokenWasRevoked delegate method to inform our class that the access token was revoked. This is going to be implemented next.


    13. Ancillary Methods

    Step 1

    Until now, we used only two delegate methods of the GoogleOAuth class, the authorizationWasSuccessful and the responseFromServiceWasReceived:andResponseJSONAsData:. There are three more of them that we should implement. We need a delegate method for handling the access revocation, another delegate for handling any error that may occur, and a final method for dealing with any error messages that may exist in Google responses.

    Regarding the access revocation, we’ll have to do only three things. First, we need to remove all calendars from the arrGoogleCalendars array. Next, we need to disable the Post and the Sign Out buttons. Finally, we need to reload the table view to keep it up to date.

    -(void)accessTokenWasRevoked{
        // Remove all calendars from the array.
        [_arrGoogleCalendars removeAllObjects];
        _arrGoogleCalendars = nil;
        // Disable the post and sign out bar button items.
        [_barItemPost setEnabled:NO];
        [_barItemRevokeAccess setEnabled:NO];
        // Reload the Google calendars section.
        [_tblPostData reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationAutomatic];
    }

    For the next two error handling delegate methods, we won’t do much. We’ll simply log the error messages and nothing further. It’s obvious that in a real app you would have to handle the errors in an appropriate way and figure out workarounds that handle unexpected situations. For now, here are our stub implementations:

    -(void)errorOccuredWithShortDescription:(NSString *)errorShortDescription andErrorDetails:(NSString *)errorDetails{
        // Just log the error messages.
        NSLog(@"%@", errorShortDescription);
        NSLog(@"%@", errorDetails);
    }
    -(void)errorInResponseWithBody:(NSString *)errorMessage{
        // Just log the error message.
        NSLog(@"%@", errorMessage);
    }

    Step 2

    During the project implementation, we made a few calls to the showOrHideActivityIndicatorView private method, which has been declared and called but not yet built. Let’s deal with it now.

    -(void)showOrHideActivityIndicatorView{
        // If the activity indicator view is not currently animating (spinning),
        // then set its view center equal to self view's center, add it as a subview and start animating.
        // Otherwise stop animating and remove it from the superview.
        if (![_activityIndicatorView isAnimating]) {
            [_activityIndicatorView setCenter:self.view.center];
            [self.view addSubview:_activityIndicatorView];
            [_activityIndicatorView startAnimating];
        }
        else{
            [_activityIndicatorView stopAnimating];
            [_activityIndicatorView removeFromSuperview];
        }
    }

    That was the last thing we had to do. Finally, our app is finished! Try out all the functionality supported.


    Conclusion

    In this tutorial I demonstrated how to work with Google Calendars using OAuth 2.0. While implementing a web service in-app is a lot of work, I hope you find the effort to have been worthwhile! Thanks for reading, and feel free to leave any questions or feedback in the comments below!

    An Interview with Nick Lockwood

    $
    0
    0

    In this interview, I talk to leading iOS developer Nick Lockwood about his open source contributions, his development workflow, and the educational resources he’s found useful in mastering the SDK.

    Nick Lockwood is a leading iOS developer and author of many popular open source projects, including iCarousel, iRate, and FXBlurView.

    Nick recently authored the book iOS Core Animation: Advanced Techniques, published by Addison-Wesley, and we’ve provided an excerpt from Chapter 5 along with this post.


    Q.Tell us a bit about yourself. How did you learn to program and what’s your professional background in the industry?

    I first picked up a programming book when I was 12 years old. I don’t recall the name of the book exactly—something like “Basic Programming on the BBC Micro”—but it was a pivotal moment in my life.

    I studied electronic engineering and then computer science at university. The former was interesting but not especially relevant to my later career; The latter taught me the fundamentals of data structures and algorithms, which has proven quite useful.

    After graduation I created my company Charcoal Design, selling simple Mac games and utilities written in REALbasic. That didn’t really make any money so I did some freelance web development to make ends meet.

    My first real job was as a front-end web developer, which initially didn’t seem to have much to do with programming at all, until JavaScript really came of age and front-end web development became a proper software engineering discipline instead of just being about who knew the most esoteric IE 6 CSS bugs.

    Q. When did you first use an iOS device, and what made you want to master the SDK?

    I saw that the iPhone was going to have a profound impact on the mobile web when it was first released, but I didn’t really think much of it. In the UK, basically nobody bought the 1st gen iPhone – it was too expensive and we already had pretty good (and much smaller) feature phones.

    That changed overnight when the iPhone 3G shipped. I got my first iPhone in July 2008. And bought Beginning iPhone 2 Development so I could learn to program it. I had dabbled with Objective-C on the Mac already, so I picked up the basics fairly quickly. I wrote Rainbow Blocks as an HTML5 app running in a full-screen UIWebView (I was still more comfortable with jQuery than UIKit at that point) and released it as open source.

    I then caught a lucky break because the company I work for got the opportunity to build an iPhone app for one of our clients, and as the only one with any iPhone experience, they gave it to me to build. I’ve been a full-time iOS developer ever since. I’ve also since rewritten Rainbow Blocks as a closed-source native app.

    Q.You’ve authored several very popular open-source projects (i.e. iCarousel, iRate, iVersion). What drives you to create and share such useful projects with the community?

    Like many programmers, I have a character flaw that makes me always try to solve the general case instead of the specific requirement. This causes me to abandon almost every project I start because I get bogged down trying to solve a problem that is only tangentially related to the task at hand.

    Like many programmers, I have a character flaw that makes me always try to solve the general case instead of the specific requirement.

    My hard drive is littered with half finished (or barely started) projects that would have been the next big thing but will never see the light of day. But I found that open source is a bit of an antidote to this problem. If I pull out those useful bits of code, document them, and stick them on Github, then I can still salvage something valuable from my abandoned ideas.

    Also, gradually, as I have built up a library of reusable components, I’ve found that building apps has become like assembling lego bricks. Instead of “That will be too complicated” I find I can answer most feature requests with “Aha! I have a library for that”.

    As I have built up a library of reusable components, I’ve found that building apps has become like assembling lego bricks.

    As for why I share them? It’s not particularly an act of philanthropy. I get a huge personal benefit from doing so, both in terms of actual feedback (bug reports, fixes and pull requests) but also recognition. My open source is a shop window for my services as a developer.

    Q.Was creating and maintaining a popular open-source project harder or easier than you expected?

    I feel a lot of pressure to maintain my projects, but I expected that – it’s part of why I released them in the first place. I’m not very good at self motivation and I work better when I’m under a bit of external pressure, so by releasing code to the community I know they will drive me to improve it.

    The trickiest part is knowing when to say “no” to features and pull requests. It’s difficult when someone has spent several hours adding something to one of my libs to say “thanks but no thanks”, but I have to do it for the sake of avoiding feature creep that makes the library worse overall.

    Q.Did you do anything to get the word out about your projects or did they just grow organically?

    I submitted a few of them to sites like CocoaControls or Binpress and offered them as answers to Stack Overflow questions like “How can I make a control like coverflow” or “How can I prompt users to rate my app”. iCarousel won the Binpress mobile development contest in 2011, which probably helped its popularity a bit.

    These days I mostly just post a “look what I made” message on Twitter and let it grow from there.

    Q.You recently authored the book iOS Core Animation: Advanced Techniques. Was this the result of your work on projects like iCarousel, or did your experience and interest in Core Animation start elsewhere?

    I’d never really done anything with Core Animation prior to iCarousel. It was kind of my “Hello World” project for the Core Animation framework. That was back in 2011 though – I’ve done quite a lot with it since!

    The book wasn’t my idea; Pearson approached me and said they were doing a new digital-only mobile programming series and asked if I would be interested in writing about Core Animation. It seemed like it might be fun, so I said OK.

    Q.The average iOS developer writes a lot of UIKit dependent code, but they may not directly interact with Core Animation very often. Why is your book relevant to the typical developer, and how could their apps benefit from a greater understanding of Core Animation?

    Because UIKit is so powerful, a lot of developers get a bit comfortable inside its confines and never venture beyond it. I think there’s a misconception that if you want to do anything fancy like 3D interfaces or masking effects then you have to drop down to doing everything with OpenGL.

    I think there’s a misconception that if you want to do anything fancy like 3D interfaces or masking effects then you have to drop down to doing everything with OpenGL.

    Many of the coverflow-like solutions that existed prior to iCarousel were written directly in OpenGL. It was quite a common thing that people wanted to do, but many developers simply have no idea that Core Animation even exists, or that it is a simple, high level API that can do these kind of effects easily without needing to work at the level of vertexes and shaders.

    Many developers simply have no idea that Core Animation even exists, or that it is a simple, high level API that can do these kind of effects easily without needing to work at the level of vertexes and shaders.

    The other thing I wanted to address with my book was performance. Performance is so easy to get wrong when you are dealing with a lot of images or vector drawing. I’ve seen many apps that judder and skip because developers just don’t understand how to use the power of threads and the GPU. A good understanding of how Core Animation works is crucial to getting good performance out of an app.

    Q.Is your book suitable for beginning iOS developers or did you focus more on intermediate and advanced readers?

    It’s aimed at intermediate readers, but it assumes no foreknowledge of Core Animation.

    Q.Writing a book is a massive undertaking. Did you learn anything especially surprising or exciting about Core Animation or iOS while researching the book?

    Yes, absolutely. In fact, one of the reasons I was so keen to do it was because of the learning opportunity. You never truly understand something until you have tried to explain it to somebody else. I found many new properties and features whilst researching the book, as well as clearing up many of my own misconceptions. I had to rewrite chapter 8 several times because when I wrote the examples I found that animations didn’t work the way I thought they did (despite the fact I’d being using them for years).

    Q.Tell us about your workflow. Are there any Xcode plugins or toolchain projects (e.g. Cocoapods) that you’ve come to rely on?

    I’m actually pretty conservative when it comes to using productivity tools. I’ve tried a lot of things, but I rarely stick with them.

    I provide Podspecs for most of my libraries, but I don’t actually use them. This is mainly because I hate static libraries – whenever possible I import the source files directly so that I can trace problems inside 3rd party components, and make fixes or improvements.

    Whenever possible I import the source files directly so that I can trace problems inside 3rd party components, and make fixes or improvements.

    Besides Xcode, I only use Tower (because Xcode’s git support is flaky and I don’t like using the command line), Photoshop (because I don’t trust designers to cut up assets), Resizer (for batch converting Retina images to standard def when I’m too lazy to redraw them), and SubEthaEdit (because Xcode has weird indenting rules for non-obj-C source files).

    Q.How about open source projects. What do you use for interacting with web services? Are there any projects you find yourself using in almost every app?

    I actually rarely use 3rd party libraries. 90% of the libs I use are my own, and if I find I’m very dependent on a 3rd party lib, I’ll usually end up writing my own version.

    I really admire Mattt Thomson’s work, but I just don’t get the obsession with using AFNetworking for every network file access task. Downloading a file asynchronously on a background queue takes one line of code. There’s certainly a lot more to interacting with web services, but mostly it’s highly specific to the service in question. I have yet to find any 3rd party network library that provides a substantial benefit over rolling a bespoke network stack, but maybe that’s just me.

    I’ve been using Mantle lately, and I like the way it handles JSON property mapping, but I wrapped it in something similar to my own BaseModel library to reduce the boilerplate of specifying file paths for persistence, etc.

    I can’t think of many 3rd party libraries that I’ve used on more than one project (SDWebImage, maybe), but I have a bunch of my own libs that I use in just about every app I write (StandardPaths, ViewUtils, BaseModel, AutoCoding).

    Q.Last question. For those who are just getting started with iOS but have some prior programming experience, what books, videos, and web sites do you recommend they research?

    That’s something I get asked a lot actually. I’d definitely recommend
    Beginning iOS 6 Development (the latest edition of the book I learned from) and iOS 6: Pushing the Limits. It’s also worth watching as many of the official WWDC videos as possible. Matt Thomson’s NSHipster site is definitely worth reading. There are many other good resources out there too. Cocoa with Love, Cocoa is My Girlfriend, Cocoanetics, Ray Wanderlich, and Mike Ash’s blog are all worth checking out. All of that said, I tend to use Twitter more than any single source to stay on top of things.

    Build an Airplane Game with Sprite Kit – Project Setup

    $
    0
    0

    This tutorial will teach you how to use the Sprite Kit framework to create a simple Airplanes game. Along the way, you’ll learn all the core concepts of Sprite Kit: animations, emitters, collision detection, and more!


    Series Format

    The Airplanes tutorial will be divided into three parts in order to completely cover each section. After reading the three part tutorial, the readers will be able to create an interesting 2D game using the new Sprite Kit framework provided with iOS 7.

    Each part will produce a practical result, and the sum of all parts will produce the final game. While each part of the series can be read independently, we recommend following along step-by-step for a complete understanding of the topic presented. The source code for the game is provided incrementally with each post.


    Final Preview

    Figure 1: Final Result!
    Illustration of Final Result – Sprite Kit.

    Acknowledgements & Recommendations

    Before we start the tutorial, we would like to thank Daniel Ferenčak for providing us with the game art used to produce this tutorial series.

    In order to fully appreciate the tutorial series, we advise that you test our code by deploying it to a real device running iOS 7. You will need Xcode 5 and the latest iOS 7 SDK. If you don’t already have these tools, you can download them from the Apple Developer Center. Once downloaded, install the software and you’ll be ready to begin.


    1. Project Setup

    Ladies and gentlemen, start your engines and launch Xcode 5!

    Once Xcode opens, go to File Menu > New > Project and you will see something like the following image:

    Figure 2: Choosing Sprite Kit Game template
    Illustration of the template chooser (Xcode).

    As you may have guessed, you need to choose the “Sprite Kit Game” template (from the iOS lateral list). This template creates what you need to start the project, and at the same time it includes the libraries required to run the Sprite Kit engine. Give the project whatever name you’d like, but be sure to select “iPad” as the targeted device.

    The project is created with 3 classes (AppDelegate, ViewController, and MyScene). Today, you will be working with MyScene.

    If you Build and Run the project, you’ll see a “Hello, World!” interface. Every time you click on the screen a new Spaceship is presented with a rotation property:

    Figure 3: Hello, World!
    Illustration of Hello World – Sprite Kit.

    All visual objects are rendered by the SKView class. One SKView is needed to present the future Scenes as well. The Sprite Kit template does this work for you. Take a look at the ViewController.m file, and note how the viewDidLoad method configures the view and calls the default scene.


    2. Creating the Game Board

    In this step, we’ll initialize the game board. The game board includes the background, the airplane, the propeller animations, and one airplane shadow.

    Before you add a sprite, you need the artwork to be used by that sprite. You should place these sprites into the Supporting Files folder of your project.

    All resources used in this tutorial are designed for the original iPad resolution. Download this post’s attachment to access them.

    Once you have downloaded the resources for this post, you’ll find 7 images. Copy them to the Supporting Files folder of your project and make sure that the option “Copy items into destination group’s folder (if needed)” is checked.

    Now that you have your images, you can place them on the screen. Sprite Kit is similar to Cocos2D in that it also uses a coordinate orientation that starts from the bottom left corner of the screen (0,0), and the x and y values increase as you move up and to the right. This game will be configured to run in portrait orientation, so we won’t focus on landscape orientation at this time. Configure this setting now by going to the Settings panel for your project, selecting the “General” tab, and unchecking all the options underneath “Deployment Info” except “Portrait.”

    Now, you’ll want to put the airplane close to the bottom and in the middle of the x axis.

    In MyScene.h, add the following code:

    @interface MyScene : SKScene{
        CGRect screenRect;
        CGFloat screenHeight;
        CGFloat screenWidth;
    }
    @property SKSpriteNode *plane;

    This just declares the variables we’ll use in the implementation.

    In the MyScene.m file, you can delete everything that is inside the if (self = [super initWithSize:size]) conditional as well as everything inside the -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event method. This will remove the boilerplate code included with the project.

    The sprite creation can be achieved using the following code snippet:

            //init several sizes used in all scene
            screenRect = [[UIScreen mainScreen] bounds];
            screenHeight = screenRect.size.height;
            screenWidth = screenRect.size.width;
            //adding the airplane
            _plane = [SKSpriteNode spriteNodeWithImageNamed:@"PLANE 8 N.png"];
            _plane.scale = 0.6;
            _plane.zPosition = 2;
            _plane.position = CGPointMake(screenWidth/2, 15+_plane.size.height/2);
            [self addChild:_plane];
            //adding the background
            SKSpriteNode *background = [SKSpriteNode spriteNodeWithImageNamed:@"airPlanesBackground"];
            background.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
            [self addChild:background];

    Now you can build and run the app. Your background and the airplane should appear just fine, similar to the next figure. The code provided begins with the initialization of the screen values to perform several calculations in this class (you will use these several times). Similar to Cocos2D, Sprite Kit comes with properties like scale, zPosition, and position, which are all really useful. Finally, to add the object to our Scene, we just need to use the addChild method. The third block of code will add the background to the center of the screen.

    Figure 4: Initial Sprites!
    Illustration of Background and Airplane – Sprite Kit.

    3. Adding Airplane Animations

    If you looked at the resources, you see two propellers (i.e. left and right), and one airplane shadow.
    The placement of the airplane shadow should be easy for you right now. To achieve the best animation, it should start 15 points to the right (x-axis) and 15 points below (y-axis) of the airplane.

    Now, we’ll go ahead and add the code to create a shadow:

    In MyScene.h, add the following:

    @property SKSpriteNode *planeShadow;

    And in Scene.m, add the following just after [self addChild:_plane];:

        _planeShadow = [SKSpriteNode spriteNodeWithImageNamed:@"PLANE 8 SHADOW.png"];
        _planeShadow.scale = 0.6;
        _planeShadow.zPosition = 1;
        _planeShadow.position = CGPointMake(screenWidth/2+15, 0+_planeShadow.size.height/2);
        [self addChild:_planeShadow];

    That was easy, right? We’re just adding a shadow sprite to the scene and positioning it relative to the plane.

    Now, lets move on to the propeller animation. To make the animation, we have two sprites (PLANE PROPELLER 1 and PLANE PROPELLER 2). The SKAction will allow you to create different animations and do several types of actions with them. In this tutorial, you need to change between just two images. To make this happen, you will need two methods: animateWithTextures:timePerFrame and repeatActionForever. As you can see, the method names are self explanatory. The first method will receive the textures (PLANE PROPELLER 1 and 2) and change the textures during the time defined (timePerFrame). The second method will repeat this action forever.

    To achieve this, start by adding the following to your header file:

    @property SKSpriteNode *propeller;

    And back in the implementation file:

            _propeller = [SKSpriteNode spriteNodeWithImageNamed:@"PLANE PROPELLER 1.png"];
            _propeller.scale = 0.2;
            _propeller.position = CGPointMake(screenWidth/2, _plane.size.height+10);
            SKTexture *propeller1 = [SKTexture textureWithImageNamed:@"PLANE PROPELLER 1.png"];
            SKTexture *propeller2 = [SKTexture textureWithImageNamed:@"PLANE PROPELLER 2.png"];
            SKAction *spin = [SKAction animateWithTextures:@[propeller1,propeller2] timePerFrame:0.1];
            SKAction *spinForever = [SKAction repeatActionForever:spin];
            [_propeller runAction:spinForever];
            [self addChild:_propeller];

    Build and run your code. Now is a good time to invest several minutes in code exploration in order to learn the basic structure of the project. Just have a look around and familiarize yourself with the basic organization.

    Unfortunately, at this time the airplane is still static. To create the movement you will use the internal accelerometer data and the plane will react to the iPad’s physical movement. Note that we will not deeply explain how the accelerometer works since this tutorial is not focused on that topic. However, if you want to learn more about the accelerometer specifically you can consult the official Apple documentation.

    In the MyScene.h you need to make some changes. You need to add the UIAcelerometerDelegate, two double variables for both axis values (i.e. AccelX and AccelY), and one property to manage CoreMotion.

    Your final MyScene.h file should resemble the following snippet:

    #import <SpriteKit/SpriteKit.h>
    #import <CoreMotion/CoreMotion.h>
    @interface MyScene : SKScene<UIAccelerometerDelegate>{
        CGRect screenRect;
        CGFloat screenHeight;
        CGFloat screenWidth;
        double currentMaxAccelX;
        double currentMaxAccelY;
    }
    @property (strong, nonatomic) CMMotionManager *motionManager;
    @property SKSpriteNode *plane;
    @property SKSpriteNode *planeShadow;
    @property SKSpriteNode *propeller;
    @end

    So, to obtain the accelerometer data you need to add some code to the end of the method -(id)initWithSize:(CGSize)size method. While still within the if (self = [super initWithSize:size]) conditional, add the following code where you left off before:

    //CoreMotion
    self.motionManager = [[CMMotionManager alloc] init];
    self.motionManager.accelerometerUpdateInterval = .2;
    [self.motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue]
                                             withHandler:^(CMAccelerometerData  *accelerometerData, NSError *error) {
                                             [self outputAccelertionData:accelerometerData.acceleration];
                                             if(error)
                                             {
                                                 NSLog(@"%@", error);
                                             }
    }];

    Now add the following method to the implementation file:

    -(void)outputAccelertionData:(CMAcceleration)acceleration
    {
        currentMaxAccelX = 0;
        currentMaxAccelY = 0;
        if(fabs(acceleration.x) > fabs(currentMaxAccelX))
        {
            currentMaxAccelX = acceleration.x;
        }
        if(fabs(acceleration.y) > fabs(currentMaxAccelY))
        {
            currentMaxAccelY = acceleration.y;
        }
    }

    Now that you have the values of the iPad accelerometer we’ll put them to use in the next step by moving the plane!


    4. Moving the Airplane

    With the values of the accelerometer set, you must actually apply them to move the airplane. Sprite Kit uses a method -(void)update:(NSTimeInterval)currentTime to update everything in your game. So, to move the airplane you just need to update the position of all sprites (airplane, shadow, and propellers). Replace or add the update method with the following code:

    -(void)update:(NSTimeInterval)currentTime{
        //NSLog(@"one second");
        float maxY = screenWidth - _plane.size.width/2;
        float minY = _plane.size.width/2;
        float maxX = screenHeight - _plane.size.height/2;
        float minX = _plane.size.height/2;
        float newY = 0;
        float newX = 0;
        if(currentMaxAccelX > 0.05){
            newX = currentMaxAccelX * 10;
            _plane.texture = [SKTexture textureWithImageNamed:@"PLANE 8 R.png"];
        }
        else if(currentMaxAccelX < -0.05){
            newX = currentMaxAccelX*10;
            _plane.texture = [SKTexture textureWithImageNamed:@"PLANE 8 L.png"];
        }
        else{
            newX = currentMaxAccelX*10;
            _plane.texture = [SKTexture textureWithImageNamed:@"PLANE 8 N.png"];
        }
        newY = 6.0 + currentMaxAccelY *10;
        float newXshadow = newX+_planeShadow.position.x;
        float newYshadow = newY+_planeShadow.position.y;
        newXshadow = MIN(MAX(newXshadow,minY+15),maxY+15);
        newYshadow = MIN(MAX(newYshadow,minX-15),maxX-15);
        float newXpropeller = newX+_propeller.position.x;
        float newYpropeller = newY+_propeller.position.y;
        newXpropeller = MIN(MAX(newXpropeller,minY),maxY);
        newYpropeller = MIN(MAX(newYpropeller,minX+(_plane.size.height/2)-5),maxX+(_plane.size.height/2)-5);
        newX = MIN(MAX(newX+_plane.position.x,minY),maxY);
        newY = MIN(MAX(newY+_plane.position.y,minX),maxX);
        _plane.position = CGPointMake(newX, newY);
        _planeShadow.position = CGPointMake(newXshadow, newYshadow);
        _propeller.position = CGPointMake(newXpropeller, newYpropeller);
    }

    Two major things are happening in the update method: you update the position and swap the displayed sprite.

    If the iPad is turning left, the airplane sprite will be changed for the “PLANE 8 L.png”. Alternatively, if the iPad is turning right, the airplane sprite will be change for the “PLANE 8 R.png”.

    Finally, go ahead and test out the movement code. You should see something similar to the next image:

    Figure 5: Moving Airplane!
    Illustration of Moving Airplane – Sprite Kit.

    Conclusion

    That’s the end of the first tutorial! At this point, you should understand how to perform the following tasks:

    • Start a Sprite Kit project
    • Add a sprite to the Scene
    • Implement simple animations
    • Receive accelerometer data
    • Update game and object data

    If any of the above is still “fuzzy”, take another look at the code we created above. Stay tuned for the next installment in this series where we will continue to build our airplane game!

    Sprite Kit vs. Cocos2D

    $
    0
    0

    Sprite Kit is one of the most exciting new technologies available with the iOS 7 SDK and Xcode 5, but how does it compare against an established game engine like Cocos2D? This tutorial will provide a brief introduction to Sprite Kit before taking a comprehensive look at how it stacks up against Cocos2D.


    Introducing Sprite Kit

    Of all the available games in the App Store, many of the most downloaded and most profitable are 2D games. Some iconic titles in this category include Angry Birds, Tiny Wings, and Cut the Rope. Driving the success of these games are several common characteristics: beautiful graphics, particle effects, a physics engine, seamless animation, and compelling sound effects.

    Before the release of the iOS 7 SDK, building games like these was only possible with the use of third-party frameworks and engines. Now, with the introduction of Sprite Kit, developers need look no further than the native SDK to find everything they need to be able to build great 2D and 2.5D games. The functionality provided by Sprite Kit includes Sprites, Shapes, Particles (e.g. fire, smoke, etc.), Animations, Physics Simulation, Audio, Video, and Visual Effects. Xcode 5 now also provides support for texture packs and particle design.

    Sprite Kit can be logically abstracted into the following three parts:

    • Scenes– As in Cocos2D, Scenes are the visual layer of the game. It is where you manage the background, the objects (like trees, cars, airplanes, avatars, etc).
    • Actions– Smooth animations are a vital part to any game. Apple designed the action system in an intuitive fashion, and it allows you to do almost anything. Some of the most common actions presented are: move, fade, scale, resize, rotate, animate with textures, and group actions. Further, if a particular action is not defined, you can always create a custom block of code to form your own action and manipulate that object.
    • Physics– If you want a game that behaves realistically, you need to add a physics engine. You don’t want a bullet that does not follow a specific trajectory, a ball that does not jump when it hits the ground, and other such amateurish effects. Fortunately, Sprite Kit comes with a physics engine baked in.

    Why Sprite Kit?

    There are some very solid benefits to having a 2D and 2.5D game platform provided and maintained by Apple. Consider the following points:

    Native Performance

    Native development and native tools are all about performance.

    Despite the fact that developers typically want their games to run on as many different platforms as possible, a native game will almost always have better performance than a non-native game. Plus, if the tools to develop those games are native, one can ensure that the code is integrated with the platform ecosystem.

    Platform Integration

    As mentioned above, Sprite Kit and Xcode 5 combine many of the essential components to building great games. This means that development can be more streamlined and tools will be more reliable and effective.

    Future Proof Development

    Writing a game using a third-party framework or game engine is always a two-edged sword. We never know if the tools will be compatible with future platform updates, or even if the game will run well after an update. When things do break, it’s uncertain how long it will take the community to fix the bugs.

    Cocos2D is an example of an open-source project that must deal with this problem. The code is constantly evolving, and at every new release several safety steps need to be performed in order to guarantee that applications built with Cocos2D will still run on the newest version of iOS and latest hardware.

    With Sprite Kit, Apple has provided a set of tools to ensure that game code will work on every compatible device without any trouble. Note that Sprite Kit is not just an iOS framework. Developers can start building Sprite Kit games for OS X as well, and it’s a safe bet that Sprite Kit games will run on any future iOS devices as well.

    Developer Friendly

    Ease of use was a major factor behind the success of game engines like Cocos2D. Generally speaking, developers found Cocos2D much easier to implement than other native alternatives like OpenGL ES. With Cocos2D, all the low level API calls were transformed in simple methods.

    Sprite Kit follows this approach and offers hundreds of methods that makes the game development process a lot easier. Sprite Kit is friendly as well. It has the custom, well-designed Apple API and comes with a complete structured documentation. Apple has done an outstanding job of sharpening this tool for third party devleopers to use. The biggest advantage of all is that it comes fully loaded with every resource that you need to create a game. Physics, sound effects, particle effects, textures, scene management -everything is included in a single bundle.

    Note that, at the initial presentation of Sprite Kit, Ricardo Quesada, the lead developer of Cocos2D said the following on Twitter:

    Sprite Kit is very good. With less features than Cocos2D, but better. I like the physics integration.

    This is high praise coming from one of the leading minds behind Cocos2D!


    Sprite Kit & Cocos2D Features

    FeatureSprite KitCocos2D
    Open SourceNoYes
    Objective-C Native SupportYesYes
    Graphics EngineYesYes
    AnimationsYesYes
    Physics SimulationYes (Integrated)No (Requires Box2D or Chipmunk)
    Particle EffectsYesYes
    Xcode Native IntegrationYesNo
    Automatic Atlas CreationYesNo
    Built-In Particle EditorYesNo
    ShadersNoYes
    CameraNoYes

    Project Comparison

    So, what do projects with each game engine actually look like? To answer this question, the authors have included the complete source code for both a Sprite Kit and a Cocos2D project. You can use these projects as a high-level comparison of each game engine.


    Source Code Comparison

    In this section we’ll actually breakdown common tasks and concepts, showing how to implement them in both Cocos2D and Sprite Kit.

    CClayer vs. SKScene

    CCLayer or SkScene is the main object used to draw other objects. You can think of this as the default view that will receive all the objects, animations, and touch events.

    The transition between scenes in Cocos2D is done with the following steps:

    GameScene* gameScene = [[GameScene alloc] init];
    [[CCDirector sharedDirector] replaceScene:gameScene];

    Note that the GameScene.h file must be of the CCLayer category and have the specific initializer available.

    @interface GameScene : CCLayer {}
    +(CCScene *) scene;

    In GameScene.m, the initial implementation is:

    +(CCScene *)scene
    {
        CCScene *scene = [CCScene node];
        GameScene *layer = [GameScene node];
        [scene addChild: layer];
        return scene;
    }
    -(id) init{
        if( (self=[super init] )) {
            // Your code here
        }
        return self;
    }

    In Sprite Kit the transition is similar:

    GameScene* gameScene = [[GameScene alloc] initWithSize:CGSizeMake(1024, 768)];
    [self.scene.view presentScene:gameScene];
    }

    The GameScene must be of the SKScene category, and the -(id)initWithSize:(CGSize)size is the custom initializer. A simple example:

    -(id)initWithSize:(CGSize)size
    {
        if (self = [super initWithSize:size])
        {
            // Your code
        }
        return self;
    }

    CCSprite vs. SKSpriteNode

    Sprite objects are normally used to display some kind of image. It can have several properties, such as: rotation, scale, position, frames, ids, and more. The implementation of both Cocos2D and Sprite Kit are similar. The Cocos2D implementation is:

    CCSprite* aSprite;
    aSprite = [CCSprite spriteWithFile:@"player.png"];
    aSprite.scale = .5;
    aSprite.position = ccp(_size.width/1.30, _size.height/1.25);
    [self addChild:aSprite];

    While in Sprite Kit the implementation is:

    SKSpriteNode* planeShadow = [SKSpriteNode spriteNodeWithImageNamed:@"player.png"];
    planeShadow.scale = 0.5;
    planeShadow.position = CGPointMake(CGRectGetMidX(self.frame)+100,CGRectGetMidY(self.frame)+200);
    [self addChild:planeShadow];

    CCLabelTTF vs. SKLabelNode

    Label objects are used to display text. It can have several properties, including text, text size, text color, position, and many others. The implementation of both Cocos2D and Sprite Kit are similar. The Cocos2D implementation is:

    CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];
    // ask director for the window size
    CGSize size = [[CCDirector sharedDirector] winSize];
    label.position =  ccp( size.width /2 , size.height/2 );
    [self addChild: label];

    The Sprite Kit implementation is:

    SKLabelNode* gameScene = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
    [gameScene setText:@"New Game"];
    [gameScene setFontSize:18];
    gameScene setPosition:CGPointMake(CGRectGetMidX(self.frame)+5,CGRectGetMidY(self.frame)-40)];
    [self addChild:gameScene];

    CCMenu and CCMenuItem vs. Sprite Kit Menu

    In Cocos2D, the menus are created using two objects: CCMenu and CCMenuItem. The following example presents a menu with 2 options in Cocos2D:

    CGSize size = [[CCDirector sharedDirector] winSize];
    [CCMenuItemFont setFontSize:28];
    CCMenuItem *itemNewGame = [CCMenuItemFont itemWithString:@"New Game" block:^(id sender) {
        // Your code
    }];
    CCMenuItem *itemOptions = [CCMenuItemFont itemWithString:@"Options" block:^(id sender) {
        NSLog(@"Second item");
    }];
    CCMenu *menu = [CCMenu menuWithItems:itemNewGame, itemOptions, nil];
    [menu alignItemsHorizontallyWithPadding:20];
    [menu setPosition:ccp( size.width/2, size.height/2 - 50)];
    [self addChild:menu];

    SpiteKit does not include any type of menu specific object. You need to create an event handler to a specific object in order to activate it for user input. So, in order to “create” a menu you must use a UIKit object or a Sprite Kit object.

    The following example uses a SKLabelNode as a menu item. First, we define the SKLabelNode:

    SKLabelNode*  gameScene = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
    [gameScene setText:@"New Game"];
    [gameScene setFontSize:18];
    [gameScene setPosition:CGPointMake(CGRectGetMidX(self.frame)+5,CGRectGetMidY(self.frame)-40)];
    [self addChild:gameScene];

    Inside the -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event method we will create the event handler that will intercept the touch event:

    for (UITouch *touch in touches)
    {
        CGPoint location = [touch locationInNode:self];
        if ([gameScene containsPoint:location]) {
            // Scene Transition Animation
            SKTransition* reveal = [SKTransition revealWithDirection:SKTransitionDirectionDown duration:1];
            GameScene* gameScene = [[GameScene alloc] initWithSize:CGSizeMake(1024, 768)];
            [self.scene.view presentScene:gameScene transition:reveal];
            NSLog(@"Touched gameScene!!!!");
        }
    }

    The aforementioned code does several things:

    1. Activates the touch events.
    2. Converts the tap location to the internal location.
    3. Tests if the tap location is inside the gameScene SKLabelNode object.
    4. Creates a transition animation.
    5. Changes the scene.

    Action vs. SKAction

    The main difference between Action and SKAction is that SKAction is a complex object with several properties. Action in Cocos2D is only an action that the programmer must define, call, and treat.

    With Sprite Kit, SKAction offers several options to the developers, such as rotation, resize, scale, repeat, fade, play sound, and more. SKaction can be seen as an abstract object that deals with any kind of action, from sound, to sprites, to nodes.

    We’ll focus for the moment on movement actions.

    In Cocos2D we need to define a scheduler to call a custom method:

    [self schedule:@selector(addSprite:) interval:1];

    And then define the custom method to do the custom animation.

    - (void) addSprite:(ccTime)dt
    {
        CCSprite* aMovableSprite = [CCSprite spriteWithFile:@"frankenstein.png"];
        aMovableSprite.scale = .8;
        [self addChild:aMovableSprite];
        CGSize winSize = [CCDirector sharedDirector].winSize;
        int minX = aMovableSprite.contentSize.width / 2;
        int maxX = winSize.width - aMovableSprite.contentSize.width/2;
        int rangeX = maxX - minX;
        int actualY = (arc4random() % rangeX) + minX;
        CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
            NSLog(@"Sprite free!");
        }];
        NSMutableArray *arrayBezier = [[NSMutableArray alloc] init];
        ccBezierConfig bezier;
        id bezierAction1;
        float splitDuration = 6 / 6.0;
        for(int i = 0; i< 6; i++){
            if(i % 2 == 0){
                bezier.controlPoint_1 = ccp(actualY+100,winSize.height-(100+(i*200)));
                bezier.controlPoint_2 = ccp(actualY+100,winSize.height-(100+(i*200)));
                bezier.endPosition = ccp(actualY,winSize.height-(200+(i*200)));
                bezierAction1 = [CCBezierTo actionWithDuration:splitDuration bezier:bezier];
            }
            else{
                bezier.controlPoint_1 = ccp(actualY-100,winSize.height-(100+(i*200)));
                bezier.controlPoint_2 = ccp(actualY-100,winSize.height-(100+(i*200)));
                bezier.endPosition = ccp(actualY,winSize.height-(200+(i*200)));
                bezierAction1 = [CCBezierTo actionWithDuration:splitDuration bezier:bezier];
            }
            [arrayBezier addObject:bezierAction1];
        }
        [arrayBezier addObject:actionMoveDone];
        id seq = [CCSequence actionsWithArray:arrayBezier];
        [aMovableSprite runAction:seq];
    }

    In Sprite Kit, we can use SKAction to control what happens to an object at the beginning and at the end of movement. The next lines show how to move any object in a straight line:

    SKSpriteNode* playerSprite = [SKSpriteNode spriteNodeWithImageNamed:@"player.png"];
    [playerSprite setScale:0.4];
    SKAction *movement =[SKAction moveTo:CGPointMake(900, 500) duration:5];
    SKAction *remove = [SKAction removeFromParent];
    [playerSprite runAction:[SKAction sequence:@[movement,remove]]];
    [self addChild:playerSprite];

    However, we can define a custom action and use SKAction to activate that action. The following example exemplifies a Bézier movement (similar to the Cocos2D version of Action). Note that we must define a scheduler to call a custom method.

    SKAction *wait = [SKAction waitForDuration:1];
    SKAction *callEnemies = [SKAction runBlock:^{
        [self sendNewSKSpriteNode];
    }];
    SKAction *updateSKSpriteNodeOnScreen = [SKAction sequence:@[wait,callEnemies]];
    [self runAction:[SKAction repeatActionForever:updateSKSpriteNodeOnScreen]];

    The method sendNewSKSpriteNode will handle the custom object movement.

    -(void) sendNewSKSpriteNode{
        CGRect screenRect = [[UIScreen mainScreen] bounds];
        // Custom SKAction
        SKSpriteNode* enemy = [SKSpriteNode spriteNodeWithImageNamed:@"frankenstein.png"];
        enemy.scale = 0.6;
        CGMutablePathRef cgpath = CGPathCreateMutable();
        //random values
        float xStart = [self getRandomNumberBetween:0+enemy.size.width to:screenRect.size.width-enemy.size.width ];
        float xEnd = [self getRandomNumberBetween:0+enemy.size.width to:screenRect.size.width-enemy.size.width ];
        //ControlPoint1
        float cp1X = [self getRandomNumberBetween:0+enemy.size.width to:screenRect.size.width-enemy.size.width ];
        float cp1Y = [self getRandomNumberBetween:0+enemy.size.width to:screenRect.size.width-enemy.size.height ];
        //ControlPoint2
        float cp2X = [self getRandomNumberBetween:0+enemy.size.width to:screenRect.size.width-enemy.size.width ];
        float cp2Y = [self getRandomNumberBetween:0 to:cp1Y];
        CGPoint s = CGPointMake(xStart, 1024.0);
        CGPoint e = CGPointMake(xEnd, -100.0);
        CGPoint cp1 = CGPointMake(cp1X, cp1Y);
        CGPoint cp2 = CGPointMake(cp2X, cp2Y);
        CGPathMoveToPoint(cgpath,NULL, s.x, s.y);
        CGPathAddCurveToPoint(cgpath, NULL, cp1.x, cp1.y, cp2.x, cp2.y, e.x, e.y);
        SKAction *planeDestroy = [SKAction followPath:cgpath asOffset:NO orientToPath:YES duration:5];
        [self addChild:enemy];
        SKAction *remove2 = [SKAction removeFromParent];
        [enemy runAction:[SKAction sequence:@[planeDestroy,remove2]]];
        CGPathRelease(cgpath);
    }

    CCParticleExplosion vs. Emitter

    Cocos2D does not have any kind of particle editor. One must use an external app to create the particle and then use specific CCParticleExplosion properties to change its behavior. After you have the particle in your Xcode project you can call it using:

    CCParticleExplosion* _particleExplosion;
    particleExplosion = [[CCParticleExplosion alloc] initWithTotalParticles:800];
    particleExplosion.texture = [[CCTextureCache sharedTextureCache] addImage:@"texture.png"];
    particleExplosion.life = 0.0f;
    particleExplosion.lifeVar = 0.708f;
    particleExplosion.startSize = 40;
    particleExplosion.startSizeVar = 38;
    particleExplosion.endSize = 14;
    particleExplosion.endSizeVar = 0;
    particleExplosion.angle = 360;
    particleExplosion.angleVar = 360;
    particleExplosion.speed = 243;
    particleExplosion.speedVar = 1;
    CGPoint g = CGPointMake(1.15, 1.58);
    particleExplosion.gravity = g;
    ccColor4F startC =  {0.89f, 0.56f, 0.36f, 1.0f};
    particleExplosion.startColor = startC;
    ccColor4F endC = {1.0f,0.0f,0.0f,1.0f};
    particleExplosion.endColor = endC;
    [self addChild:_particleExplosion];
    particleExplosion.position = ccp(_size.width/5, _size.height/5);
    [particleExplosion resetSystem];

    Emitters are used within Sprite Kit for particle generation. In order to use them, you need to add a particle to your project. Go to New -> File -> Resource -> Sprite Kit Particle File. Next you should name it and choose any type of particle (fire, magic, smoke, snow, among others). Now you will see that two new files will appear on your Xcode project. You’ll implement them with:

    SKEmitterNode* smokeTrail;
    NSString *smokePath = [[NSBundle mainBundle] pathForResource:@"MyParticle" ofType:@"sks"];
    smokeTrail = [NSKeyedUnarchiver unarchiveObjectWithFile:smokePath];
    smokeTrail.position = CGPointMake(CGRectGetMidX(self.frame)+40,CGRectGetMidY(self.frame)-100);
    [self addChild:smokeTrail];

    The SKEmitterNode class is extensive and contains several properties. We advise you to read it in order to learn every property that an emitter node can have.

    SimpleAudioEngine vs. Sprite Kit Sound

    Sound is an active part of any game or multimedia application. In Cocos2D, we can achieve that with two steps. The first is to include the SimpleAudioEngine header file.

    #import "SimpleAudioEngine.h"

    Then you use the following lines to call the music file inside our project:

    [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"sound.caf" loop:YES];
    [[SimpleAudioEngine sharedEngine] setEffectsVolume:0.4f];

    Sometimes, Xcode does no automatically include the music file in the “Copy Bundle Resources”. If that happens you should add it manually.

    With Sprite Kit, the inclusions of sounds is straightforward:

    SKAction* soundAction = [SKAction playSoundFileNamed:@"preview.mp3" waitForCompletion:NO];
    [self runAction:soundAction];

    Note that to accomplish this with Sprite Kit you once again used the SKAction object.


    Conclusion

    As you can see from the above analysis, Cocos2D and Sprite Kit have many similarities. Cocos2D uses several layers for each object, while Sprite Kit encapsulate more objects and uses the NSObject super class to achieve certain objectives (like buttons or menus).

    In terms of user friendliness, Sprite Kit really shines when you want to use the Particle system or the Action performer. However, when working with more general objects, both frameworks are at about the same level of difficulty.

    Nonetheless, building a game with Sprite Kit brings many key benefits, including a fully integrated physics engine, streamlined workflow tools in Xcode 5, compatibility with both iOS and OS X, and official maintenance by Apple.

    The question is: which will you use for your next 2D game project? Let us know in the comments.

    iOS 7 SDK Essentials

    $
    0
    0

    Mobiletuts+ is pleased to announce a comprehensive session on the iOS 7 SDK and Xcode 5! This session will begin with in-depth coverage of Sprite Kit. Vote in today’s poll to determine what features of the SDK we cover next!


    Session Preparation

    In order to participate in this session, you’ll need the iOS 7 SDK and Xcode 5. Head over to the Apple Developer Center if you haven’t already downloaded these tools.

    We also recommend that you watch the WWDC 2013 Keynote. While all of the WWDC 2013 videos are phenomenal, pay close attention to anything in the “Special Events” category. Watching these videos will ensure that you stay updated on fundamental advances in the iOS and OS X ecosystem!


    Session Format

    We’ll be kicking off our session with tutorial content on Sprite Kit! Sprite Kit is a 2D and 2.5D game engine provided by Apple and fully integrated with Xcode 5. With Sprite Kit, building exciting games and compelling experiences has never been easier.

    However, where we take our session from here is up to you! Vote in the poll below to let us know what you think we should cover next. We’ll announce the updated session format on Wednesday, September 25th.


    Requests & Comments

    Have a specific tutorial concept you’d like us to cover? Make your voice heard by leaving a comment below. We’ll be publishing at least 2 iOS 7 SDK tutorials each week for the duration of this session, and we’d love to have your input!

    Corona SDK: Build a Monkey Defender

    $
    0
    0

    In this tutorial, we will be creating a game called Monkey Defender using the Corona SDK! This game will serve as a great foundation for a lot of different genres include defense style games. So, let’s get started!


    Project Overview

    In this version of Monkey Defender, the player will have to defend the monkey by shooting monkey grenades at the incoming spaceships. Every time the player successfully hits an enemy spaceship, their score will increase by one. If they fail to hit the enemy spaceship before it reaches the monkey, they will lose one banana, or one life. When the player runs out of bananas, it’s game over!

    This game was built with the Corona SDK and here are some of the things you’ll learn:

    • How to utilize Storyboard
    • How to use widgets
    • How to rotate objects based on touch
    • How to use Corona’s Collision
    • How to build a full game with the Corona SDK

    Tutorial Prerequisites

    In order to use this tutorial, you’ll need to have the Corona SDK installed on your computer. If you do not have the SDK, head over to http://www.coronalabs.com to create a free account and download the free software.

    To download the graphics that I used for the game, please download the source files attached to this post. The graphics for this game come from www.opengameart.org and www.vickiwenderlich.com. The background graphic comes from Sauer2 at Open Game Art and the rest of the graphics come Vicki Wenderlich. If you decide to publish this game with these graphics, please be sure to credit both artists.


    1. Build Configuration

    The first step to build our game, Monkey Defender, is to create a new file called build.settings and place it inside of your project folder. The build.settings file handles all of the build time properties inside of our app. For our game, we only need to worry about the orientation of the game, and we are only going to allow landscape mode.

    settings = {
      orientation = {
        default = "landscapeRight",
        supported = { "landscapeRight", "landscapeLeft"}
      },
    }

    2. Runtime Configuration

    Next, we will create another file called config.lua and place it within your project folder. The config.lua file handles all of our runtime configurations such as the height, width, scaling type, and frame rate. For our game, we are going to set up our app to be 320×480, to be in a letter box and to have 30 frames per second.

    application = {
      content = {
        width = 320,
        height = 480,
        scale = "letterBox",
        fps = 30,
      },
    }

    3. Building main.lua

    Now that we have our project configured, we can move forward with creating main.lua. The main.lua file is the starting point of every app built with the Corona SDK, so create a new file called main.lua and move it to your project folder. Inside of our main.lua file, we will hide the status bar, add some global variables, and use Corona’s Storyboard feature to manage our scenes.

    -- hide the status bar
    display.setStatusBar( display.HiddenStatusBar )
    -- Set up some global variables for our game
    screenW, screenH, halfW, halfH = display.contentWidth, display.contentHeight, display.contentWidth*0.5, display.contentHeight*0.5
    -- include the Corona "storyboard" module
    local storyboard = require "storyboard"
    -- load menu screen
    storyboard.gotoScene( "menu" )

    4. Building the Menu

    With our main.lua file set up, we are going to move on to our menu. The menu for this game will be simple. It will display the title of the game and a button to start the game.

    Step 1

    To get started, create a new file called menu.lua and place the file in your project folder. The first addition to this file is to add a storyboard and the widget library. While the storyboard will allow us to easily manage our scene, the widget library will allow us to easily add common elements to our app. In this case, we will be using the widget library to add a button to our menu. We’ll get to that later.

    local storyboard = require( "storyboard" )
    local scene = storyboard.newScene()
    local widget = require "widget"

    Step 2

    After the requires, we will create our first function called scene:createScene(). This function will be called when the scene does not exist and is a perfect place for our game title and button.

    -- Called when the scene's view does not exist:
    function scene:createScene( event )
      local group = self.view
    end

    Step 3

    Inside of our scene:createScene() function, we will create a new display object that will be used as our background. If you haven’t already, make sure you download the source files for this tutorial and place all of the graphics inside a folder named images in your project.

    The background display object will be centered on the screen and inserted into our group variable. By inserting the display object into our group variable, we are telling Corona that this object belongs to this scene. When we switch scenes, Corona will know to remove this object or hide it because we are no longer viewing the menu scene.

    An in-depth look at storyboards is outside of the scope of this tutorial, but you can read more at the official documentation.

    -- Insert a background into the game
    local background = display.newImageRect("images/background.png", 480, 320)
      background.x = halfW
      background.y = halfH
      group:insert(background)

    Step 4

    After our background object, we will place a text object that will display the title of our game. This text object will be centered on the screen and inserted into the group variable.

    -- Insert the game title
    local gameTitle = display.newText("Space Monkey",0,0,native.systemFontBold,32)
      gameTitle.x = halfW
      gameTitle.y = halfH - 80
      group:insert(gameTitle)

    Step 5

    Our last addition to the function scene:createScene() will be a button widget. This widget will allow players to start the game. Before we can add the widget, we need to create a function that will handle the touch event.

    When the button is touched, the following function will be called. This function will send players to the game scene, which we will be creating later.

    -- This function will only be fired when the widget playBtn is touched.
    local function onPlayBtnRelease()
      storyboard.gotoScene( "game", "fade", 500 )
      return true
    end

    Step 6

    After the onPlayBtnRelease function, we will then add the button to the menu scene. We add the button by using widget.newButton with a couple of parameters. The label property will set the text of our button and the onRelease property will tell our app which function to fire when it’s touched. Then, we will place the button in the center of the screen and insert it into the group variable. The playBtn will be the last piece added to the scene:createScene() function.

    -- Create a widget button that will let the player start the game
    local playBtn = widget.newButton
    {
      label="Play Now",
      onRelease = onPlayBtnRelease
    }
    playBtn.x = halfW
    playBtn.y = halfH
    group:insert( playBtn )

    Step 7

    Right after the scene:createScene() function, we are going to add the scene:enterScene() function. This function will be called after the scene is created and it’s on the screen.

    function scene:enterScene(event)
      local group = self.view
      if(storyboard.getPrevious() ~= nil) then
        storyboard.purgeScene(storyboard.getPrevious())
        storyboard.removeScene(storyboard.getPrevious())
      end
    end

    Step 8

    To wrap up our menu.lua file, we will add two event listeners and return the scene variable. This is an important step because the two event listeners will fire the appropriate functions and return the scene variable to signify the end of the file.

    scene:addEventListener("createScene", scene)
    scene:addEventListener("enterScene", scene)
    return scene

    5. Game Logic

    By now, we’ve completed the configuration, the main.lua file and the menu.lua file. Next, we are going to create the logic for our game.

    Step 1

    The game logic will be held inside a file called game.lua. To get started, create a new file called game.lua and place it inside your project folder. Our first addition to the new file is to require Corona’s Storyboard.

    local storyboard = require( "storyboard" )
    local scene = storyboard.newScene()

    Step 2

    Next, we will add physics to our game. We will use physics to make collision detection between the bullets and the enemy ships easier. Right after the physics capability is added, we will pause it so it doesn’t interfere with the creation of the scene.

    local physics = require "physics"
    physics.start(); physics.pause()

    Step 3

    After the physics, we will predefine the variables for our game.

    local background, monkey, bullet, txt_score
    local tmr_createBadGuy
    local lives = {}
    local badGuy = {}
    local badGuyCounter = 1
    local score = 0

    Step 4

    The next set of variables will be used as settings for our game. Feel free to change the speeds of the game or increase the number of lives for the player.

    local numberOfLives = 3
    local bulletSpeed = 0.35
    local badGuyMovementSpeed = 1500
    local badGuyCreationSpeed = 1000

    Step 5

    Now we will create our scene:createScene function.

    -- Called when the scene's view does not exist:
    function scene:createScene( event )
    local group = self.view

    Step 6

    Next, we will create a function that will be fired when the background display object is touched, and this function will contain the bulk of our game logic. When fired, we will rotate the monkey towards the touch event and fire a bullet towards the same touch event.

    First, let’s create the touched function and create a conditional statement so our logic only runs during the begin phase.

    function touched(event)
      if(event.phase == "began") then

    Within the if-then statement, we use the math library to determine the angle between the monkey and the touch event. This is accomplished by using a combination of math.deg and math.atan2 to find where the monkey needs to be rotated. After the rotation degree is found, we rotate the monkey to the appropriate position.

      angle = math.deg(math.atan2((event.y-monkey.y),(event.x-monkey.x)))
      monkey.rotation = angle + 90

    Since this function is going to fire a bullet, we have to create the bullet as a display object. Once it’s created, we will make the physics object so it can respond to collisions with the enemies.

      bullet = display.newImageRect("images/grenade_red.png",12,16)
      bullet.x = halfW
      bullet.y = halfH
      bullet.name = "bullet"
      physics.addBody( bullet, "dynamic", { isSensor=true, radius=screenH*.025} )
      group:insert(bullet)

    Now that we have our bullet, we need to find out where to send it. To do this, we first determine whether we need to send the bullet to the left or right and then use the y = mx + b formula to determine the y location. Our last bit of math is to find the distance between the two points so we can determine how fast to project the bullet.

      -- Find out if we need to fire the bullet to the left or right
      local farX = screenW*2
      if(event.xStart >= screenW/2)then
        farX = screenW*2
      else
        farX = screenW-(screenW*2)
      end
      -- Use y = mx + b to find the Y position
      local slope = ((event.yStart-screenH/2)/(event.xStart-screenW/2))
      local yInt = event.yStart - (slope*event.xStart)
      local farY = (slope*farX)+yInt
      -- Get the distance from the bullet to bullet destination
      local xfactor = farX-bullet.x
      local yfactor = farY-bullet.y
      local distance = math.sqrt((xfactor*xfactor) + (yfactor*yfactor))

    Now that we know the distance and the x/y coordinates of the bullet destination, we can send our bullet to the destination using transition.to. We’ll also need to include a couple of end statements to wrap up the touched function.

      bullet.trans = transition.to(bullet, { time=distance/bulletSpeed, y=farY, x=farX, onComplete=nil})
      end
    end

    Step 7

    After all that math, the next few steps are simple. We will add a background to our game (we will attach an event listener to the background later), the monkey, and a text object to display the score.

    -- Create a background for our game
    background = display.newImageRect("images/background.png", 480, 320)
      background.x = halfW
      background.y = halfH
      background:setFillColor( 128 )
      group:insert(background)
    -- Place our monkey in the center of screen
    monkey = display.newImageRect("images/spacemonkey-01.png",30,40)
      monkey.x = halfW
      monkey.y = halfH
      group:insert(monkey)
    -- Create a text object for our score
    txt_score = display.newText("Score: "..score,0,0,native.systemFont,22)
      txt_score.x = 430
      group:insert(txt_score)

    We will also insert three bananas to represent three player lives in the top right of the screen.

    -- Insert our lives, but show them as bananas
    for i=1,numberOfLives do
      lives[i] = display.newImageRect("images/banana.png",45,34)
      lives[i].x = i*40-20
      lives[i].y = 18
      group:insert(lives[i])
    end

    Step 8

    Next, we will create a function that will send bad guys toward our player. We are going to call this function createBadGuy and we will first determine which direction to send the bad guy from.

    -- This function will create our bad guy
    function createBadGuy()
      -- Determine the enemies starting position
      local startingPosition = math.random(1,4)
      if(startingPosition == 1) then
        -- Send bad guy from left side of the screen
        startingX = -10
        startingY = math.random(0,screenH)
      elseif(startingPosition == 2) then
        -- Send bad guy from right side of the screen
        startingX = screenW + 10
        startingY = math.random(0,screenH)
      elseif(startingPosition == 3) then
        -- Send bad guy from the top of the screen
        startingX = math.random(0,screenW)
        startingY = -10
      else
        -- Send bad guy from the bototm of the screen
        startingX = math.random(0,screenW)
        startingY = screenH + 10
    end

    After we have determined the direction that our bad guy will come from, we will then create a new display object for our bad guy and turn the bad guy into a physics object. We’ll use physics to detect collisions later on.

    -- Start the bad guy according to starting position
    badGuy[badGuyCounter] = display.newImageRect("images/alien_1.png",34,34)
      badGuy[badGuyCounter].x = startingX
      badGuy[badGuyCounter].y = startingY
      physics.addBody( badGuy[badGuyCounter], "dynamic", { isSensor=true, radius=17} )
      badGuy[badGuyCounter].name = "badGuy"
      group:insert(badGuy[badGuyCounter])

    Then, we will use Corona’s transition.to to move the bad guy towards the center of the screen. Once the transition is done and the enemy has not been hit, we will remove the bad guy and subtract one life from the player.

    If the player’s lives have reached 0 or less, we will stop sending the bad guys and remove the player’s ability to send more bullets. We will also show two text objects to signify that the game is over and let the player return to the menu.

    badGuy[badGuyCounter].trans = transition.to(badGuy[badGuyCounter], {
      time=badGuyMovementSpeed, x=halfW, y=halfH,
      onComplete = function (self)
      self.parent:remove(self);
      self = nil;
      -- Since the bad guy has reached the monkey, we will want to remove a banana
      display.remove(lives[numberOfLives])
      numberOfLives = numberOfLives - 1
      -- If the numbers of lives reaches 0 or less, it's game over!
      if(numberOfLives <= 0) then
        timer.cancel(tmr_createBadGuy)
        background:removeEventListener("touch", touched)
        local txt_gameover = display.newText("Game Over!",0,0,native.systemFont,32)
          txt_gameover.x = halfW
          txt_gameover.y = screenH * 0.3
          group:insert(txt_gameover)
          local function onGameOverTouch(event)
          if(event.phase == "began") then
            storyboard.gotoScene("menu")
          end
      end
      local txt_gameover = display.newText("Return To Menu",0,0,native.systemFont,32)
        txt_gameover.x = halfW
        txt_gameover.y = screenH * 0.7
        txt_gameover:addEventListener("touch",onGameOverTouch)
        group:insert(txt_gameover)
      end
    end; })
    badGuyCounter = badGuyCounter + 1
    end

    Step 9

    The last function inside of scene:createScene is for collision detection. When a bullet and bad guy collide, this function will be trigged and the following will happen:

    • Add 1 to the player score and update the score text object.
    • Set the alpha of both objects to 0.
    • Cancel the transition on each object so it does not interfere with the removal process.
    • Finally, we will create a timer that will wait 1 millisecond before removing both objects. It’s always a bad idea to remove display objects in the middle of collision detection.
    function onCollision( event )
      if(event.object1.name == "badGuy" and event.object2.name == "bullet" or  event.object1.name == "bullet" and event.object2.name == "badGuy") then
        -- Update the score
        score = score + 1
        txt_score.text = "Score: "..score
        -- Make the objects invisible
        event.object1.alpha = 0
        event.object2.alpha = 0
        -- Cancel the transitions on the object
        transition.cancel(event.object1.trans)
        transition.cancel(event.object2.trans)
        -- Then remove the object after 1 cycle. Never remove display objects in the middle of collision detection.
        local function removeObjects()
          display.remove(event.object1)
          display.remove(event.object2)
        end
      timer.performWithDelay(1, removeObjects, 1)
      end
      end
    end

    Step 10

    After the scene:createScene, we will then write our enter scene function. This function is fired after the scene is created and moved on to the screen. Inside the enter scene function, we will start all of the functions that we wrote in the create scene function.

    function scene:enterScene( event )
      local group = self.view
      -- Actually start the game!
      physics.start()
      -- Start sending the bad guys
      tmr_createBadGuy = timer.performWithDelay(badGuyCreationSpeed, createBadGuy, 0)
      -- Start listening for the background touch event to fire the bullets
      background:addEventListener("touch", touched)
      -- Start the listener to remove bad guys and bullets when they collide
      Runtime:addEventListener( "collision", onCollision )
    End

    Step 11

    We are almost done! The last piece of our code is to add the scene event listeners and return the variable scene. The event listeners will trigger our functions and the return statement lets Corona know we are done with this scene.

    scene:addEventListener( "createScene", scene )
    scene:addEventListener( "enterScene", scene )
    return scene

    Conclusion

    I hope you enjoyed this tutorial on creating a Monkey Defender game with the Corona SDK! We covered a lot of topics ranging from storyboards to geometric formulas! If you have questions or comments, please leave them below and thank you for reading.

    Build an Airplane Game with Sprite Kit – Enemies & Emitters

    $
    0
    0

    This tutorial will teach you how to use the Sprite Kit framework to create a simple Airplanes game. Along the way, you’ll learn all the core concepts of Sprite Kit: animations, emitters, collision detection, and more!


    Series Format

    The Airplanes tutorial will be divided into three parts in order to completely cover each section. After reading the three part tutorial, the readers will be able to create an interesting 2D game using the new Sprite Kit framework provided with iOS 7.

    Each part will produce a practical result, and the sum of all parts will produce the final game. While each part of the series can be read independently, we recommend following along step-by-step for a complete understanding of the topic presented. The source code for the game is provided incrementally with each post.


    Final Preview

    Figure 1: Final Result!
    Illustration of Final Result – Sprite Kit.

    Where We Left Off…

    Welcome back to the second part of our Airplanes game with Sprite Kit. In today’s tutorial, you will program one emitter that will form the smoke trail of an airplane. This tutorial part focuses on several things like movements, touches, and so on, but we’ll explain everything further below. If you haven’t yet completed Part 1 of the series, you can download the project from part 1 and pickup exactly where we left off.


    1. Adding a Smoke Trail

    Particles are used to achieve many different types of effects like fire, smoke, magic, rain, snow, or waterfalls. In this case, we will use them to create a smoke trail for your airplane. The particle will stay activated for the duration of the game.

    Fortunately, Xcode 5 introduced an Emitter Editor as a builtin feature. This is an extremely useful tool and will allow us to easily edit properties like particle texture, background color, birthrate particle, maximum particles, lifetime, position, range, angle, speed, acceleration, scale, rotation, and more. By default, Xcode 5 also provides several turnkey Emitters ready for use. So, lets start and add one emitter to our game.

    The particle images needed are available within the Resources folder of the attached download.

    To add one emitter to your game, you need to go to File > New > File... You will see something like the following image:

    Figure 1: Creating SpriteKit Emitter File
    Illustration of the Creation of SpriteKit Emitter File (Xcode).

    Select the iOS > Resource and SpriteKit Particle File option (as in the aforementioned figure). Click Next. Now, you will be asked what template you want to use. That are 8 different templates available. Select the smoke template and click on Next, then give it a name (we named ours “trail”) and click Create. Xcode will add two new files to your project (trail.sks and spark.png). You need to change the number of particles, the texture, the position range, the angle, and the scale for best results. Take a look at our configuration:

    Figure 2: Emitter properties
    Illustration of the Emitter Properties (Xcode).

    Now, let’s add the smoke to our plane.

    Within MyScene.h, add a smoke trail property:

    @property SKEmitterNode *smokeTrail;

    At the end of the if (self = [super initWithSize:size]) conditional in MyScene.m, add the following snippet:

            //adding the smokeTrail
            NSString *smokePath = [[NSBundle mainBundle] pathForResource:@"Smoke" ofType:@"sks"];
            _smokeTrail = [NSKeyedUnarchiver unarchiveObjectWithFile:smokePath];
            _smokeTrail.position = CGPointMake(screenWidth/2, 15);
            [self addChild:_smokeTrail];

    Of course, when the airplane moves, the trail needs to move too. At the end of the -(void)update:(NSTimeInterval)currentTime method, add this line:

    _smokeTrail.position = CGPointMake(newX,newY-(_plane.size.height/2));

    Build and run the project and if everything went well it will be awesome!

    You should see something like the following:

    Figure 3: Emitter properties
    Illustration of the Emitter Properties (Xcode).

    2. Add & Move Enemies

    So far, you just have the airplane moving around the screen. But the fun starts when more airplanes become available. So, let’s add some enemy airplanes!

    Not only do you need to create enemies, but you also need to define a random path for each in order to simulate a real battlefield. To achieve this, you will use the action followPath. You will create random paths (with CGPath) and then each enemy will move over that path.

    One great method that we had to do this with Cocos2D was schedule:interval:. Unfortunately, Apple did not add a similar method to Sprite Kit, but it is easy to create a similar one using SKActions. To achieve this schedule, we need to create an SKAction calling for a method waitForDuration. After that, we will create an SKAction that can run a block and use it to call the method that adds enemies. Then, we’ll put these two actions on a sequence and just say to repeat it over time.

    To recreate the explanation you will only need the following snippet. Add it to the end of the if conditional if (self = [super initWithSize:size] ):

    //schedule enemies
    SKAction *wait = [SKAction waitForDuration:1];
    SKAction *callEnemies = [SKAction runBlock:^{
        [self EnemiesAndClouds];
    }];
    SKAction *updateEnimies = [SKAction sequence:@[wait,callEnemies]];
    [self runAction:[SKAction repeatActionForever:updateEnimies]];

    Easy enough? If you have any questions, do not hesitate to ask them within the comments section.

    Now you must add the method that creates the movement paths for the enemies to follow. We choose to use the CGPathAddCurveToPoint, since this method creates a Bézier curve with two control points. The following image explains how this works:

    Figure 3: Bezier Curve
    Illustration of the Bézier Curve Creation (Xcode).

    So, you need to add the following code to our MyScene.m file:

    -(void)EnemiesAndClouds{
        //not always come
        int GoOrNot = [self getRandomNumberBetween:0 to:1];
        if(GoOrNot == 1){
            SKSpriteNode *enemy;
            int randomEnemy = [self getRandomNumberBetween:0 to:1];
            if(randomEnemy == 0)
                enemy = [SKSpriteNode spriteNodeWithImageNamed:@"PLANE 1 N.png"];
            else
                enemy = [SKSpriteNode spriteNodeWithImageNamed:@"PLANE 2 N.png"];
            enemy.scale = 0.6;
            enemy.position = CGPointMake(screenRect.size.width/2, screenRect.size.height/2);
            enemy.zPosition = 1;
            CGMutablePathRef cgpath = CGPathCreateMutable();
            //random values
            float xStart = [self getRandomNumberBetween:0+enemy.size.width to:screenRect.size.width-enemy.size.width ];
            float xEnd = [self getRandomNumberBetween:0+enemy.size.width to:screenRect.size.width-enemy.size.width ];
            //ControlPoint1
            float cp1X = [self getRandomNumberBetween:0+enemy.size.width to:screenRect.size.width-enemy.size.width ];
            float cp1Y = [self getRandomNumberBetween:0+enemy.size.width to:screenRect.size.width-enemy.size.height ];
            //ControlPoint2
            float cp2X = [self getRandomNumberBetween:0+enemy.size.width to:screenRect.size.width-enemy.size.width ];
            float cp2Y = [self getRandomNumberBetween:0 to:cp1Y];
            CGPoint s = CGPointMake(xStart, 1024.0);
            CGPoint e = CGPointMake(xEnd, -100.0);
            CGPoint cp1 = CGPointMake(cp1X, cp1Y);
            CGPoint cp2 = CGPointMake(cp2X, cp2Y);
            CGPathMoveToPoint(cgpath,NULL, s.x, s.y);
            CGPathAddCurveToPoint(cgpath, NULL, cp1.x, cp1.y, cp2.x, cp2.y, e.x, e.y);
            SKAction *planeDestroy = [SKAction followPath:cgpath asOffset:NO orientToPath:YES duration:5];
            [self addChild:enemy];
            SKAction *remove = [SKAction removeFromParent];
            [enemy runAction:[SKAction sequence:@[planeDestroy,remove]]];
            CGPathRelease(cgpath);
        }
    }
    -(int)getRandomNumberBetween:(int)from to:(int)to {
        return (int)from + arc4random() % (to-from+1);
    }

    The enemiesAndClouds method only adds Enemies for now. We’ll wait to add clouds in the third and final part of this series.

    The essence of this method is generating random values. First, it will decide if a new enemy will be released, then it creates its position. Afterward, it creates the enemy control points, and, finally, the actions are created.

    When we add or remove a sprite to the screen, we need to make sure the memory allocation and deallocation is treated with care and success. The action removeFromParent takes care of this for us.

    Now, build and run the project and watch as enemies begin to appear on the screen.

    Figure 3: Enemies
    Illustration of the Enemies (Xcode).

    3. Create Airplane Bullets

    To make the game fun, our enemies need to be destroyable. You will add some bullets to your airplane to achieve this. To do this, we’ll need to do the following:

    • Get the current airplane position
    • Create the bullet sprite
    • Create the action to move the bullet
    • Create the action to remove the bullet
    • Add the bullet to the screen

    Replace the touchesBegan method with the following snippet:

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        /* Called when a touch begins */
        CGPoint location = [_plane position];
        SKSpriteNode *bullet = [SKSpriteNode spriteNodeWithImageNamed:@"B 2.png"];
        bullet.position = CGPointMake(location.x,location.y+_plane.size.height/2);
        //bullet.position = location;
        bullet.zPosition = 1;
        bullet.scale = 0.8;
        SKAction *action = [SKAction moveToY:self.frame.size.height+bullet.size.height duration:2];
        SKAction *remove = [SKAction removeFromParent];
        [bullet runAction:[SKAction sequence:@[action,remove]]];
        [self addChild:bullet];
    }

    Build and run your project. If you want to fire a bullet you only need to tap the screen!


    Conclusion

    You’ve reached the end of the second tutorial in our series.

    At this point, you should understand and be able to perform the following tasks:

    • Create an Emitter
    • Add bullets to sprites
    • Create bézier paths for sprite movement

    Stay tuned for the next installment in this series, where we will continue to build our airplane game!


    Acknowledgements & Recommendations

    We would like to thank Daniel Ferenčak for providing us with the game art used to produce this tutorial series.

    In order to fully appreciate the tutorial series, we advise that you test our code by deploying it to a real device running iOS 7. You will need Xcode 5 and the latest iOS 7 SDK. If you don’t already have these tools, you can download them from the Apple Developer Center. Once downloaded, install the software and you’ll be ready to begin.


    Build an Airplane Game with Sprite Kit – Explosions & Clouds

    $
    0
    0

    This tutorial will teach you how to use the Sprite Kit framework to create a simple Airplanes game. Along the way, you’ll learn all the core concepts of Sprite Kit: animations, emitters, collision detection, and more!


    Series Format

    The Airplanes tutorial will be divided into three parts in order to completely cover each section. After reading the three part tutorial, the readers will be able to create an interesting 2D game using the new Sprite Kit framework provided with iOS 7.

    Each part will produce a practical result, and the sum of all parts will produce the final game. While each part of the series can be read independently, we recommend following along step-by-step for a complete understanding of the topic presented. The source code for the game is provided incrementally with each post.


    Final Preview

    Figure 1: Final Result!
    Illustration of Final Result – Sprite Kit.

    Where We Left Off…

    Welcome back to the third part of our airplanes game with Sprite Kit. In our last post, we focused on adding enemies and emitters to the game. In today’s tutorial, you will program the collision detection, work with a texture atlas, and create some explosions in order to finish the game. Let’s get started!


    1. Adding Collision Detection

    Intersection tests are frequently used in environments where more than one object exists. In Sprite Kit, you will use Collisions and Contacts to detect if a given object hit another object.

    In this game, you will use collision detection. When a bullet makes contact with one enemy, both the bullet and the enemy will be removed from the screen.

    To do this, you need to define the category mask values. There should be one category for each physics object. In MyScene.h, add the following code:

    static const uint8_t bulletCategory = 1;
    static const uint8_t enemyCategory = 2;

    Now, while still within MyScene.h, add SKPhysicsContactDelegate as we did before with the UIAccelerometerDelegate.

    @interface MyScene : SKScene<UIAccelerometerDelegate, SKPhysicsContactDelegate>
    {

    Before you can use physics, you need to initiate the physics settings. At the if (self = [super initWithSize:size]) conditional, instantiate the gravity with a 0 value (i.e. no gravity) and then the contact delegate:

    self.physicsWorld.gravity = CGVectorMake(0, 0);
    self.physicsWorld.contactDelegate = self;

    The two bodies that need physics are the bullet and the enemies. Let’s set several properties for each one. Let’s add the code below within the -(void)EnemiesAndClouds method:

    enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:enemy.size];
    enemy.physicsBody.dynamic = YES;
    enemy.physicsBody.categoryBitMask = enemyCategory;
    enemy.physicsBody.contactTestBitMask = bulletCategory;
    enemy.physicsBody.collisionBitMask = 0;

    The code above states that the contact area of the airplane will be a rectangle that has the size of the enemy sprite. The dynamic property indicates whether the physics body is moved by the physics simulation. Next, the categoryBitMask is where you set the category to the object, and the contactTestBitMask refers to which bodies the enemies will interact with (in this case with bullets).

    Now let’s define the physics for the bullet object. Within the -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event method, the bullet code should be modified to add:

    bullet.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:bullet.size];
    bullet.physicsBody.dynamic = NO;
    bullet.physicsBody.categoryBitMask = bulletCategory;
    bullet.physicsBody.contactTestBitMask = enemyCategory;
    bullet.physicsBody.collisionBitMask = 0;

    So far, you have defined the properties for collisions. However, we must detect if a contact is made.

    You need to use the method didBeginContact to know what objects have contact with other objects. So, the following code calculates the two bodies that have contacted and simultaneously removes them from the scene:

    -(void)didBeginContact:(SKPhysicsContact *)contact{
        SKPhysicsBody *firstBody;
        SKPhysicsBody *secondBody;
        if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
        {
            firstBody = contact.bodyA;
            secondBody = contact.bodyB;
        }
        else
        {
            firstBody = contact.bodyB;
            secondBody = contact.bodyA;
        }
        if ((firstBody.categoryBitMask & bulletCategory) != 0)
        {
            SKNode *projectile = (contact.bodyA.categoryBitMask & bulletCategory) ? contact.bodyA.node : contact.bodyB.node;
            SKNode *enemy = (contact.bodyA.categoryBitMask & bulletCategory) ? contact.bodyB.node : contact.bodyA.node;
            [projectile runAction:[SKAction removeFromParent]];
            [enemy runAction:[SKAction removeFromParent]];
        }
    }

    Pretty simple, right? Now, build and run. If everything went right, then the enemy and bullet will disappear when they collide.


    2. Incorporating a Texture Atlas

    Our game is nearly complete, but needs some action and animation. The next two steps will add explosions and some background animations made from clouds.

    So far, we haven’t used Texture Atlas. Sprite Kit includes a texture atlas generator that has several interesting features. In Xcode 5, you can create a texture atlas with the following steps:

    1. Place all the sprites into a single folder. For our project, you can find all the images in the attached download within the “EXPLOSION” folder.
    2. Change the extension of the folder to *.atlas. In our case, rename EXPLOSION to EXPLOSION.atlas.
    3. Drag-and-drop the folder into the project. I added it to the Supporting Files folder within the Xcode navigator.
    4. Make sure that the Option “Enable Texture Altas Generation” is on. To check this, go to the Build Settings of your project.

    That’s it. Once again, the images for this part are available within the Resources folder of the attached download.

    Now, you need to load the texture atlas into the project.

    Within MyScene.h add:

    @property NSMutableArray *explosionTextures;

    At the end of the if (self = [super initWithSize:size]) conditional, add the following code snippet:

    //load explosions
            SKTextureAtlas *explosionAtlas = [SKTextureAtlas atlasNamed:@"EXPLOSION"];
            NSArray *textureNames = [explosionAtlas textureNames];
            _explosionTextures = [NSMutableArray new];
            for (NSString *name in textureNames) {
                SKTexture *texture = [explosionAtlas textureNamed:name];
                [_explosionTextures addObject:texture];
            }

    3. Adding Explosions

    Once you have the explosions loaded, another step is needed to see them in action. You will now create an explosion that occurs when a bullet hits an enemy. At the end of the if conditional if ((firstBody.categoryBitMask & bulletCategory) != 0), add the following snippet:

            //add explosion
            SKSpriteNode *explosion = [SKSpriteNode spriteNodeWithTexture:[_explosionTextures objectAtIndex:0]];
            explosion.zPosition = 1;
            explosion.scale = 0.6;
            explosion.position = contact.bodyA.node.position;
            [self addChild:explosion];
            SKAction *explosionAction = [SKAction animateWithTextures:_explosionTextures timePerFrame:0.07];
            SKAction *remove = [SKAction removeFromParent];
            [explosion runAction:[SKAction sequence:@[explosionAction,remove]]];

    Build and run the project to test the collision and explosion animation. You should see something like the next figure:

    Figure 1: Explosion
    Illustration of the Explosion (Xcode).

    4. Adding Clouds

    We’ve almost completed the game! This is just the last touch. Now you need to create the clouds atlas, and then load the texture atlas to memory.

    Before we write the code for this step, be sure to add the .atlas extension to the “Clouds” folder in the attached download and to drag it into your project.

    Within the MyScene.h file add the following:

    @property NSMutableArray *cloudsTextures;

    Within the MyScene.m file, beneath the “load explosions” code, add the following:

            //load clouds
            SKTextureAtlas *cloudsAtlas = [SKTextureAtlas atlasNamed:@"Clouds"];
            NSArray *textureNamesClouds = [cloudsAtlas textureNames];
            _cloudsTextures = [NSMutableArray new];
            for (NSString *name in textureNamesClouds) {
                SKTexture *texture = [cloudsAtlas textureNamed:name];
                [_cloudsTextures addObject:texture];
            }

    The last step is to randomly generate clouds and present them on screen with some movement. You need to add the following snippet at the end of the EnemiesAndClouds method:

     //random Clouds
        int randomClouds = [self getRandomNumberBetween:0 to:1];
        if(randomClouds == 1){
            int whichCloud = [self getRandomNumberBetween:0 to:3];
            SKSpriteNode *cloud = [SKSpriteNode spriteNodeWithTexture:[_cloudsTextures objectAtIndex:whichCloud]];
            int randomYAxix = [self getRandomNumberBetween:0 to:screenRect.size.height];
            cloud.position = CGPointMake(screenRect.size.height+cloud.size.height/2, randomYAxix);
            cloud.zPosition = 1;
            int randomTimeCloud = [self getRandomNumberBetween:9 to:19];
            SKAction *move =[SKAction moveTo:CGPointMake(0-cloud.size.height, randomYAxix) duration:randomTimeCloud];
            SKAction *remove = [SKAction removeFromParent];
            [cloud runAction:[SKAction sequence:@[move,remove]]];
            [self addChild:cloud];
        }

    Build and run the project yet again. If everything goes well, you should see something like the next figure:

    Figure 2: Final
    Illustration of the Final Game (Xcode).

    Conclusion

    This concludes the third and final tutorial demonstrating how to create an airplanes game using the new Sprite Kit framework available with the iOS 7 SDK. If you’ve followed this series from start-to-finish, you should now have enough knowledge to create a simple Sprite Kit game using this dynamic new game engine. If you have any questions or comments, please feel free to leave them below!


    Acknowledgements & Recommendations

    We would like to thank Daniel Ferenčak for providing us with the game art used to produce this tutorial series.

    In order to fully appreciate the tutorial series, we advise that you test our code by deploying it to a real device running iOS 7. You will need Xcode 5 and the latest iOS 7 SDK. If you don’t already have these tools, you can download them from the Apple Developer Center. Once downloaded, install the software and you’ll be ready to begin.

    Android SDK: Supporting Alternative Input Devices

    $
    0
    0

    This tutorial will explore alternative mobile interaction methods like trackballs, mice, and styluses. To explore this concept, we’ll focus on enhancing a drawing application to add support for these input devices.

    Android devices are now many and varied, with differing hardware controls as well as software versions. In a recent series, we created a drawing app for Android using touchscreen interaction, but some users may be accessing your apps through different methods. For example, the Android platform runs on devices with trackballs, styluses, and even the traditional mouse and keyboard model. In this tutorial, we will run through the options you can explore when making apps accessible to a range of user hardware, as well as outlining additional capabilities these interaction models offer.

    We’ll be referring throughout this tutorial to options you can see in action if you check out the Android SDK API Demos app. You can find this in your SDK installation folder at samples/android-<version>/ApiDemos. The relevant classes to start looking at are TouchPaint and FingerPaint, although they both refer to other classes in the app. The FingerPaint app uses touchscreen interaction, while the TouchPaint app includes support for trackball, mouse, and stylus interaction. You can open, explore and experiment with the API Demos app in Eclipse, running it on an emulator or device to get acquainted with the functionality.

    We won’t be building an app in this tutorial, but we will indicate ways that you can enhance any drawing functions you use to suit the aims you have for your own projects. We will indicate how to use the code we cover if you build the app from the drawing series, and you will be able to use this tutorial as inspiration for possible extensions of the functionality within it.

    The source code download contains the Java classes for the drawing app we created in the series (plus pattern and opacity follow-ups) with the trackball functionality below added. We will be focusing primarily on trackball interaction since it is the most complex and is fundamentally different to touch interaction. We will also use this to explore the details of touch interaction at a deeper level than we did in the series.


    1. Preparation

    Step 1

    Although we won’t actually build a new app in this tutorial, let’s first run through a sample excerpt of drawing functionality you can use to try out the options we explore below. If you built the drawing series app, you can use it to try out the new options.

    A typical Android drawing app will have a custom View representing the canvas area users can draw on. The following demonstrates a basic example of such a View class:

    public class DrawingView extends View {
    	//drawing path
    	private Path drawPath;
    	//drawing and canvas paint
    	private Paint drawPaint, canvasPaint;
    	//initial color
    	private int paintColor = 0xFFFF0000;
    	//canvas
    	private Canvas drawCanvas;
    	//canvas bitmap
    	private Bitmap canvasBitmap;
    	//constructor
    	public DrawingView(Context context, AttributeSet attrs){
    		super(context, attrs);
    		setupDrawing();
    	}
    	//prepare drawing
    	private void setupDrawing(){
    		drawPath = new Path();
    		drawPaint = new Paint();
    		drawPaint.setColor(paintColor);
    		drawPaint.setAntiAlias(true);
    		drawPaint.setStrokeWidth(50);
    		drawPaint.setStyle(Paint.Style.STROKE);
    		drawPaint.setStrokeJoin(Paint.Join.ROUND);
    		drawPaint.setStrokeCap(Paint.Cap.ROUND);
    		canvasPaint = new Paint(Paint.DITHER_FLAG);
    	}
    	//view assigned size
    	@Override
    	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    		super.onSizeChanged(w, h, oldw, oldh);
    		canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    		drawCanvas = new Canvas(canvasBitmap);
    	}
    	//draw view
    	@Override
    	protected void onDraw(Canvas canvas) {
    		canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
    		canvas.drawPath(drawPath, drawPaint);
    	}
    	//respond to touch interaction
    	@Override
    	public boolean onTouchEvent(MotionEvent event) {
    		float touchX = event.getX();
    		float touchY = event.getY();
    		//respond to down, move and up events
    		switch (event.getAction()) {
    		case MotionEvent.ACTION_DOWN:
    			drawPath.moveTo(touchX, touchY);
    			break;
    		case MotionEvent.ACTION_MOVE:
    			drawPath.lineTo(touchX, touchY);
    			break;
    		case MotionEvent.ACTION_UP:
    			drawPath.lineTo(touchX, touchY);
    			drawCanvas.drawPath(drawPath, drawPaint);
    			drawPath.reset();
    			break;
    		default:
    			return false;
    		}
    		//redraw
    		invalidate();
    		return true;
    	}
    }

    In this case, the View facilitates drawing using the onTouchEvent listener for touch screens, so this is ideal for finger-painting style interaction. When the user touches the screen, the path moves to their finger’s start point. When they move their finger, still touching the screen, the path takes a line from the previous position to the new one. When the user takes their finger off the screen, the path is submitted and drawn.

    Notice that in the above class, the drawing is implemented by detecting the X and Y co-ordinates of where the user’s finger has touched the screen, whether they have just touched it, are currently dragging it across, or have just lifted it off. This interaction model works in exactly the same way if the user is drawing with a mouse or stylus, although these offer additional options we will explore below. If the user chooses to draw using a trackball, we need a different implementation we will work through next. The trackball event listener also receives a MotionEvent parameter, but the information we can retrieve from it is different.


    2. Trackball Interaction

    Step 1

    If the user is interacting using a trackball, you can handle this in a number of possible ways. In the TouchPaint sample code, moving the trackball on the drawing area is treated the same way as touching and moving the finger, mouse, or stylus over it, with a series of oval shapes painted along the path followed by the user. Since in the drawing app series we adopted a slightly different approach (indicated in the custom View class above) we will translate that to trackball interaction here. The result will be a simplistic one, but will illustrate the differences between trackball and touchscreen interaction.

    If touching and moving across the canvas is treated as a drawing action, then we could treat pressing and rolling the trackball in the same way. This means that, just as we detected pressing, moving and lifting the finger, stylus or mouse, we will want to detect the trackball being pressed, rolled, and released. As with the touch interaction, we can start a path where the trackball is pressed, move it using a line when the trackball is rolled, and complete the drawing path operation when it is released.

    We will assume that we are only going to handle trackball interaction for drawing on the canvas, so the user will not be able to use the trackball to interact with the other UI elements. Trackballs on Android devices are typically coupled with touch screens.

    To detect trackball interaction, add the following method to your View class:

    @Override
    public boolean onTrackballEvent(MotionEvent event) {
    //respond to trackball interaction
    }

    The method is similar to the touch event listener, receiving a MotionEvent parameter and returning a boolean value which determines how future events of the same kind are handled.

    Step 2

    When handling trackball actions, we first need to work out what user action triggered the method. We are interested in three actions: pressing the trackball, moving it after pressing it, and releasing it after drawing. We are only interested in the trackball move event when it is pressed. For this reason, we want to detect presses that occur, indicating that the user is currently drawing. To achieve this, add a boolean variable to your class to keep track of whether or not the trackball is currently pressed:

    private boolean trackOn=false;

    We can assume that the trackball will be up initially. We will also want to keep track of the user’s position as logged via the trackball, so add another couple of instance variables:

    private float trackX, trackY;

    We will scale the trackball movement values up since the trackballs on Android devices are typically small and we don’t want the user to have to roll theirs too much to draw across the canvas. Add another instance variable for the scaling value we will use:

    private int scale=5;

    You can adjust this if you like. Since the trackball coordinates are relative, we are going to use the width and height of the canvas area as part of our calculation. Add instance variables for these:

    private int canvasWidth, canvasHeight;

    You can initialize these after the canvas size has been set, so for the drawing series app, do it in the onSizeChanged method:

    canvasWidth = canvasBitmap.getWidth();
    canvasHeight = canvasBitmap.getHeight();

    Step 3

    Back in your onTrackballEvent method, you can now retrieve information about where the trackball is positioned. In the touch event listener, we simply retrieved the X and Y coordinates from the MotionEvent object using getX and getY. However, when the MotionEvent has been fired by a trackball, these actually indicate different information. With a trackball, the X and Y values are relative rather than absolute, so we must carry out some processing to turn this into a value we can pass to the Path and Canvas objects to draw in the right place.

    To use the trackball interaction to draw a line as we did with touch, we can adopt the following technique, which uses a simplified and slightly altered version of the algorithm you will see in the API Demos app. In the onTrackballEvent method, first retrieve the type of event that has occurred:

    int action = event.getActionMasked();

    Let’s now calculate the X and Y co-ordinates we want to pass to the drawing objects:

    trackX += event.getX() * event.getXPrecision() * scale;
    trackY += event.getY() * event.getYPrecision() * scale;

    Multiplying the X or Y pointer by the precision should give us a more accurate hardware value. We also multiply by the scaling number we defined as a variable. Since the trackball coordinates are relative, we need to check in case we move off the canvas area:

    if(trackX >= canvasWidth) trackX = canvasWidth-1;
    if(trackY >= canvasHeight) trackY = canvasHeight-1;

    Step 4

    Now let’s handle the event that occurs when the user presses the trackball, after calculating the X and Y values:

    if (action==MotionEvent.ACTION_DOWN)
    {
        //trackball pressed
    }

    Inside the conditional block, first set the boolean variable we created to true:

    trackOn=true;

    Begin the drawing operation using the same technique we used for the touchscreen model:

    drawPath.moveTo(trackX, trackY);

    When the user first presses the trackball to draw, it will by default start at the top left corner. For subsequent drawing operations, the starting point will be relative to previous drawing actions. Now we are ready to draw when the user moves the trackball after pressing it – after the conditional block testing for the “down” action:

    if (action==MotionEvent.ACTION_MOVE && trackOn) {
    //trackball pressed and moving
    }

    We check for the move event, but only want to implement drawing when the trackball is pressed because the move event will also fire when the user moves the trackball without pressing it. Inside this block, we can draw again using the same technique.

    drawPath.lineTo(trackX, trackY);

    Finally, we can complete drawing when the trackball is released, after the conditional for the move event:

    if(action==MotionEvent.ACTION_UP)
    {
        //trackball released
    }

    Now we can again use the same approach as when the user stops touching the screen. If the trackball is currently pressed, we’ll know that drawing has been occurring:

    if(trackOn){
    	drawCanvas.drawPath(drawPath, drawPaint);
    	drawPath.reset();
    	trackOn=false;
    }

    After the “up” event conditional block, complete the method by invalidating the View and returning a true value so that future trackball events will be processed:

    invalidate();
    return true;

    Step 5

    That completes the basic algorithm for trackball drawing. However, your custom drawing View class will only be able to handle the trackball events if it has focus. In the Activity hosting your custom View (the main Activity in the drawing series app), you can achieve this by dispatching the event as follows:

    public boolean dispatchTrackballEvent(MotionEvent ev) {
    //trackball event
    }

    Inside this method, you will need a reference to the custom drawing View in your Activity. To do this, focus on it and specify the event handling method we added:

    drawView.requestFocus();
    return drawView.onTrackballEvent(ev);

    Step 6

    Trackballs on Android devices are relatively rare now, but you can test your functionality on the emulator. Note, however, that the emulator results will be a little crude. When you create a virtual device, enable trackball support on it. You can then toggle trackball interaction on and off while interacting with your app on the virtual device by pressing F6. You may encounter issues getting the trackball to function on the emulator for certain API levels.

    When you try the drawing function using the trackball, emulating trackball presses by clicking your mouse button, you will see instantly that this isn’t the most sensitive drawing interaction model. This is why some apps use the approach demonstrated in the API Demos, which involves a slightly more complex algorithm. You will also see the inherent difficulty in handling drawing interaction from a trackball rather than touch, a stylus, or a mouse. The problem is that the user cannot know where their start point is. One possible way to address this would be emulating a cursor while the trackball is in use, moving it to reflect the drawing position before the user presses it so that they can start their drawing operations with more accuracy.

    Drawing With Trackball
    Pressing F6 with a virtual device running toggles trackball mode on and off, you can then interact with the virtual track ball using your mouse.
    Tip: If you want to learn more about trackball interaction, have a look at the MotionEventgetAxisValue() method, passing MotionEvent.AXIS_X|Y as a parameter. The class defines values for both axes within the range of -1 to 1, representing the relative displacement of the trackball along each axis. Full horizontal displacement to the left would be an AXIS_X value of -1, with full displacement downwards an AXIS_Y value of 1 and so on. To map these to a UI element, you could add one, divide by 2, and multiply by the View width or height. This would give, for example, an X value of 100 if the X axis value was 0 and the View had a width 200, since 0 is the halfway point in the full trackball range.

    Tip: For a more extensive approach to mapping trackball coordinates to painting operations, see the TouchPaint class in the API Demos. It uses the historical information provided by the MotionEvent to draw a series of points instead of a line, moving each one relative to the last by referring to the getHistoricalX and getHistoricalY methods within a loop.


    3. Mouse and Stylus Interaction

    Step 1

    As mentioned above, your touch event-driven drawing functions will work for mouse and stylus interaction. However, there are other options you can explore to enhance drawing functionality for these hardware items. For example, for both mouse and stylus, you can detect pressure, tilt, and orientation data, allowing you to implement drawing improvements such as increased opacity or perhaps brush size, depending on your existing algorithms. The tilt and orientation data can be used in drawing apps where a non-round brush shape is being used. In some cases a touchscreen device may also provide pressure and orientation information. All of the relevant methods are in the MotionEvent class.

    Check out the following methods for this additional data:

    //used in event handlers
    motionEvent.getPressure();
    motionEvent.getTouchMajor();
    motionEvent.getTouchMinor();
    motionEvent.getOrientation();
    MotionEvent.AXIS_DISTANCE;
    MotionEvent.AXIS_TILT;

    Step 2

    Your apps can detect interaction through the buttons on a mouse or stylus as well as refinements on the drawing function itself. For example, in the TouchPaint class from the API Demos, the buttons are used to change colors and to switch drawing tools. You can also handle hover events for these interaction models, potentially letting you indicate the user’s drawing position or implement certain drawing functions before the screen is actually touched.

    See the following code excerpts for more on this:

    //used in event handlers tailored to specific input tools
    motionEvent.getToolType();
    MotionEvent.BUTTON_PRIMARY;
    MotionEvent.BUTTON_SECONDARY;
    MotionEvent.BUTTON_TERTIARY;

    See the API Demos classes for a more detailed overview of how to use these.


    Conclusion

    We have now covered and indicated a range of user interaction options for drawing apps in Android. If you have been working on the app we initially created in the series, see if you can think of ways to use this new information to enhance the app further. There are lots of other options to consider too, such as different brush types, the ability to set a wider range of colors or patterns, loading images into the app, and sharing images from it. If you think of more and have any luck implementing them, let us know in the comments!

    Working with SKTransition

    $
    0
    0

    This tutorial will teach you to combine UIKit views and the SKTransition class to create beautiful, custom transitions between different SKScenes. Read on!


    Final Preview

    Figure 1: Final Result!
    Illustration of Final Result.

    1. Transitions Between Scenes

    Scenes are interfaces that hold several view objects. Normally, you design several scenes for each part of your game, and then use transitions between the scenes as necessary. For example, you might create different scene classes to represent any or all of the following concepts:

    • A main menu scene to choose the difficulty of a specific level the user wants to play.
    • A scene to configure the details of the sound and music effects of a game.
    • A scene that provides the game-play interface.
    • A scene that provides the online leader board interface.
    • A scene that provides current and overall game achievements.

    As you can see, a scene can be anything that the programmer would like to create. Typically, you transition to a new scene based on game-play objectives or direct user input. For example, if the timer runs out, a new scene presenting a “game over” may be presented. Alternatively, if a user presses an options button, you might transition to a new scene to configure the game settings. Note that, at the transition step, the scene property is immediately updated to point to the new scene. After this, the transition occurs.

    A transition can also have a transition object (an effect or an animation). That object will create a dynamic, beautiful presentation when the transition occurs. Several objects exist, and for a complete and official reference you should consult the SKTransition class reference.


    2. Class Methods

    The SKTransition class presents several methods and two properties (more about those later). The goal of all methods is to create a shiny and dynamic transition between scenes. The class methods can be divided into four main sections:

    • With Duration: Transitions that will occur over a defined period of time.
    • With Color: Transitions that will use a UIColor object to color the inherent transition.
    • With Direction: Transitions that will be made from a specified direction.
    • With CIFilter: Transitions that will use a custom filter to produce a visual effect in the transition.

    Duration and Color are simple objects, but both Direction and CIFilter are not.

    As the name suggestions, the direction property means that the transition will occur in a specific direction. The direction property can have one of four constants. These constants are declared as an NS_ENUM, like this:

    typedef NS_ENUM(NSInteger,
       SKTransitionDirection) {
       SKTransitionDirectionUp,
       SKTransitionDirectionDown,
       SKTransitionDirectionRight,
       SKTransitionDirectionLeft,
    };

    CIFilter is even more robust than Direction since it is also a reference class with class methods, instance methods, and properties. This tutorial will not cover the CIFilter class in-depth, but it will present an example of how to use it to create a custom filter and the inherent SKTransition. An additional note regarding the CIFilter class: it supports dozens of effects, but not all are supported by the latest version of iOS. You should consult the Core Image Filter Reference to see the compatibility list.

    Note that you can use several “grouped methods” in order to create an SKTransiton. But how do you know which ones can be combined? For this, you must look to the method signature and determine the properties accepted by each method.

    For instance, let’s analyze three methods to see what they can handle:

    • doorsOpenVerticalWithDuration:
    • fadeWithColor:duration:
    • revealWithDirection:duration:

    As previously stated, the methods names allow you to quickly understand what each method can do. To elaborate, the doorsOpenVerticalWithDuration: method will only take into consideration a duration The fadeWithColor:duration: method uses both a color and a duration. You must first define a UIColor object and then a duration time. The revealWithDirection:duration: method will only use a direction, which, in turn, can be one of four properties. Note that you can also extend the SKTransition class to create custom transitions and join Duration, Color, Direction, and CIFilter.

    Figure 2: revealWithDirection
    revealWithDirection (UP) illustration

    3. Class Properties

    The SKTransition class only has two properties: pausesIncomingScene and pausesOutgoingScene. Both configure whether animations play during the transition and both properties are Boolean values. The difference is as follows:

    • pausesIncomingScene determines whether the incoming scene is paused during the transition.
    • pausesOutgoingScene determines whether the outgoing scene is paused during the transition.

    Since both are Boolean values, the definition is easy and can be understood in the next snippet:

      // other code ...
      transitionCrossFade = [SKTransition crossFadeWithDuration:1];
      transitionCrossFade.pausesIncomingScene = TRUE;
      transitionDoorsCloseHorizontal = [SKTransition doorsCloseHorizontalWithDuration:2];
      transitionDoorsCloseHorizontal.pausesOutgoingScene = FALSE;

    The pausesIncomingScene and pausesOutgoingScene properties on the transition object define which animations are played during the transition. By default, both scenes continue to process animation during the transition. However, you might want to pause one or both of the scenes until the transition completes.


    4. The Tutorial Project

    Now that you know the basics of the SKTransition class, you can now start the programming phase.

    Step 1

    The first step is to open Xcode and start a new SpriteKit project. Next, you should add another Objective-C class named TransitionResult and a super-class of SKScene.

    The objective of this project is to have two classes that will be swapped between them. The first (MyScene already defined by the Xcode) will contain a UITableView that will hold the reference to each SKTransition. The second (TransitionResult) will be the destination scene after a transition.

    When the user taps the screen after a transition it will once again be transferred to MyScene.

    Step 2

    In MyScene.h, you will declare 3 objects: a UITableView, UISlider, and an NSArray. The UITableView will display the names of each transition, the UISlider will define the Duration of that transition, and the NSArray will contain the names of each SKTransition. The final MyScene.h code will be similar to this snippet:

    @property (retain, nonatomic) IBOutlet UITableView *tableView;
    @property (nonatomic, retain) IBOutlet UISlider *sliderTimer;
    @property (strong, nonatomic) NSArray *transitionsArray;

    Step 3

    Now, focus your attention in the MyScene implementation file.

    The first step is to use the -(id)initWithSize:(CGSize)size method to initialize the aforementioned objects. One possible configuration setup is the following:

      _tableView = [[UITableView alloc] initWithFrame:CGRectMake(CGRectGetMinX(self.frame), CGRectGetMinY(self.frame)+20, CGRectGetMaxX(self.frame), CGRectGetMaxY(self.frame)-80)];
      _tableView.dataSource = self;
      _tableView.delegate = self;
      _sliderTimer = [[UISlider alloc] initWithFrame:CGRectMake(CGRectGetMidX(self.frame)-70, CGRectGetMaxY(self.frame)-40, 140, 3)];
      [_sliderTimer addTarget:self action:@selector(sliderAction) forControlEvents:UIControlEventValueChanged];
      [_sliderTimer setBackgroundColor:[UIColor clearColor]];
      _sliderTimer.minimumValue = 1;
      _sliderTimer.maximumValue = 4;
      _sliderTimer.continuous = YES;
      _sliderTimer.value = 1;
      _transitionsArray = [[NSArray alloc] initWithObjects:
                                 @"crossFadeWithDuration",
                                 @"doorsCloseHorizontalWithDuration",
                                 @"doorsCloseVerticalWithDuration",
                                 @"doorsOpenHorizontalWithDuration",
                                 @"doorsOpenVerticalWithDuration",
                                 @"doorwayWithDuration",
                                 @"fadeWithColor:duration",
                                 @"fadeWithDuration",
                                 @"flipHorizontalWithDuration",
                                 @"flipVerticalWithDuration",
                                 @"moveInWithDirectionDown:duration",
                                 @"moveInWithDirectionUp:duration",
                                 @"moveInWithDirectionLeft:duration",
                                 @"moveInWithDirectionRight:duration",
                                 @"pushWithDirection:duration",
                                 @"revealWithDirection:duration",
                                 @"transitionWithCIFilter:duration",
                                 nil];

    However, a warning is presented since the sliderAction is missing. The method will update in real time the transitionTimerText taking into account the UISlider value.

    -(void)sliderAction{
        transitionTimerText.text = [[NSString alloc] initWithFormat:@"Transition Duration: %f", _sliderTimer.value];
    }

    Note that the views, location, configuration, and layout are completely configurable. If you want, you can tune this for your best interests. Additionally, you will add a SKLabelNode to store and display the UISlider value. That value will be representative of the SKTransition Duration effects. Add the SKLabelNode* transitionTimerText to your implementation file and the corresponding initialization will be:

      transitionTimerText = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
      transitionTimerText.text = [[NSString alloc] initWithFormat:@"Transition Duration: %f", _sliderTimer.value];
      transitionTimerText.fontSize = 10;
      transitionTimerText.color = [SKColor colorWithRed:0 green:0 blue:0 alpha:1];
      transitionTimerText.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMinY(self.frame)+45);

    Step 4

    Now that you have the objects configured you just need to add them to the scene. For that, you will use the -(void) didMoveToView:(SKView *)view method. Add it to your file and inside add the aforementioned views to the main view:

    -(void) didMoveToView:(SKView *)view{
        [self addChild:transitionTimerText];
        [self.scene.view addSubview:_sliderTimer];
        [self.scene.view addSubview:_tableView];
    }

    If you run the project now you will see two objects on the screen: a UISlider and a SKLabelNode.

    Step 5

    The next step is to display the SKTransition methods in the UITableView. For this, you need to modify your MyScene.h file and extend your class with the <UITableViewDataSource, UITableViewDelegate> protocols. The final MyScene.h should look like this:

      @interface MyScene : SKScene <UITableViewDataSource, UITableViewDelegate>

    Go back to the implementation file and you will be presented with a warning. That warning says that you need to implement additional methods inherent to the UITableView. The methods needed are: -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section and -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath. The first will return the number of rows in the table, while the second will handle the logic for each cell inside the table. For additional notes regarding the UITableView class, you should consult the official reference class.

    The first method is simple and is only a single line:

    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return [_transitionsArray count];
    }

    The second method is more complex since we must define the table cell properties and configurations (cell contents). In this example, you will use a simple UITableViewCellStyleSubtitle. If you have problems writing the method, the full version is presented bellow:

    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        NSString *transitions = [_transitionsArray objectAtIndex:indexPath.row];
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Identifier"];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"Identifier"];
        }
        [cell.textLabel setText:transitions];
        return cell;
    }

    Run your code now and you should see each cell line with a unique name. Each name represents the inherent SKTransiton used if the user taps that cell. You will also note that the UITableView does not have a title. Let’s fix that!

    Step 6

    Add the following method: - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section. Within this method, add the following code:

    NSString *sectionName;
        switch (section)
        {
            case 0:
                sectionName = NSLocalizedString(@"SKTransition List", @"SKTransition List");
                break;
            default:
                sectionName = @"";
                break;
        }
        return sectionName;

    This method is permitted to have multiple titles for multiple UITableView sections. However, we will only have one section, so the title will be “SKTransition List” (or any other of your choice).

    Step 7

    At this point, you need to add user interaction to the cells. To do this, another additional method is needed. This time the -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method should be called. This method is long, but it is simple to understand. You will allocate the necessary resources for each SKTransition and, based on the cell tapped, you will present another SKScene.

    The first step is to import the TransitionResult header file, then define a TransitionResult object for the resulting SKScene. Take a look at the following to see this in action:

      TransitionResult* transitionResult;
      SKTransition* transitionCrossFade;
      SKTransition* transitionDoorsCloseHorizontal;
      SKTransition* transitionDoorsCloseVertical;
      SKTransition* transitiondoorsOpenHorizontal;
      SKTransition* transitionDoorsOpenVertical;
      SKTransition* transitionDoorway;
      SKTransition* transitionFadeWithColor;
      SKTransition* transitionFadeWithDuration;
      SKTransition* transitionFlipHorizontal;
      SKTransition* transitionFlipVertical;
      SKTransition* transitionMoveInWithDirectionDown;
      SKTransition* transitionMoveInWithDirectionUp;
      SKTransition* transitionMoveInWithDirectionLeft;
      SKTransition* transitionMoveInWithDirectionRight;
      SKTransition* transitionPushWithDirection;
      SKTransition* transitionRevealWithDirectionUp;
      SKTransition* transitionWithCIFilter;

    Now, in the -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method, it is time to allocate the necessary resources. The complete code is:

    transitionCrossFade = [SKTransition crossFadeWithDuration:_sliderTimer.value];
        transitionCrossFade.pausesIncomingScene = TRUE;
        transitionDoorsCloseHorizontal = [SKTransition doorsCloseHorizontalWithDuration:_sliderTimer.value];
        transitionDoorsCloseHorizontal.pausesOutgoingScene = FALSE;
        transitionDoorsCloseVertical = [SKTransition doorsCloseVerticalWithDuration:_sliderTimer.value];
        transitiondoorsOpenHorizontal = [SKTransition doorsOpenHorizontalWithDuration:_sliderTimer.value];
        transitionDoorsOpenVertical = [SKTransition doorsOpenVerticalWithDuration:_sliderTimer.value];
        transitionDoorway = [SKTransition doorwayWithDuration:_sliderTimer.value];
        transitionFadeWithColor = [SKTransition fadeWithColor:[UIColor yellowColor] duration:_sliderTimer.value];
        transitionFadeWithDuration = [SKTransition fadeWithDuration:_sliderTimer.value];
        transitionFlipHorizontal = [SKTransition flipHorizontalWithDuration:_sliderTimer.value];
        transitionFlipVertical = [SKTransition flipVerticalWithDuration:_sliderTimer.value];
        transitionMoveInWithDirectionDown = [SKTransition moveInWithDirection:SKTransitionDirectionDown duration:_sliderTimer.value];
        transitionMoveInWithDirectionUp = [SKTransition moveInWithDirection:SKTransitionDirectionUp duration:_sliderTimer.value];
        transitionMoveInWithDirectionLeft = [SKTransition moveInWithDirection:SKTransitionDirectionLeft duration:_sliderTimer.value];
        transitionMoveInWithDirectionRight = [SKTransition moveInWithDirection:SKTransitionDirectionRight duration:_sliderTimer.value];
        transitionPushWithDirection = [SKTransition pushWithDirection:SKTransitionDirectionDown duration:_sliderTimer.value];
        transitionRevealWithDirectionUp = [SKTransition revealWithDirection:SKTransitionDirectionUp duration:_sliderTimer.value];
        CGRect screenRect = [[UIScreen mainScreen] bounds];
        CIVector  *extent = [CIVector vectorWithX:0  Y:0  Z:screenRect.size.width  W:screenRect.size.height];
        transitionWithCIFilter = [SKTransition transitionWithCIFilter:[CIFilter filterWithName: @"CIFlashTransition"
                                                                                 keysAndValues: @"inputExtent", extent,
                                                                       @"inputCenter",[CIVector vectorWithX:0.3*screenRect.size.width Y:0.7*screenRect.size.height],
                                                                       @"inputColor", [CIColor colorWithRed:1.0 green:0.8 blue:0.6 alpha:1],
                                                                       @"inputMaxStriationRadius", @2.5,
                                                                       @"inputStriationStrength", @0.5,
                                                                       @"inputStriationContrast", @1.37,
                                                                       @"inputFadeThreshold", @0.85, nil] duration:_sliderTimer.value];
        transitionResult = [[TransitionResult alloc] initWithSize:CGSizeMake(CGRectGetMaxX(self.frame), CGRectGetMaxY(self.frame))];
        switch (indexPath.row) {
            case 0:
                [self.scene.view presentScene:transitionResult transition:transitionCrossFade];
                [self removeUIKitViews];
                break;
            case 1:
                [self.scene.view presentScene:transitionResult transition:transitionDoorsCloseHorizontal];
                [self removeUIKitViews];
                break;
            case 2:
                [self.scene.view presentScene:transitionResult transition:transitionDoorsCloseVertical];
                [self removeUIKitViews];
                break;
            case 3:
                [self.scene.view presentScene:transitionResult transition:transitiondoorsOpenHorizontal];
                [self removeUIKitViews];
                break;
            case 4:
                [self.scene.view presentScene:transitionResult transition:transitionDoorsOpenVertical];
                [self removeUIKitViews];
                break;
            case 5:
                [self.scene.view presentScene:transitionResult transition:transitionDoorway];
                [self removeUIKitViews];
                break;
            case 6:
                [self.scene.view presentScene:transitionResult transition:transitionFadeWithColor];
                [self removeUIKitViews];
                break;
            case 7:
                [self.scene.view presentScene:transitionResult transition:transitionFadeWithDuration];
                [self removeUIKitViews];
                break;
            case 8:
                [self.scene.view presentScene:transitionResult transition:transitionFlipHorizontal];
                [self removeUIKitViews];
                break;
            case 9:
                [self.scene.view presentScene:transitionResult transition:transitionFlipVertical];
                [self removeUIKitViews];
                break;
            case 10:
                [self.scene.view presentScene:transitionResult transition:transitionMoveInWithDirectionDown];
                [self removeUIKitViews];
                break;
            case 11:
                [self.scene.view presentScene:transitionResult transition:transitionMoveInWithDirectionUp];
                [self removeUIKitViews];
                break;
            case 12:
                [self.scene.view presentScene:transitionResult transition:transitionMoveInWithDirectionLeft];
                [self removeUIKitViews];
                break;
            case 13:
                [self.scene.view presentScene:transitionResult transition:transitionMoveInWithDirectionRight];
                [self removeUIKitViews];
                break;
            case 14:
                [self.scene.view presentScene:transitionResult transition:transitionPushWithDirection];
                [self removeUIKitViews];
                break;
            case 15:
                [self.scene.view presentScene:transitionResult transition:transitionRevealWithDirectionUp];
                [self removeUIKitViews];
                break;
            case 16:
                [self.scene.view presentScene:transitionResult transition:transitionWithCIFilter];
                [self removeUIKitViews];
                break;
            default:
                break;
        }

    You will receive a warning that says that a method (removeUIKitViews) is missing. That method is a simple call to remove some views from the parent and super view. While simplistic, the necessary code is:

    -(void) removeUIKitViews
    {
        [transitionTimerText removeFromParent];
        [_tableView removeFromSuperview];
        [_sliderTimer removeFromSuperview];
    }

    Now for several notes regarding the -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method.

    • The SKTransition transition initialization is similar to all transitions.
    • The filter defined is a customized one. As stated above, you can re-configure it or define a totally new filter.
    • The Duration time is defined by the UISlider value.

    Step 8

    In order to run the code and test the transitions, you will need to populate the TransitionResult class. Move that class and add the -(id)initWithSize:(CGSize)size method. It is similar to the MyScene.m method. You can try to write it yourself. Copy-and-paste from the other class to make it look like the next method:

    -(id)initWithSize:(CGSize)size {
        if (self = [super initWithSize:size]) {
            self.backgroundColor = [SKColor colorWithRed:0.35 green:0.45 blue:0.23 alpha:1.0];
            SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
            myLabel.text = @"Tap go back";
            myLabel.fontSize = 15;
            myLabel.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
            [self addChild:myLabel];
        }
        return self;
    }

    You can now run the code and test the transitions. Go ahead and try them!

    Step 9

    As you may have already noticed, every time you want to test a new transition you need to run the code again. So, let’s modify the TransitionResult.m file that enables an infinite navigation. Every time the user taps the screen it will be moved to the initial scene.

    You will need the -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event method and you will need to import the MyScene.h class. So, the final step is to allocate and initiate a class object and swap the scenes. The next snippet will help you do just that:

    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
            MyScene* home = [[MyScene alloc] initWithSize:CGSizeMake(CGRectGetMaxX(self.frame), CGRectGetMaxY(self.frame))];
            [self.scene.view presentScene:home];
    }

    Finally, run your program and test all the SKTransitions. The next image represents one of the transitions:

    Figure 3: SKTRansition
    Another SKTRansition effect illustration

    Conclusion

    Over the course of this SKTransition tutorial, we have covered the following:

    • A complete overview of the SKTransition class.
    • How to create and configure all of the SKTransition options.
    • Working with SKTransition properties.
    • How to create and configure a UITableView and UISlider and use them in parallel with Sprite Kit.

    If you have any questions or comments, please feel free to leave them below!

    iOS 7 SDK: Working with Background Fetch

    $
    0
    0

    This tutorial will teach you how to use Background Fetch, a multitasking API provided with the iOS 7 SDK. To do so, we’ll create a simple list of delicious dishes that are automatically fetched in the background. Read on!


    Project Overview

    Background Fetch is an awesome feature released with iOS 7. Today, we live in a social world, and most of our users have several social network apps on their mobile devices. However, every time the user opens each app, they typically must wait until the app updates to view more recent content. This can be painful if several apps and profiles are used. Now, with background fetch, all content can be automatically fetched and updated before the user loads the app.

    The default Traffic application is a simple example of how Background Fetch works in action. If you check it every morning, let’s say at 8:20 AM, your iOS app must get that information at that time. Now, if the operating system knows you will access the app around 8:20 AM, it can fetch the data beforehand and have it ready when desired.

    For a more comprehensive overview of the new multitasking features, be sure to read our introduction to this topic. The rest of this tutorial will be dedicated to a practical project that demonstrates how to implement Background Fetch.

    1. Project Setup

    The first step is to create an iOS 7 project and choose single view app. Next let’s add some properties which will be useful along the tutorial:

    @property (nonatomic) NSMutableArray *objects;
    @property (nonatomic) NSArray *possibleTableData;
    @property (nonatomic) int numberOfnewPosts;
    @property (nonatomic) UIRefreshControl *refreshControl;

    The NSMutablearray objects will be used to save the objects listed within the TableView. Note that, in this tutorial, you will not call any service to obtain data. Instead, you will use the possibleTableData array and randomly choose several objects from it. However, the app can easily be improved to fetch data from a server if you’d like.

    The integer numberOfnewPosts represent the new posts that are available every time you will pull a request or receive a background fetch. The refrestControl is a control that is used when updating tasks. Since it is out of the tutorial context we will not cover it. However, you should look at this Mobiletuts+ tutorial if you’d like to learn more.

    In the Main.storyboard, change the ViewController to a UITableViewController. Next, click on the UITableViewController and go to Editor > Embed in > Navigation Controller. Don’t forget to set the Custom Class to ViewController.

    Now, move to ViewController.m. the first step is to load some data. The following code will alloc and create the data object, create a title, and initialize the refreshControl:

        self.possibleTableData = [NSArray arrayWithObjects:@"Spicy garlic Lime Chicken",@"Apple Crisp II",@"Eggplant Parmesan II",@"Pumpkin Ginger Cupcakes",@"Easy Lasagna", @"Puttanesca", @"Alfredo Sauce", nil];
        self.navigationItem.title = @"Delicious Dishes";
        self.refreshControl = [[UIRefreshControl alloc] init];
        [self.refreshControl addTarget:self action:@selector(insertNewObject:) forControlEvents:UIControlEventValueChanged];
        [self.tableView addSubview:self.refreshControl];

    The above code will generate a warning because the insertNewObject method is missing. Let’s resolve that!

    The method will generate a random number and will get that exact same number of objects from the data array. Then, it will update the tableview with new values.

    - (void)insertNewObject:(id)sender
    {
        self.numberOfnewPosts = [self getRandomNumberBetween:0 to:4];
        NSLog(@"%d new fetched objects",self.numberOfnewPosts);
        for(int i = 0; i < self.numberOfnewPosts; i++){
            int addPost = [self getRandomNumberBetween:0 to:(int)([self.possibleTableData count]-1)];
            [self insertObject:[self.possibleTableData objectAtIndex:addPost]];
        }
        [self.refreshControl endRefreshing];
    }

    The getRandomNumberBetween warning will be suppressed when you add the following method:

    -(int)getRandomNumberBetween:(int)from to:(int)to {
        return (int)from + arc4random() % (to-from+1);
    }

    To load the objects on the NSArray object, we need to implement the delegate methods of the TableView.

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        return 1;
    }
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return self.objects.count;
    }
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
        cell.textLabel.text = self.objects[indexPath.row];
        if(indexPath.row < self.numberOfnewPosts){
            cell.backgroundColor = [UIColor yellowColor];
        }
        else
            cell.backgroundColor = [UIColor whiteColor];
        return cell;
    }

    Pretty simple, right? If you Run the project you will have an interface similar to the following image:

    Figure 1: After Setup - TableView!

    2. Background Fetch

    Now, you want to create the Background Fetch feature. To make the background fetch available, you need to go to Project > Capabilities > Put Background Modes ON and then select Background Fetch, as presented in the next figure:

    Figure 2: Background Fetch ON!

    However, doing this alone is not enough. By default, the app will never call the background API, so you need to add the following line to the -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method within the AppDelegate.m file:

    [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

    This will allow the system to decide when it should get new content.

    Now that your app already knows to initiate background fetch, let’s tell it what to do. The method -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler will assist in doing so. This method is called every time that a background fetch is performed, and should be included in the AppDelegate.m file. The complete version is provided below:

    -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
        UINavigationController *navigationController = (UINavigationController*)self.window.rootViewController;
        id topViewController = navigationController.topViewController;
        if ([topViewController isKindOfClass:[ViewController class]]) {
            [(ViewController*)topViewController insertNewObjectForFetchWithCompletionHandler:completionHandler];
        } else {
            NSLog(@"Not the right class %@.", [topViewController class]);
            completionHandler(UIBackgroundFetchResultFailed);
        }
    }

    Next you should also import the ViewController header file into the AppDelegate.m class.

    #import "ViewController.h"

    Note that, the insertNewObjectForFetchWithCompletionHandler was not yet created. So, move to the ViewController.h and declare it.

    - (void)insertNewObjectForFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;

    Now focus your attention on the implementation file. The implementation is very similar to the insertNewObject call added before. However, we use the completionHandler to talk to the system and tell us if the app fetched new data, or if no data was available.

    - (void)insertNewObjectForFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
        NSLog(@"Update the tableview.");
        self.numberOfnewPosts = [self getRandomNumberBetween:0 to:4];
        NSLog(@"%d new fetched objects",self.numberOfnewPosts);
        for(int i = 0; i < self.numberOfnewPosts; i++){
            int addPost = [self getRandomNumberBetween:0 to:(int)([self.possibleTableData count]-1)];
            [self insertObject:[self.possibleTableData objectAtIndex:addPost]];
        }
        /*
         At the end of the fetch, invoke the completion handler.
         */
        completionHandler(UIBackgroundFetchResultNewData);
    }

    At this point, the code should be completed. Now, let’s simulate a test and verify that everything is up and running!


    3. Simulated Background Fetch

    So, if you want to make sure if everything is configured, you need to edit your Schemes. Go to the Schemes list and click on the Manage Schemes option, as presented in the following figure:

    Figure 3: Manage Schemes!

    Under the Schemes management section you can duplicate the scheme of your application:

    Figure 4: Duplicate Scheme!

    After duplicating the scheme a new window will be presented. You can change its name from the Options Tab. Check the Launch due to a background fetch event box. Now, just click Ok in all windows.

    Figure 5: Background Fetch Scheme Enabled!

    Next, run the app using the duplicated scheme.
    Note that the app will not open in the foreground, but it should have already fetched some content. If you open the app and several recipes are already available, that means that you succeeded! To force a background fetch, you can also use Debug > Simulate Background Fetch. from the Xcode menu.


    Conclusion

    At the end of this tutorial, you should understand the background fetch mechanism and how to implement it in your own apps.

    If you have any questions, please leave them in the comments section below!

    CoronaSDK: Create an Entertaining Bouncing Game

    $
    0
    0

    In this tutorial, I’ll show you how to create a bouncing game with the Corona SDK. You’ll learn more about the Drawing API, touch controls, and random numbers. The objective of this game is to use a paddle to prevent balls from touching the floor. To learn more, read on!

    1. Application Overview

    App Overview

    We’ll use pre-made graphics to code an exciting game using Lua and Corona SDK API’s.

    Upon completion, the player will use the touch screen on the device to control a paddle. The parameters in the code can be modified to customize the game.


    2. Target Device

    Target Device

    The first thing we have to do is select the platform we want to run our app in. This way we’ll be able to choose the size for the images we will use.

    The iOS platform has the following characteristics:

    • iPad 1/2/Mini: 1024x768px, 132 ppi
    • iPad Retina: 2048×1536, 264 ppi
    • iPhone/iPod Touch: 320x480px, 163 ppi
    • iPhone/iPod Retina: 960x640px, 326 ppi
    • iPhone 5/iPod Touch: 1136×640, 326 ppi

    Because Android is an open platform, there are many different devices and resolutions. Some of the common screen characteristics are:

    • Asus Nexus 7 Tablet: 800x1280px, 216 ppi
    • Motorola Droid X: 854x480px, 228 ppi
    • Samsung Galaxy SIII: 720x1280px, 306 ppi

    In this tutorial we’ll focus on the iOS platform with the graphic design, specifically to develop for distribution to an iPhone/iPod touch, but the code presented here applies to Android development with the Corona SDK as well.


    3. Interface

    Interface

    A simple and friendly interface will be used. This involves multiple shapes, buttons, bitmaps, and more.

    The interface graphic resources necessary for this tutorial can be found in the attached download.


    4. Export Graphics

    Export Graphics

    Depending on the device you have selected, you may need to export the graphics in the recommended PPI. You can do that in with your favorite image editor.

    I used the Adjust Size… function in the Preview app on Mac OS X.

    Remember to give the images a descriptive name and save them in your project folder.


    5. App Configuration

    We’ll use an external file to make the application become full-screen across devices (the config.lua file). This file shows the original screen size and the method used to scale that content in case the app runs in a different screen resolution.

    application=
    {
     content=
    {
     width=320,
     height=480,
     scale="letterbox"
    },
    }

    2. Main.lua

    Let’s write the application!

    Open your preferred Lua editor (any Text Editor will work, but you won’t have syntax highlighting) and prepare to write your awesome app. Remember to save the file as main.lua in your project folder.


    7. Code Structure

    We’ll structure our code as if it were a Class. If you know ActionScript or Java, you’ll find the structure familiar.

    Necessary Classes
    Variables and Constants
    Declare Functions
        contructor (Main function)
        class methods (other functions)
    call Main function

    8. Hide Status Bar

    display.setStatusBar(display.HiddenStatusBar)

    The above code hides the status bar. The status bar is the bar on top of the device screen that shows the time, signal, and other indicators.


    9. Background

    Background

    A simple vector is used as the background for the application interface. The next line of code creates it.

    -- Graphics
    -- [Background]
    local bg = display.newRect(0, 0, display.contentWidth, display.contentHeight)
    bg:setFillColor(52, 46, 45)

    10. Title View

    Title View

    This is the Title View, it will be the first interactive screen to appear in our game. These variables store its components:

    -- [Title View]
    local title
    local playBtn
    local creditsBtn
    local titleView

    11. Credits View

    Credits View

    This view will show the credits and copyright of the game. This variable will be used to store it:

    -- [CreditsView]
    local creditsView

    12. Instruction Message

    Instructions

    An instruction message will appear at the start of the game and will be tweened out after 2 seconds. You can change the time later in the code.

    -- Instructions
    local ins

    13. Color Circles

    Buttons

    Here are the circles or balls. The objective of the game is to prevent them from touching the bottom of the screen.

    -- Color Circles
    local circles = display.newGroup()

    14. Alert

    Alert

    This is the alert that will be displayed when a ball touches the floor. It will display the score and end the game.

    -- Alert
    local alertView

    15. Sounds

    Sounds

    We’ll use Sound Effects to enhance the feeling of the game. The sounds used in this game were created in as3sfxr.

    -- Sounds
    local bounceSnd = audio.loadSound('bounce.wav')
    local loseSnd = audio.loadSound('lose.wav')

    16. Variables

    These are the variables we’ll use. You can read the comments in the code to learn more about them.

    -- Variables
    local circleTimer -- Adds a new circle every time is called
    local colors = {{71, 241, 255},{255, 204, 0},{245, 94, 91},{0, 255, 204},{250, 140, 254},} -- Possible colors for the circles (R, G, B)

    17. Declare Functions

    Next, declare all functions as local at the start.

    -- Functions
    local Main = {}
    local startButtonListeners = {}
    local showCredits = {}
    local hideCredits = {}
    local showGameView = {}
    local gameListeners = {}
    local moveBar = {}
    local addCircle ={}
    local onCollision = {}
    local alert = {}

    18. Constructor

    During this step we’ll create the function that initializes the game logic:

    function Main()
    	-- code...
    end

    19. Add Title View

    Now we’ll place the TitleView in the stage and call a function that adds the tap listeners to the buttons.

    function Main()
    	title = display.newImage('title.png')
    	playBtn = display.newImage('playBtn.png', 130, 248)
    	creditsBtn = display.newImage('creditsBtn.png', 125, 316)
    	titleView = display.newGroup(title, playBtn, creditsBtn)
    	startButtonListeners('add')
    end

    20. Start Button Listeners

    This function adds the necessary listeners to the TitleView buttons:

    function startButtonListeners(action)
    	if(action == 'add') then
    		playBtn:addEventListener('tap', showGameView)
    		creditsBtn:addEventListener('tap', showCredits)
    	else
    		playBtn:removeEventListener('tap', showGameView)
    		creditsBtn:removeEventListener('tap', showCredits)
    	end
    end

    21. Show Credits

    The credits screen is shown when the user taps the about button, a tap listener is added to the credits view to remove it.

    function showCredits:tap(e)
    	playBtn.isVisible = false
    	creditsBtn.isVisible = false
    	creditsView = display.newImage('credits.png', 0, display.contentHeight)
    	transition.to(creditsView, {time = 300, y = display.contentHeight - (creditsView.height - 40), onComplete = function() creditsView:addEventListener('tap', hideCredits) end})
    end

    22. Hide Credits

    When the credits screen is tapped, it’ll be tweened out of the stage and removed.

    function hideCredits:tap(e)
    	transition.to(creditsView, {time = 300, y = display.contentHeight + 40, onComplete = function() creditsBtn.isVisible = true playBtn.isVisible = true creditsView:removeEventListener('tap', hideCredits) display.remove(creditsView) creditsView = nil end})
    end

    23. Show Game View

    When the Play button is tapped, the TitleView is tweened and removed, revealing the GameView. There are many parts involved with this view, so we’ll split them into the next few steps.

    function showGameView:tap(e)
    	transition.to(titleView, {time = 300, x = -titleView.height, onComplete = function() startButtonListeners('rmv') display.remove(titleView) titleView = nil end})

    24. Instructions Message

    The following lines add the instructions message:

    ocal ins = display.newImage('ins.png', 160, 355)
    	transition.from(ins, {time = 200, alpha = 0.1, onComplete = function() timer.performWithDelay(2000, function() transition.to(ins, {time = 200, alpha = 0.1, onComplete = function() display.remove(ins) ins = nil end}) end) end})

    25. Add Paddle

    This step creates the paddle and places it on the stage. A name can be added later for easier access.

    -- Add Bar
    	bar = display.newRoundedRect(70, 340, 160, 10, 3)
    	bar.name = 'bar'

    26. Walls

    Now we’ll create walls around the screen to prevent the balls from leaving the stage.

    -- Walls
    left = display.newLine(0, 240, 0, 720)
    left.isVisible = false
    right = display.newLine(320, 240, 320, 720)
    right.isVisible = false
    bottom = display.newLine(160, 480, 480, 480)
    bottom.isVisible = false

    27. Score

    Here’s a score TextField to create at the top-right of the stage:

    -- Score
    	score = display.newText('0', 300, 0, 'Futura', 15)

    28. Physics

    Next we need to add physics to our objects. Here we’ll use the Filter property that prevents certain objects from colliding with each other. This prevents our circles from colliding while keeping collisions between the walls and paddle. You can find a simple explanation of its behavior at the Corona Site.

    	-- Physics
    	physics.addBody(bar, 'static', {filter = {categoryBits = 4, maskBits = 7}})
    	physics.addBody(left, 'static', {filter = {categoryBits = 4, maskBits = 7}})
    	physics.addBody(right, 'static', {filter = {categoryBits = 4, maskBits = 7}})
    	physics.addBody(bottom, 'static', {filter = {categoryBits = 4, maskBits = 7}})
    	gameListeners('add')
    end

    29. Game Listeners

    The following function adds the necessary listeners to start the game logic:

    function gameListeners(action)
    	if(action == 'add') then
    		bg:addEventListener('touch', moveBar)
    		circleTimer = timer.performWithDelay(2000, addCircle, 5)
    		bar:addEventListener('collision', onCollision)
    		bottom:addEventListener('collision', alert)
    	else
    		bg:removeEventListener('touch', moveBar)
    		timer.cancel(circleTimer)
    		circleTimer = nil
    		bar:removeEventListener('collision', onCollision)
    		bottom:removeEventListener('collision', alert)
    	end
    end

    30. Move the Paddle

    Touching the background calls the next function that handles the paddle’s movement. It follows the finger and stays on top of it.

    function moveBar(e)
    	if(e.phase == 'moved') then
    		bar.x = e.x
    		bar.y = e.y - 40
    	end
    	-- Keep bar 1/3 from the top
    	if(bar.y < 160) then
    		bar.y = 160
    	end
    end

    31. Add a Circle

    The circleTimer calls this code. It creates a circle or ball at the top of the screen (which is then moved down by gravity) and gives it a random size and color picked from our colors Table. The color values are then stored to to change the paddle as well. A little push is added in a random direction calculated by the dir and r variables.

    function addCircle()
    	local r = math.floor(math.random() * 12) + 13
    	local c = display.newCircle(0, 0, r)
    	c.x = math.floor(math.random() * (display.contentWidth - (r * 2)))
    	c.y =  - (r * 2)
    	-- Circle color
    	local color = math.floor(math.random() * 4) + 1
    	c.c1 = colors[color][1]
    	c.c2 = colors[color][2]
    	c.c3 = colors[color][3]
    	c:setFillColor(c.c1, c.c2, c.c3)
    	physics.addBody(c, 'dynamic', {radius = r, bounce = 0.95, filter = {categoryBits = 2, maskBits = 4}})
    	circles:insert(c)
    	--Move Horizontally
    	local dir
    	if(r < 18) then dir = -1 else dir = 1 end
    	c:setLinearVelocity((r*2) * dir, 0 )
    end

    32. Collisions

    This function runs when the paddle collides with a ball. It plays a sound, increases the score, and changes the paddle color.

    function onCollision(e)
    	audio.play(bounceSnd)
    	bar:setFillColor(e.other.c1, e.other.c2, e.other.c3)
    	score.text = tostring(tonumber(score.text) + 50)
    	score:setTextColor(e.other.c1, e.other.c2, e.other.c3)
    	score.x = 300
    end

    33. Alert

    The alert function creates an alert view, animates it, and ends the game.

    function alert()
    	audio.play(loseSnd)
    	gameListeners('rmv')
    	alertView = display.newImage('alert.png', 90, 200)
    	transition.from(alertView, {time = 200, alpha = 0.1})
    	local scoreTF = display.newText(score.text, 145, 253, 'Futura', 17)
    	scoreTF:setTextColor(255, 255, 255)
    	-- Wait 100 ms to stop physics
    	timer.performWithDelay(100, function() physics.stop() end, 1)
    end

    34. Call Main Function

    In order to start the game, the Main function needs to be called. With the above code in place, we’ll do that here:

    Main()

    35. Loading Screen

    Loading Screen

    The Default.png file is an image that’s displayed when the application starts while iOS loads the basic data to show in the Main Screen. Add this image to your project source folder, then it will be automatically added by the Corona compliler.


    36. Icon

    Icon

    Using the graphics you created before, you can now create a good looking icon. The icon size for the non-retina iPhone icon is 57x57px, but the retina version is 114x114px. Keep in mind that the iTunes store requires a 512x512px version. I suggest creating the 512×512 version first and then scaling down for the other sizes.

    It doesn’t need to have the rounded corners or the transparent glare, iTunes and the iPhone does that for you.


    37. Testing in Simulator

    Testing

    It’s time for the final test. Open the Corona Simulator, browse to your project folder, and then click Open. If everything works as expected, you are ready for the last step!


    38. Build

    Build

    In the Corona Simulator go to File > Build and select your target device. Fill the required data and click Build. Wait a few seconds and your app is ready for device testing and/or submission for distribution!


    Conclusion

    In this tutorial, we’ve learned about drawing API, timers, random numbers, and other skills that can be incredibly useful in a wide number of games.

    Experiment with the final result and try to make your own custom version of the game!

    I hope you enjoyed this tutorial series and found it helpful. Thank you for reading!

    iOS 7 SDK: Background Transfer Service

    $
    0
    0

    This tutorial will show you how to use the background transfer service, a Multitasking API provided by iOS 7. I’ll teach you how to create an app that will download a file without the application in the foreground. Once the file fully downloads, a notification message will pop-up. Continue reading to create this service!


    Introduction

    Background transfer service originated with iOS 6. This feature allowed apps to transfer files in both foreground and background modes, but limited the minutes. The biggest problem was when the “limited minutes” did not allow the user to download or upload large files. This is why Apple improved the framework in iOS 7.

    With iOS 7, this feature underwent major changes, including:

    • iOS manages downloads and uploads
    • The transfer continues even when the user closes the application
    • Time is unlimited
    • It can be put in the queue anytime (foreground and background)
    • The app wakes up to handle authentication, errors, or completion
    • The app includes a Progress View

    Background Transfer Service can be used for several distinct and useful tasks such as: uploading photos or videos, combining background fetch and remote notifications, and for keeping the app up to date, like with purchases for books, TV shows, podcasts, game content, maps, and more.


    1. Setup the Project

    To create this service, we need a single view with the following properties:

    • A ViewController
    • A NavigationController
    • A Bar Item (to start the Download)
    • An UIDocumentInterationController (to open the PDF document download)

    First, start a new Xcode iPhone project. Then create a Single View Application. Next, go to the Main.Storyboard and add some objects to our View. To add the NavigationController select the Default View Controller. In the Xcode menu, select Editor > Embed In > Navigation Controller. You need to drag-and-drop the Bar Item and the Progress View to your View Controller. Once you’re finished the View Controller should look similar to the following image:

    Figure 1: After Setup - Background Transfer!
    Illustration of App – After Setup – Background Transfer

    Now, let’s add the properties necessary to interact with the objects we added. In ViewController.h, add the following lines:

    @property (weak, nonatomic) IBOutlet UIProgressView *progressView;
    - (IBAction)start:(id)sender;

    Now change the view for the ViewController.m. A warning will appear, but don’t worry about it; we’ll fix it later. Go back to the Main.Storyboard and connect the objects with the properties and actions.

    This step is trivial, but if you have any concerns feel free to use the comment section below.


    2. NSURLSession

    The NSURLSession class and related classes provide an API to download or upload content via HTTP. This API is responsible for managing a set of transfer tasks. You will need to create three objects that directly relate with that class: one NSURLSession, NSURLSessionDownloadTask, and UIDocumentInteractionController.

    Your ViewController.h will be something like this:

    @property (nonatomic) NSURLSession *session;
    @property (nonatomic) NSURLSessionDownloadTask *downloadTask;
    @property (strong, nonatomic) UIDocumentInteractionController *documentInteractionController;

    Additionally, you will also declare four protocols: NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDownloadDelegate, and UIDocumentInteractionControllerDelegate. Your @interface should look like:

    @interface ViewController : UIViewController < NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDownloadDelegate,UIDocumentInteractionControllerDelegate>

    The properties we’ll add are useful to instantiate and manipulate our session and the download process, which will allow you to resume, suspend, cancel, or retrieve the state. The last property, UIDocumentInterationController is used to present the PDF document downloaded in this tutorial.

    Now move to ViewController.m.

    The first task to complete is to add a string to the location of the file to download. You should use a standard Apple PDF.

    static NSString *DownloadURLString = @"https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/ObjC_classic/FoundationObjC.pdf";

    On the viewDidLoad method, let’s instantiate and set both the session and the progress views:

        self.session = [self backgroundSession];
        self.progressView.progress = 0;
        self.progressView.hidden = YES;

    Since you call the backgroundSession method, and it does not exist, you must declare it now. This method is responsible for dispatching one action that will be the background session. The backgroundSession through the dispatch_once executes a block once for the entire lifetime of the application. The NSString received by the NSURLSessionConfiguration represents the ID of our session. This ID needs to be unique for each NSURLSession instance.

    The complete method is as follows:

    - (NSURLSession *)backgroundSession {
      static NSURLSession *session = nil;
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.example.apple-samplecode.SimpleBackgroundTransfer.BackgroundSession"];
        session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
      });
      return session;
    }

    The (IBAction)start:(id)sender method starts the document download. You will then initiate an NSURL and a NSURLRequest and use the downloadTask property to pass the request object to the downloadTaskWithRequest method. The complete method is below.

    - (IBAction)start:(id)sender {
      if (self.downloadTask) {
            return;
        }
      NSURL *downloadURL = [NSURL URLWithString:DownloadURLString];
      NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];
      self.downloadTask = [self.session downloadTaskWithRequest:request];
        [self.downloadTask resume];
        self.progressView.hidden = NO;
    }

    3. Protocols

    At this point, you’ll notice that three warnings are present. They state that the protocol method should be implemented. The NSURLSessionDownloadDelegate protocol defines the methods to handle the download task. To perform the download, it’s required to use the three delegate methods.

    So, add the following three methods:

    • 1. (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
    • 2. (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)downloadURL {
    • 3. (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes

    The (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite method is responsible to track the overall download process. It also updates the progressView accordingly. The complete method is below.

    - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
        if (downloadTask == self.downloadTask) {
            double progress = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
            NSLog(@"DownloadTask: %@ progress: %lf", downloadTask, progress);
            dispatch_async(dispatch_get_main_queue(), ^{
                self.progressView.progress = progress;
            });
        }
    }

    4. Download Task

    The (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)downloadURL method deals with the data itself (origin and destination). It controls the file only once it’s completely downloaded. To put it simply, it tells the delegate that a download task has finished downloading. It contains the session task that’s finished, the download task that’s finished, and a file URL where the temporary file can be found. It should look like this:

    - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)downloadURL {
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSArray *URLs = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
        NSURL *documentsDirectory = [URLs objectAtIndex:0];
        NSURL *originalURL = [[downloadTask originalRequest] URL];
        NSURL *destinationURL = [documentsDirectory URLByAppendingPathComponent:[originalURL lastPathComponent]];
        NSError *errorCopy;
        // For the purposes of testing, remove any esisting file at the destination.
        [fileManager removeItemAtURL:destinationURL error:NULL];
        BOOL success = [fileManager copyItemAtURL:downloadURL toURL:destinationURL error:&errorCopy];
        if (success) {
            dispatch_async(dispatch_get_main_queue(), ^{
                //download finished - open the pdf
                self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:destinationURL];
                // Configure Document Interaction Controller
                [self.documentInteractionController setDelegate:self];
                // Preview PDF
                [self.documentInteractionController presentPreviewAnimated:YES];
                self.progressView.hidden = YES;
            });
        } else {
            NSLog(@"Error during the copy: %@", [errorCopy localizedDescription]);
        }
    }

    Finally, the (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes must also be declared. But be aware that we wont use it any further.

    -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {
    }

    5. Session Tasks

    You’re almost done with this class, only two methods remain: (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error, and - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session.

    The first method informs the delegate that the task has finished transferring data. You should also use it to track any error that occurs.

    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
        if (error == nil) {
            NSLog(@"Task: %@ completed successfully", task);
        } else {
            NSLog(@"Task: %@ completed with error: %@", task, [error localizedDescription]);
        }
        double progress = (double)task.countOfBytesReceived / (double)task.countOfBytesExpectedToReceive;
      dispatch_async(dispatch_get_main_queue(), ^{
        self.progressView.progress = progress;
      });
        self.downloadTask = nil;
    }

    Finally, you need to add the (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session method. It tells the delegate that all messages enqueued for a session have been delivered. It instantiates your AppDelegate in order to launch a UILocalNotification. The method you need to use is:

    - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
        AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
        if (appDelegate.backgroundSessionCompletionHandler) {
            void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
            appDelegate.backgroundSessionCompletionHandler = nil;
            completionHandler();
        }
        NSLog(@"All tasks are finished");
    }

    Several errors will appear because you haven’t imported the AppDelegate.h into your class yet.

    #import "AppDelegate.h"

    Move to the AppDelegate.h and add the two following objects:

    @property (strong, nonatomic) UIWindow *window;
    @property (copy) void (^backgroundSessionCompletionHandler)();

    In the AppDelegate.m you should implement the delegate method (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler. It tells the delegate that events related to a URL session are waiting to be processed and calls a custom method (presentNotification) to notify the user when the file completely downloads. The complete method is:

    - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier
      completionHandler:(void (^)())completionHandler {
      self.backgroundSessionCompletionHandler = completionHandler;
        //add notification
        [self presentNotification];
    }

    6. Local Notification

    The presentNotification method uses the UILocalNotification class to create a local notification. It creates a sound and uses the badge system for that notification. Here’s the complete method:

    -(void)presentNotification{
        UILocalNotification* localNotification = [[UILocalNotification alloc] init];
        localNotification.alertBody = @"Download Complete!";
        localNotification.alertAction = @"Background Transfer Download!";
        //On sound
        localNotification.soundName = UILocalNotificationDefaultSoundName;
        //increase the badge number of application plus 1
        localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
        [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
    }

    By the way, to restart the counter on the top left at the App Icon, you must add the following line to the (void)applicationDidBecomeActive:(UIApplication *)application method in the AppDelegate.

    application.applicationIconBadgeNumber = 0;

    The notification should be similar to the following image:

    Figure 2: Notification!
    Illustration of App – Notification – MTBackgroundTransfer

    It is now time to Run the app and test the background download.


    Conclusion

    At the end of this tutorial, you should have completed your background transfer service in iOS 7. You should understand the background transfer service and how to implement it. If you have any questions, please leave them in the comment section below.

    PhoneGap: Build a Feed Reader – Configuration

    $
    0
    0

    This is the third and final part of the series about Audero Feed Reader. In this article, you’ll learn how to create the configuration file and complete the project we started in a prior lesson.


    1. Finishing the App

    A Better Responsive Layout

    In the first part of this series I wrote about the importance of the data-iconpos attribute for the links in the header and the footer. In this section, you’ll learn about why we use them. I’m using it, with a bit of JavaScript, to create a better responsive effect. I use it to hide the text of the links where it’s applied. The purpose of this is to save space, which is important, especially for smaller screens. But what if the screen is large enough, say larger than 480 pixels, to display the text? For this, we’ll listen for the pagebeforecreate event, and attach a handler, the updateIcons() method of the Application class, to react once it’s fired. As the names indicate, the event is triggered before the page and its widgets are initialized. Our handler, will first test if the page is larger than 480px and, if so, it’ll remove the data-iconpos attribute, so the link text will be shown.

    The code that implements this method is the following:

    updateIcons: function () {
       var $buttons = $('a[data-icon], button[data-icon]');
       var isMobileWidth = ($(window).width() <= 480);
       isMobileWidth ? $buttons.attr('data-iconpos', 'notext') : $buttons.removeAttr('data-iconpos');
    }

    2. Build Configuration

    The Adobe PhoneGap Build service allows you to specify the metadata of your project with a configuration file called config.xml. It follows the W3C widget specification and must stay inside the app’s root, at the same level of index.html. The first line is the XML declaration and the root of the document is a <widget> tag that has several attributes available. The most important ones are id, the unique identifier of the application, and version, which specifies the version of the application. Inside the <widget> tag, you can write the metadata.

    If you’ve followed the tutorial so far, you’ll recall that when we initialized the application using the PhoneGap CLI, it created a default configuration file. The generated configuration specifies too many settings for each platform compared to our needs. In fact, we’ll use several settings, but since this is a tutorial, we’ll focus on a few platforms. However, you’re absolutely free to expand to fit your individual needs.

    In the configuration file, we have:

    • Name (required): This is the app’s name. It doesn’t have to be unique.
    • Description (required): Text specifying what your app is for. This is very important because it’ll appear as the description of your app in the marketplaces.
    • Author (optional): The app’s author. It has two optional properties: href, a URL to the developer or company homepage, and email, the email address of the developer or the company. Unfortunately, you can only specify one author, so you cannot have details for multiple authors here.
    • Icon (optional): This will be the icon that will display on the devices that install your app. If it is not specified then the Cordova logo will be used.
    • Splash (optional): It sets the splash screen of the application, this is the image that’s showed while loading.
    • Preference (optional): A set of preferences you want to apply to your app. It’s a closed tag and you can have zero or more <preference> tags inside the file. It has two attributes and both are required: name and value. There are several preferences you can define, but the most important one to use in my opinion is the Cordova version.
    • Access (optional): Provides your app with access to resources on other domains – in particular, it allows your app to load pages from external domains that can take over your entire webview. Keep in mind what I explained earlier in the section titled “The InAppBrowser Plugin”- that to open the external links in the Cordova WebView, you must add them to the app whitelist. For brevity, we’ll allow for any external resource using the * special character.
    • Gap:plugin (optional): Specifies the features you want to use. For example, Android before installing any app, shows to the user the permissions it requires and if the user agrees, it continues.

    If you’ve read carefully the list above and have used PhoneGap in the past, you probably noticed the introduction, in version 3.0.0, of a new setting called gap:plugin. The latter has replaced the feature setting but, apart from the name, the concept is exactly the same.

    Now that I’ve noted the key points of the format, you can understand the source of the configuration file of our project. However, if you want to read more on this topic, take a look at the official documentation page. The complete file is below.

    <?xml version="1.0" encoding="utf-8"?><widget id="com.audero.free.utility.auderofeedreader" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:gap="http://phonegap.com/ns/1.0"><name>Audero Feed Reader</name><description>
            Audero Feed Reader is a very basic feed aggregator to keep in one place all the news and the articles you care about.</description><author email="a.derosa@gmail.com" href="http://www.audero.it">
            Aurelio De Rosa</author><gap:plugin name="org.apache.cordova.core.network-information" /><gap:plugin name="org.apache.cordova.core.dialogs" /><gap:plugin name="org.apache.cordova.core.inappbrowser" /><preference name="permissions" value="none" /><preference name="phonegap-version" value="3.0.0" /><preference name="orientation" value="default" /><preference name="target-device" value="universal" /><preference name="fullscreen" value="true" /><preference name="webviewbounce" value="true" /><preference name="prerendered-icon" value="true" /><preference name="stay-in-webview" value="false" /><preference name="ios-statusbarstyle" value="black-opaque" /><preference name="detect-data-types" value="true" /><preference name="exit-on-suspend" value="false" /><preference name="show-splash-screen-spinner" value="true" /><preference name="auto-hide-splash-screen" value="true" /><preference name="disable-cursor" value="false" /><preference name="android-minSdkVersion" value="7" /><preference name="android-installLocation" value="auto" /><icon src="icon.png" /><icon gap:density="ldpi" gap:platform="android" src="res/icon/android/icon-36-ldpi.png" /><icon gap:density="mdpi" gap:platform="android" src="res/icon/android/icon-48-mdpi.png" /><icon gap:density="hdpi" gap:platform="android" src="res/icon/android/icon-72-hdpi.png" /><icon gap:density="xhdpi" gap:platform="android" src="res/icon/android/icon-96-xhdpi.png" /><gap:splash src="splash.png" /><gap:splash gap:density="ldpi" gap:platform="android" src="res/screen/android/screen-ldpi-portrait.png" /><gap:splash gap:density="mdpi" gap:platform="android" src="res/screen/android/screen-mdpi-portrait.png" /><gap:splash gap:density="hdpi" gap:platform="android" src="res/screen/android/screen-hdpi-portrait.png" /><access origin="*" /></widget>

    3. Enabling the Application to Run

    At this point we’ve reached the end of this series. Its purpose has been to demonstrate how we can start the app safely with all the files we’ve built so far. Our handlers and methods can be safely executed once Cordova is fully loaded, ensuring that you can call the Cordova APIs. But wait…When is Cordova ready? I’m glad you asked! The framework provides an event called deviceready that you can listen to. Given that, in the index.html file (the entry point of the application), we’ll listen to the event and attach as a handler our initApplication() method of the Application class. It will be executed once the event is fired.

    The code that implements this is shown below.

    <script>
       $(document)
               .on('pagebeforecreate', Application.updateIcons)
               .one('deviceready', Application.initApplication);</script>

    4. Building and Testing the Application

    Our app is now complete. All that’s left to do is to build and test it on an emulator or a real device. To build the app you have two possibilities: your computer or the Adobe cloud service, called Adobe PhoneGap Build. Remember that if you want to use your computer, you must install the SDK for each platform you want to target. The PhoneGap CLI has a command to build the app (build), to test it (install), and to perform both tasks (run). So, let’s say that you want to build and test Audero Feed Reader on Android, you have to type the following command:

    phonegap run android

    Please note that if you have an Android device connected and properly configured to the computer, the application will run on it by default. Otherwise it’ll run on the SDK emulator.

    In case you want to use Adobe PhoneGap Build to generate the installable files, you can use the CLI as well, just by using the remote command as shown below:

    phonegap remote build android

    Keep in mind that since the remote build environment doesn’t have an emulator, the install and run commands simply generate a QR code in the PhoneGap Build interface. In addition, to use the service you need to have an Adobe account. This means that (unfortunately) you cannot use the GitHub credentials.


    Conclusion

    As you’ve seen throughout this series, creating a Feed Reader can be very easy thanks to frameworks such as jQuery Mobile and Cordova, and to some APIs like the Google Feed API. I hope you enjoyed this tutorial and if you’d like to improve the project further, consider adding some features you feel I missed and use it on your own mobile devices.


    Android SDK Requirements

    $
    0
    0

    This is the first in our Learn Android SDK From Scratch series! In this tutorial you will learn about the requirements necessary to get up and running with the Android SDK!


    Introduction

    Welcome to the series on learning the Android SDK from scratch! If you want to start developing Android apps, this series will teach you the skills necessary from the very beginning. If you have any programming or coding experience at all it will help, but we will try to assume as little knowledge as possible.

    We will start by setting up the Android development resources on your computer and work through to create completely functional Android apps. Android development involves a few distinct types of skill, but if you focus on each one in turn you can build a solid foundation for working on the platform. Once we get the initial setup tasks out of the way, we will head right into the development process! You will be working towards concrete results in no time!


    Series Overview

    In this first part of this series we will look at how to set up with the Android SDK, including Java requirements. The process is a little less complex than it used to be thanks to the ADT Bundle download. However there are a couple of requirements in terms of your system and the Java JDK. At the end of this tutorial you’ll be ready to start developing apps for Android.

    Here is an overview of the series:

    • Android SDK Requirements
    • Development Environments – Eclipse
    • Development Environments – Android Studio
    • Android App Structure
    • User Interface Design – Layouts and Views
    • User Interaction
    • Java Application Programming
    • Android App Resources
    • The Project Manifest
    • Android App Data
    • Devices – Virtual and Physical
    • Running and Debugging
    • Activities and Lifecycle
    • Common Android Components
    • SDK Samples
    • Publishing and Releasing
    • Next Steps
    • Android from Scratch Quiz

    Although you do not need to have any specific programming experience to get started with Android, a little Java and/or XML will of course help, as will any markup or scripting skills. If you have no relevant experience we will run through the basics and point you in the right direction for any areas you need to acquaint yourself with in order to get the best out of Android development. In the next couple of tutorials we will look at the Eclipse and Android Studio IDEs before we get onto the specifics of Android development itself.

    For the purposes of this tutorial let’s assume that you have not installed Eclipse or any of the Android tools yet. If you have, refer to the official Android Developer Guide if you are having trouble with your installation setup or need it updated. The instructions below also cover installing a fresh JDK, so if you already have Java 6 installed you can skip to step 3. If you have Java 7 installed, you may encounter some problems developing for Android as it only supports Java 6 at the moment – in this case you may wish to set your Eclipse preferences to use Java 6.


    1. Operating System Requirements

    Users of most operating systems should be able to run the Android development tools. If you’re using Windows XP, Vista, or Windows 7, then you’re set! The Android tools support 32-bit editions of all three Windows versions, plus 64-bit editions of Vista and Windows 7.

    On Mac, you can develop for Android using the official tools on OS X versions from 10.5.8 (x86).

    On Linux, the Android tools are supported for Ubuntu from version 8.04 and on the GNU C Library from 2.7. If you run a 64-bit Linux installation, it will need to be able to run 32-bit applications.


    2. Download and Install JDK 6

    To develop Android applications, you need to install the Java Development Kit (JDK) on your computer. You may already have this if you have programmed in Java before. If not, you need to download and install JDK version 6 from Oracle. This is not the most recent version, but it is the version supported on the Android platform. If you already have the JRE (Java Runtime Environment) this is not enough to run the Android tools – you need the JDK installed.

    On the Oracle Java download page, browse to Previous Releases to download version 6. Choose Java SE 6 and select the most recent update of the Java SE Development Kit. Accept the license agreement and select the proper download for your operating system. You need to sign into an Oracle account for the download, so set one up if you don’t already have one. Once you have the JDK downloaded, run to install it and follow the instructions.


    3. Download the ADT Bundle

    Step 1

    Once you have the JDK set up you can get started with the Android development software. Download the ADT Bundle from the Android site. The ADT Bundle simplifies the setup process for Android development, since it packages everything you need into a single download.

    The bundle contains the Android Software Development Kit (SDK), the Eclipse Integrated Development Environment (IDE), and the Android Developer Tools (ADT) plugin and various platform tools. The SDK contains the resources you need to build, test, and deploy Android apps. You will develop apps in Eclipse, which is a software program that is primarily used for developing Java applications. To develop Android apps in Eclipse, you need the ADT plugin. With all of this in place, you will be able to use Eclipse to write your code, to design your user interfaces, to compile, run, test, and debug your Android apps on actual and virtual devices.

    Developing for Android means targeting a potentially wide range of computing devices, with varying hardware controls and Internet connectivity. All of this means a tremendous range of possibilities but can also involve serious complexity when testing your apps. For this reason the Android development download includes lots of different utilities to aid the development process. However, this does not mean that you have to be a programming expert to start developing apps for Android as you will see, so don’t be intimidated by how complex things may seem at first. Select the ADT Bundle for your platform and download it.

    Step 2

    Once your ADT Bundle download is complete, unzip the folder and place it in your chosen location. Navigate to Eclipse, which you should find in the “eclipse” directory inside your download folder. Run Eclipse by double-clicking the executable “eclipse” file.

    Starting Eclipse Bundle

    You will be prompted to choose a location for your workspace during setup – you can either let Eclipse create one or create one yourself and point Eclipse to it. The workspace folder is where the files associated with your Android projects will be stored, including the code you write and any media items involved in your apps. In most cases you will interact with these files via Eclipse, but remember this is where the files are if you need to access them.

    Eclipse Workspace

    The Eclipse installation automatically uses the ADT resources you downloaded along with it. As long as you leave everything you downloaded in place inside the download folder it should continue to function each time you launch the Eclipse software.

    On the first run, Eclipse will display some options for getting started with Android, including creating a new project and working through tutorials. Feel free to try out some of these options or simply ignore the start screen. We will work through the process of creating your first apps in this series anyway. Upon closing the tab displaying this initial message, the Eclipse workspace will appear. We will examine it in the next tutorial.


    4. Keeping Everything Up To Date

    Step 1

    Once you have Eclipse and the ADT up and running, keeping it all up to date is straightforward, but does require frequent checks in a few places. In Eclipse, regularly check for general software updates by choosing “Help” then “Check for Updates”. Be aware that it may take a few minutes to retrieve the available update information.

    Eclipse Updates

    If Android ADT updates are available they will appear here, so you can select or deselect to suit your needs, accept any license agreements and click “Finish” to download and install the updates, which can take some time depending on how substantial they are.

    Available Updates
    Eclipse Updating

    Step 2

    As well as checking for Eclipse updates regularly, you should frequently run the Android SDK Manager to see what’s available. In Eclipse, choose “Window” then “Android SDK Manager” to launch it. Once the data is loaded you can see what you have installed at the moment, what updates are available, and what other platform components are available that you may also wish to install. Browse through the list to see what’s there. You can automatically select updates to resources you already have installed if you simply want to keep what you have up to date. Make your selection and click to install, accepting license agreements as necessary.

    Android SDK Updates

    When you begin developing for Android you can stick with what comes by default in the ADT Bundle.

    Step 3

    To ensure you keep up to date with your ADT resources, you can also add the Android ADT update URL to Eclipse to check for updates. In Eclipse, choose, “Help” then “Install New Software”. If the site does not appear when you click the drop-down arrow for the “Work with” text-field, enter it and click to add it:

    https://dl-ssl.google.com/android/eclipse/

    Select the ADT update site from the list to see any available updates. You can check the “Hide items that are already installed” checkbox to simplify the process. When ADT updates are available, you can install them from here.


    Conclusion

    That was the setup to start Android development! In the next tutorial we will familiarize ourselves with the Eclipse environment to be acquainted with the essential features of the software to create Android apps. We will then take a look at Android Studio, which is only available in preview form at the moment, but it is what you are likely to use for Android development down the line. After that we will work through each aspect of the basic Android development processes, including coding, design, and running your apps.

    Android SDK: Working with Eclipse

    $
    0
    0

    In this series you’ll learn about Android development from the beginning. In the first section we setup the Android SDK and Eclipse. In this part we will acquaint ourselves with the Eclipse software. Eclipse is an IDE (Integrated Development Environment) for Java. Together with the ADT (Android Developer Tools) plugin, Eclipse provides an environment in which you can build, code, design, and run Android apps. We will learn more about Eclipse throughout the series, but in this tutorial we will explore the basic features of the Eclipse user interface so that you know your way around before we start developing.

    At the time of writing this tutorial, Eclipse is the officially supported IDE for Android, but be aware that this is set to change with the new Android Studio program. We will look at Android Studio in the next tutorial, but it’s only available as an early access preview at the moment, so you should initially focus on Eclipse for your Android development projects.


    1. Create an Android Project

    Step 1

    To begin, simply open Eclipse. To get started in the Eclipse environment, let’s go ahead and create an Android project we will later build on. Don’t worry too much about the details at this stage, we will explore each element of Android projects as the series progresses. For the moment we just need to create a basic project so that we can use it to become familiar with the Eclipse interface. Also, keep in mind that there is a lot more to Eclipse than what we will cover here. In this tutorial we will focus on what you need to know to get going in Android.

    Eclipse models each app you create as a project, with the coding and other resources related to the app stored and managed from within a directory for the project in your workspace. Creating a new Android project involves a few steps, which we will gloss over at this stage just to get a project setup to show how the Eclipse workspace will look while you are working on an Android app. Click the “New” button.

    Eclipse New Button

    In the wizard, expand the “Android” folder and select “Android Application Project”. This is the process you will use whenever you create a new project for an Android app. Click “Next”.

    New Android Project

    Step 2

    In the “New Android Application” screen, you will see various fields you can set. When you click on the text-fields, Eclipse will display some informative text near the bottom of the window. Enter “MyFirstApp” as the Application Name. This will automatically be populated in the Project Name field and a package name will also automatically populate. You can alter these but for the moment leave them with their default contents.

    New Android Application

    You can also leave the SDK options as they stand – these allow you to target particular API levels and to specify the minimum level you wish to support. As you progress with your Android development skills, you will see that the types of functionality you include will sometimes have implications in terms of which platform levels your app will support. Of course you want to aim to support as wide a range of devices as possible but this can sometimes be tricky. To continue, click “Next”.

    The next screen you will see lets you configure the project. By default Eclipse selects certain settings. Check the options to create a launcher icon for your app, create an Activity for it (this is a user interface screen), and to create the project in your workspace. Click “Next”.

    Configure Android Application

    Step 3

    Next you will see the Launcher Icon screen. In general you will likely use this to specify a launcher icon image file and to set display properties, but for now just leave it as is and click “Next”.

    Launcher Icon

    In the next screen get Eclipse to generate an Activity for you. This is likely what you will do for a majority of the apps you create at first. The Activity generated is a single user interface screen, which most apps need at the very least. Leave the “Create Activity” box checked, with “Blank Activity” selected and click “Next”.

    Blank Activity

    Step 4

    We’re almost there! In the last screen you will see an overview of the project Activity details before it is created. You can alter the Activity and layout names, but leave them as they are for this tutorial. Click “Finish” to create your project.

    Project Details

    Eclipse will create your project, opening the Activity file. Don’t worry too much about the contents of the files or the project directory at this stage, we will explore them in future tutorials. But for the moment we will use this basic project to get used to Eclipse.


    2. Using Eclipse Views

    Step 1

    Now that we have a project open we can see what Eclipse will look like while you develop your Android apps. You will see various tabbed areas within the Eclipse window, all of which can be modified to suit your own preferences. These tabbed sections are referred to as views. By default you should see a central editor area in which files appear for viewing and editing. To the left you should see the Package Explorer view and to the right the Outline view. Beneath the editor you should see a few default tabs providing additional information.

    You can add views to the visible display by choosing “Window” then “Show View” and making a selection. To remove a view from display simply close it using the cross on its tab. You can also minimize and maximize visible views at any time using the buttons in the top right corners of each. Views in Eclipse are designed to let you see and interact with the various items within your projects in different ways. Let’s look at each of the most relevant views in turn.

    Step 2

    To the left of your Eclipse window you should see the Package Explorer. You can think of this as a file explorer, presenting the content of your projects within a directory structure. You can click to expand and collapse the folders in a project, as well as double-click to open any editable files in the editor. Each project is stored in a dedicated directory in your workspace, represented in tree form within the Package Explorer. This will be your main source for accessing the files that you need to work on when developing your apps.

    Package Explorer

    If you expand the “src” folder in your new project, you will see the package you originally created when starting the project. Inside that you will see the Activity class file, which should automatically have opened in the editor. Your Java files are always organized into packages like this inside your projects. Most of your initial Android projects only use a single package, but you can have more than one. We will look into Java class files later on in this series, so don’t worry if you haven’t used them before.

    When we look closer at the application project structure in the upcoming tutorials we will pay particular attention to the “res” directory and the Manifest file, so take a moment to locate and browse these in the Package Explorer. When we begin developing, most of our attention will be paid to the “src” and “res” folders.

    Step 3

    The editor area is displayed in the center of the Eclipse window. You should see the Activity file you created along with your project opened for editing. Don’t worry about the content of the file just now – we’ll get to that soon. The editor view displays all files you have open at any time.

    Eclipse Editor

    Eclipse also should have opened the layout file for your app. Switch to it now by clicking the top of the tab where it reads “activity_main.xml”. Initially the layout file will be opened for editing graphically as this file represents the user interface for your app’s main screen. Click on the “activity_main.xml” tab. You should see at the bottom of the view to switch from the Graphical Layout. As you can see, the editor displays the XML code for editing directly.

    Eclipse Editor for XML

    As you will see when we start coding, the Eclipse editor aids the programming process by displaying suggested code excerpts as you type. This applies to Java and XML files, both of which you will be using plenty of.

    Step 4

    To the right of the editor, you should see the Outline view. We will explore more about the Outline view when we look at the basic programming tasks involved in Android. For now all you need to understand is that the view presents a structural overview of the content of any open Java or XML files. You will be able to use the outline to navigate your source code quickly.

    Outline View

    Step 5

    At the bottom of the Eclipse window, you will see a few views displayed by default, including the Problems, Javadoc, and Declarations views. Developers often use this area for outputting error and debugging messages, typically with the Eclipse Console view, which you can add to the display if you wish. However, the Android tools include a dedicated view for outputting messages that will help you to develop and debug your apps, so let’s open that now.

    Select “Window”, then “Show View”, and choose “Other”. In the Show View pop-up, expand the “Android” folder, select “LogCat”, and click “OK”. The LogCat view will appear in the bottom area of the Eclipse window. We will use this when we start to develop. With the LogCat view, we will write messages out during the execution of our apps. This step helps us find out what happens as the programs run.

    Show View
    LogCat View
    Tip: On certain operating systems you may encounter problems with the LogCat view in Eclipse. If this occurs, try switching to the deprecated version of the LogCat, and if that fails try to run the LogCat from a command prompt or Linux terminal.

    3. Using Eclipse Perspectives

    Step 1

    The Eclipse views we’ve looked at provide different ways to interact with the content of your projects. As you have seen, you can configure the visible views in a way that suits your needs most effectively. Eclipse also provides Perspectives, which give you a quick way to switch between useful collections of views for common tasks. The default perspective you see initially is called “Java”. Near the top right corner of the window you should see a button with “Java” on it.

    For most of your Android development you will use the Java perspective. However, when you debug your apps you may also find the DDMS (Dalvik Debug Monitor Server) perspective useful. We will explore the details of this perspective later in the series. For now try switching to it to acquaint yourself with how the perspectives work. Choose “Window” then “Open Perspective”, or click the “Open Perspective” button next to the “Java” button. Select DDMS from the list. At the moment the perspective will not show much – it will display virtual or connected physical devices when we work with them later.

    DDMS View

    Switch back to the Java perspective now by clicking the “Java” button or using the “Window” menu again. As you can see, Eclipse will display buttons for perspectives you recently used to make switching faster.

    Perspective Buttons

    Conclusion

    Now we have completed our Eclipse familiarization phase. Bear in mind that most of the aspects of the software will make a lot more sense to you once we start working on some Android projects. In the next part of the series we will look at Android Studio as we have with Eclipse, since you may wish to use it now and will certainly use it later if you continue with Android development. After that we will get to grips with the task of developing an Android app, including the basics of Java programming. Feel free to continue exploring Eclipse on your own. It is a highly configurable program that you can setup to reflect your own preferences at any time.

    Android SDK: Working with Android Studio

    $
    0
    0

    The goal of this series is to learn about Android development, including the tools and resources you need to in order to start creating apps. In the last part we became acquainted with the Eclipse IDE. Since the platform began, Eclipse has been the main supported development environment used to create Android apps. Eclipse is still the recommended IDE for Android, but this is set to change with the new Android Studio IDE. Android Studio is not yet complete, but it is available as an early access preview. This new IDE is designed specifically for Android development and based on IntelliJ IDEA in conjunction with JetBrains. When it is complete, Android Studio will improve several aspects of its Android development, not the least of which is the process of designing UIs to support the range of Android devices in use. In this tutorial we will install and explore Android Studio.


    Introduction

    Although Eclipse should still be your main focus for developing Android apps, it is worth spending some time with Android Studio, particularly if you intend to be involved in Android development long term.


    1. Installation

    Step 1

    As you have seen, the ADT Bundle download includes the Eclipse IDE for Android development. To try out Android Studio, download it from the Android Developer site. There are versions for Windows, Mac, and Linux, so choose the one for your operating system.

    Step 2

    On Windows, install Android Studio by running the executable “.exe” file that you downloaded. Follow the instructions to complete the installation. On Mac OS X, install by opening the DMG file you downloaded, then drag Android Studio to your Applications folder. On Linux, you need to first unzip the downloaded directory. Inside the unpacked folder, browse to the “bin” directory. You can execute Android Studio from here by running the “studio.sh” file.

    Android Studio

    2. Start a Project

    Step 1

    Let’s get to know Android Studio by starting a project as we did with Eclipse. When you start Android Studio for the first time, you will be presented with a welcome screen that offers a few options. Choose “New Project”.

    Android Studio Welcome

    As you can see, the process of creating a new project is very similar to Eclipse. In the New Project screen, leave the default options for naming the application elements and API level support and then click “Next”.

    New Project

    In the launcher icon config screen, leave everything as-is and click “Next”.

    New Icon

    In the Activity config screen, let Android Studio create a new blank Activity for you by leaving “Blank Activity” selected and click “Next”.

    New Activity

    Leave the Activity and layout text-fields with the automatically populated file names and click “Finish”.

    New Project Finish

    Android Studio will build your project and create a folder for it in the workspace. Like Eclipse, Android Studio manages the files for a project in a single directory and they are all saved inside a folder named “AndroidStudioProjects” onto your system.

    New Project Build
    Tip: Android Studio can be pretty unstable. If anything goes wrong when creating your first project, try updating the software by choosing “Help” and “Check for Updates”.

    3. The Environment

    Step 1

    Let’s now look at the elements of the Android Studio environment with your new project open. When it creates a new project, Android Studio opens the layout and Activity files for editing, as well as loads a preview of your app’s UI on a virtual device screen. As you can see, the default window layout is slightly different than Eclipse.

    Android Studio Workspace

    Releases of Android Studio vary and will likely continue to, but at the time of writing, by default Android Studio initially displays an editor area for your Java and XML files together with the preview area to the right of the screen. Remember that with Eclipse, we had an area to the left of the window in which we could explore the project structure and open files to edit. In Android Studio you can also do this. If you look above the editor area you will see links to the project directories. Double-click on “MyApplicationProject” to open the project directory in a dedicated view.

    Android Studio Project

    Experiment with the project view by expanding the folders that appear within it. Expand “MyApplication” to access the contents of your new project. You will find the items we will work with as we continue to learn Android development inside the “src/main” directory. We will be particularly interested in the content of the “java” and “res” folders. Notice that there are quick contextual links above the editor to locations within the project structure relative to the current file.

    The files Android Studio should have opened when you created your project are the Activity file, which you will find in the package folder inside “java”, and the layout file, which is stored inside the “layout” folder in “res”. Notice that when a layout file is open in the editor, you can switch between design and text views, which will allow you to build and edit your UI elements both graphically and via code. When the Design view is open, to the right you will see the Component Tree, a structural overview of the layout. When the text view of a layout is open, to the right you will see the preview of the layout.

    Android Studio Design

    Step 2

    Although you may not yet be familiar with the structure of an Android project, once you learn a little more you will see that Android Studio structures the content of your app project’s a little differently than Eclipse. The files you are most likely to work with are stored inside “src”. This is because the build system in Android Studio is Gradle-based. Don’t worry too much about this difference if you are working in both Eclipse and Android Studio in the future, as the differences are unlikely to affect you. Just get used to the fact that the source files you work with will be located in different places in the two IDEs.


    4. Project Interaction

    Step 1

    One of the better features in Android Studio is that many of the tools you need are accessible via the buttons in the toolbar. Take a moment to scroll over these now. Notice that there are quick links to launch various utilities including the AVD Manager, SDK Manager, and the Monitor that includes debugging tools.

    Android Studio Buttons

    Step 2

    Like Eclipse, Android Studio provides a range of views you can use to interact with the contents of your projects. Select the “View” and “Tool Windows” menu to see the range of options. Clicking these toggles them in-and-out of visibility. Views you may find useful include the Structure view, which is similar to the Outline view in Eclipse and the Event Log view, which displays system output messages.

    One view you may find particularly useful once you are attempting to develop and debug apps is the “Android” view. Open it now from the “Tool Windows” menu. This view displays information about actual and virtual devices, together with the LogCat for outputting debugging messages.

    Android Studio DDMS

    5. Updates

    Step 1

    As with Eclipse, you need to keep your Android Studio installation up to date to get the best use out of it. You can use the “Help”, “Check for Update” tool to keep the software itself up to date regularly. This is advisable since Android Studio is under constant development, with patches often released to address issues you may be facing.

    Step 2

    As we’ve seen with Eclipse, as well as keeping the IDE up to date, you should check for Android updates regularly as well. In Android Studio you can do this by clicking the “SDK Manager” button you see in the toolbar.

    SDK Manager

    The process of keeping the Android SDK up to date is exactly the same as with Eclipse.

    Tip: For more tips on Android Studio see the IntelliJ IDEA documentation.

    Conclusion

    In this tutorial we touched on the basics of using the Android Studio interface, but there is a lot more to the software than what we have mentioned here. Lots of tasks are easier in Android Studio, like with forming new files and building user interfaces, simply because the IDE has been created specifically for Android development, unlike Eclipse which is designed to support a vast range of Java development tasks. The software UI provides quicker ways to carry out Android-specific tasks and doesn’t have options that are not relevant to the platform. This IDE also provides easier interfaces to resources such as Google Services. As we work through the skills involved in Android development in Eclipse you may wish to periodically try them out in Android Studio as well. Now that we have our development tools setup, in the next part of this series we will look at the structure of an Android app.

    Android SDK: App Structure

    $
    0
    0

    In this series we are learning about Android development. So far we installed the development tools and became acquainted with them. In this tutorial, we will explore the structure and content of an Android project, using the simple project we created previously. We will look at the source directory and the project resources. We will also begin looking briefly at the project manifest.


    Introduction

    This tutorial will primarily involve exploration, but we will begin development tasks in the next few tutorials, when we look at building user interfaces, responding to user interaction, and using Java to code application logic. We will focus on the project ingredients that you are most likely to interact with when you start to develop for Android, but you will find other elements already inside your application structure and many more are possible. We will not go into too much detail about any particular element in this tutorial, but will get to know some of the basic building blocks of an Android app.


    1. Source

    Step 1

    Open Eclipse and expand the Package Explorer folder for the project we created. Inside the “src” folder you should see the package you named when you set the project up. Inside the package should be your Activity class file, which should also be open in the editor. The source folder holds all of the Java files you work on when you develop Android apps.

    Project Folders

    Each time you create a project you will create a package with your Java class files in it. An app may have more than one package in it and each package may hold multiple class files. The class files contain the processing code that presents your app to the user, responds to user interaction, and carries out any necessary processing. Essentially, the class files divide up the code involved in the application according to the Object Oriented conceptual model.

    We will cover more about Java concepts and practices later in this series. For now, just understand that a Java application splits the various processing tasks between a number of objects. Each object is defined by a class declaration, which is typically a single file in an application, but which can also be nested inside another class file. An object is basically a chunk of code which carries out some part of the functionality involved in the app. The code in a class file can refer to the other classes in the application or in any package within the application.

    When you start developing apps, you need to add Java classes to your package(s) in the source folder. A typical Android app that presents a user interface to the user will have at least one Activity file in it, with extra Activity classes for each screen in the app. There are other types of app such as those involving widgets and services, which can adopt a different structure. It’s best to learn about the Activity-focused UI type of app to begin with and learn about the others later.

    Step 2

    Have a look at the Activity class file in your new app. We will explore more of the Activity code later on in this series, so don’t worry too much about the details. This is your app’s main Activity, which starts when the app launches. Your app may then launch other Activities on user interaction. When you created your project, Eclipse sets the app up to use this as the main class. It is listed as the main Activity in the project Manifest, which we will look at soon.

    Inside the main Activity class, you will see the onCreate method, which contains the code that will execute when the Activity is created, i.e. when the app is launched. Inside the method you will see the following line of code:

    setContentView(R.layout.activity_main);

    This line specifies the layout file we created when we started the project, telling Android to use it as content view. This means that whatever is in the layout file will be what users see when this Activity is on the screen.

    We will look more at this later but for the moment notice the “R.layout.activity_main” syntax. This is how your Java code refers to the resources in the app. We will use similar syntax to refer to resources by their ID value, as well as referring to other types of resources such as images and data values. The “R” represents the app resources and what follows specifies the item type, in this case a layout, stored inside the “res/layout” directory. The resource is finally identified using its name – in the case of the layout this is the filename. The syntax is therefore “R.type.name”. You will get used to this when we start to code.

    Later in this series we will add code to the Activity class file to handle user interaction. Expand your app “res” folder now. Inside it you will see a number of sub-folders. These are the folders Eclipse and ADT create by default when you start a new Android project, but there are a number of other possible directories you can also add for different types of resources.


    2. Layout Resources

    As we have already seen, the layout file formed when the project was created appears in the “res/layout” folder. If an app has multiple Activity screens, it will typically have a layout file for each. You may also use layout files for individual UI items. When you create the class file for an Activity, you set the layout using setContentView as we saw above. You can alternatively define a layout in Java code, in which case it is built dynamically when the app executes. However, the advantage to using XML is that you can see a visual representation of the layout while you design it.

    Inside the main layout file for your app, which should be open in the editor, you will see XML structures. Don’t worry if you have no XML experience, we will run over the basics later on in this series. For now, just understand that XML is a markup language, similar to HTML if you have tried Web development before. XML files model data within a tree structure. Typically a layout file has a root layout element modeling a particular type of layout, with child elements inside it for the UI items such as buttons, images, and text.


    3. Drawable Resources

    You will see multiple folders in the resources directory with “drawable” in the name. These store the image files your app uses. These image files can be digital image files you prepare outside Eclipse, with formats such as PNG or JPEG. Alternatively, you can define certain drawables using XML code to describe shapes, color, and appearance. Once you have a file in your drawable folders you can refer to it in the app layout files or in Java code. This allows you to build images into your app’s UI.

    The resource directory includes drawable folders for each density bucket. The density buckets are generalized categories for the the different screen densities on devices running Android. The generalized categories are for low, medium, high, extra high, and extra extra high density. Using these allows you to simplify the process of supporting multiple screen densities by catering for each of these categories. This means that when you include image files in your projects, you can include versions of them in each density folder, tailoring the images to the densities in each case.


    4. Data Resources

    In your “res” directory you will see some folders with “values” in the title. These are for data values you wish to use within your app. Such values can include text strings and numbers. The values folders contain XML files in which one or more values are listed. Each listing includes a name and the value in question. Other files in the app, such as Java class or layout files, can refer to the values using their names. A typical use for such a value would be to store a text string to display within a UI element such as a button.

    The different values files in the app are designed to allow you to tailor values to particular screen sizes and API levels. If the same value can be used across devices, it can be saved in the plain “values” folder.


    5. The Manifest

    If you look in the main folder for your app, you will see the project Manifest file. Open it in the editor by double-clicking it. You will see a graphical interface to its content. Click the “AndroidManifest.xml” tab at the bottom of the editor window to see the XML code. This file defines multiple aspects of the app as a whole. Eclipse and ADT build certain elements into the Manifest when you create the app, basing these on the settings you chose during project creation. You can add other elements to the Manifest manually. For example, if you add other Activities to your app.

    Manifest Tab

    We will run through some of the main elements to understand the Manifest, but there are many other elements you can include. Listed in the Manifest for your new app project you will see the uses-sdk element, in which we indicate minimum and target API levels. The application element contains attributes indicating the launcher and app name. Inside the application element is an activity element, listed as the main Activity to launch when the app runs via the intent-filter element. When you add new Activities to an app you will include a new activity element for each.

    Other elements you may need to add to the Manifest include the uses-permission element in which you list permissions the app requires – the user sees a list of these before installing the app. Permissions include actions such as fetching data over the Internet, writing to storage, or accessing other features of the device such as the camera. The Manifest also lists data regarding which devices the app supports, as well as lists other app components such as background services.


    6. Other Files

    So far we have covered the main aspects of an Android app project structure that you need to know for your first few apps. We will work with these files as we learn the skills involved in Android development. There are several other files and directories in the project as you can see in Eclipse, but for the most part you can ignore them for now.

    As we saw above, you can refer to resources using the “R.” syntax. Eclipse and the ADT manage the system that refers to the resources in your app from Java. When you add or edit the resources in your project, Eclipse writes to the “R.java” file, which in turn allows you to refer to the resources using “R.”. When you start working in your Java files, you will see that Eclipse will prompt you with suggestions when you refer to R, making it easier to manage the resources in your app.

    The “R.java” file is stored in the “gen” folder. Do not attempt to edit this file directly, it automatically generates when you edit the resources in your project. The system manages this process by allocating a unique integer ID to each resource in your app.

    Tip: When you start developing Android apps, you may encounter problems with R. If Eclipse displays an error message regarding R, particularly “R cannot be resolved to a variable”, check the top of your class file for an import statement with “R” in it, such as “import android.R;”. If you find this common, especially if you have copied and pasted code into your file, remove the import statement. If you have other problems referring to resources via R first make sure there are no errors in your resource files. If the problem persists, try cleaning your project using “Project”, “Clean”. If nothing else works try to restart Eclipse.

    Conclusion

    In this tutorial we explored the basics of an Android project structure. Feel free to spend more time exploring the other files and folders in your project to get to know its overall structure. In the following sections of this series we will build user interface elements and handle user interaction with our app. We will also look at some of the essential features of Java programming to understand it in order to get the best out of our Android development project.

    Xcode 5 Essentials

    $
    0
    0

    Xcode 5 is a major step forward for the Apple ecosystem, bringing more possibilities, features, and tools to developers than ever before. With Version 5, Xcode has grown into an extremely powerful IDE. Read this article to learn what’s new!

    Introduction

    Xcode 5 is full of improvements and additions, both large and small. All of these changes provide enormous assistance to developers. Changes begin in the interface, where the updated look-and-feel style was adjusted to fit into the new iOS 7 ecosystem. Just by touring yourself around, you’ll notice a number of stylistic modifications, starting at the welcome screen.

    The new additions are apparent upon using Xcode, and once you work with it for a while, you’ll discover that in this version Apple targets two major points. The first goal is to relieve developers from various configuration tasks regarding their applications. The other objective it to elevate debugging and testing to a whole new level and provide developers with useful tools that make these tasks easier and more effective.

    All of the new features will be introduced to you right away. In short, here is a list of all the new features or ones with essential changes that you’ll encounter in this tutorial:

    • Automatic Configuration
    • Source Control Enhancements
    • Interface Builder and Autolayout Enhancements
    • Asset Catalog
    • Debugger Enhancements
    • Debug Gauges
    • Testing and Bots
    • Compiler Improvements

    1. Automatic Configuration

    Enabling an Apple service into an application was always a task that required a certain number of steps that should be performed by the developer until the app is fully setup and working. Frameworks need to be linked to the project, entitlements have to be added to the App ID, keys should be appended in the *.plist file, and all tasks must be done according to the service’s requirements. The many small steps made this a difficult process.

    Xcode 5 removes the hassle of doing all the above from developers, thanks to the Automatic Configuration feature. With Automatic Configuration, the only requirement for developers is their Apple ID (associated to a developer program). Xcode then automatically enables and sets up any services that developers want, by linking frameworks, managing entitlements, and doing anything else necessary for a service to work. Developers really don’t need to do anything else, apart from selecting the services that they would love to see in their applications. Even provisioning profiles can be optionally created automatically with the proper settings. This is an awesome feature for developers!

    Let’s take a more detailed look at Automatic Configuration.

    It is straightforward to assign your Apple ID within Xcode. Simply open Xcode menu > Preferences… > Accounts. The Accounts tab is a new feature in Xcode 5.

    gt8_1_accounts

    At the bottom left of the Preferences window there are three buttons: a plus sign, a minus sign, and a gear sign. Click on the Plus sign > Add Apple ID… option. In the form that appears, provide your Apple ID and your password and click Add.

    gt8_2_add_apple_id

    If everything goes as planned, the Apple ID you just added should be listed at the left side of the window. At the right side, if you select your ID and click on the View Details button, another window shows up on the screen.

    gt8_3_view_details

    This one contains all of your signing identities and provisioning profiles. You can create, remove, or revoke signing identities using the appropriate buttons under the signing identities area. Also with the refresh button at the bottom of the window, you can update all changes you perform online on your provisioning profiles.

    gt8_4_provisioning

    To delete an Apple ID, simply select the respective ID from the list on the Accounts and click on the Menus button at the bottom left side of it.

    The Capabilities tab automatically allows Apple services to be configured. This feature can be found if you click on your project on the Project Navigator.

    gt8_5_capabilities

    As you see in the figure, it is just a matter of enabling or disabling a switch button. Capabilities provide automatic configuration support for the following services:

    1. iCloud
    2. Game Center
    3. Passbook
    4. In-App Purchase
    5. Maps
    6. Background Modes
    7. Keychain Sharing
    8. Inter-App Audio
    9. Data Protection

    If you expand any one of those, a description about the selected service and information about the actions becomes visible. For example, if you expand the Game Center service the following figure appears, stating that the “Game Center” entitlement was added to the App ID, the “GameKit” key was added into the info plist file, and the GameKit framework was linked to your project. These are actions and steps that you could do manually, but now Xcode can do it automatically on your behalf! If you so choose, you can continue to do it on your own, but Xcode saves you some time.

    gt8_6_game_center

    In the General tab (the one at the left of the Capabilities tab), inside the Identity section, there is the Team dropdown menu. If you successfully added your Apple ID into Xcode, click it to select a development team exactly as it appears on iTunes Connect. For developers playing solo, their full name only appears. If you want Automatic Configuration to properly work for you, I recommend to select your team (or name) before enabling any service in the Capabilities tab. In case you leave the Team value to None, then when you try to enable a service you will be asked by Xcode to select your team.

    gt8_7_general_team

    Based on the Apple ID in the Accounts tab of Xcode preferences, the signing identity settings and the Capabilities settings, Xcode can create new provisioning profiles for you, using proper settings, instead of doing so manually. Also, fixes are applied to existing provisioning profiles with issues.

    To recap, Automatic Configuration saves you from some demanding manual work by doing many steps for you. However, you can still create and set everything manually as you traditionally have done, or do some steps by yourself and let others to be automatically done by Xcode. It’s a great feature, use it at your will.


    2. Source Control

    Source and version control systems are always helpful, and they are mandatory for projects that tend to become large and are developed by a team of programmers. Even lone-rider developers should adopt the habit of using a source control system because it is a great tool, especially when it comes to code change tracking. A source control system allows you to keep track of code changes and to revert back to a more stable version when it’s necessary. For team development, it’s great because it allows each developer to build a part of the project, simply by creating a copy of it (branch) and without interfering with other developers’ code. When various project pieces are ready, they can be put together (merged) into one working version of code. Also, in cases where too many bugs appear, developers can go back to a more stable version and track down the code changes, simply by comparing two versions of the same file. Git is such a source control system.

    Xcode 5 gives special gravity to source control. In Xcode 4.6, source control could be found under the File menu. In Version 5 source control enjoys its own top-level menu in the Xcode menu bar.

    gt8_8_source_control

    As you see in the figure, in this menu you can directly see the current project you are working on and access certain operations, such as Commit, Push, New Branch, Switch to branch, Merge from branch, and many more. It is really easy and fast to access the source control system and to keep any changes you want in your repositories.

    Speaking of repositories, you can reach them directly when launching Xcode, even from the welcome screen, simply by clicking on the Check out an existing project option.

    gt8_9_repositories

    Navigate to the Check out form, where you can see a list of all of your repositories, your favorites, or the most recent ones. Alternatively, you can type a location where a repository can be found.

    Another useful option regarding source control and Xcode 5 is the Blame for this line operation under the Editor menu. This option displays comment information about the current line that the cursor is on and states who made the last comment. This is especially helpful in team projects because it makes it easy to find the developer who last changed the code.

    gt8_10_blame

    Note that if you try to use the Blame option without committing at least one of your files using the Source Control menu, no information will be shown to you.

    Like many other aspects of Xcode, source control is configurable as well. Go to Xcode > Preferences… > Source Control to access the settings of it. If you’d like, you can completely disable the source control for your project (but it’s recommended not to do so). Set the options according to your preference and work in your customized environment.

    If you are not using Source Control when developing applications, then you are strongly encouraged to start doing so. You’ll notice that keeping versions of your files, reverting to older versions, or comparing them is a process that can save you lots of time when you try to track down the errors in your code.

    3. Interface Builder and Autolayout

    Interface Builder, the GUI designer of Xcode, doesn’t seem to have many apparent changes, except for the missing grid and the general aesthetic upgrade. However, one major feature that was added in this version of Xcode is the ability to preview the interface setup for iOS versions equal or earlier than 6.1. All graphic elements (subviews) were redesigned and developers need to know whether the position, the size, or the layout of the subviews works for both iOS 7 and previous versions of iOS.

    To use the preview feature on Interface Builder, at first show the Assistant Editor.

    gt8_11_assistant_editor

    If Xcode automatically shows any file containing code on the Assistant Editor, then locate and open the .xib or storyboard file you want to preview manually, as shown in the next figure.

    gt8_12_locate_xib

    Once you have the GUI file opened in both the Standard and the Assistant Editor, click on the Related Files button > Preview >Your File of the Assistant Editor.

    gt8_13_related_button

    Notice a frame at the bottom-right of the screen, where it says iOS 7.0 and later. Click on it, select the iOS 6.1 and Earlier option and you’ll have the preview ready.

    gt8_14_ib_preview

    Preview is a useful tool for developers who want to keep backwards compatibility in their applications and to support previous iOS versions. So if your application not only supports iOS 7, use it when you design your interface.

    Let’s talk about the Autolayout feature now. Autolayout is not something new in iOS 7, but in Xcode 5 it was redesigned from the ground up, giving developers the ultimate freedom to set and change constraints. That means that you can set any constraints you want, they way you want (even delete them) without an automatic intervention from Xcode. It will warn you if there are any missing or constraints that do not match, but it will let you do whatever you want without limitations.

    Contradictory to previous versions of Xcode, in Version 5 a new subview was added to a view that doesn’t include any constraints. This lets developers decide what constraints they need. Also, new options for setting constraints are available at the bottom-right frame of the Interface Builder (alternatively, in the Editor menu), which you can use to either set custom values and certain constraints or to allow Xcode to automatically setup the layout for you.

    gt8_15_autolayout_options

    When you set constraints and Xcode detects that any ambiguity or issues exist, it colors the constraint lines in red instead of blue. They stay that way until all issues regarding the problematic subview are resolved. Here is an example where constraints are missing and Xcode warns us using the line color:

    gt8_16_red_lines

    Warnings or errors about missing constraints or misplaced views are also shown by Xcode in the Document Outline, next to the view that inconsistencies exist. To examine what the problem is, simply click on the little yellow or red arrow that appears right next to the view, and a list of all the layout issues appears. The most easy way to fix everything is to click on each warning or error sign that appears, and through a list of suggested and possible solutions that Xcode provides, to select the most appropriate one according to your needs. The other way is to keep playing around with the constraints of the view or the views that cause the issues, until you manage to silence all warnings or errors.

    gt8_17_outline_warning
    gt8_18_autolayout_suggestions

    As a piece of advice, I recommend that when you use the Update Constraints, Add Missing Constraints, or Reset to Suggested Constraints options to let Xcode automatically setup all the constraints you don’t need to manually touch. Those options can be found either in the menu Editor > Resolve Auto Layout Issues or in the respective button that appears at the bottom-right side of the drawing area of the Interface Builder.

    gt8_19_autolayout_buttons

    4. Asset Catalog

    Asset Catalog is another new feature of Xcode 5 with dual purpose:

    1. To put all of your images together and let you keep them in one place.
    2. To relieve you of the need to remember all naming conventions required for app icons and launch images.

    With Asset Catalog you don’t have to remember the rules that applies to app icon or launch image naming. Assets with these kind of images can now have any name you like. Xcode accepts everything and automatically gives the proper name to them. Also, Asset Catalog consists of the best place to have your images together and to access all of them at once when it’s necessary.

    Asset Catalog is represented as a group with a blue folder icon among the list of your groups and files on the Project Navigator.

    gt8_20_asset_catalog

    Note: If you create a new iOS 7 application project on Xcode, the Asset Catalog is in its place. However, if you move an existing project to iOS 7, then you need to create the Asset Catalog on your own. This is easy to do. In the General tab of your project, inside the App Icons section there is a button with title Use Asset Catalog. Click on it and the catalog forms.

    If you click on the Asset Catalog icon on the Project Navigator, you’ll see a series of empty slots waiting to accept the icons of the application. The Asset Catalog feature displays slots for all the target devices you set in your project. To add an app icon, you can simply drag and drop one from a directory on your computer to the appropriate slot. The same rule applies to the launch images too, where there are empty slots for all the devices and supported orientation you have in the project options. Once again I’ll remind you that app icons and launch images can have any name you like; Xcode sets the appropriate ones automatically.

    gt8_21_slots

    Any other images you want to add to an application can be easily put in the Asset Catalog, simply by dragging and dropping them in there. If there are already images in your project, here is the quickest way to move them from the Project Navigator into the Asset Catalog:

    1. Click on the Plus button that resides at the bottom-left corner on the left pane of the Asset Catalog.
    2. Click on the Import from project… option.
    3. Select the images you want on the window that shows up (if they are not selected already) and then click on the Import button.

    Once the images are imported or added directly from your computer, you’ll notice that inside the Asset Catalog there is one record for every image. If you click on any of them, you’ll see that there are two slots associated with it. The first accepts the normal resolution image (1x) and the second accepts the retina display resolution image (2x).


    5. Debugger

    Debugging on Xcode 5 offers a new experience to developers, as new features were added to the debugger. Tracking down variable values is easier. Previewing images, documents, and other objects is now just a matter of a single click, and great flexibility occurs when working with breakpoints. The debugger on Xcode 5 is based on the LLDB engine, which totally replaced the gdb engine. LLDB is more powerful and underlies all the new debugging features. So, let’s take a look at the improvements.

    The first great visual improvement exists on data tips. A data tip displays a variable’s value during debugging, when the mouse pointer hovers over the variable. For simple data type variables, the data tip shows simply the value, just like in the following figure:

    gt8_22_simple_datatip

    Regarding objects, data tips provide summary information for every object that hovers, but the biggest change is that more than text can be displayed now. Images, text documents, bezier curves, and more can be previewed on Xcode during debugging, so it’s easier for developers to examine their objects and be assured about their contents. The data and graphic combination gives super flexibility when trying to find bugs, as both single variables and objects can be previewed at once. This is a great feature that reduces debugging time! Take a look now at the next image to see an example:

    gt8_23_image_datatip

    Next to each object that you can preview, just like in the previous image, an eye and an info buttons are displayed. You can preview (Quick Look functionality) the selected object by clicking on the eye button. Also you can see detailed information by clicking on the info button.

    gt8_24_datatip_buttons

    Apart from the data tips, breakpoints were improved as well. If you previously debugged a project, then you know that breakpoints can be set simply by clicking at the left side of the lines where you want them to be. Breakpoints can be enabled or disabled either by clicking on each one of them, or by using the breakpoints button. With Xcode 5 this doesn’t exist any more on the top toolbar, but it’s been moved to the debug toolbar at the bottom of the Xcode window. Using this button, you can toggle all breakpoints at once. Enabled breakpoints are displayed in blue, and disabled breakpoints are displayed in grey. To completely remove a break point, right click on it and select the Delete Breakpoint option.

    On Xcode 5 breakpoints conditionally work. Furthermore, actions attach to them when a condition is satisfied. That way, developers don’t have to set and unset breakpoints all the time, they just need to add conditions or select breakpoints to ignore for certain times and focus more on debugging. The provided actions that are available and can attach to a break point when a condition is met are listed below:

    • AppleScript
    • Capture OpenGL ES frame
    • Debugger Command
    • Log Message
    • Shell Command
    • Sound

    More than one action can be set to breakpoints when conditions are satisfied. For example, you may log a message and at the same time play a sound that notifies you on the break points condition. Here is an example:

    gt8_25_breakpoint

    So, when using these new features, debugging becomes much easier. Buggy code can be tracked down faster and wasted time can now be saved and given to other tasks. In combination with the next brand new feature, debugging becomes a whole new experience!


    6. Debug Gauges

    A long time ago, when system resources (such as CPU and memory) were limited in a computer system, programmers had to spend a great deal of time making sure their programs work using as few resources as possible. That was a hard task, but it was the best way to ensure that no memory leaks existed or pointless CPU usage occurred. Today, with the new powerful and fast sub-systems that devices use, it’s quite common for developers to ignore any leaks their applications cause, because they simply see their apps running fairly fast on modern devices. However resources are always limited, and by ignoring them, a potential application crash would definitely lead to a bad user experience.

    Here is where Debug Gauges make their debut, coming as auxiliary debugging tools that let developers track down unwanted usage of system resources. Actually, Debug Gauges consist of a lightweight version of some Instruments tools, they are embedded into Xcode (no need to open in new window like Instruments) and, above all, they can run all the time along with the application during debugging. Gauges allow you to observe the following resources:

    • CPU
    • Memory
    • Energy
    • iCloud
    • OpenGL ES

    Debug Gauges are accessible through the Debug Navigator, and they appear when an application runs. The big, graphic elements represent every resource that’s watched, so it’s simple to use them.

    gt8_26_debug_navigator

    Of course, for a thorough and detailed profiling of your application, you can use Instruments any time you need. A button which you can click to open Instruments at once is always at the top-right side of the gauges window. When an app runs, you can click from gauge to gauge and watch all measurements taking place in real time. If you notice any abnormal behavior, then you may suspect that something is wrong in your code and needs to be fixed.

    gt8_27_gauge

    You are encouraged to use these tools as much as possible in order to notice and fix bugs.


    7. Testing and Bots

    Testing is an important part in the development process, and special care should always be given to it. Thankfully with Xcode 5 testing applications is a lot easier. Particularly with the new Test Navigator. Test Navigator can be found on the navigator pane, and it lists all tests that you create.

    gt8_28_test_navigator

    Through navigator, tests can easily be edited, ran, or deleted. Next to each test its current state is displayed, whether it has succeeded, failed, or not yet ran. Great flexibility was also given to the way that tests run. So you can initiate a single test, select a bunch of them, or let them run simultaneously.

    A new unit test framework was introduced on Xcode 5, the XCTest, which exists in parallel with the previous framework, the OCUnit. However, the first one will dominate the future. Therefore, it is recommended to use the XCTest in your projects. By default, new projects use this framework. Also, in Xcode 5, the tested code and the test itself can be placed side by side using the Assistant Editor. That way, you can watch both the code and test details while it’s running.

    Bots are a completely new feature on Xcode 5. A bot is a service, which repeatedly does a series of tasks, such as building, testing, analyzing, archiving, and signing an application (tasks that traditionally would be done manually by developers). These series of tasks are called integration process. With bots, the integration process is automatic and can continue for as long as needed.

    What makes bots special is that instead of running tests on the local computer, they can move those tests into a server and perform the integration process there. That way, computers used for development are not charged with test execution duties, and moreover, test results can be shared to all the developing team at once. In addition, bots can run multiple tests for multiple applications on devices attached to the server.

    Bots can be configured to work in two ways. According to the first way, bots perform the integration process on code that is taken from a source control system like Git. When new changes are available, bots start the integration process over and keep going until the app has been completed and no more testing is needed. These bots are called continuous. The second way is that the integration process repeats as soon as possible. Bots that are configured to work in this manner are called nightly or periodic bots, and they sign and archive the app on every reproduction step, with one more result, to keep track of history during time.

    For developing teams, bots consist of a great way to run tests and share the results. Also, through the extensive testing that is performed due to the continuous integration process, finding bugs and errors is much easier, while at the same time due to the nature of testings, bugs can be isolated or located in regard to specific hardware or other settings. Bots are a tremendous leap for Xcode!


    8. Compiler Improvements

    Until now, all new Xcode 5 features were presented one by one, but this tutorial wouldn’t be complete if no reference was made to improvements under the surface. So, let’s have a brief tour of the major changes and additions made to the compiler.

    First of all, until version 4.6, Xcode supported two compilers: Apple LLVM and LLVM-GCC 4.2. On Xcode 5, the latter is gone, and only Apple LLVM remains, empowered with new features that make it even more useful.

    LLVM compiler introduces the logic of Modules. But before explaining what a module is, let’s see in short the problem that it counterattacks. When a compiler parses a file, it doesn’t parse just the code existing into that file, but it also does that for all the header files that are imported (using the #import command) to the file. This process works recursively, and all files imported are finally parsed until the last line of code. This means that instead of parsing only the lines of code existing in the initial file, thousands more lines have to be parsed due to the continuing imports. This is not a new problem and modules came to provide a solution. A module is a simple, optimized database which keeps the parsed code of a single system header file (for example UIKit.h, Webkit.h, etc.) within. Compiler builds a set of such modules, and when it’s time to parse our own file, it doesn’t have to parse the header files again. Taking into account that the same files are imported again and again multiple times, it becomes obvious that modules give great performance on compile. Moreover, Xcode itself uses modules to achieve some of its advanced features, such as syntax, highlighting, and auto-completion.

    Another new feature of the compiler is the Auto-vectorizer, which was added clearly for performance reasons. Its job is to analyze code and find segments, where two or more operations (up to 32) can run at the same time. That’s because the new, modern CPUs offer great vector features for virtual multi-threading, and Autovectorizer takes advantage of this. In applications where intensive calculations are required, this feature can truly boost performance, depending on the type of calculations.

    The compiler can now read the code documentation and produce help tips, just like it does with the built-in documentation. So, the more you document your code, the more detailed help is provided for it by Xcode. This features makes much more sense in case you use custom code from other developers. Here is an example of the help provided for custom code documentation:

    gt8_29_comments

    Finally, regarding the compiler, there are a couple of points about the static analyzer feature that should be mentioned. Static analyzer was improved and it now can do deeper code analysis to help you find more bugs. But what actually makes developers happy is the new feature that allows the user to perform static analysis on a single file, or even build a single file, instead of analyzing the whole project over and over again. That’s a great improvement and lets you focus just on the file you are working on.


    Conclusion

    Xcode 5 is a developer’s dream because it helps the user build a bug-free and extensively tested application. It’s not hard to adopt all the changes, and once you do it you’ll love them. If you haven’t moved to the latest version yet, then I strongly encourage you to do so and enjoy all of Xcode’s new features. As far as Xcode 5 is concerned, keep exploring and you will be rewarded!

    Viewing all 1836 articles
    Browse latest View live