2011-12-30 40 views
5

Có bất kỳ tài liệu google tích hợp nào vào ứng dụng iOS của họ không? Sau khi đã trải qua mã ví dụ, API cho Google Documents phức tạp hơn nhiều so với dự kiến ​​của tôi và các ví dụ là tất cả các hệ điều hành MacOS. Có hỗ trợ iOS, nhưng có một thiếu riêng biệt của mã ví dụ về cách sử dụng nó, và tài liệu là hơi thiếu.Trình bao bọc đối tượng iOS-C cho Google Documents

Tôi đã tìm thấy một lớp giao diện trên web, nhưng nó dựa trên phiên bản cũ hơn, không dùng nữa của API Google Documents và nó không biên dịch với XCode 4.2.

Những gì tôi là sau khi có một giao diện chuyển tiếp tương đối thẳng cho phép:

  1. Logging in/out từ một tài liệu google tài khoản.
  2. Lấy danh sách tài liệu trong tài khoản đó (tùy chọn một loại cụ thể), có thể với khả năng điều hướng cấu trúc thư mục.
  3. Có thể tải xuống tài liệu cụ thể về bộ nhớ cục bộ.
  4. Có thể tải tài liệu cụ thể lên tài liệu google.

Tôi đã bắt đầu viết một giao diện như vậy, nhưng cho đến nay nó có liên quan nhiều hơn tôi đã cho phép. Nếu bất cứ ai có bất cứ đề nghị, hoặc mẫu mà họ có thể hướng dẫn tôi đến, tôi thực sự đánh giá cao nó.

Tùy chọn của tôi là cho trình bao bọc là hệ điều hành trung tính; có nghĩa là tôi muốn có thể sử dụng cùng một giao diện trong cả MacOS và iOS. Một lần nữa, đây là những gì tôi đã bắt đầu viết, nhưng tôi không thể không cảm thấy rằng tôi phải tái phát minh bánh xe ở đây.

Cảm ơn

+0

+1, google có mã nguồn khủng khiếp. – CodaFi

+0

Và nó dường như theo hướng dẫn phong cách ... – PKCLsoft

Trả lời

4

OK, vì vậy trong sự vắng mặt của bất kỳ câu trả lời từ những người khác, tôi cắn đạn và viết một wrapper bản thân mình.

Tôi hiện có trình bao bọc đơn hoạt động cho cả Mac OS và iOS giúp đơn giản hóa đáng kể giao diện bằng Google Tài liệu.

Dưới đây là tất cả mã cho giao diện thực tế. Tôi nên chỉ ra rằng lớp này hoạt động như một singleton và bạn cần phải tùy chỉnh nó một chút cho từng dự án bằng cách cập nhật các dòng:

#define GOOGLE_DATA_CLIENT_ID @"<client id>.apps.googleusercontent.com" 
#define GOOGLE_DATA_SECRET @"<google data secret>" 
#define GOOGLE_DATA_USERNAME @"googleDocsUsername" 
#define GOOGLE_DATA_PASSWORD @"googleDocsPassword" 

với các giá trị thích hợp bạn nhận được từ Google.

Tôi cũng chỉ ra rằng lớp lưu trữ mật khẩu qua NSUserDefaults và sử dụng một lớp tiện ích riêng biệt để thực hiện việc này theo kiểu mã hóa. Thay vì làm tắc nghẽn câu trả lời này ở đây với tất cả các mã thêm, tôi đã tạo ra một kho lưu trữ trong bitbucket tại địa chỉ:

https://bitbucket.org/pkclsoft/gdatainterface

chứa toàn bộ một dự án XCode rằng xây dựng hai mục tiêu, một dành cho Mac OS và một cho iOS. Ive đã sử dụng cả hai ứng dụng đó trong một ứng dụng có trong kho ứng dụng ngay bây giờ với kết quả tuyệt vời. Nó có thể là trong khi dự án này xây dựng cho tôi, bạn phải tinh chỉnh nó cho các mục đích của bạn. Dự án chứa một bộ hoàn chỉnh của Google SDK được xây dựng và chạy với mã của tôi. Tôi đã bao gồm nó để thử và giảm nguy cơ không tương thích với các phiên bản SDK mới hơn cho bất kỳ ai lấy nó.

Dưới đây là spec giao diện vì nó hiện đang đứng:

// 
// GDataInterface.h 
// GDataInterface 
// 
// Some of the code in this class is from the original GData sample code, but it has been 
// enhanced somewhat and made to work on both iOS and MacOS transparently. 
// 
// Created by Peter Easdown on 19/12/11. 
// Copyright (c) 2011 PKCLsoft. All rights reserved. 
// 

#import <Foundation/Foundation.h> 
#if TARGET_OS_IPHONE 
#import "GDataDocs.h" 
#import <UIKit/UIKit.h> 
#else 
#import "GData/GData.h" 
#endif 

@interface GDataInterfaceTypes 

// This handler is used by methods that have no explicit result. The boolean value indicates 
// the success or failure of the the methods action. 
// 
typedef void (^CompletionHandler)(BOOL successful); 

// This handler is called to update a progress indicator as a file is uploaded. 
// 
typedef void (^UploadProgressHandler)(double min, double max, double value); 

// This handler is called to update a progress indicator as a file is downloaded. 
// 
typedef void (^DownloadProgressHandler)(double min, double max, double value); 

@end 

@interface GDataInterface : NSObject { 

#if TARGET_OS_IPHONE 
    // Needed so that when authenticating under iOS, we can push the google authentication 
    // view, and later pop it. 
    // 
    UIViewController *rootController_; 
#endif 

    GDataFeedDocList *mDocListFeed; 
    GDataServiceTicket *mDocListFetchTicket; 
    NSError *mDocListFetchError; 

    GDataFeedDocRevision *mRevisionFeed; 
    GDataServiceTicket *mRevisionFetchTicket; 
    NSError *mRevisionFetchError; 

    GDataEntryDocListMetadata *mMetadataEntry; 

    GDataServiceTicket *mUploadTicket; 

    id uploadWindow; 
    CompletionHandler uploadCompletionHandler; 

    NSString *username_; 
    NSString *password_; 

} 

// This handler is used when a list of documents has been requested. The results parameter 
// will be nil if the request failed. If successful, then it will contain an array of 
// GDataEntryDocBase objects. 
// 
typedef void (^RetrievalCompletionHandler)(GDataFeedDocList* results, BOOL successful); 

// This handler is used when a document has been downloaded. If something prevented the 
// download from succeeding, then error parameter will be non-nil. 
// 
typedef void (^DocumentDownloadCompletionHandler)(NSData* fileContents, BOOL successful); 

// Initializer that provides the username and password. 
// 
- (id) initWithUsername:(NSString*)username andPassword:(NSString*)password; 

// Returns the shared instance of the class. There will only ever be a single instance 
// of this class. 
// 
+ (GDataInterface*) sharedInstance; 

// Returns YES if currently signed in. 
// 
- (BOOL) isSignedIn; 

// Signs in or out depending on current state, and executes the options completion handler 
// block. The window parameter is used to specify the root viewController object used when 
// displaying login windows via GData, or error dialogs. 
// 
- (void) signInOrOutWithCompletionHandler:(CompletionHandler)handler forWindow:(id)window; 

// Will retrieve a list of documents using the cached connection, and call the specified 
// handler block, providing the list of documents, and a success/fail indication. 
// 
- (void) retrieveDocumentListWithCompletionHandler:(RetrievalCompletionHandler)handler; 

// Will download the file at the specified URL. This is not Google Docs specific and will work 
// for any URL. Be careful not to try and retrieve large files and the result is stored 
// in memory. 
// 
- (void) downloadURL:(NSURL*)url withProgressHandler:(DownloadProgressHandler)progressHandler andCompletionHandler:(DocumentDownloadCompletionHandler)handler; 

// Will download the specified google docs document. 
// 
- (void) downloadDocument:(GDataEntryDocBase*)document withProgressHandler:(DownloadProgressHandler)progressHandler andCompletionHandler:(DocumentDownloadCompletionHandler)handler; 

// Uploads the document entry, optionally updating it with a new revision. 
// 
- (void) uploadEntry:(GDataEntryDocBase*)docEntry asNewRevision:(BOOL)newRevision forWindow:(id)window withProgressHandler:(UploadProgressHandler)progressHandler andCompletionHandler:(CompletionHandler)handler; 

// Uploads the specified file to the authenticated google docs account. 
// 
- (void)uploadFileAtPath:(NSString *)path forWindow:(id)window withProgressHandler:(UploadProgressHandler)progressHandler andCompletionHandler:(CompletionHandler)handler; 

// More for internal use than anything else. Used to determine the mime type based on the google docs class 
// and/or file extension. 
// 
- (void)getMIMEType:(NSString **)mimeType andEntryClass:(Class *)class forExtension:(NSString *)extension; 

// Getter and Setter for username, 
// 
- (void) setUsername:(NSString*)newUsername; 
- (NSString*) username; 

// Getter and Setter for password. The password will be encrypted before storing it in user preferances. 
// 
- (void) setPassword:(NSString*)newPassword; 
- (NSString*) password; 

// Returns the username that google is given for signing in. 
// 
- (NSString *)signedInUsername; 

// Returns a static instance of the docs service. 
// 
+ (GDataServiceGoogleDocs *)docsService; 

@end 

Và đây là việc thực hiện:

// 
// GDataInterface.m 
// GDataInterface 
// 
// Created by Peter Easdown on 19/12/11. 
// Copyright (c) 2011 PKCLsoft. All rights reserved. 
// 

#import "GDataInterface.h" 
#import "Util.h" 
#if TARGET_OS_IPHONE 
#import "GTMOAuth2ViewControllerTouch.h" 
#import "GData.h" 
#else 
#import "GData/GTMOAuth2WindowController.h" 
//#import "GDataServiceGoogleSpreadsheet.h" 
#endif 

#define GOOGLE_DATA_CLIENT_ID @"<client id>.apps.googleusercontent.com" 
#define GOOGLE_DATA_SECRET @"<google data secret>" 
#define GOOGLE_DATA_USERNAME @"googleDocsUsername" 
#define GOOGLE_DATA_PASSWORD @"googleDocsPassword" 

@interface GDataInterface (PrivateMethods) 

- (GDataServiceTicket *) uploadTicket; 
- (void) setUploadTicket:(GDataServiceTicket *)ticket; 

- (GDataFeedDocList *)docListFeed; 
- (void)setDocListFeed:(GDataFeedDocList *)feed; 
- (NSError *)docListFetchError; 
- (void)setDocListFetchError:(NSError *)error; 
- (GDataServiceTicket *)docListFetchTicket; 
- (void)setDocListFetchTicket:(GDataServiceTicket *)ticket; 

@end 

@implementation GDataInterface 

static NSString *const kKeychainItemName = @"GDataInterface: Google Docs"; 

// Initializer that provides the username and password. 
// 
- (id) initWithUsername:(NSString*)username andPassword:(NSString*)password { 
    self = [super init]; 

    if (self != nil) { 
     username_ = [username retain]; 
     password_ = [password retain]; 
     [[GDataInterface docsService] setUserCredentialsWithUsername:username_ password:password_]; 
    } 

    return self; 
} 

- (void) setUsername:(NSString*)newUsername { 
    username_ = [newUsername retain]; 
    [[GDataInterface docsService] setUserCredentialsWithUsername:newUsername password:password_]; 
} 

- (NSString*) username { 
    return username_; 
} 

- (void) setPassword:(NSString*)newPassword { 
    password_ = [newPassword retain]; 
    [[GDataInterface docsService] setUserCredentialsWithUsername:username_ password:newPassword]; 
    [Util setPassword:newPassword forKey:GOOGLE_DATA_PASSWORD]; 
} 

- (NSString*) password { 
    return password_; 
} 


static GDataInterface *shared_instance_; 

// Returns the shared instance of the class. There will only ever be a single instance 
// of this class. 
// 
+ (GDataInterface*) sharedInstance { 
    if (shared_instance_ == nil) { 
     shared_instance_ = [[GDataInterface alloc] initWithUsername:[[NSUserDefaults standardUserDefaults] valueForKey:GOOGLE_DATA_USERNAME] andPassword:[Util getPassword:GOOGLE_DATA_PASSWORD]]; 

     // Load the OAuth token from the keychain, if it was previously saved 
     NSString *clientID = GOOGLE_DATA_CLIENT_ID; 
     NSString *clientSecret = GOOGLE_DATA_SECRET; 

     GTMOAuth2Authentication *auth; 

#if TARGET_OS_IPHONE 
     auth = [GTMOAuth2ViewControllerTouch authForGoogleFromKeychainForName:kKeychainItemName clientID:clientID clientSecret:clientSecret]; 
#else 
     auth = [GTMOAuth2WindowController authForGoogleFromKeychainForName:kKeychainItemName 
                    clientID:clientID 
                   clientSecret:clientSecret]; 
#endif 

     [[GDataInterface docsService] setAuthorizer:auth]; 
    } 

    return shared_instance_; 
} 

- (NSString *)signedInUsername { 
    // Get the email address of the signed-in user 
    GTMOAuth2Authentication *auth = [[GDataInterface docsService] authorizer]; 
    BOOL isSignedIn = auth.canAuthorize; 

    if (isSignedIn) { 
     return auth.userEmail; 
    } else { 
     return nil; 
    } 
} 

- (BOOL) isSignedIn { 
    return ([self signedInUsername] != nil); 
} 

- (void)runSigninThenInvokeHandler:(CompletionHandler)handler forWindow:(id)window { 
    // Applications should have client ID and client secret strings 
    // hardcoded into the source, but the sample application asks the 
    // developer for the strings 
    NSString *clientID = GOOGLE_DATA_CLIENT_ID; 
    NSString *clientSecret = GOOGLE_DATA_SECRET; 

    // Show the OAuth 2 sign-in controller 
    NSString *scope = [GTMOAuth2Authentication scopeWithStrings: 
         [GDataServiceGoogleDocs authorizationScope], 
         [GDataServiceGoogleSpreadsheet authorizationScope], 
         nil]; 

#if TARGET_OS_IPHONE 
    NSAssert((window != nil), @"window must be a non-nil navigation controller"); 

    GTMOAuth2ViewControllerTouch *viewController; 
    viewController = [GTMOAuth2ViewControllerTouch 
         controllerWithScope:scope 
         clientID:clientID 
         clientSecret:clientSecret 
         keychainItemName:kKeychainItemName 
         completionHandler:^(GTMOAuth2ViewControllerTouch *viewController, GTMOAuth2Authentication *auth, NSError *error) { 

          [rootController_ dismissModalViewControllerAnimated:YES]; 
          [rootController_ release]; 
          rootController_ = nil; 

          // callback 
          if (error == nil) { 
           [[GDataInterface docsService] setAuthorizer:auth]; 

           username_ = [self signedInUsername]; 

           handler(YES); 
          } else { 
           NSLog(@"Authentication error: %@", error); 
           NSData *responseData = [[error userInfo] objectForKey:@"data"]; // kGTMHTTPFetcherStatusDataKey 
           if ([responseData length] > 0) { 
            // show the body of the server's authentication failure response 
            NSString *str = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] autorelease]; 
            NSLog(@"%@", str); 
           } 
           handler(NO); 
          } 
         }]; 

    // Optional: display some html briefly before the sign-in page loads 
    NSString *html = @"<html><body bgcolor=silver><div align=center>Loading sign-in page...</div></body></html>"; 
    viewController.initialHTMLString = html; 

    // For iOS, window is a navigation controller. 
    // 
    rootController_ = [(UIViewController*)window retain]; 
    [rootController_ presentModalViewController:viewController animated:YES]; 

#else 
    NSBundle *frameworkBundle = [NSBundle bundleForClass:[GTMOAuth2WindowController class]]; 
    GTMOAuth2WindowController *windowController; 
    windowController = [GTMOAuth2WindowController controllerWithScope:scope 
                  clientID:clientID 
                 clientSecret:clientSecret 
                keychainItemName:kKeychainItemName 
                 resourceBundle:frameworkBundle]; 

    [windowController signInSheetModalForWindow:window 
           completionHandler:^(GTMOAuth2Authentication *auth, NSError *error) { 
            // callback 
            if (error == nil) { 
             [[GDataInterface docsService] setAuthorizer:auth]; 
             username_ = [auth userEmail]; 
             handler(YES); 
            } else { 
             handler(NO); 
            } 
           }]; 
#endif 
} 

- (void) signInOrOutWithCompletionHandler:(CompletionHandler)handler forWindow:(id)window { 
    if (![self isSignedIn]) { 
     // Sign in 
     [self runSigninThenInvokeHandler:handler forWindow:window]; 
    } else { 
     // Sign out 
     GDataServiceGoogleDocs *service = [GDataInterface docsService]; 

#if TARGET_OS_IPHONE 
     [GTMOAuth2ViewControllerTouch removeAuthFromKeychainForName:kKeychainItemName]; 
#else 
     [GTMOAuth2WindowController removeAuthFromKeychainForName:kKeychainItemName]; 
#endif 

     [service setAuthorizer:nil]; 
     handler(YES); 
    } 
} 

- (void) retrieveDocumentListWithCompletionHandler:(RetrievalCompletionHandler)handler { 

    [self setDocListFeed:nil]; 
    [self setDocListFetchError:nil]; 
    [self setDocListFetchTicket:nil]; 

    GDataServiceGoogleDocs *service = [GDataInterface docsService]; 
    GDataServiceTicket *ticket; 

    // Fetching a feed gives us 25 responses by default. We need to use 
    // the feed's "next" link to get any more responses. If we want more than 25 
    // at a time, instead of calling fetchDocsFeedWithURL, we can create a 
    // GDataQueryDocs object, as shown here. 

    NSURL *feedURL = [GDataServiceGoogleDocs docsFeedURL]; 

    GDataQueryDocs *query = [GDataQueryDocs documentQueryWithFeedURL:feedURL]; 
    [query setMaxResults:1000]; 
    [query setShouldShowFolders:NO]; 

    ticket = [service fetchFeedWithQuery:query 
         completionHandler:^(GDataServiceTicket *ticket, GDataFeedBase *feed, NSError *error) { 
          // callback 
          [self setDocListFeed:(GDataFeedDocList *)feed]; 
          [self setDocListFetchError:error]; 
          [self setDocListFetchTicket:nil]; 

          if (handler != nil) { 
           handler((GDataFeedDocList *)feed, (error == nil)); 
          } 
         }]; 

    [self setDocListFetchTicket:ticket]; 
} 

- (void) downloadDocument:(GDataEntryDocBase*)document withProgressHandler:(DownloadProgressHandler)progressHandler andCompletionHandler:(DocumentDownloadCompletionHandler)handler { 

    // the content src attribute is used for downloading 
    NSURL *exportURL = [[document content] sourceURL]; 

    if (exportURL != nil) { 
     GDataQuery *query = [GDataQuery queryWithFeedURL:exportURL]; 
     [query addCustomParameterWithName:@"exportFormat" 
            value:@"txt"]; 
     NSURL *downloadURL = [query URL]; 
     // Read the document's contents asynchronously from the network 

     // requestForURL:ETag:httpMethod: sets the user agent header of the 
     // request and, when using ClientLogin, adds the authorization header 
     NSURLRequest *request = [[GDataInterface docsService] requestForURL:downloadURL 
                     ETag:nil 
                   httpMethod:nil]; 

     GTMHTTPFetcher *fetcher = [GTMHTTPFetcher fetcherWithRequest:request]; 
     [fetcher setAuthorizer:[[GDataInterface docsService] authorizer]]; 

     __block double maxSize = 10240.0; 

     if (progressHandler != nil) {    
      [fetcher setReceivedDataBlock:^(NSData *dataReceivedSoFar) { 
       if ([[fetcher response] expectedContentLength] > 0) { 
        maxSize = [[fetcher response] expectedContentLength]; 
       } else if ([dataReceivedSoFar length] > maxSize) { 
        maxSize += 5120.0; 
       } 

       progressHandler(0.0, maxSize, (double)[dataReceivedSoFar length]); 
      }]; 
     } 

     [fetcher setCommentWithFormat:@"downloading \"%@\"", [[document title] stringValue]]; 
     [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { 
      if (progressHandler != nil) { 
       // Update the progress handler with a "complete" progress. 
       // 
       progressHandler(0.0, (double)[data length], (double)[data length]); 
      } 

      // callback 
      if (error == nil) { 
       // Successfully downloaded the document 
       //     
       if (handler != nil) { 
        handler(data, YES); 
       } 
      } else { 
       if (handler != nil) { 
        handler(nil, NO); 
       } 
      } 
     }]; 
    } 
} 

- (void) downloadURL:(NSURL*)url withProgressHandler:(DownloadProgressHandler)progressHandler andCompletionHandler:(DocumentDownloadCompletionHandler)handler { 

    NSURL *downloadURL = [url copy]; 
    // Read the document's contents asynchronously from the network 

    NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL]; 

    GTMHTTPFetcher *fetcher = [GTMHTTPFetcher fetcherWithRequest:request]; 

    __block double maxSize = 10240.0; 

    if (progressHandler != nil) {    
     [fetcher setReceivedDataBlock:^(NSData *dataReceivedSoFar) { 
      if ([[fetcher response] expectedContentLength] > 0) { 
       maxSize = [[fetcher response] expectedContentLength]; 
      } else if ([dataReceivedSoFar length] > maxSize) { 
       maxSize += 5120.0; 
      } 

      progressHandler(0.0, maxSize, (double)[dataReceivedSoFar length]); 
     }]; 
    } 

    [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) { 
     if (progressHandler != nil) { 
      progressHandler(0.0, (double)[data length], (double)[data length]); 
     } 

     // callback 
     if (error == nil) { 
      // Successfully downloaded the document 
      //     
      if (handler != nil) { 
       handler(data, YES); 
      } 
     } else { 
      if (handler != nil) { 
       handler(nil, NO); 
      } 
     } 
    }]; 

    // Block, waiting for 60 seconds for the download. 
    // 
    [fetcher waitForCompletionWithTimeout:60.0]; 

    if ([fetcher isFetching] == YES) { 
     // OK, so this looks like we've timed out waiting for the download to complete. Cancel the 
     // fetch. 
     // 
     [fetcher stopFetching]; 

     if (handler != nil) { 
      handler(nil, NO); 
     } 
    } 
} 

#pragma mark Upload 

- (void)getMIMEType:(NSString **)mimeType andEntryClass:(Class *)class forExtension:(NSString *)extension { 

    // Mac OS X's UTI database doesn't know MIME types for .doc and .xls 
    // so GDataEntryBase's MIMETypeForFileAtPath method isn't helpful here 

    struct MapEntry { 
     NSString *extension; 
     NSString *mimeType; 
     NSString *className; 
    }; 

    static struct MapEntry sMap[] = { 
     { @"csv", @"text/csv", @"GDataEntryStandardDoc" }, 
     { @"doc", @"application/msword", @"GDataEntryStandardDoc" }, 
     { @"docx", @"application/vnd.openxmlformats-officedocument.wordprocessingml.document", @"GDataEntryStandardDoc" }, 
     { @"ods", @"application/vnd.oasis.opendocument.spreadsheet", @"GDataEntrySpreadsheetDoc" }, 
     { @"odt", @"application/vnd.oasis.opendocument.text", @"GDataEntryStandardDoc" }, 
     { @"pps", @"application/vnd.ms-powerpoint", @"GDataEntryPresentationDoc" }, 
     { @"ppt", @"application/vnd.ms-powerpoint", @"GDataEntryPresentationDoc" }, 
     { @"rtf", @"application/rtf", @"GDataEntryStandardDoc" }, 
     { @"sxw", @"application/vnd.sun.xml.writer", @"GDataEntryStandardDoc" }, 
     { @"txt", @"text/plain", @"GDataEntryStandardDoc" }, 
     { @"xls", @"application/vnd.ms-excel", @"GDataEntrySpreadsheetDoc" }, 
     { @"xlsx", @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", @"GDataEntrySpreadsheetDoc" }, 
     { @"jpg", @"image/jpeg", @"GDataEntryStandardDoc" }, 
     { @"jpeg", @"image/jpeg", @"GDataEntryStandardDoc" }, 
     { @"png", @"image/png", @"GDataEntryStandardDoc" }, 
     { @"bmp", @"image/bmp", @"GDataEntryStandardDoc" }, 
     { @"gif", @"image/gif", @"GDataEntryStandardDoc" }, 
     { @"html", @"text/html", @"GDataEntryStandardDoc" }, 
     { @"htm", @"text/html", @"GDataEntryStandardDoc" }, 
     { @"tsv", @"text/tab-separated-values", @"GDataEntryStandardDoc" }, 
     { @"tab", @"text/tab-separated-values", @"GDataEntryStandardDoc" }, 
     { @"pdf", @"application/pdf", @"GDataEntryPDFDoc" }, 
     { nil, nil, nil } 
    }; 

    NSString *lowerExtn = [extension lowercaseString]; 

    for (int idx = 0; sMap[idx].extension != nil; idx++) { 
     if ([lowerExtn isEqual:sMap[idx].extension]) { 
      *mimeType = sMap[idx].mimeType; 
      *class = NSClassFromString(sMap[idx].className); 
      return; 
     } 
    } 

    *mimeType = nil; 
    *class = nil; 
    return; 
} 

- (void) uploadEntry:(GDataEntryDocBase*)docEntry asNewRevision:(BOOL)newRevision forWindow:(id)window withProgressHandler:(UploadProgressHandler)progressHandler andCompletionHandler:(CompletionHandler)handler { 

    uploadWindow = [window retain]; 
    uploadCompletionHandler = [handler copy]; 

    NSURL *uploadURL; 

    if (newRevision == YES) { 
     GDataQueryDocs *query = [GDataQueryDocs queryWithFeedURL:[[docEntry 
                    uploadEditLink] URL]]; 
     [query setShouldCreateNewRevision:YES]; 
     uploadURL = [query URL]; 
    } else { 
     uploadURL = [GDataServiceGoogleDocs docsUploadURL]; 
    } 

    // make service tickets call back into our upload progress selector 
    GDataServiceGoogleDocs *service = [GDataInterface docsService]; 
    [service setServiceUploadProgressHandler:^(GDataServiceTicketBase *ticket, unsigned long long numberOfBytesRead, unsigned long long dataLength) { 
     if (progressHandler != nil) { 
      progressHandler(0.0, (double)dataLength, (double)numberOfBytesRead); 
     } 
    }]; 

    // insert the entry into the docList feed 
    // 
    // to update (replace) an existing entry by uploading a new file, 
    // use the fetchEntryByUpdatingEntry:forEntryURL: with the URL from 
    // the entry's uploadEditLink 
    GDataServiceTicket *ticket; 

    if (newRevision == YES) {   
     ticket = [service fetchEntryByUpdatingEntry:docEntry 
             forEntryURL:uploadURL 
              delegate:self 
            didFinishSelector:@selector(uploadFileTicket:finishedWithEntry:error:)]; 
    } else { 
     ticket = [service fetchEntryByInsertingEntry:docEntry 
              forFeedURL:uploadURL 
              delegate:self 
            didFinishSelector:@selector(uploadFileTicket:finishedWithEntry:error:)]; 
    } 

    [ticket setUploadProgressHandler:^(GDataServiceTicketBase *ticket, unsigned long long numberOfBytesRead, unsigned long long dataLength) { 
     // progress callback 
     if (progressHandler != nil) { 
      progressHandler(0.0, (double)dataLength, (double)numberOfBytesRead); 
     } 
    }]; 

    // we turned automatic retry on when we allocated the service, but we 
    // could also turn it on just for this ticket 

    [self setUploadTicket:ticket]; 
    [service setServiceUploadProgressHandler:nil]; 
} 

- (void)uploadFileAtPath:(NSString *)path forWindow:(id)window withProgressHandler:(UploadProgressHandler)progressHandler andCompletionHandler:(CompletionHandler)handler { 

    NSString *errorMsg = nil; 

    // make a new entry for the file 

    NSString *mimeType = nil; 
    Class entryClass = nil; 

    NSString *extn = [path pathExtension]; 
    [self getMIMEType:&mimeType andEntryClass:&entryClass forExtension:extn]; 

    if (!mimeType) { 
     // for other file types, see if we can get the type from the Mac OS 
     // and use a generic file document entry class 
     mimeType = [GDataUtilities MIMETypeForFileAtPath:path 
             defaultMIMEType:nil]; 
     entryClass = [GDataEntryFileDoc class]; 
    } 

    if (mimeType && entryClass) { 

     GDataEntryDocBase *newEntry = [entryClass documentEnt 
+0

Xin chào, Có bất kỳ tham chiếu hoặc URL nào mà tôi có thể nhận thêm thông tin về việc triển khai không? Tôi cũng cần trình bao bọc hoặc SDK như vậy cho Google Documents từ iOS. Thx – SkyEagle888

+0

Tôi phải kiểm tra lại mặt MacOS của nó, nhưng ngoài việc nó hoạt động thực sự tốt. Tôi sẽ xem xét đánh bóng nó một chút một đặt nó lên trên github. – PKCLsoft

+0

Tôi cũng muốn ** rất quan tâm đến điều này! – lnafziger

Các vấn đề liên quan