Google APIs Client Library for Objective-C

repository·main·Indexed 21 days ago

https://github.com/google/google-api-objectivec-client-for-rest

A flexible and efficient Objective-C framework for accessing JSON-based Google APIs, recommended for Apple platforms including iOS, macOS, tvOS, and watchOS. The library provides pre-generated classes for many Google services and includes a ServiceGenerator tool to create custom interfaces from discovery documents. It supports integration via CocoaPods and Swift Package Manager, utilizing GTLRService, GTLRQuery, and GTLRObject as its core class hierarchy.

Tokens
7.3K
Snippets
24
Records
33
Agent score
75%

What's inside google-api-objectivec-client-for-rest

  1. Overview of Google APIs Client Library for Objective-C

    main
    The Google APIs Client Library for Objective-C is a flexible and efficient framework designed for accessing JSON-based Google APIs. It is the recommended library for iOS, macOS, tvOS, and watchOS applications. The library provides pre-generated classes for many Google services and is built on top of the GTM Session Fetcher project. For XML-based APIs, developers should use the older gdata-objectivec-client library instead.
  2. Understand Objects and Queries in GTLR

    main

    The library maps Google API responses to Objective-C objects.

    • GTLRObject: The base class for individual items returned by the server. It acts as a wrapper for JSON data, allowing you to access JSON fields using standard Objective-C property notation (e.g., item.snippet.title).
    • GTLRCollectionObject: A subclass of GTLRObject used for collections (lists of items). It provides indexed access via subscripts and supports for loops via the NSFastEnumeration protocol.
    • Query: Represents a single request to the server. Each API method has a unique query class.
    • Service: The object used to execute queries. It manages persistent data like cookies and should ideally be reused throughout the app for performance.
    • Service Ticket: A GTLRServiceTicket is returned when executing a query. It allows you to monitor or cancel the ongoing request.
    ```Objective-C
    // Example of iterating over a collection object
    GTLRYouTube_PlaylistItemListResponse *playlistItemList = ...;
    for (GTLRYouTube_PlaylistItem *item in playlistItemList) {
      NSLog(@
  3. Optimize performance with Partial Responses

    main

    To avoid fetching unnecessary data, use the fields property on a query to select only the specific fields required. This uses a syntax similar to XPath.

    Important Considerations:

    • Include kind fields: Always include the kind field for both items and collections in your fields string. The library uses this to correctly instantiate the proper object classes; omitting it may cause the library to incorrectly use the GTLRObject base class.
    • Include nextPageToken: For collection queries, include nextPageToken if you need to handle pagination.
    • Discover fields: Use the fieldsDescription method on a GTLRObject to get a string describing all set fields, which can serve as a template for your query's fields property.
    // Example: Requesting only IDs, author emails, and kind for items, plus collection metadata
    query.fields = @"items(id,author/email,kind),kind,nextPageToken";
  4. Configure Authentication and Authorization

    main

    The library handles Authorization by allowing you to pass an OAuth 2 authorization object to a service class's setAuthorizer: method.

    Important Notes:

    • Authentication Support: The library itself (and its CocoaPods/SwiftPM distributions) does not include authentication support. To handle user sign-in, you must use an external library such as GTMAppAuth or the Google Sign-In SDK.
    • OAuth 2 Protocol: The GTMSessionFetcher library provides an Objective-C protocol for OAuth 2; any library supporting this protocol can be used.
    • Podspec Clarification: The Oauth2 subspec in CocoaPods is intended for interacting with that specific service directly, not for providing the general authentication mechanism for the library.
  5. Add custom data to GTLRObjects

    main

    You can attach local, non-server-side data to GTLRObject instances using two methods:

    1. User Properties

    Use the userProperties dictionary to store arbitrary key-value pairs. This data is local to your Objective-C code and is not sent to the server or included in NSKeyedArchiver serialization.

    GTLRDrive_File *file = [GTLRDrive_File object];
    file.userProperties = @{ @"LocalFileURL" : fileLocalURL };

    2. Subclassing with an Object Class Resolver

    To have your custom subclasses instantiated instead of standard classes during JSON parsing, configure the service's objectClassResolver with a map of kind strings to your surrogate classes.

    Service-wide configuration:

    GTLRDriveService *service = [[GTLRDriveService alloc] init];
    NSDictionary *surrogates = @{
      [GTLRDrive_File class] : [MyFile class],
      [GTLRDrive_FileList class] : [MyFileList class]
    };
    NSDictionary *serviceKindMap = [[service class] kindStringToClassMap];
    GTLRObjectClassResolver *updatedResolver = [GTLRObjectClassResolver resolverWithKindMap:serviceKindMap
                                                                                   surrogates:surrogates];
    service.objectClassResolver = updatedResolver;

    Single query configuration:

    GTLRDriveQuery_FilesList *query = [GTLRDriveQuery_FilesList query];
    query.executionParameters.objectClassResolver = updatedResolver;
  6. Execute Batch Operations

    main

    Batching allows you to execute multiple unrelated queries in a single request, which is faster than individual executions. You can obtain results using two different patterns:

    1. Individual Query Completion Blocks

    Best for unrelated methods (e.g., requesting different attributes of a single item). You assign a completionBlock to each query before adding it to the batch.

    Error Handling: If a specific query within a batch fails but the batch execution itself succeeds, the error passed to the individual completion block will contain a GTLRErrorObject accessible via [GTLRErrorObject underlyingObjectForError:error].

    2. Unified Batch Completion Handler

    Best for batches of related methods (e.g., requesting the same attributes for an array of items). The handler receives a GTLRBatchResult containing two dictionaries: successes and failures.

    Important:

    • Each query must have a unique, non-empty requestID. You can set a custom ID on the query object before execution.
    • Individual completion blocks (if provided) are always called before the unified batch completion handler.
    // Example: Using Individual Completion Blocks
    GTLRCalendarQuery_EventsList *eventsQuery = [GTLRCalendarQuery_EventsList queryWithCalendarId:calendarID];
    eventsQuery.completionBlock = ^(GTLRServiceTicket *callbackTicket, GTLRCalendar_Events *events, NSError *callbackError) {
      if (callbackError == nil) {
        // Query succeeded
      }
    };
    
    GTLRBatchQuery *batch = [GTLRBatchQuery batchQuery];
    [batch addQuery:eventsQuery];
    
    // Example: Using Unified Batch Completion Handler
    GTLRBatchQuery *batchQuery = [GTLRBatchQuery batchQuery];
    [batchQuery addQuery:query1];
    [batchQuery addQuery:query2];
    
    [service executeQuery:batchQuery completionHandler:^(GTLRServiceTicket *callbackTicket, GTLRBatchResult *batchResult, NSError *callbackError) {
      if (callbackError == nil) {
        // Step through successes
        NSDictionary *successes = batchResult.successes;
        for (NSString *requestID in successes) {
          GTLRObject *result = [successes objectForKey:requestID];
        }
    
        // Step through failures
        NSDictionary *failures = batchResult.failures;
        for (NSString *requestID in failures) {
          GTLRErrorObject *errorObj = [failures objectForKey:requestID];
        }
      } else {
        // The entire batch execution failed
      }
    }];
  7. Set up development with CocoaPods

    main

    To develop using CocoaPods, ensure you have CocoaPods 1.12.0 or later installed, along with the cocoapods-generate plugin.

    Generate an Xcode project from the podspec using the following command:

    pod gen GoogleAPIClientForREST.podspec --local-sources=./ --auto-open --platforms=ios

    Note: You can change the --platforms option to macos, tvos, or watchos to target different Apple platforms.

    pod gen GoogleAPIClientForREST.podspec --local-sources=./ --auto-open --platforms=ios
  8. Add the Google APIs Client Library to a project via Swift Package Manager

    main

    To integrate using Swift Package Manager (SwiftPM), use the GoogleAPIClientForRESTCore product for the common library parts, and specific products for each service API.

    For example, to use the Drive API, depend on the GoogleAPIClientForREST_Drive product.

    If you are generating code for your own custom APIs, add GoogleAPIClientForRESTCore to get the supporting runtime, then manually add your generated source files to your Xcode project.

    GoogleAPIClientForREST_Drive
  9. Update Sources/GeneratedServices

    main

    The Sources/GeneratedServices directory is updated periodically to reflect the current state of services.

    Standard Generation

    Run the following script to update the services:

    Tools/GenerateCheckedInServices

    If a service has issues (e.g., a discovery document is missing or malformed), use the --skip [name] argument to ignore that specific service.

    Generation from Discovery Artifact Manager

    To avoid networking issues, you can generate services from a local checkout of the googleapis/discovery-artifact-manager repository. Use Tools/preferred_paths_from_cache.py to determine the preferred paths. This script also supports a --skip argument.

    Example workflow: If discovery-artifact-manager is checked out as a sibling directory, use this command to generate services while skipping specific problematic paths and explicitly including required admin services:

    Tools/GenerateCheckedInServices \
      --no-preferred \
      `Tools/preferred_paths_from_cache.py --skip poly ../discovery-artifact-manager/discoveries` \
      ../discovery-artifact-manager/discoveries/admin.directory_v1.json \
      ../discovery-artifact-manager/discoveries/admin.datatransfer_v1.json
    Tools/GenerateCheckedInServices
  10. Perform Partial Updates with Patch Queries

    main

    Instead of replacing an entire item, use a patch query to update only specific fields.

    Key behaviors:

    • Patching fields: Create a new object containing only the fields you wish to change and pass it to a patch query (e.g., GTLRCalendarQuery_CalendarsPatch).
    • Deleting fields: To delete a field, set its value to [GTLRObject nullValue] in the patch object.
    • Arrays: Note that providing an array in a patch object replaces the entire array on the server; it does not perform a partial array update.
    • Helper method: Use patchObjectFromOriginal: on a GTLRObject to automatically generate a patch object containing only the differences between the original and a modified version.
    // Example: Updating only the name of a calendar
    GTLRCalendar_Calendar *patchObject = [GTLRCalendar_Calendar object];
    patchObject.summary = newCalendarName;
    
    GTLRCalendarQuery_CalendarsPatch *query = [GTLRCalendarQuery_CalendarsPatch queryWithObject:patchObject calendarId:calendarID];
    [service executeQuery:query ...]
    
    // Example: Deleting the location field
    GTLRCalendar_Calendar *deleteLocationObject = [GTLRCalendar_Calendar object];
    deleteLocationObject.location = [GTLRObject nullValue];
    
    GTLRCalendarQuery_CalendarsPatch *deleteQuery = [GTLRCalendarQuery_CalendarsPatch queryWithObject:deleteLocationObject calendarId:calendarID];
    [service executeQuery:deleteQuery ...]
  11. Release a new version

    main

    Follow these steps to release a new version of the library:

    1. Update Version Number: Use the update_version.py script to update all necessary files. The version must be in X.Y.Z format.
      ./update_version.py 3.2.1
    2. Submit Changes: Commit and push the version updates to the repository.
    3. Create GitHub Release:
      • Go to the project's release page and select Draft a new release.
      • Use a tag in the format vX.Y.Z (e.g., v3.2.1) that exactly matches the version provided to the update script.
      • Use the Generate release notes button to assist with the description.
    4. Publish CocoaPod: Push the podspec to the trunk. Note that validations and tests are skipped locally because they are handled by CI and can be extremely slow on local machines.
      pod trunk push --skip-import-validation --skip-tests GoogleAPIClientForREST.podspec
    ./update_version.py 3.2.1