2010年3月26日 星期五

iOS 開發教學 - 使用 Google Data APIs 以 Login 為例

Google 有一系列的免費服務,大部分都有提供豐富的 APIs 以便其他開發者善加利用,其清單如下:


然而,雖然知道要使用大多是透過網路連線,回傳如 XML 格式的處理,但要自己親手處理還是有些繁雜,幸運的,這些都已經有人處理好囉!


以下就實作一個簡單使用的範例,稍稍繁雜的地方是設定編譯的環境:


  1. 下載程式碼,此例使用 gdata-objectivec-client-1.9.1.zip ,解壓縮後開啟其目錄下的 Source/GData.xcodeproj

  2. 建立一個新的 Project ,[Xcode]->[NewProject]->[iPhone
    OS]->[Application]->[Window-based Application],以 UseGoogleAPI 為例

  3. 接著將 GData 中的 GData Sources 拖拉到 UseGoogleAPI 下面,不勾選 Copy items into destination group's folder

    • 拖拉 GData Sources

  4. 設定 UseGoogleAPI 的編譯環境:

    • 參考 Compiling the Source Files Directly into a Mac or iPhone Application

    • [Xcode]->[Project]->[Edit Project Settings]->[Build]

      • C Language Dialect: C99 [-std=c99]

      • Other C Flags: -DDEBUG=1

        • 開發時可以用的 debug mode

      • Header Search Paths: /usr/include/libxml2

      • Other Linker Flags: -lxml2

      • Other C Flags: -DGDATA_REQUIRE_SERVICE_INCLUDES=1 -DGDATA_INCLUDE_CONTACTS_SERVICE=1

        • 可以精簡編出來的大小,將沒用到的去除

        • 建議最後才加!因為我嘗試一開始就加了反而有些物件宣告會出現 error ,如 expected specifier-qualifier-list before 'GDataServiceGoogleBlogger' ,但明明我已經加了 GDataServiceGoogleBlogger.h 過了!反而試 GDataServiceGoogleContact 沒出錯,完整 code 片段:

          • #import <UIKit/UIKit.h>
            #import "GDataServiceGoogleBlogger.h"
            //#import "GDataServiceGoogleContact.h"

            @interface UseGoogleAPIAppDelegate : NSObject <UIApplicationDelegate> {
                UIWindow *window;
                GDataServiceGoogleBlogger *service;
            //    GDataServiceGoogleContact *service;
            }
            @property (nonatomic, retain) IBOutlet UIWindow *window;
            @end

  5. 以上設定完後,可以先按 Build 一下,即使還沒寫什麼程式,也可以先編看看是否正確,此測試編譯檔案有 282 個。

開始測試 Google Data APIs:

UseGoogleAPIAppDelegate.h

#import <UIKit/UIKit.h>
#import "GDataBlogger.h"
//#import "GDataServiceGoogleBlogger.h"

@interface UseGoogleAPIAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    IBOutlet UITextField *username;
    IBOutlet UITextField *password;
    IBOutlet UIButton *button;

    GDataServiceGoogleBlogger *service;
    GDataServiceTicket *ticket;
    BOOL logged;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
- (IBAction)doLoginOrLogout;

@end

UseGoogleAPIAppDelegate.m

#import "UseGoogleAPIAppDelegate.h"

@implementation UseGoogleAPIAppDelegate

@synthesize window;

- (IBAction)doLoginOrLogout {
    username.userInteractionEnabled = NO;
    password.userInteractionEnabled = NO;
    if ( logged ) {    // do logout
        [button setTitle: @"登入" forState:UIControlStateNormal];
        logged = NO;
    } else if( [username.text isEqualToString:@""] || [password.text isEqualToString:@""] ) {
        [button setTitle: @"帳密不可為空, 請重新登入" forState:UIControlStateNormal];
        username.userInteractionEnabled = YES;
        password.userInteractionEnabled = YES;
    } else {            // do login
        [button setTitle: @"登入中..." forState:UIControlStateNormal];
        [service setUserCredentialsWithUsername:username.text password:password.text];
        ticket = [service fetchFeedWithURL:[GDataServiceGoogleBlogger blogFeedURLForUserID:kGDataServiceDefaultUser]
                        feedClass:[GDataFeedBlog class]
                        delegate:self
                        didFinishSelector:@selector(checkLogin:finishedWithFeed:error:)];
    }
}

- (void)checkLogin:(GDataServiceTicket *)ticket
      finishedWithFeed:(GDataFeedBase *)feed
                 error:(NSError *)error {
    if (error == nil) {
        logged = YES;
        [button setTitle: @"登出" forState:UIControlStateNormal];
    } else {
        logged = NO;
        username.userInteractionEnabled = YES;
        password.userInteractionEnabled = YES;
        [button setTitle: @"帳密錯誤, 請重新登入" forState:UIControlStateNormal];
    }
}

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    username.keyboardType = UIKeyboardTypeEmailAddress;
    username.returnKeyType = UIReturnKeyDone;
    password.keyboardType = UIKeyboardTypeEmailAddress;
    password.returnKeyType = UIReturnKeyDone;
  
    service = [[GDataServiceGoogleBlogger alloc] init];
    [service setShouldCacheDatedData:YES];
    [service setServiceShouldFollowNextLinks:YES];
  
    logged = NO;
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}

- (void)dealloc {
    [service release];
    [window release];
    [super dealloc];
}

@end

UseGoogleAPIAppDelegate.xib

google_api_xib_layout

排好後,別忘了幫按鈕接上 doLoginOrLogout 事件,除此之外,也接另一條線跟 button 變數結合,這樣才能透過程式去更改按鈕上的文字,其他部分則是把 UITextField 也接好變數,這樣才能從 UI 上把物件的數值取下來。

起始畫面:

google_api_init

輸入帳密錯誤:

google_api_access_fail

帳密欄位空白:

google_api_password_or_id_empty

正確登入後:

google_api_after_login

最後一提的,其實 Google Data APIs Objective-C Client Library 裡頭有附上豐富的 Example 囉,不過一開始編譯時,我是在 Mac OS X 10.6.2 環境,最後會出現找不到 MacOSX10.4u.sdk ,在此我是直接用 MacOSX10.6.sdk 替代,程式至少還跑的起來囉

$ cd /Developer/SDKs/
$ sudo ln -s MacOSX10.6.sdk MacOSX10.4u.sdk

BloggerSample



1 則留言:

  1. 您好
    我想請問一下libxml2是Mac本身就內建的還是需要額外下載安裝?

    如果需要額外下載安裝
    想請問一下該去哪邊下載呢?
    謝謝!!

    版主回覆:(10/25/2010 02:24:47 PM)


    Hi, 超久沒玩了 XD

    這通常跟自家作業系統裝的如何有關
    你可以用 terminal/終端機 去查看, 如

    $ ls /usr/include/libxml2
    libxml

    若有看到資料代表系統已經有了,這樣就只剩開發時加好 path 就行了
    你再玩看看~

    回覆刪除