views:

185

answers:

3

I want to make an app that uses on the Google Reader API. But I'm finding out that there isn't an offical API for it - is there a problem using the unofficial API, in terms of App Store guidelines/approval? Would other apps (Reeder, etc) use this?

Also what is the best method for logging in? Is OAuth the preffered method? Is using Janrain a good idea?

+2  A: 

Frankly Apple doesn't care if you use Google's unofficial API.

I worked for a customer on a RSS reader app that used Google Reader for syncing. We didn't use OAuth but the standard HTTP login which returns you a cookie where you'll have to extract a token from to use in consecutive calls to the various reader URLs.

I can post you the login code from my (old) proof of concept app. It uses ASIHTTP and some custom string categories. The idea is to send a login request, get the response and extract the session ID/auth code from the response's cookie header. Then you can use that session ID/auth code for consecutive calls.

#pragma mark -
#pragma mark login

//this is your sessionID token you get from the login
//use this in consecutive calls to google reader
//this method returns you the header string you have to add to your request
//[request addRequestHeader: @"Cookie" value: [self sidHeader]];
- (NSString *) sidHeader
{
    return [NSString stringWithFormat: @"SID=%@", [self sid]];
}

- (NSString *) authHeader
{
    return [NSString stringWithFormat: @"GoogleLogin auth=%@",[self auth]];
}


//login to your google account and get the session ID
- (void) login
{
    NSString *username = @"[email protected]";
    NSString *password = @"mypassword123";
    NSString *loginUrl = @"https://www.google.com/accounts/ClientLogin?client=NNW-Mac";
    NSString *source = @"NNW-Mac"; //let's fake NetNewsWire
    NSString *continueUrl = @"http://www.google.com";

    ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString: loginUrl]]; // log in & get cookies
    [request addRequestHeader: @"User-Agent" value: @"NetNewsWire/3.2b25 (Mac OS X; http://www.newsgator.com/Individuals/NetNewsWire/)"];

    [request setPostValue: username forKey: @"Email"];
    [request setPostValue: password forKey: @"Passwd"];
    [request setPostValue: @"reader" forKey: @"service"];
    [request setPostValue: source forKey: @"source"];
    [request setPostValue: continueUrl forKey: @"continue"];

    [request setDelegate: self];
    [request setDidFailSelector: @selector(loginRequestFailed:)];
    [request setDidFinishSelector: @selector(loginRequestFinished:)];

    [request start];
}   

-(void)loginRequestFinished:(ASIHTTPRequest *)request
{
    NSString *responseString = [request responseString];

    //login failed
    if ([responseString containsString: @"Error=BadAuthentication" ignoringCase: YES])
    {
        [self setLastError: [self errorWithDescription: @"Bad Username/Passsword" code: 0x001 andErrorLevel: 0x00]];

        if ([delegate respondsToSelector: @selector(gReaderLoginDidFail:)])
        {
            [delegate gReaderLoginDidFail: self];
        }

        return NO;
    }

    //captcha required
    if ([responseString containsString: @"CaptchaRequired" ignoringCase: YES])
    {
        [self setLastError: [self errorWithDescription: @"Captcha Required" code: 0x001 andErrorLevel: 0x00]];

        if ([delegate respondsToSelector: @selector(gReaderLoginDidFail:)])
        {
            [delegate gReaderLoginDidFail: self];
        }

        return NO;
    }

    //extract SID + auth
    NSArray *respArray = [responseString componentsSeparatedByCharactersInSet: [NSCharacterSet newlineCharacterSet]];

    NSString *sidString = [respArray objectAtIndex: 0];
    sidString = [sidString stringByReplacingOccurrencesOfString: @"SID=" withString: @""];
    [self setSid: sidString];

NSString *authString = [respArray objectAtIndex: 2];
authString = [authString stringByReplacingOccurrencesOfString: @"Auth=" withString: @""];
[self setAuth: authString];
    //mesage delegate of success
    if ([delegate respondsToSelector: @selector(gReaderLoginDidSucceed:)])
    {
        [delegate gReaderLoginDidSucceed: self];
    }

    return YES;
}

- (void)loginRequestFailed:(ASIHTTPRequest *)request
{
    NSError *error = [request error];

    //NSLog(@"login request failed with error: %@", [error localizedDescription]);
    [self setLastError: error];

    if ([delegate respondsToSelector: @selector(gReaderLoginDidFail:)])
    {
        [delegate gReaderLoginDidFail: self];
    }

}

After login you can use sid and auth to forge requests to the Reader's API endpoints.

Example:

- (ASIHTTPRequest *) requestForAPIEndpoint: (NSString *) apiEndpoint
{
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString: apiEndpoint]];
    [request addRequestHeader: @"User-Agent" value: @"NetNewsWire/3.2b25 (Mac OS X; http://www.newsgator.com/Individuals/NetNewsWire/)"];
    [request addRequestHeader: @"Cookie" value: [self sidHeader]];
    [request addRequestHeader: @"Authorization" value: [self authHeader]];

    return request;
}

An interesting read about Google Reader and its private API is http://timbroder.com/2007/08/google-reader-api-functions.html

Please make sure to read the latest comments :)

/edit: I updated the code to use the auth header (which google introduced in june this year). I guess this would be the place to put your OAuth token in if you would use OAuth. guess

Jaroslaw Szpilewski
Thanks for that Jaroslaw! I'm worried about using an unofficial API for an app. Should I be?
daidai
Yes and No :) No because Apple does not care if you use someone else's unofficial APIs (they care only for their own APIs). So you won't get any trouble from Apple if you try to put a Google Reader app into the store.\n\n But there's the problem with unofficial APIs in general as they can change any moment. For example: My example code I posted here first was broken and I had to fix it because Google decided to use the new "Auth" parameter for auth and ignore the SID. Supporting an unofficial 3rd party API is always work and you should be aware of that.
Jaroslaw Szpilewski
Hmm yeh what a pain. But you think apps like Reedera and all have the same problem? I wont mind if all other Reader apps fail at the same time :)
daidai
hey is ASIFormDataRequest and the other library files acceptable by apple? Im confused by their policy. Ive heard they decline apps for using external libraries. Isnt this one of them?
daidai
A: 

@daidai did you end up implementing everything right? and if so, are you able to help me out with my own application?

the0rkus
no havent yet, you might be better off asking a separate question.
daidai