iOS Quickstart

Complete the steps described in the rest of this page, and in about five minutes you'll have a simple iOS application that makes requests to the Google Apps Script Execution API.

Prerequisites

To run this quickstart, you'll need:

  • Xcode 7.0 or greater.
  • CocoaPods dependency manager.
  • Access to the internet and a web browser.
  • A Google account with Google Drive enabled.
  • A target Apps Script to call with the API.

Step 1: Turn on the Google Apps Script Execution API

  1. Open your target Apps Script in the editor and select Resources > Developers Console Project.
  2. In the dialog that opens, click on the blue link (that starts with your script's name) at the top to open the console project associated with your script.
  3. The left sidebar should say API Manager. If it does not, click the icon in the upper-left to open a side panel and select API Manager. Select Library in the left sidebar.
  4. In the search bar under the Google APIs tab, enter "Google Apps Script Execution API". Click the same name in the list that appears. In the new tab that opens, click Enable API.
  5. Click Credentials in the left sidebar.
  6. Select the Credentials tab, click the Create credentials button and select OAuth client ID.
  7. Select the application type iOS, enter the name "Google Apps Script Execution API Quickstart", bundle ID com.example.QuickstartApp, and click the Create button.
  8. Take note of the client ID in the resulting dialog. You will need it in a later step.

Step 2: Prepare the workspace

  1. Open Xcode and create a new project:
    1. Click File > New > Project, select the iOS > Application > Single View Application template, and click Next.
    2. Set the Product Name to "QuickstartApp", Organization Name to "com.example", and Language to Objective-C. Click Next.
    3. Select a destination directory for the project and click Create.
  2. Close the project by clicking File > Close Project.
  3. Open a Terminal window and navigate to the directory that contains the QuickstartApp.xcodeproj file you just created.
  4. Run the following commands to create the Podfile, install the library, and open the resulting XCode project:

    cat << EOF > Podfile &&
    platform :ios, '7.0'
    target 'QuickstartApp' do
        pod 'GoogleAPIClient/Core', '~> 1.0.2'
        pod 'GTMOAuth2', '~> 1.1.0'
    end
    EOF
    pod install &&
    open QuickstartApp.xcworkspace
    

Step 3: Set up the sample

Replace the contents of the ViewController.h file with the following code:

#import <UIKit/UIKit.h>

#import "GTMOAuth2ViewControllerTouch.h"
#import "GTLService.h"

@interface ViewController : UIViewController

@property (nonatomic, strong) GTLService *service;
@property (nonatomic, strong) UITextView *output;

@end

Replace the contents of ViewController.m with the following code:

#import "ViewController.h"

static NSString *const kKeychainItemName = @"Google Apps Script Execution API";
static NSString *const kClientID = @"YOUR_CLIENT_ID_HERE";
static NSString *const kScriptID = @"ENTER_YOUR_SCRIPT_ID_HERE";
@implementation ViewController

@synthesize service = _service;
@synthesize output = _output;

// When the view loads, create necessary subviews, and initialize the Google Apps Script Execution API service.
- (void)viewDidLoad {
  [super viewDidLoad];

  // Create a UITextView to display output.
  self.output = [[UITextView alloc] initWithFrame:self.view.bounds];
  self.output.editable = false;
  self.output.contentInset = UIEdgeInsetsMake(20.0, 0.0, 20.0, 0.0);
  self.output.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
  [self.view addSubview:self.output];

  // Initialize the Google Apps Script Execution API service & load existing credentials from the keychain if available.
  self.service = [[GTLService alloc] init];
  self.service.authorizer =
  [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName
                                                        clientID:kClientID
                                                    clientSecret:nil];
}

// When the view appears, ensure that the Google Apps Script Execution API service is authorized, and perform API calls.
- (void)viewDidAppear:(BOOL)animated {
  if (!self.service.authorizer.canAuthorize) {
    // Not yet authorized, request authorization by pushing the login UI onto the UI stack.
    [self presentViewController:[self createAuthController] animated:YES completion:nil];

  } else {
    [self callAppsScript];
  }
}

// Calls an Apps Script function to list the folders in the user's
// root Drive folder.
- (void)callAppsScript {
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://script.googleapis.com/v1/scripts/%@:run",
                                       kScriptID]];
    // Create an execution request object.
    GTLObject *request = [[GTLObject alloc] init];
    [request setJSONValue:@"getFoldersUnderRoot" forKey:@"function"];

    // Make the API request.
    [self.service fetchObjectByInsertingObject:request
                                        forURL:url
                                      delegate:self
                             didFinishSelector:@selector(displayFoldersWithServiceTicket:finishedWithObject:error:)];
}

// Displays the retrieved folders returned by the Apps Script function.
- (void)displayFoldersWithServiceTicket:(GTLServiceTicket *)ticket
                     finishedWithObject:(GTLObject *)object
                                  error:(NSError *)error {
    if (error == nil) {
        NSMutableString *output = [[NSMutableString alloc] init];
        if ([object.JSON objectForKey:@"error"] != nil) {
            // The API executed, but the script returned an error.

            // Extract the first (and only) set of error details and cast as a
            // NSDictionary. The values of this dictionary are the script's
            // 'errorMessage' and 'errorType', and an array of stack trace
            // elements (which also need to be cast as NSDictionaries).
            NSDictionary *err =
                [[object.JSON objectForKey:@"error"] objectForKey:@"details"][0];
            [output appendFormat:@"Script error message: %@\n",
                                [err objectForKey:@"errorMessage"]];

            if ([err objectForKey:@"scriptStackTraceElements"]) {
                // There may not be a stacktrace if the script didn't start
                // executing.
                [output appendString:@"Script error stacktrace:\n"];
                for (NSDictionary *trace in [err objectForKey:@"scriptStackTraceElements"]) {
                    [output appendFormat:@"\t%@: %@\n",
                                        [trace objectForKey:@"function"],
                                        [trace objectForKey:@"lineNumber"]];
                }
            }

        } else {
            // The result provided by the API needs to be cast into the correct
            // type, based upon what types the Apps Script function returns.
            // Here, the function returns an Apps Script Object with String keys
            // and values, so must be cast into a NSDictionary (folderSet).
            NSDictionary *folderSet =
                [[object.JSON objectForKey:@"response"] objectForKey:@"result"];
            if (folderSet == nil) {
                [output appendString:@"No folders returned!\n"];
            } else {
                [output appendString:@"Folders under your root folder:\n"];
                for (id folderId in folderSet) {
                    [output appendFormat:@"\t%@ (%@)\n",
                                        [folderSet objectForKey:folderId],
                                        folderId];
                }
            }
        }
        self.output.text = output;
    } else {
        // The API encountered a problem before the script started executing.
        NSMutableString *message = [[NSMutableString alloc] init];
        [message appendFormat:@"The API returned an error: %@\n",
                                error.localizedDescription];
        [self showAlert:@"Error" message:message];
    }
}

// Creates the auth controller for authorizing access to Google Apps Script Execution API.
- (GTMOAuth2ViewControllerTouch *)createAuthController {
  GTMOAuth2ViewControllerTouch *authController;
  // If modifying these scopes, delete your previously saved credentials by
  // resetting the iOS simulator or uninstall the app.
  NSArray *scopes = [NSArray arrayWithObjects:@"https://www.googleapis.com/auth/drive", nil];
  authController = [[GTMOAuth2ViewControllerTouch alloc]
           initWithScope:[scopes componentsJoinedByString:@" "]
                clientID:kClientID
            clientSecret:nil
        keychainItemName:kKeychainItemName
                delegate:self
        finishedSelector:@selector(viewController:finishedWithAuth:error:)];
  return authController;
}

// Handle completion of the authorization process, and update the Google Apps Script Execution API
// with the new credentials.
- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
      finishedWithAuth:(GTMOAuth2Authentication *)authResult
                 error:(NSError *)error {
  if (error != nil) {
    [self showAlert:@"Authentication Error" message:error.localizedDescription];
    self.service.authorizer = nil;
  }
  else {
    self.service.authorizer = authResult;
    [self dismissViewControllerAnimated:YES completion:nil];
  }
}

// Helper for showing an alert
- (void)showAlert:(NSString *)title message:(NSString *)message {
    UIAlertController *alert =
        [UIAlertController alertControllerWithTitle:title
                                            message:message
                                     preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *ok =
        [UIAlertAction actionWithTitle:@"OK"
                                 style:UIAlertActionStyleDefault
                               handler:^(UIAlertAction * action)
                               {
                                   [alert dismissViewControllerAnimated:YES completion:nil];
                               }];
    [alert addAction:ok];
    [self presentViewController:alert animated:YES completion:nil];

}

@end

Replace the placeholder YOUR_CLIENT_ID_HERE in the copied code with the client ID you generated in Step 1. Be sure to also replace the placeholder ENTER_YOUR_SCRIPT_ID_HERE with the script ID of your target script.

Step 4: Run the sample

Switch to the scheme QuickstartApp and run the sample (Cmd+R) using the device simulator or a configured device. The first time you run the sample, it will prompt you to log in to your Google account and authorize access.

Notes

  • Authorization information is stored in your Keychain, so subsequent executions will not prompt for authorization.

Further reading

Send feedback about...

Apps Script
Apps Script