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.


To run this quickstart, you'll need:

  • Xcode 8.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. Use this wizard to create a new app or select an existing one.
  2. Enter "com.example.QuickstartApp" into the field iOS Bundle ID and click the Continue button.
  3. Click the Google Sign-In icon and then click the Enable Google Sign-in button. Click the Continue button.
  4. Click the Download GoogleService-Info.plist button to download the configuration file. Take note of where you saved it. Click the Enable the Google Apps Script Execution API button.
  5. Use the dropdown menu to select the same project you use in the previous wizard and click the Continue button.
  6. Close the wizard.

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 Identifier 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, '8.0'
    target 'QuickstartApp' do
        pod 'GoogleAPIClientForREST/Script', '~> 1.2.1'
        pod 'Google/SignIn', '~> 3.0.3'
    pod install &&
    open QuickstartApp.xcworkspace

  5. In the XCode Project Navigator select the project node "QuickstartApp" and click the menu item File > Add files to "QuickstartApp".

  6. Locate the GoogleService-Info.plist file downloaded earlier and select it. Click the Options button and ensure that Copy items if needed and all the targets are checked. Click the Add button.
  7. With the project node still selected, select "QuickstartApp" in the TARGETS section, then select the Info tab, and expand the URL Types section.
  8. Click the + button, and add a URL scheme for your reversed client ID. To find this value, open the GoogleService-Info.plist configuration file, and look for the REVERSED_CLIENT_ID key. Copy the value of that key, and paste it into the URL Schemes box on the configuration page. Leave the other fields blank.
  9. Rebuild the project by clicking Product > Clean Build Folder (while holding the option key) and Product > Build.

Step 3: Set up the sample

Replace the contents of the following files with the code provided:

#import <UIKit/UIKit.h>
#import <Google/SignIn.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

#import "AppDelegate.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSError* configureError;
    [[GGLContext sharedInstance] configureWithError: &configureError];
    NSAssert(!configureError, @"Error configuring Google services: %@", configureError);

    return YES;

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    return [[GIDSignIn sharedInstance] handleURL:url

#import <UIKit/UIKit.h>
#import <Google/SignIn.h>
#import <GTLRScript.h>

@interface ViewController : UIViewController <GIDSignInDelegate, GIDSignInUIDelegate>

@property (nonatomic, strong) IBOutlet GIDSignInButton *signInButton;
@property (nonatomic, strong) UITextView *output;
@property (nonatomic, strong) GTLRScriptService *service;

#import "ViewController.h"

static NSString *const kScriptID = @"ENTER_YOUR_SCRIPT_ID_HERE";

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Configure Google Sign-in.
    GIDSignIn* signIn = [GIDSignIn sharedInstance];
    signIn.delegate = self;
    signIn.uiDelegate = self;
    signIn.scopes = [NSArray arrayWithObjects:kGTLRAuthScopeScriptDrive, nil];
    [signIn signInSilently];

    // Add the sign-in button.
    self.signInButton = [[GIDSignInButton alloc] init];
    [self.view addSubview:self.signInButton];

    // 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.output.hidden = true;
    [self.view addSubview:self.output];

    // Initialize the service object.
    self.service = [[GTLRScriptService alloc] init];

- (void)signIn:(GIDSignIn *)signIn
didSignInForUser:(GIDGoogleUser *)user
     withError:(NSError *)error {
    if (error != nil) {
        [self showAlert:@"Authentication Error" message:error.localizedDescription];
        self.service.authorizer = nil;
    } else {
        self.signInButton.hidden = true;
        self.output.hidden = false;
        self.service.authorizer = user.authentication.fetcherAuthorizer;
        [self callAppsScript];

// Calls an Apps Script function to list the folders in the user's
// root Drive folder.
- (void)callAppsScript {
    // Create an execution request object.
    GTLRScript_ExecutionRequest *request = [GTLRScript_ExecutionRequest new];
    request.function = @"getFoldersUnderRoot";

    // Make the API request.
    GTLRScriptQuery_ScriptsRun *query =
    [GTLRScriptQuery_ScriptsRun queryWithObject:request
    [self.service executeQuery:query

// Displays the retrieved folders returned by the Apps Script function.
- (void)displayResultWithTicket:(GTLRServiceTicket *)ticket
                     finishedWithObject:(GTLRScript_Operation *) response
                                  error:(NSError *)error {
    if (error == nil) {
        NSMutableString *output = [[NSMutableString alloc] init];
        if (response.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).
            GTLRScript_Status_Details_Item *err = response.error.details[0];
            [output appendFormat:@"Script error message: %@\n",
             [err JSONValueForKey:@"errorMessage"]];

            if ([err JSONValueForKey:@"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 JSONValueForKey:@"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 = [response.response JSONValueForKey:@"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],
        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",
        [self showAlert:@"Error" message:message];

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

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.


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

Further reading


Apps Script
Apps Script