Google Objective-C API 'Gtl' with Swift

Google Objective-C API 'GTL' with Swift

I eventually managed to do this by following

Stack OverFlow 11370752

and adding a bridging-header.h file with

#import "GTLDrive.h"
#import "GTMOAuth2ViewControllerTouch.h"

To save someone time I include my Objective-C to Swift Translation of the sample included in the Google Quickstart

IOS Quickstart for Google Drive

import UIKit
import MobileCoreServices

class ViewController: UIViewController , UINavigationControllerDelegate ,UIImagePickerControllerDelegate {
var window: UIWindow?
let driveService : GTLServiceDrive = GTLServiceDrive()

let kKeychainItemName : NSString = "Google Drive Quickstart"
let kClientID : NSString = "Your Client ID"
let kClientSecret : NSString = "Your Secret"

func showWaitIndicator(title:String) -> UIAlertView {
// println("showWaitIndicator \(title)")
var progressAlert = UIAlertView()
progressAlert.title = title
progressAlert.message = "Please Wait...."
progressAlert.show()

let activityView = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.White)
activityView.center = CGPointMake(progressAlert.bounds.size.width / 2, progressAlert.bounds.size.height - 45)
progressAlert.addSubview(activityView)
activityView.hidesWhenStopped = true
activityView.startAnimating()
return progressAlert
}

override func viewDidLoad() {
super.viewDidLoad()
self.driveService.authorizer = GTMOAuth2ViewControllerTouch.authForGoogleFromKeychainForName(kKeychainItemName,
clientID: kClientID,
clientSecret: kClientSecret)
}

override func viewDidAppear(animated: Bool) {
self.showCamera()
}

func showCamera() {
var cameraUI = UIImagePickerController()
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera) {
cameraUI.sourceType = UIImagePickerControllerSourceType.Camera
} else {
cameraUI.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad {
self.showAlert("Error", message: "Ipad Simulator not supported")
return
}
}

cameraUI.mediaTypes = [kUTTypeImage as String]
cameraUI.allowsEditing = true
cameraUI.delegate = self
self.presentModalViewController(cameraUI, animated: true)
println("Show Camera \(self.isAuthorized())")
if (!self.isAuthorized())
{
// Not yet authorized, request authorization and push the login UI onto the navigation stack.
cameraUI.pushViewController(self.createAuthController(), animated:true);
}
}
// Handle selection of an image
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info:NSDictionary) {
println("imagePickerController didFinishPickingMediaWithInfo")
let image = info.valueForKey(UIImagePickerControllerOriginalImage) as UIImage
self.dismissModalViewControllerAnimated(true)
self.uploadPhoto(image)

}

// Handle cancel from image picker/camera.

func imagePickerControllerDidCancel(picker: UIImagePickerController){
self.dismissModalViewControllerAnimated(true)
}

// Helper to check if user is authorized
func isAuthorized() -> Bool {
return (self.driveService.authorizer as GTMOAuth2Authentication).canAuthorize
}

// Creates the auth controller for authorizing access to Google Drive.
func createAuthController() -> GTMOAuth2ViewControllerTouch {
return GTMOAuth2ViewControllerTouch(scope: kGTLAuthScopeDriveFile,
clientID: kClientID,
clientSecret: kClientSecret,
keychainItemName: kKeychainItemName,
delegate: self,
finishedSelector: Selector("viewController:finishedWithAuth:error:"))

}
// “func join(string s1: String, toString s2: String, withJoiner joiner: String)”

// Handle completion of the authorization process, and updates the Drive service
// with the new credentials.
func viewController(viewController: GTMOAuth2ViewControllerTouch , finishedWithAuth authResult: GTMOAuth2Authentication , error:NSError ) {
if error != nil
{
self.showAlert("Authentication Error", message:error.localizedDescription)
self.driveService.authorizer = nil
} else {
println("Authentication success")
self.driveService.authorizer = authResult
}

}

// Uploads a photo to Google Drive
func uploadPhoto(image: UIImage) {
println("uploading Photo")
let dateFormat = NSDateFormatter()
dateFormat.dateFormat = "'Quickstart Uploaded File ('EEEE MMMM d, YYYY h:mm a, zzz')"

let file = GTLDriveFile.object() as GTLDriveFile
file.title = dateFormat.stringFromDate(NSDate())
file.descriptionProperty = "Uploaded from Google Drive IOS"
file.mimeType = "image/png"

let data = UIImagePNGRepresentation(image)
let uploadParameters = GTLUploadParameters(data: data, MIMEType: file.mimeType)
let query = GTLQueryDrive.queryForFilesInsertWithObject(file, uploadParameters: uploadParameters) as GTLQueryDrive
let waitIndicator = self.showWaitIndicator("Uploading To Google Drive")
// self.driveService.executeQuery(query, completionHandler: {(ticket: GTLServiceTicket, insertedFile: AnyObject, error: NSError) in {
//
//
// }
// elf.driveService.executeQuery(<#query: GTLQueryProtocol?#>, completionHandler: <#((GTLServiceTicket!, AnyObject!, NSError!) -> Void)?#>)
self.driveService.executeQuery(query, completionHandler: { (ticket, insertedFile , error) -> Void in
let myFile = insertedFile as? GTLDriveFile

waitIndicator.dismissWithClickedButtonIndex(0, animated: true)
if error == nil {
println("File ID \(myFile?.identifier)")
self.showAlert("Google Drive", message: "File Saved")
} else {
println("An Error Occurred! \(error)")
self.showAlert("Google Drive", message: "Sorry, an error occurred!")
}

})
}

func showAlert(title: String, message: String ) {
let cancel = "OK"
println("show Alert")
let alert = UIAlertView()
alert.title = title
alert.message = message
alert.addButtonWithTitle(cancel)
alert.show()
}

}

Adding Google Objective-C API 'GTL' to iPhone project

I struggled with this error message as well. This is how I solved it:

Make sure you have added the folder for the service that you are using under GTLSource/Common/ (e.g., add the Drive folder for GoogleDrive).

Under GTL.xcodeproj (that you have already added to your workspace) find the GTLSource folder and drag it to your main project (Golf in your case). Done!

Now you can remove references to the GTL.xcodeproj that you have added to the workspace.

With this approach, you don't even need to add the libraries (so remove them from the list of linked libraries if you have added them).

The Google API documentation is nothing like Apple's documentation (it's not good).

I should also mention that I'm building an app for iOS and not MacOSX, but this should work for OSX as well.

Sample Image

Adding Google Objective-C API 'GTL' to iPhone project

I struggled with this error message as well. This is how I solved it:

Make sure you have added the folder for the service that you are using under GTLSource/Common/ (e.g., add the Drive folder for GoogleDrive).

Under GTL.xcodeproj (that you have already added to your workspace) find the GTLSource folder and drag it to your main project (Golf in your case). Done!

Now you can remove references to the GTL.xcodeproj that you have added to the workspace.

With this approach, you don't even need to add the libraries (so remove them from the list of linked libraries if you have added them).

The Google API documentation is nothing like Apple's documentation (it's not good).

I should also mention that I'm building an app for iOS and not MacOSX, but this should work for OSX as well.

Sample Image

iOS Google Drive integration

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

Method for performing Google Drive Services requests.

- (GTLRDriveService *)driveService {
static GTLRDriveService *service;

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
service = [[GTLRDriveService alloc] init];

// Turn on the library's shouldFetchNextPages feature to ensure that all items
// are fetched. This applies to queries which return an object derived from
// GTLRCollectionObject.
service.shouldFetchNextPages = YES;

// Have the service object set tickets to retry temporary error conditions
// automatically
service.retryEnabled = YES;
});
return service;
}

After Google Authentication, Authorise driveService using these lines:

In your case,

if (authState) {
// Creates a GTMAppAuthFetcherAuthorization object for authorizing requests.
GTMAppAuthFetcherAuthorization *gtmAuthorization =
[[GTMAppAuthFetcherAuthorization alloc] initWithAuthState:authState];

// Sets the authorizer on the GTLRYouTubeService object so API calls will be authenticated.
strongSelf.driveService.authorizer = gtmAuthorization;

// Serializes authorization to keychain in GTMAppAuth format.
[GTMAppAuthFetcherAuthorization saveAuthorization:gtmAuthorization
toKeychainForName:kKeychainItemName];

// Your further code goes here
//
[self fetchFileList];
}

Then, You can use below method to fetch files from Google Drive:

- (void)fetchFileList {

__block GTLRDrive_FileList *fileListNew = nil;

GTLRDriveService *service = self.driveService;

GTLRDriveQuery_FilesList *query = [GTLRDriveQuery_FilesList query];

// Because GTLRDrive_FileList is derived from GTLCollectionObject and the service
// property shouldFetchNextPages is enabled, this may do multiple fetches to
// retrieve all items in the file list.

// Google APIs typically allow the fields returned to be limited by the "fields" property.
// The Drive API uses the "fields" property differently by not sending most of the requested
// resource's fields unless they are explicitly specified.
query.fields = @"kind,nextPageToken,files(mimeType,id,kind,name,webViewLink,thumbnailLink,trashed)";

GTLRServiceTicket *fileListTicket;

fileListTicket = [service executeQuery:query
completionHandler:^(GTLRServiceTicket *callbackTicket,
GTLRDrive_FileList *fileList,
NSError *callbackError) {
// Callback
fileListNew = fileList;

}];
}

Try DriveSample from the reference library, include GTLRDrive Files in your project and you are ready to use above method.

To get the GTMAppAuthFetcherAuthorization working, you've to include the pod "GTMAppAuth" or include the files manually in your project.

Actually above methods are copied from DriveSample example of referenced library and this example is working fine for Drive requests.

Google Drive API IOS Permissions of GTLRDriveService

try to Change your scope like:

class ViewController: UIViewController, GIDSignInDelegate, GIDSignInUIDelegate
{
// If modifying these scopes, delete your previously saved credentials by

private let scopes = ["https://www.googleapis.com/auth/drive"]

...
}

Objective-C using block when get list file using Google Driver API

Your can try it.

@property (nonatomic, copy) void(^blockHandler)(id data);


// get list file
- (void)listFiles:(NSString *)fileId complete:(void(^)(id data))completion {
self.blockHandler = completion;

GTLRDriveQuery_FilesList *query = [GTLRDriveQuery_FilesList query];
query.fields = @"nextPageToken, files(id, name, thumbnailLink, webViewLink)";
query.pageSize = 1000;
query.q = [NSString stringWithFormat:@"'%@' In parents and trashed=false",fileId];

[self.service executeQuery:query
delegate:self
didFinishSelector:@selector(displayResultWithTicket:finishedWithObject:error:)];
}

- (void)displayResultWithTicket:(GTLRServiceTicket *)ticket
finishedWithObject:(GTLRDrive_FileList *)result
error:(NSError *)error {
if (error == nil) {
NSMutableString *output = [[NSMutableString alloc] init];
if (result.files.count > 0) {
[output appendString:@"Files:\n"];
for (GTLRDrive_File *file in result.files) {
itemGG *temp = [[itemGG alloc] initWithName:file.name linkThumb:file.thumbnailLink fileID:file.identifier];
[self.lstItem addObject:temp];
[output appendFormat:@"%@ (%@)\n", file.name, file.identifier];
}
} else {
[output appendString:@"No files found."];
}
NSLog(@"%@", output);
} else {
NSLog(@"Error getting presentation data: %@\n", error.localizedDescription);
}

if (self.blockHandler) {
self.blockHandler([[NSArray alloc] initWithArray:self.lstItem]);
}
}


__weak typeof(self) w = self;
[self.cloud listFiles:@"root" complete:^(id data) {
w.tableData = data;
[w.myCollection reloadData];
}];

Error after converting objective-c code to swift 3.0.2 Google Drive Rest API

Refer with this SO thread. You may try changing the unwrapping of the parameters in the closure. Maybe this is required to match what the Objective-C implementation of the function is expecting.

You may also check this additional references:

  • Swift 2 to Swift 3: Cannot convert value of type '(Data?, NSError?) -> Void' to to expected argument type 'GTMSessionFetcherCompletionHandler?'

    As per SE-0112, NSError is now bridged to Swift as the Error protocol. In fact, if you + click on the GTMSessionFetcherCompletionHandler type in Swift, you'll see exactly how it's bridged:

    typealias GTMSessionFetcherCompletionHandler = (Data?, Error?) -> Void

  • Swift error Cannot convert value of type '(AFHTTPRequestOperation?, AnyObject?) -> ()

  • Cannot convert value of type (PFUser!, NSError) void to expected argument type PFUserResultBlock

Google GTL Objective-C API

The YouTube XML API has not yet been replaced by a JSON API.



Related Topics



Leave a reply



Submit