2011年1月4日 星期二

Facebook ActionScript Graph API ( 1 ) 取得認證與授權,以及登入

首先準備幾件事:第一,下載Adobe ActionScript 3 SDK for Facebook Platform API,裡面有原始檔,SWC,Docs,Examples,是個規模還算小的API,所以其實花點時間就看完了。第二,雖然Adobe上面有一系列介紹文章,建議可以先開發AIR應用,再將程式碼改為WEB App.,但我試過好像也沒多方便,所以還是習慣丟到網站上測試。要在網路上測試,當然要安裝Flash Player Debug版,還要有個可以讀取Flash Log的工具,例如Vizzy Flash Tracer。第三,開一個測試App.,在"網站"裡面設定好Site URL,以及"Facebook整合"裡面的Canvas Page與Canvas URL,我們等等會練習一般Web連結Facebook,以及Facebook上IFrame App.的認證授權與登入。最後將"應用程式 ID"複製下來,接下來會用到。

外部Web連結Facebook

html
由於這個AS3 API會透過之前介紹的JavaScript SDK去做一些事情,因此之前說過需要在html上加的兩樣東西也要加上。第一個,include這個js檔:
src="http://connect.facebook.net/en_US/all.js"
中文版可以改成:
src="http://connect.facebook.net/zh_TW/all.js"
第二個是加上這個div:
而Flash要正常呼叫ExternalInterface需要設定好Embed id,如果透過swfObject來embed,要設定attributes(最後一個參數)的name。如果是Progression,則progression.js會自動幫你設定一個,因此不用特地去設定。
設定好之後就可以進入ActionScript的部分了。

ActionScript
在這個API中,我們幾乎都是透過com.facebook.graph.Facebook這個Class來操作,先將它import進來。接著進入頁面的時候我們就要先對這個API初始化,同時做認證與授權的動作。只要執行一行程式:
Facebook.init(_appID, initHandler);
Facebook不需要產生實體,直接呼叫它的init方法,第一個_appID就是之前我們複製過來的"應用程式 ID",initHandler是個callback function,接著就來設定它:
private function initHandler(result:Object, fail:Object):void 
{
  if (result)
  {
    trace("result.uid = " + result.uid);
    //若曾經登入過,這邊就可以取得session,可以執行自動登入的動作
  }else {
    
  }
}
這個function必須設定兩個輸入參數,兩個都設為Object。Facebook.init()無論如何會先初始化API,然後如果user最近有登入過這個App.,這邊就可能可以取得session,result就會是個com.facebook.graph.data.FacebookSession類別。result.uid就可以取得user的user id。若有取得session,其實就完成登入的動作了,我們接著可以執行登入後的所有步驟。但若是第一次進來,或上次登入的時間已經很久了,result就會等於null。如果我們希望user一定要按"登入"或"連結Facebook"之類的按鈕才能進行之後的步驟,這邊也可以不做任何處理。
接下來我們放一個"登入"的Button,Click後執行:
Facebook.login(loginHandler, {perms:"user_about_me, user_photos"});
loginHandler一樣是callback function,第二個參數可以輸入data,perms是當要求授權時希望user同時同意的extended permissions,用逗號隔開。這邊應該盡量要求越少越好。loginHandler與initHandler差不多:
private function loginHandler(result:Object, fail:Object):void 
{
  if (result)
  {
    trace("result.uid = " + result.uid);
    //處理登入後的動作
  }else {
    
  }
}
到這裡,如果有跳出授權的popup window,允許後成功trace出user id的話,就大功告成了!很簡單吧!兩個指令,兩個處理函式,就完成登入的動作。之前使用過Facebook Connect的人,應該感動到想哭了吧!除了uid,另一個更重要的東西是access_token了,因為uid用me或me()就可以取代了。access_token可以在登入時由result.accessToken取得,之後也可以經由 Facebook.getSession() 先取回FacebookSession,後面再接.accessToken就可以了。
登入後也可以加個"登出"的Button,Click後執行:
Facebook.logout(logoutHandler);
logoutHandler再去處理登出後要做的事就可以了。

IFrame App.

就是套上Facebook外框,網址為 http://apps.facebook.com/xxxxxx/ 的App.。前面已經先請大家設定好了。這種App.通常授權時我們不使用popup window的方式,而是在一開始直接轉到授權頁去要access_token,之後就不會再放"登入"或"登出"的Button,這是因為外面已經套了Facebook的外框了,使用者經驗的問題。當然我們可以先放些App.的簡介,等到user大概知道這是怎樣的App.,再用一個"進入"或"開始使用"的Button去要授權。
html
html除了之前應該加的三個地方,我們要多寫一個JavaSctipt function,這樣使用上比較靈活:
function redirect() {
  var addID = "xxxxxxxxxxxxxxxx";
  var permission = "user_about_me, user_photos";
  var canvas = "xxxxxx";
  var params = window.location.toString().slice(window.location.toString().indexOf('?'));
   top.location = 'https://graph.facebook.com/oauth/authorize?client_id='+addID+'&scope='+permission+'&redirect_uri=http://apps.facebook.com/'+canvas+'/'+params;
}
這是個會轉到授權頁要求授權,成功後轉回App.網址的function,請輸入addID,需取得的permission,canvas則是App.網址 http://apps.facebook.com/ 後面接的路徑名稱,每個App.就改這三個參數就好了。params則是網址上面如果有帶其他參數,授權完轉回App.時也會再帶回來。這邊也可以不管三七二十一就直接去呼叫redirect(),但我們把呼叫它的工作放到Flash裡面。

ActionScript
如果我們希望一進Flash就檢查是否能取得session,取不到就執行轉到授權頁的動作。這時候就盡量放在讀取大檔案之前。假設我們有個preloader.swf會去讀取index.swf那麼就在preloader.swf要去讀取index.swf之前加上:
Facebook.init(_appID, initHandler);
而initHandler則是:
private function initHandler(result:Object, fail:Object):void 
{
  if (result)
  {
    //讀取index.swf
    }else {
      ExternalInterface.call("redirect");
    }
}
如果能取得session,就直接進入index,否則呼叫JavaScript轉到授權頁。
假設流程改成前面所講的,先讓user看一些App.的簡介再讓他進入,就可以先讀取index.swf,在index.swf一進入時執行:
Facebook.init(_appID, initHandler);
initHandler改成:
private function initHandler(result:Object, fail:Object):void 
{
  if (result)
  {
    //直接進入App.內容
    }else {
      
    }
}
若能取得session就讓user直接進入App.內容,否則放個"開始"之類的Button,Click後執行:
ExternalInterface.call("redirect");
這樣就可以了。

最後補充一點,Facebook的init、login、logout等都需要透過ExternalInterface呼叫JavaScript SDK,因此在使用時最好加上個判斷:
if (ExternalInterface.available)
{
  Facebook.init(_appID, initHandler);
}
這樣就比較不會在local端發布時出問題啦。

上一篇文章:Facebook ActionScript Graph API ( 0 ) Graph API與Facebook官方文件介紹
下一篇文章:Facebook ActionScript Graph API ( 2 ) Graph API的GET、POST與DELETE

15 則留言:

  1. 我照著你的步驟做了
    並把SWF檔放到FACEBOOK APP測試
    但Facebook.init(_appID, initHandler)無論成功或失敗都不會呼叫initHandler
    請問你知道為什麼嗎?
    另外html裡的attributes的id是隨便設定一個值就可以了嗎?
    謝謝

    回覆刪除
  2. To Sam:
    我發現我寫錯了,應該要設定attributes的name屬性才對
    可能是這個沒設定好導致JavaScript沒辦法回call ActionScript,請再試試囉

    回覆刪除
  3. yes!可以了~就是name沒錯
    謝謝你喔:D

    回覆刪除
  4. One of the changes to the API was wrapping the supporting JS code in an AS file. We call ExternalInterface.objectID to get a reference to the embed/object tag so we can communicate with the Facebook JS API (used to login, get login status, etc). However, ExternalInterface.objectID returns the id attribute in IE or the name attribute in Netscape browsers (referenced in AS3 docs). In order to support Chrome/Mozilla, the name attribute has to be included in the embed/object tag and set to the same value as the id. For example, when embedding using swfObject we had to include the {name:"flashContent"} param in the embed swf call. That way, it should work for IE, Chrome, and FF.
    There is a known issue in Opera though but this seems to be a workaround. (http://forum.developers.facebook.net/viewtopic.php?pid=235642#p235642)

    回覆刪除
  5. Gray 您好

    我測試使用者第一次登入 app , 會出現授權頁面, 但是點完 "確定" 授權後 .... 頁面並沒有重新回到 app ... ( 已經使用 IFrame 方式將 app 內嵌在 Facebook 中 ... )
    想請問我是不是遺漏什麼地方了 ... 或是我應該檢查哪邊?
    > <! 謝謝

    回覆刪除
  6. 不好意思!!我解決了 .... 是我自己流程編寫不好~~~報歉!

    回覆刪除
  7. Gray你好:

    我想請問一下我在
    Facebook.init(_appID, initHandler)可以收到回call function,
    但在Facebook.logout(logoutHandler)卻無法收到,
    請問你有這個問題嗎?
    非常謝謝你的教學!!

    回覆刪除
  8. To erika:
    我使用的時候會正確呼叫,所以可能要請妳再檢查看看了

    回覆刪除
  9. Gray你好:
    我也遇到用progression.js去embed swf,結果js無法回扣flash function!
    但我不大會javascript,只能大概去看~~~
    想請問你怎麼解決的呢?

    然後可以附上sample嗎?

    真是打擾了XD

    回覆刪除
  10. To 吸膠の男孩:
    如果使用progression.js基本上只需要include該用的js以及在body裡面加上fb-root這個div, 這兩步都有做的話就可以了, 不需要修改什麼耶

    回覆刪除
  11. To Gray:
    是哦,但我的不work,現在只能去網路上找最普通的embed方法~~~
    不過我很好奇,用普通的embed,為什麼progression的deep-linking還是在勒?

    回覆刪除
  12. To 吸膠の男孩:
    deep-linking是使用swfAddress, 跟embed比較無關

    回覆刪除
  13. Gray您好!!
    想請教您以下問題:

    我在Flash裡放置一個了text欄位 name=test1
    在if (result)
    {
    test1.text="User ID"+result['uid'];
    }else {

    }
    可成功顯示出 User IDxxxxxxx
    但是我想試著把"User ID"改成中文的"使用者ID",但只要將test1內嵌字體加入中文,瀏覽時就沒辦法顯示

    我在html中已經有加入
    src="http://connect.facebook.net/zh_TW/all.js"
    請問我有疏忽什麼部份嗎?

    回覆刪除
  14. To Joe:
    如果只有"使用者"三個字要用中文,可以用靜態文字加在前面,ID的部分才用動態文字。我不知道你用甚麼方法嵌入中文字體,是否有指定嵌入的範圍,文字框裡的文字可以清掉看看。總之,看起來只是單純中文嵌入的問題,跟FB是沒有關係的。

    回覆刪除
  15. Hi Gray,
    謝謝您的回覆!!
    我在Flash置入一個文字欄位 命名為"test2"
    我試著要讓FB的回傳值顯示在test2欄位,如下列程式碼片段:
    protected function getUserHandler(result:Object,fail:Object):void{
    if (result) {
    test2.appendText('id :'+result['id']+'\n');
    test2.appendText('name :'+result['name']+'\n');
    test2.appendText('locale :'+result['locale']+'\n');
    test2.appendText('gender :'+result['gender']+'\n');
    } else {
    test2.text = "err"+JSON.encode(fail);
    }
    }

    進入網頁,FLASH的test2欄位可以成功列出id,locale,gender
    但是name的回傳值因為是中文的所以顯示不出來,所以我要在test2的屬性裡面,點選"內嵌字體",然後加入繁體中文

    但是只要我一做這種嵌入中文的動作,在進入網站整個FLASH就顯示不出來
    移除掉中文,就又恢復正常

    PS.我不是用程式碼的方式嵌入中文,是從欄位的設定裡面去嵌入

    回覆刪除