2010年3月2日 星期二

自己新增facebook-actionscript-api類別來使用dashboard的相關功能

有用Flash開發Facebook app.的人應該對facebook-actionscript-api這個library又愛又恨。使用它加上一些javascript就可以開發Flash版的Facebook app.,可是它的說明文件內容相當缺乏,而且很久沒更新了。其實這個library一直有在更新,目前出到v3.4版,一些新的功能都有陸續放進去。上次隨意點開它的as檔案來瀏覽,發現了com.facebook.commands.stream這個package,裡面的PublishPost類別,就是對應PHP api的stream.publish方法。於是想說,應該可以依樣畫葫蘆來新增command。這樣在facebook-actionscript-api還沒更新前就可以自己新增一些PHP api有的新功能,例如前一陣子才新增的dashboard。實際測試之後發現可行,正好notification通知的功能,app.也不能再使用了,就趕緊來試用一下dashboard怎麼玩。這篇就同時介紹如何自己幫facebook-actionscript-api增加新的功能,以及dashboard這個功能大概是怎麼運作的。

首先,先來了解一下dashboard是什麼。先看這張圖:(點選可放大)

每個app會被facebook分為兩大類:應用程式(application)或遊戲(game),大概是依照app.的描述去分類的吧?這兩類就會個別被放到新版首頁左邊的應用程式集跟遊戲中心。就看我們開發的app.被分到哪一類,假設在應用程式集裡,點開來後就長得跟上圖一樣,遊戲中心也是一樣。

中間上面那塊「你在用的應用程式」這欄裡面的訊息叫做News,每次發布可以指定前面那張圖64x64 px,還後一個短訊息,可包含使用者與朋友名字,共50字元,後面可以接一個action link,顯示文字可以有25字元。這可以讓使用者在app.中對指定的朋友發送,一次可以同時發8則,不過一次一則應該就夠了。也可以讓app.的管理者對複數或所有使用者發布,例如app.的更新消息之類的。這部分當然要另外寫個管理程式之類的。

往下一個區塊是「朋友的近期遊戲動態」叫做Activity,圖片固定是app.的logo不能換,後面接一個短訊息,一定要含使用者的名字,然後也可以加好友的名字,一樣50個字元,跟News一樣,後面也可以接一個action link。Activity是當使用者發布後,所有朋友都可以看到。不過,facebook特別註明這功能還在實驗階段,隨時都會改,我實際使用起來也怪怪的,有時發布成功卻只有自己可以看到

而在左邊,如果使用者有把這個app.加入書籤的話,就可以在列表上面看到。而後面有時候有個數字,這個數字叫做Counter,目的是讓使用者知道這個app.有新消息,或者更新,又或者你的朋友在上面做了什麼之類的。所以使用上可以在發News的同時讓這個朋友的Counter也+1,發東西到塗鴉牆或送禮物時也可以結合來用。這個數字其實完全是由程式來控制,它不會自動歸0,使用者也可以隨意將它設定成任何數字!這真的很妙,因為數字本身其實沒有意義,最大的意義在於利用很多人「看到數字就很想點下去讓它歸0」的心態,不知不覺就點到app.去了。app.的管理者也可以寫個管理介面更改複數或所有使用者的Counter。

Dashboard的長相跟功能介紹完畢,如果不是開發者的話,可以關掉視窗離開囉。接下來要介紹如何新增facebook-actionscript-api的功能來玩dashboard。

要自己動手來新增類別,當然是假設大家都已經玩過一陣子了,登入,取得Session等等都沒問題,而且對基本的發送command以及偵聽complete事件去做處理,這樣的流程都很熟悉了,才有辦法玩。然後要下載這個library的as檔,用它的swc是沒辦法做修改的喔。還有,我們要對照線上的wiki來看,所以要搞清楚一件事情:這個library對應的,是PHP api,不是javascript版的喔。找相關的網頁來看時可別搞錯。

這個library有玩過的大概知道,除了一開始驗證的流程,最常用的應該就是commands跟data兩個package。這兩個package底下,也依照api項目去做分類。commands管如何發送命令給相對應的PHP api去執行,data管的則是這中間使用到的資料類別,以及接收回來拆解成適合的資料來使用。data類其實可有可無,只要定義好commands,用Object或Array等資料型態一樣能傳。data類主要讓你方便知道每種資料型態下有哪些參數要下,哪些資料可抓,這對使用FlashDevelop來開發相當有利。反之,使用Flash IDE來開發,反而會覺得一大堆data的類別既複雜又難記。

接著我們就來做個Dashboard.addNews的功能。這功能就是發一個News給一個指定的朋友。先到com.facebook.commands底下開一個dashboard的資料夾。然後我們複製一個command來改,這邊使用com.facebook.commands.stream裡的PublishPost,將它複製到dashboard資料夾底下,然後檔名先改成AddNews.as。然後打開它,最上面一段註解,如果有提到api方法或網址的,就把它改成Dashboard.addNews以及它的wiki網址。接著32行的地方當然要把package改成:
package com.facebook.commands.dashboard
import跟use namespace的部分通常不用改,先不管它。40跟52行的類別名稱跟建構式要改成AddNews,這些有基本類別觀念應該都沒問題。42行METHOD_NAME就是它相對應的api名稱,要改成
public static const METHOD_NAME:String = 'Dashboard.addNews';
下一行SCHEMA是它需要接收的參數名稱,參考它的wiki,知道需要傳入的有三個,所以改成:
public static const SCHEMA:Array = ['uid','news','image'];
接著是這個類別需要的參數,我們自己定:
public var to_id:String;
  public var news:Array;
  public var image:String;
再往下則是建構式,
public function AddNews(to_id:String,news:Array,image:String=null){ 
   super(METHOD_NAME);
   
   this.to_id = to_id;
   this.news = news;
   this.image = image;
  }
接收值當然也是參考wiki來決定,通常就使用String、Array、Object等flash的資料類別就好,有預設值就設一下,例如image可以不給,也就是預設使用app.的logo。三個參數分別解釋一下:to_id是要發給哪個user,通常app.裡面會有機會讓使用者選擇朋友之類的。news是個陣列,前面提到最多一次可以發8個,每個element裡面基本上是個Object,也就是每個news的內容。image就是一張64x64 px圖檔的完整連結,不給的話就用app. logo。建構式的裡面,第一行呼叫父類別建構式,把METHOD_NAME丟給它,這行是固定的不要動,下面則是把接進來的資料丟給類別裡剛定義的參數,這樣就好了。最後需要override一個叫initialize()的function:
override facebook_internal function initialize():void {
   var parsedNews:String = JSON.encode(news);
   applySchema(SCHEMA, to_id, parsedNews, image);
   super.facebook_internal::initialize();
  }
第1行,凡是Array或Object要真正丟出去處理前,要轉成JSON編碼,所以news要處理一下。記得檢查一下上面有沒有把com.adobe.serialization.json.JSON給import進來。第2行處理SCHEMA,第一個參數固定是SCHEMA,第二個以後就依序是SCHEMA裡面剛剛設的參數,順序要對起來。最後一行是固定的不用改。這樣就完成了這個command了。完整程式碼重貼一次:(註解就省掉了)
package com.facebook.commands.dashboard {
 
 import com.adobe.serialization.json.JSON;
 import com.facebook.net.FacebookCall;
 import com.facebook.utils.FacebookDataUtils;
 import com.facebook.facebook_internal;

 use namespace facebook_internal;
 
 /**
  * The AddNews class represents the public  
      Facebook API known as Dashboard.addNews.
  * @see http://wiki.developers.facebook.com/index.php/Dashboard.addNews
  */
 public class AddNews extends FacebookCall {

  
  public static const METHOD_NAME:String = 'Dashboard.addNews';
  public static const SCHEMA:Array = ['uid','news','image'];
  
  public var to_id:String;
  public var news:Array;
  public var image:String;
  
  public function AddNews(to_id:String,news:Array,image:String=null){ 
   super(METHOD_NAME);
   
   this.to_id = to_id;
   this.news = news;
   this.image = image;
  }
  
  override facebook_internal function initialize():void {
   var parsedNews:String = JSON.encode(news);
   applySchema(SCHEMA, to_id, parsedNews, image);
   super.facebook_internal::initialize();
  }
 }
}

然後怎麼用咧?開一個app.,登入那些都處理完後,抓一個朋友的id,或抓登入者自己的,做一個button來發布News,這個button的MouseEvent.CLICK的事件處理函數,以及發完News的COMPLETE事件處理函數長這樣:
private function addNewsClickHandler(e:MouseEvent):void {
   var uid:String="xxxxxxxxxxxxxxxxx";
   var uid_to:String="ooooooooooooooooo";
   var actionLink:Object = new Object();
   actionLink.href = "http://apps.facebook.com/xxxxxx/";
   actionLink.text = "你也來問候他!!";
   var news1:Object = new Object();
   news1.message = "你的好朋友@:" + uid + "問候你!!";
   news1.action_link = actionLink;
   var imagesURL:String = "http://1001.webgene.tw/gray/091006_fbtest/images/64x64.jpg";
   var call:FacebookCall = new AddNews(uid_to,[news1],imagesURL);
   call.addEventListener(FacebookEvent.COMPLETE, addNewsCompleteHandler);
   _facebook.post(call);
  }
  
  private function addNewsCompleteHandler(e:FacebookEvent):void {
   e.currentTarget.removeEventListener(FacebookEvent.COMPLETE,addNewsCompleteHandler);
   if (e.error != null) {
    trace("addNews Error:", e.error.errorMsg);
   }
   if (e.success && e.data != null) {
    trace(StringResultData(e.data).value);
    ExternalInterface.call("window.alert", "addNews更新成功");
   }
  }
這裡先用基本的Object與Array類別來設定資料就好。uid是登入者的uid,等等訊息裡面要用而已,uid_to是接收者的uid。actionLink就是最後面的連結,需要href與text屬性來設定連結與顯示文字。action link不是必須的,也可以不要。news1是第一則news,當然我們只設定一則。message就是訊息內容,使用@:xxxxxxx可以把使用者的名字塞進去。action_link就是剛剛設好的actionLink。imagesURL就指定一張圖檔的網址給它,當然也可不給。接著三行就是標準的command呼叫而已:建立一個FacebookCall,當然是使用我們剛剛新增的AddNews,把上面該給的資料給它。設定COMPLETE的事件處理函數。最後post出去。COMPLETE的事件處理函數很單純,有error就trace出來,如果成功且有data,就把它trace出來,然後用js彈個alert視窗告訴你成功了。接回來的e.data是個StringResultData,它的value裡面帶一串id,應該是剛剛那個news的id,可以給dashboard.clearNews清除用。

以上,單純新建一個command就可以用了,進一步的話,可以在com.facebook.data下一樣開個dashboard資料夾,可以參考其他data裡面相似的檔案來改,例如把stream裡的ActionLinkData搬過來用,然後自己新增NewsCollection以及NewsData等類別來用,再把button click裡面的Array以及Object換成這些類別就好了。改法比command還簡單,就不多佔篇幅了。

不確定Adobe是否有版權問題,所以就先不丟下載檔案上來。有興趣的私下再...嗯。況且等v3.5版出來,這些功能應該也都新增進去了吧。方法弄出來,以後as版的更新跟不上PHP版的時候,就自己更新吧!改完第一個,第二個以後都很簡單的啦~~。

順帶提一下dashboard底下幾個東西我測試的心得:
dashboard.addNews:重要,上面玩完了。
dashboard.clearNews:清除剛剛發的News。可是這東西應該是發出去就給它覆水難收才對。所以不理它。
dashboard.getNews:抓某人(uid)在這個app.的News。
接著相對以上三個,有針對Global的三個方法:
dashboard.addGlobalNews
dashboard.clearGlobalNews
dashboard.getGlobalNews
這三個需要直接給它app.的secret,不像前三個有session secret就可以呼叫,所以應該是屬於管理者才能使用的方法,而管理者使用的管理介面應該不會用flash來開發,所以也不用費力去改它。再來三個針對多個使用者的三個方法也是屬於管理者用的:
dashboard.multiAddNews
dashboard.multiClearNews
dashboard.multiGetNews
News完了,接著有關Activity的三個,Activity跟News的差別上面提過了:
dashboard.getActivity:傳回目前登入使用者,這個app.最多100則Activity。
dashboard.publishActivity:發一個Activity出去。會回傳Activity的id。
dashboard.removeActivity :移除多個Activity。
接著是關於Counter,給一般使用者的有:
dashboard.decrementCount:Count - 1,找不太到機會用它。
dashboard.getCount:取回現在的Count數。
dashboard.incrementCount:Count + 1,想加的時候就呼叫一下,常用。
dashboard.setCount :將Count設定為某個數值。通常大概是點回來app.時把它設為0吧。我試過沒大腦的設為1,000也行,也許搞個7,777吸引user注意的另類手法也行!?
最後,相對上面四個,也有多人版的可用:
dashboard.multiDecrementCount
dashboard.multiGetCount
dashboard.multiIncrementCount
dashboard.multiSetCount
也是需要secret,所以我覺得也是偏管理者來用。

好了好了,終於又結束一篇了~~

4 則留言:

  1. 您好 有緣走到你這邊 看到您的文章...
    最近我剛好在研究 dashboard 這一塊
    想請教一下
    dashboard.decrementCount 可以達到+1的部分
    但是 當我沒在facebook首頁看的時候 他則不會有+1的動作出現
    不過看別人的應用程式 就算離線 下次在上 都還是會看到有 2 之類的數字呈現 這部分該如何做呢.... 請教一下了

    回覆刪除
  2. To 張家修:
    這篇已經不適用了,請使用Facebook新的Graph API
    另外dashboard.decrementCount應該是 -1 不是 +1 喔

    回覆刪除
    回覆
    1. 目前 +1 -1 跟指定數字 dashboard.setCount
      都可以執行
      就是 如果facebook關掉 他就無法接收到 也無法紀錄住這次的數字在
      這真是困難的點
      哭哭

      刪除
  3. 恩恩 很感謝您的回覆
    讓我還有一絲希望 QQ
    因為目前還是卡在
    當我沒在facebook首頁看的時候 他則不會有+1的動作出現
    不過看別人的應用程式 就算離線 下次在上 都還是會看到有 2 之類的數字呈現
    您有遇過這個問題嗎?

    回覆刪除