2009年10月27日 星期二

Flash版GoogleMap使用街景


前一陣子(好大一陣子),GoogleMap的台北街景上線,順便的我發現GoogleMap api for flash也有多了一些東西,像是路徑規劃、3D地圖等等…。
3D地圖基本上只是把地圖變成可以旋轉改變角度而已,事實上仍然是平面的,「非常的」耗效能,國外是有人把建築物用pv3D直接疊在3D地圖上感覺像是Google Earth一樣,但是說真的我的電腦已經算不慢的了,跑起來還是慢到可怕…。

說起來比較讓人興奮的應該是路徑規劃了吧。
之前Flash版的GoogleMap少了這個總覺得少了什麼,現在有了就好多了。
不過這一篇不是要講路徑規劃的部份,而是要講街景。
之前因為台灣都沒有街景,所以一直沒去碰這個,現在台北有了,就很好奇的想把街景跟Flash的GoogleMap結合起來看看。
有把玩過GoogleMap街景的應該都會注意到,街景的介面是Flash的,我想這是因為Flash在處理圖片的移動及blur這些部份是比js來得方便的原因吧?但是目前為止雖然街景介面本身是個Flash,但是仍然無法直接被Flash版的GoogleMap直接載入使用,所以我只好用土法練鋼的方法 – 透過js溝通。

Google在文件上寫得還算清楚明白,大概看一下就知道怎麼叫出街景了,挺簡單的。
先從html開始,首先載入GoogleMap的js,要改變的只有key這個變數,key就是跟Google申請的api key。
然後在body上加入onload跟onunload的處理方法,我這邊是先分別指定initialize()跟unloadAll()兩個function來負責。onunload一定要處理,否則很有可能會造成記憶體沒有回收的狀況。


由於地圖是由Flash來處理,因此就不產生js的GoogleMap實體。
所以直接宣告廣域的街景物件(GStreetviewPanorama)及一個判別是否由flash版GoogleMap指定座標的flag。由於GStreetviewPanorama需要一個dom來放置,所以在html裡我們放一個div來裝GStreetviewPanorama。
然後就編寫initialize()及unloadAll()。


GStreetviewPanorama的error事件我們主要會用到的大概是兩個:
1. 錯誤代碼603:表示沒有Flash Player。
2. 錯誤代碼600:被指定的座標沒有街景。
基本上這兩個都要實作,以避免出問題。
而GStreetviewPanorama的initialized事件,則是當GStreetviewPanorama的座標位置改變的時候會被觸發,因此我們可以監聽這個事件來控管目前地圖跟街景之間座標的同步。
因此這兩個事件處理函式應該會很像是這樣子:


最後就很簡單了。
需要顯示哪邊的街景時,就直接從Flash版的GoogleMap用ExternalInterface去呼叫一個function來指定GStreetviewPanorama的座標就好。


在看文件時,其實js的GoogleMap有一個優點是可以把目前有支援街景的路線疊上一個overlay在地圖上,但是Flash版的沒有,所以如果要用Flash版的GoogleMap去結合街景,使用者只能用「試試看」的方式去點選某條路是否有街景,這是比較不方便的,也許也只能等Google下次更新Flash api時再期待會不會有這功能出現了。

2009年9月3日 星期四

Facebook Flash Application開發心得(4) – Iframe的架構下取得Session


相對於FB Connect在取得Facebook登入Session值的複雜度,Iframe架構下的Application在這方面反而方便許多。
前一篇已經有說到Flash api裡的FacebookSessionUtil在FB Connect的情況下會有bug,但是在iframe之下卻可以運作得非常順利。其中很大的原因,是因為iframe的架構原本就是附屬在Facebook裡的,登入的狀況都由Facebook先處理掉了,Facebook才會開始載入iframe,也就是說user很少會在還沒登入的狀況之下就接觸到你的iframe application,因此我們可以少掉一部份處理尚未登入的情況,但如果user真的有辦法在未登入的情況下進入我們的iframe application(會有,在某些情況下會發生),我們只要直接把頁面導回給Facebook處理就好,等登入後Facebook會自動再幫我們導回來(很方便吧!)。這個利用Facebook來做導向的機制也會發生在user第一次進入應用程式的時候的那個授權頁。
另一個很重要的原因,正由於iframe架構是由Facebook所載入的,因此Facebook「很貼心」的順便帶了一些十分有用的資訊放在url後面的變數裡給iframe,這一大堆的資訊裡面就包括了Session值。

既然知道了這很重要的兩點,就來實作吧。
首先當然是針對javascript下手。

依照剛剛所說的兩個重點,一開始先要取得的就是Facebook帶給iframe的所有必要參數。

上面這段code最重要的部份就在於取得所有網址列後面的變數並放在flashVars裡。
另一個重點就是fb_sig_added變數的取得,它代表了user是否已經授權使用你的application,如果是0(尚未登入的情況下好像也會是0),我們就把整個頁面導向到http://www.facebook.com/login.php?api_key=" + api_key + "&next=index.htm&v=1.0&canvas=1的這個網址,網址列後面的參數api_key就是你的api_key,next指的是授權後要再導回來的頁面,我習慣是再導回index.htm。(有興趣的人可以觀察一下,事實上Facebook如果是在你已經登入的情況但沒授權的時候是會導到另外一頁的,不過next也會跟著被帶過去,所以我們只要直接全交給login.php去處理就好)
當一切都就續時,我最後呼叫一個initFB的function,這個function裡我就開始初始化facebook javascript api。

初始化Facebook javascript api的部份,跟FB Connect不一樣,我這次採用FB_RequireFeatures來做為初始化的點,因為我很確定user已經是登入狀態,所以一開始就初始化所有該用到的東西。
而且如果我沒記錯的話(說真的印象有點久遠了),使用FB_RequireFeatures的話,Facebook會強制在你的appilication外層加上它的外框(上面的header及下面的footer),所以如果你是直接輸入你application實際的網址的話,遇到FB_RequireFeatures時還是會Facebook框起來。
因此之後有時候,我們將會遇到iframe及FB Connect同時應用在一個application的情況中,也就是說即使在iframe的情況之下,有時還是要用到FB Connect,這也是我先介紹FB Connect的原因之一。(如果我以後還會繼續寫下去的話)
至於FB_RequireFeatures裡所帶的一些值的意義,可以去官方的wiki上看,基本上我也沒有實際的去比較這幾個之間差多少,所以我就乾脆直接初始化三種我覺得可能會用到的。
通常這個function這樣應該就ok了,不需要改寫,直接拿去用就好。
等到一切都就緒後,就呼叫initFlash這個function來載入flash,這function我就不寫出來了,反正就是用swfObject載入就是了 (記得要將flashVars帶進去)

接下來就是Flash裡的code了。
既然已經說了FacebookSessionUtil在iframe裡很好用,就直接大方的用了吧。

基本上,user算是通過層層關卡才會到達flash這一層的驗證:Facebook本身一層,javascript有兩層驗證,第四層才會是FacebookSessionUtil,所以基本上在上面的code裡使用FacebookSessionUtil.login()是用於開發時直接在本機端跑的情況下,否則應該都是直接verifySession就可以取得登入uid了。
ps:如果是在開發的時候,api secret值需要寫入,否則無法登入,這就是Facebook建議我們不要把api secret值寫死在code裡的原因,因為一但被取得,其它cracker就可以利用本機端寫程式來破壞你的application,所以記得上線時要把api secret值從code裡拿掉,FacebookSessionUtil自動會從loadInfo裡所有的flashVars取得它該使用的secret值。

2009年8月20日 星期四

Facebook Flash Application開發心得(3) - 由Flash Api從Facebook取得資料


當最煩人的session問題解決之後,就該試著跟Facebook要點資料來瞧瞧了。
這一篇會大概解說一下Flash api如何跟Facebook索取資料的動作。
基本上Facebook Flash api在這方面的流程很簡單,其實就是先產生一個「命令」然後把這個命令丟給Facebook類別往外post出去就好,要做什麼動作就去產生相對應的命令類別就可以了。
所有的命令類別都繼承com.facebook.net.FacebookCall,有興趣的人可以直接去說明文件看這個類別,它就有列出所有它的子類了。
說明文件在這邊:
http://facebook-actionscript-api.googlecode.com/svn/release/current/docs/index.html
幾乎所有的命令類別都是在com.facebook.command的package裡。

相對於發出命令的簡易,Facebook Flash api在接收資料時的繁複卻是不可思議到讓人惱怒。有時一個命令發出後,收到的資料型別居然要層層解析,動輒用到四五個類別,再加上說明文件的陽春,所以往往需要不斷的一直trace,最後才能得到你想要的資料。
這個部份待會的code就會見識到…。

接下來,我們繼續接著上一篇的去修改,Html的部份就不用動了,這次沒動到javascript,所以只改ActionScript。
我們這次要從Facebook取得自己的個人資料,因此在上次的connectHandler裡驗證成功後馬上執行這個動作:
使用到的是com.facebook.commands.users.GetInfo;這個類別。



GetInfo這個類別是用來跟Facebook索取會員資料用的,它可以允許一次索取很多人的,因此第一個參數是會員uid組成的Array。然後也可以指定要索取哪一些欄位,這些欄位的定義都在GetInfoFieldValues這個類別裡的靜態屬性,一樣是Array的形式,如果你要索取所有的欄位,那就直接帶入GetInfoFieldValues.ALL_VALUES就好,它本身就是一個Array型態。

接下來就是要處理事件回傳的結果:



開發Facebook application時,一直trace回傳的FacebookEvent會是一個好習慣…。FacebookEvent的形態基本上會是這樣:
[FacebookEvent type="complete" success=true data=[object GetInfoData] error=null]
type就不用講了,要注意的是success及data。
success就只有true或false,通常都是true,除非你跟Facebook之間的connection斷了,那success就會是false然後error會有東西。
data則是主要的資料,data會依照你命令的種類不同而有不同的資料型態,理論上命令的類別都是在com.facebook.command.xxxx的package裡,相對應的資料型態類別則會放在com.facebook.data.xxxx的package裡。
也就是送出命令時是去command裡找,接收到事件時就回來data這邊找。

這次的命令是com.facebook.command.users.GetInfo,收到的資料是com.facebook.data.users.GetInfoData。
但是其實討人厭的就在這邊,光一個GetInfoData還不夠,真的資料是存在GetInfoData類別裡的userCollection屬性 (com.facebook.data.users.FacebookUserCollection類別),所以只好不斷的轉型別把它轉成陣列,最後陣列裡儲存的是一個一個的com.facebook.data.users.FacebookUser型別的資料…。
因此光解析個人資料就要動用三個型別… 加上發出命令的類別的話一共是五個,老實說,說明文件夠好的話這都還ok,偏偏不是,所以開發Facebook application的話一直trace會是一個好習慣。
當熟悉它的運作方式後,十分建議自己寫一些類別來整合簡化這些步驟。


如果沒意外的話,當登入後就可以看到自己的名字跟照片顯示在畫面上了。

下一篇
Facebook Flash Application開發心得(4) – Iframe的架構下取得Session

2009年8月19日 星期三

FP9操作影格造成child MovieClip裡的動畫暫停的bug


這問題是奶綠前兩天發現的。
通常我們很習慣在操作動畫時,有時為了要控制快轉倒轉,常常會使用nextFrame()及prevFrame(),而且通常是配合Event.EnterFrame來使用。
但是奶綠發現,如果這個MovieClip有一個child MovieClip自己裡面有動畫在跑的時候,這樣的操作會造成這個child MovieClip的動畫「停止」,等到parent不再受到nextFrame()及prevFrame()的命令時,child MovieClip才會繼續跑它的動畫,因此就造成了不同步的狀況。

我自己試驗了一下,其實child MovieClip裡的動畫不是真的停止了,而是「跑得比較慢(應該說非常慢)」而已。
我猜可能是因為nextFrame()及prevFrame() (gotoAndStop()也一樣)所花掉的效能讓Flash Player無法同時處理child MovieClip的影格,因此造成child MovieClip的動畫delay。
目前似乎無解。

但是奶綠發現Ticore之前有提到在Flash Player 10之下這個問題就不會再發生。
也許是Flash Player 10有發現這一點並做了修正了吧?

Facebook Flash Application開發心得(2) - FB Connect - 接上Flash


使用FB.init初始化Facebook之後,除了要藉由javascript的api來應用Facebook的一些功能以外,其實最重要的就是要取得Facebook的登入session資訊。
由於Facebook的判別登入權限是由很多參數所記錄及驗證的,flash的api也需要這些參數來進行資料的傳遞,因此取得這些參數是很必要的。
這些參數裡有兩個值是最重要的,分別是session_key及secret,前者是此次使用者登入的session值,後者則是facebook動態產生的secret值,這個secret值跟Application設定時所看到的secret不太一樣,基本上Facebook官方建議我們不要將Application設定畫面上的secret值直接寫在程式裡,因為很容易被有心人破解取得,所以Facebook的javascript api在進行驗證時會自己從Server取得一組由Facebook動態產生的secret來使用,但是Flash api就辦不到,必需要將secret寫死在flash或是flashvars裡,這也就是要使用javascript api來進行登入動作的原因之一。
另一個使用javascript api的原因就是session的取得,雖然官方的flash api的文件裡建議我們使用com.facebook.utils.FacebookSessionUtil類別來統一處理session,文件裡說FacebookSessionUtil會自己判斷是該使用DesktopSession、JSSession或是WebSession,但是我發現FacebookSessionUtil是有bug的,即使在網頁上跑flash,它仍然會使用DesktopSession來做為session的處理類別,但是這麼一來一但當頁面被refresh時,flash將會失去session的相關處理能力,需要再次重新登入一次,對使用者來說這會變得非常的不友善。
雖然說FacebookSessionUtil有這種缺點,但是它在iframe架構的application裡卻可以運作正常且很好用,因此關於FacebookSessionUtil的部份就留到iframe的時候再講,目前為止在FB connect的部份我將會直接使用WebSession。

現在要將flash放入到FB connect的application裡,會延用到上一篇的東西,但稍作改寫,由於我假設我們是要開發全Flash的application,因此我也將登入Facebook的按鈕從html裡搬到flash裡。

整個主要程式的運作流程會是:
1. 載入swf。
2. Swf呼叫javascript進行FB.init。
3. Javascript去跟Facebook驗證使用者是否已經登入。
4. 若是已經登入,javascript取得必要的session_key及secret,並將這兩個值傳給swf。
5. Swf依照這兩個參數進行WebSession的初始化。

一、 HTML上javascript的改寫:

應該很直覺,不用再多做解釋。

二、 Flash裡的處理:
因為code不算多,直接全部po出來,加上註解。


三、 其它解說:
在Flash裡,我捨棄了使用Flash api裡的login method,而決定呼叫javascript來處理的原因,是因為如果沒有將application secret傳出的話,facebook.login()不知為何一直無法正常運作,但是如果我把application secret寫入,那就又失去了安全性,因此我才又將登入動作交還給javascript處理。
FB.Connect.requireSession有兩個參數,第一個是登入後的callback function,由於我們已經實作了ifUserConnected,因此這個function可帶入null,第二個參數是決定是否要另開一個視窗當登入窗口,通常這個參數可以忽略,在純html的狀況之下呼叫FB.Connect.requireSession一定會另開,不過如果這個動作是由flash所觸發的話,預設值會是直接蓋在頁面上,可是flash的wmode沒有設成transparent的話flash反而會蓋在登入畫面之上,因此我特別將第二個參數設成true來強迫它另開一個視窗出來。
更正:經過實驗,似乎只有在IE才會跳出新視窗,FireFox裡好像不管怎樣都是跳lightbox...

這個程式的整個流程還沒有完全的完整,但是已經有考量到使用者是先登入再到這頁面或是來到這頁面才進行登入動作的兩種狀況,在一般自己的網頁上來處理應該是足夠了,但是還沒處理到使用者半途登出Facebook的情況,這一點可以事後再繼續補足,至少最麻煩的session取得已經解決。

接下來我也許會先介紹幾個從Facebook取得資料的類別,然後就可以再回過頭來介紹iframe的架構,其實iframe與FB connect最多最大的差別就只在於session的取得,其它的都大同小異。

下一篇
Facebook Flash Application開發心得(3) - 由Flash Api從Facebook取得資料

2009年7月29日 星期三

Facebook Flash Application開發心得(1) - FB Connect - how to start


使用Facebook的api來開發的應用程式基本上有很多種,Adobe這邊有大概的說明:
http://www.adobe.com/devnet/facebook/


其實說穿了就大概可以分成四大種,
1. 在Facebook裡的應用程式
2. 在Facebook裡的iframe應用程式
3. 不在Facebook裡的應用程式 (例如你自己的website)
4. 桌面應用程式 (就AIR囉)

為什麼要分種類呢? 因為四種的api寫法都有一點點不同,需要注意的地方也不一樣,不過就我玩了這一段時間,如果是要專心於用Flash當主題來開發的話,也許有些事情會簡單一點(雖然還是很麻煩!)。
Adobe官網也有一些簡單的入門教學,可以大概看一下,不過好像都是針對第1、2種的方式在做入門就是了,但是不無小補。

一、下載Facebook flash api:
OK,首先要做的當然是去下載Facebook flash api。
http://code.google.com/p/facebook-actionscript-api/


二、申請Facebook應用程式:
接著就是到Facebook登記一個自己的應用程式,取得API金鑰及Application Secret code。
http://www.facebook.com/developers/

登記好應用程式後就要先進行一些設定:
1. 基本資料的部份 -> 應用程式名稱 -> 就是填你的應用程式名稱…
2. 驗證、個人檔案、Widgets以及進階的部份先不用管沒關係,不影響開發。
3. 如果是要開發在Facebook裡的應用程式的話,就要去填「畫布(Canvas)」裡的資料,如果是要開發不在Facebook裡的應用程式,那就要去填「Connect」裡的資料。
4. 畫布(Canvas) -> 畫布頁面網址 -> 使用者打這個網址就會連到你的應用程式
5. 畫布(Canvas) -> Canvas Callback URL -> 你的應用程式「實際上」的網址。
6. 畫布(Canvas) -> 呈現方法 -> 選iframe或是FBML (就是最上面第一種跟第二種的差別)
7. Connect -> Connect URL -> 你應用程式「實際上」的網址。
8. 先填選Connect吧,從Connect入手我覺得比較快,而且一但Connect的部份上手了之後,再轉成iframe應該很多部份會很快。

基本上由於目前我只試過用iframe及connect的方法開發,為什麼我不用FBML? 因為我不太會php…,所以我為了怕以後需要用asp或asp.NET整合時會發生的問題,因此我一開始玩Facebook api的時候就是先玩iframe,之後才試著玩connect。
所以我之後會記錄在這裡的一些經驗大多都會是以這iframe及connect為主。
這一篇則會是以Connect做為開始,因為如果開發iframe application話,關於畫布(Canvas)裡的很多設定就要去處理,也要瞭解每個設定為什麼要這麼設(為了try這些設定的不同真的很花時間),而Connect的大部份api寫法都跟在iframe裡的差別不會很大,所以我才會想說先從Connect application下手應該會是比較好的方法。


三、建立一個crossdomain policy:
由於facebook的api需要許多的認證,因此他們有他們自己的crossdomain檔,不像flash一樣都是用crossdomain.xml。這個facebook的crossdomain檔我通常都沒去改它的名字 - xd_receiver.htm。
把xd_receiver.htm它放在你application「實際存在」的空間裡,當facebook需要時自然會來讀它,例如:如果你的Application是位於http://iamjason.com/demo/,那麼你就可以把它丟在這兒就好。
xd_receiver.htm會長成像這個樣子:

你可以自己寫一個,或者是乾脆到這裡下載,裡面什麼東西都不用改。


四、來個Hello World:
請注意,這個Hello World是使用Connect的方式,因此請注意如果在application裡的設定沒有填寫Connect URL的話會有點問題。

1. 建立一個index.htm,使用Connect的話,html的宣告需要依照facebook的標準,如下:


2. 即使我們要用Flash來開發,但是Facebook的一些限制,我發現很多時候需要借用Facebook的javascript api才能達到一些功能(例如邀請朋友以及獲得某些授權...等等),所以我們要引用需要的javascript檔進來:

3. 編寫需要的javascript,初始化facebook connect,並判斷登入狀態:

這邊寫完大概就可以放上去測試一下了,如果你的Connect URL填寫的是
http://iamjason.com/demo/
那麼就把這個htm放到這裡去,然後打開瀏覽器輸入這個網址,理論上你就會得到一個”not connected”的alert。

4. 加入一個登入的鈕:
Facebook允許它的javascript去render一些需要的視覺控制元件,這邊我們使用登入鈕來做測試。
在<body>裡加上一個div,裡面塞入登入鈕:


然後改寫一下剛剛的javascript裡onConnected及onNotConnected的function,讓還沒登入時出現登入鈕,登入後就把登入鈕隱藏起來:

完成了,這樣基本上就可以測試一下了。
會看到一個facebook的制式藍色登入鈕,點了它之後會跳出一個小視窗,登入後就會把登入鈕隱藏起來。
由於Facebook是用session的方式來驗證登入狀態,因此一但登入後,只要這個瀏覽器的session沒有改變,重新整理畫面的話仍然會被視為是登入狀態。不過我遇到一個狀況,如果重新整理畫面,onNotConnected會先被觸發,過一陣子才會觸發onConnected,不過我想這很正常,應該是連到Facebook去驗證的時間差,所以順道提一下,之後在開發時盡量避免被這問題卡到。

另外,要初始化Facebook api的方法其實很多,大部份看到的都是用new一個FB.ApiClient來處理,但是當FB.ApiClient被new出來的時候,Facebook如果判斷使用者的狀況是尚未登入的話就會馬上將使用者導去登入,可是如果我們使用Connect來建立application時,常常的情況是要將Facebook的api用在自己的網站上,又不想使用者一來就馬上就先被要求登入,所以我才會選擇使用FB.init的方式進行初始化,然後在真的需要使用者登入的時候再進行登入的動作。
這兩種作法要採用哪一種方法,我想就是看當時要開發的需求而定了,之後在進行iframe的application開發的時候,將會採用new FB.ApiClient的方式。(因為一定要先登入)

現在我們有了Hello World,下一篇就是準備把Flash給帶進來了。

下一篇
Facebook Flash Application開發心得(2) - FB Connect - 接上Flash

2009年7月17日 星期五

DisplayObject上層擋到下層滑鼠事件問題


有一個常遇到但是一但遇到老是不求甚解的就把它解決掉的問題,這幾天在處理一個案子的時候又遇到了。
在AS3裡,位於上層的DisplayObject會阻擋滑鼠事件,所以會導致較下層的物件無法接收到滑鼠事件。這理論上看起來是合理的,只是問題的發生點通常都是在我們常會忽略掉的地方,那就是透明圖層。
設計師們常常會利用PNG的透明背景來處理一些效果,而我們也常常忘了這個PNG其實是一個方形的存在,因此就會在Runtime時遇到明明看起來沒東西的地方但是滑鼠事件就是不會work的狀況。

Ok,解決的方法就是將擋到的DisplayObjec的mouseChildren及mouseEnabled設為false。通常這樣也都可以解決問題。
但是這次我遇到的狀況比較不一樣,才發現事實沒這麼簡單。
我這次的狀況是,場景上一個MovieClip(簡稱MC_A)裡面有動畫,其中有一個按鈕。但是很不幸的這些動畫擋到了場景上的另一個MovieClip(簡稱MC_B)裡的按鈕。(請注意MC_A及MC_B是位於同一個DisplayObjectContainer裡)
很直覺的我用一個迴圈將所有MC_A裡除了按鈕以外的DisplayObject的mouseChildren及mouseEnabled都設為false,感覺這樣就可以解決問題,但是很遺憾發佈後MC_B還是一樣被MC_A的一些東西擋住(這些東西我都已經設成mouseChildren及mouseEnalbed為false了)。
於是我做了一些實驗,我在MC_A裡把MC_A的按鈕都放到最低的層級裡,把動畫都拉上來,如果我沒跑迴圈去將動畫的mouseChildren及mouseEnalbed設為false的話,MC_A裡的按鈕及MC_B裡的按鈕都不能work。但如果我有跑迴圈,那麼只有MC_B裡的按鈕會無法work。
有些人也許已經知道是怎麼回事了。

照這種情況看起來,MC_A裡面的DisplayObject其mouseChildren及mouseEnabled屬性只會在MC_A這個DisplayObjectContainer裡生效,對於MC_B這個與MC_A存在於同樣一個層級的物件來說,MC_A的「滑鼠有效範圍」仍然是整個MC_A的所有範圍。
因此在MC_A裡不管怎樣的最裡面的mouseChildren或mouseEnabled做操作,對於MC_A以外的物件來說,它們只認識MC_A自己的mouseChilren及mouseEnabled。

在這個案例裡,由於我的MC_A裡還有按鈕,所以我不可能將整個MC_A自己的mouseChilren及mouseEnabled設為false,因為這樣一來我MC_A裡的按鈕也跟著廢掉了。
最後我才知道我忽略了一個很簡單的解決方法,那就是直接將MC_A的hitArea屬性設為按鈕實際的感應區域就好了。這樣子對MC_B來說,MC_A的實際「滑鼠有效範圍」就會被改變了。

2009年6月17日 星期三

Facebook Flash Application開發心得(前言)


Facebook的API很久以前就有了,嗯。
不過前一段時間,就在Adobe跟Facebook正式宣佈要一起建構什麼新型態的社交平台之後,終於有了CS3版本的swc。(之前都是Flex版的)
基本上我仍然十分習慣在CS3之下工作,還不是很喜歡打開Flex。所以一看到有CS3的版本後就開始把玩了起來。

說真的,目前為止,我個人覺得Facebook的API說明文件寫得真的不是很好,有太多東西需要開發者自己去摸索。其實我可以理解Facebook針對client端語言的一些限制,畢竟權限以及預防API的被濫用是他們很大的一個課題,只是這些東西我都是要google好久才發現原來我必需要繞一條路去跑。

另一個部份是Application的設定問題,倒是也花了我不少時間才搞清楚什麼東西要怎麼設。

接下來應該會花幾篇的功夫記錄我這幾天在Facebook上開發flash application的心得。Adobe官網上的文章在某方面可以一看,但是更進階的部份卻更新十分緩慢,O’Reilly Inside RIA裡Mirza Hatipovic寫的幾篇文章倒是給了我一些方向,有興趣的可以先從他的文章開始。
http://www.oreillynet.com/pub/au/3675
他似乎是預計要寫二十篇來做教學,但是似乎很不巧的在他寫到一半時Facebook for Flash的API有了一些改變,但是我想基本原理不變。


至於我的部份,純粹會是記錄我在實際設定以及執行上遇到的一些問題及解決方法,一來讓我可以自己將來回頭再來翻閱,而來如果有人也需要這些資訊的話希望可以幫上一點忙。

之後新增的有關Facebook開發的文章將會列舉連結在下面:
-----------

Facebook Flash Application開發心得(1) - FB Connect - how to start
Facebook Flash Application開發心得(2) - FB Connect - 接上Flash
Facebook Flash Application開發心得(3) - 由Flash Api從Facebook取得資料
Facebook Flash Application開發心得(4) – Iframe的架構下取得Session
Facebook Flash Application開發心得(5) - 新版的streamPublish

2009年6月11日 星期四

Loader跨網域讀取圖檔,以及讀取Picasa的限制


Loader在跨網域讀取圖檔基本上是不需要crossdomain policy的,只是純粹當個乖乖的DisplayObject是沒什麼問題的,但是如果一但需要使用BitmapData對它做draw的動作時,flash player的安全性原則會封鎖這個動作。

這個問題很常見,之前也遇到過好幾次,但是一直沒有白紙黑字記下來,所以搞得自己常常忘記。
基本上要避開這個問題會需要用到LoaderContext這個類別。

通常我們在使用Loader讀取圖片或swf時:
public function load(request:URLRequest, context:LoaderContext = null):void

第一個參數URLRequest一定要的,第二個LoaderContext一般來說我們常常省略不下。不過現在要解決上述的問題時,我們就需要用到它了。
將LoaderContext. checkPolicyFile設成true再帶入就ok。但前題是遠端網域那邊要有允許你crossdomain才行 ,不然的話依舊沒輒。


順帶一提跟Picasa有關的,當Loader在讀取Picasa相簿裡的大圖時,很奇怪的事會發生。
開發時都很正常,丟到FireFox上也可以跑,但是一但用IE(測試的版本是IE 6)就怎樣都會遇到http 404,可是網址copy出來直接用IE開就又讀得到。
後來才知道在IE裡Loader如果去讀Picasa裡尺寸大於800 pixels的圖檔就會這樣,這似乎是Picasa的限制,只對外提供最大尺寸為800的圖(只是我不懂為什麼只有IE會這樣...)。

總之要解決這個問題就只能在Picasa大圖的網址後面加上「?imgmax=800」就好了。

2009年6月9日 星期二

URLLoader取得的bytesLoaded有可能大於bytesTotal!?


無意中發現了這一個很奇怪但是我目前為止無法解釋的現象。
我現在並不認為這是URLLoader的「Bug」,因為我覺得這種情況是有點複雜的,也許並不完全是URLLoader的問題。


情況如下:
今天手癢想寫個類別把我自己在Picasa相簿裡的一些照片資訊取出,讓自己以後可以方便編寫相簿瀏覽的介面。
因為在本機開發還不需要顧慮到crossdomain的問題,所以一開始我是直接取用Picasa的RSS,起初都還挺順利的,RSS的解析也都寫得差不多了,但是當我改讀另一個照片比較多的相簿時,就發現要將URLLoader.data給轉型成XML時一直出錯。
這個RSS的URL如下:
http://picasaweb.google.com/data/feed/base/user/jason.tseng76/albumid/5243914003216812001?alt=rss&kind=photo&hl=zh_TW

第一個反應就是,會不會是RSS的檔太大了? 導致RSS在還沒被完全讀取完全之前URLLoader的COMPLETE事件就被觸發了?
所以我就多監聽了一下ProgressEvent.PROGRESS事件,結果就很有趣了,trace出來的結果是bytesLoaded的值居然比bytesTotal還大。就看著ProgressEvent硬生生的把破表的值給丟了出來。
我也試過把URLLoader.data的值給trace出來,但是可能真的太大了,每次trace就每次當。

於是我也只能再次懷疑是不是檔頭或什麼的東西造成了URLLoader的判別出錯,直接把URLLoader.data轉型成XML出問題恐怕一定是整個資料讀取不完全(或是讀到多的東西!!?)。
所以我只好改走Picasa專門提供給Flash使用的RSS(有crossdomain policy的路)。
http://code.google.com/intl/zh-TW/apis/picasaweb/reference.html#Flash

轉換過後原本RSS的URL會變成這樣:
http://photos.googleapis.com/data/feed/base/user/jason.tseng76/albumid/5243914003216812001?alt=rss&kind=photo&hl=zh_TW

再try一次。
過了!
但是bytesTotal永遠都是顯示為0…。
好吧… 只能說至少work了。
至於為什麼bytesTotal會是0? 我想這已經有點超出我知識的範圍了…。