Facebook Multi-Friend-Selector for Flash AS3
Posted by Philip Bulley | Filed under Actionscript 3, Facebook Development
UPDATE Nov 2010: This requires the old REST API Facebook_library_v3.4_flash.swc, which has now been deprecated in favour of the Graph API. Please feel free to fork this for use with the new GraphAPI SWC. There is a little more info on this in the comments. I’d love to update it myself, but not sure when that might happen at the moment :-/
One of the drawbacks of the current Facebook Actionscript API is that it doesn’t come bundled with UI components, it’s simply a data API. Fortunately you can use the JavaScript Client Library’s FB.UI.FBMLPopupDialog() to render FBML overlaying your SWF (if you don’t mind using wmode=”transparent”). But still, when it comes to the FBML fb:multi-friend-selector, if you want to do anything but send out invites to your Facebook app (via a browser-redirecting POST) , you’re out of luck.
Ideally, the fb:multi-friend-selector would allow the setting of a callback which would return the UIDs of the selected friends. It would then be down to the developer to choose what to do with them.
So, I decided to recreate the fb:multi-friend-selector directly in Flash. It will allow you to input an array of uid strings and later return a FacebookUserCollection featuring the selected users. Unfortunately I haven’t created this to be a fully resizable component, it simply does what it says on the tin. Hopefully, you may find that this gets you out of a sticky situation once you realise the shortcomings of the FBML fb:multi-friend-selector.
You can download it from the milkisevil-toolbox on github. You’ll need to add the “lib/milkisevil/FacebookComponents.swc” to your project and create a new instance of the “com.milkisevil.ui.facebook.MultiFriendSelector” class.
Here’s a rough guide to how you might want to instantiate the MultiFriendSelector:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | // Don't forget to make the following imports where appropriate import com.milkisevil.ui.facebook.MultiFriendSelector; import com.milkisevil.events.StatusEventEnhanced; // And the following inside your class private var multiFriendSelector:MultiFriendSelector; private function showFriendSelector():void { multiFriendSelector = new MultiFriendSelector( facebook, 16 ); multiFriendSelector.title = 'Your friends'; multiFriendSelector.subtitle = 'Irritate the hell out of your friends!'; multiFriendSelector.addEventListener( MultiFriendSelector.STATUS_EVENT, multiFriendSelectorStatus ); addChild( multiFriendSelector ); multiFriendSelector.getFriends(); } private function hideFriendSelector():void { removeChild( multiFriendSelector ); multiFriendSelector = null; } private function multiFriendSelectorStatus(event:StatusEventEnhanced):void { trace('exec multiFriendSelectorStatus: ' + event.code); switch(event.code) { case MultiFriendSelector.CLOSE: hideFriendSelector(); break; case MultiFriendSelector.SUBMIT: var selectedUsers:FacebookUserCollection = multiFriendSelector.getSelected(); hideFriendSelector(); var uidList:Array = []; for(var i:int = 0; i<selectedUsers.length; i++) { var facebookUser:FacebookUser = selectedUsers.getItemAt(i) as FacebookUser; uidList.push( facebookUser.uid ); } // Now do some custom stuff with those uids myCustomMethod( uidList ); break; } } |
Tags: as3, facebook api
26 Responses to “Facebook Multi-Friend-Selector for Flash AS3”
-
MultiFriendSelectorAsset is not found.. how to rectify it?
Can anyone help me?
-
Hi Archana,
Did you add the lib/milkisevil/FacebookComponents.swc to your project? -
Hi,
can u tell me why my flash cs4/5 doesn’t load swc? Do i have to use Flash builder or Flex? Is there a way to keep flash instead of flex?I also tried to change extension (swc –> zip): in this manner i obtain library.swf and catalog.xml but i suppose that i have to rebuild your classes…
Can anyone help me pls?
-
Hi Mark,
The FacebookComponents.swc only contains the UI assets, so make sure you’ve also included the ‘src’ folder in your class path. Ultimately, you need to add the SWC and the actual src classes to your project.
It’d surely be easier for others using this if everything was in one SWC. So I’ll keep that in mind for any future releases.
Let me know if that solves your problem.
-
i get this error in the MultiFriendSelector.as
when I do this.
multiFriendSelector = new MultiFriendSelector;
I’m not really sure how to call the friend selector
1046: Type was not found or was not a compile-time constant: Facebook.
thanks for the help
-
Hi Andres,
This currently can only be used with the old REST API Facebook SDK SWC. So if you’re using this with the latest Graph API SWC, it won’t work.
If you’re up to it, you should be able to rework the classes to support the Graph API. You’ll just need to replace the parts of class MultiFriendSelector that gets your friend’s data from the API (which is what passing an instance of facebook:Facebook via the constructor used to do).
You’ll also need to change how the MultiFriendSelector dispatches data back to your application class. This means getting rid of FacebookUserCollection and using an Array or Vector instead, as I don’t think the new Graph API SWC contains these classes.
Sorry I can’t be of more help just now, but feel free to fork this on github as it will definitely quicker than rewriting from scratch.
-
thanks! I’ll try that see if i can get the job done!
-
Philip,
If you can help me briefly explaining how to call the class so i can create the Friend selector.
All libraries are running for mi now
I create the variable:
var multiFriendSelector:MultiFriendSelector;
no problem… I created the MultiFriendSelectorCall.as file with the above code :
// Don’t forget to make the following imports where appropriate
import com.milkisevil.ui.facebook.MultiFriendSelector;
import com.milkisevil.events.StatusEventEnhanced;// And the following inside your class
private var multiFriendSelector:MultiFriendSelector;private function showFriendSelector():void
{
multiFriendSelector = new MultiFriendSelector( facebook, 16 );
multiFriendSelector.title = ‘Your friends’;
multiFriendSelector.subtitle = ‘Irritate the hell out of your friends!’;
…And I imported it in my main flash : import com.milkisevil.ui.facebook.MultiFriendSelectorCall;
when I do:
multiFriendSelector.showFriendSelector();
It does not call the function.
Can you show me a quick run on how to call the multi riend selector?
-
ey man, congrats for the hard work
can you please eligthen me :)
i get this error
1046: Type was not found or was not a compile-time constant: NativeWindowBoundsEvent. -
so I converted this to graph api, using the shortcut of complining in the deprecated restAPI just to get the UI components.
I have 2 problems that hopefully you can help with:
1) when the Multifriends selector is added to the displaylist, it seems to add 2 copies of itself. i.e Once the list is populated, if I click on the close button – it closes but a second copy the the multifriedselector is present right underneath it.
2) when I look at the logs it says “Warning failed to place object at depth ” and “:Warning failed to place object at depth 2″ – and has 50 such warnings.
I suspect it has to do with the tweening classes and the fact that my test code is pure actionscript (no flash).Any hints of where to look would be greatly appreciated.
-
Well,
I solved the issue of the component being added twice – seems like the showFriendSelector() method from your sample code in this post was being called twice because I had a call to this method in my onLogin method and that was triggered twice during the Facebook login process. I moved the creation of the multifriendselector component into the class constructor to ensure only one instance is created and this seems to have solved that problem.
I have no idea what the “Failed to place objet at Depth 1″ error is and there is no documentation about this on the web – but the component seems to work.
Final questions: Do your components require the TweenMax library to be downloaded separately (this is what I had to do to get them to compile with acompc)
-
I have adapted this utility to work with the new facebook Graph API.
You can pull the code from :
git://github.com/letapjar/milkisevil-toolbox.git
Please note, this version requires 1 new library – the as3commons-reflection library.
downloadable from:
http://www.as3commons.org/as3-commons-reflect/The MultiFriendSelector will work with either web-based flash apps or desktop apps – simply pass in the third constructor argument of isAir:Boolean – default is ‘true’ meaning the desktop api is used – instantiate with false to use the facebook – web api.
getSelectedFriends returns and Array of the selected friends – typed as objects with fields uid, name and pic_square
hope this helps everyone!
-
Thanks Letapjar!
I also did a work arround with this library, my results were not as good as I expected but did the work i requiered.
I’ll check out your adaptation and post results!
Thanks for contribuiting!
-
I was able to compile Letapjar’s fork into my app, however I am getting a runtime error. Here’s what it says:
Type Coercion failed: cannot convert flash.display::MovieClip@1df55301 to fl.containers.ScrollPane.
at com.milkisevil.ui.facebook::MultiFriendSelector()[/Users/jonnymorrill/Projects/whatsinaword/flash/include/letapjar-milkisevil-toolbox-b806879/src/com/milkisevil/ui/facebook/MultiFriendSelector.as:67]Any Ideas? Thanks :)
-
I’m having the same problem jrmorrill has. It looks like the MultiFriendSelectorAsset content.scrollPane isn’t of type scrollPane but a MovieClip. Any attempt to set it up or convert it to a ScrollPane throws that error. I’m guessing that the “scrollpane” is in some kind of holder of type MovieClip. Can we get an update to that swc or something?
-
I believe that is correct. the MultiFriendSelector itself extends BaseUI which extends movieclip. It has a child sprite cleverly called “child”). The child sprite is of type MultiFriendSelectorAsset – and this is the component that contains the actual scrollpane.
I don’t have flash – I program in pure actionscript so I ended up writing my own container code and just used the friend buttons and the logic for handling their various clicks.
To access the scrollpane you’d need to write in a getter / setter.
-
Thanks Letapjar, I believe the following line (67 in MultiFriendSelector.as) is what you’re describing:
scrollPane = child.content.scrollPane;
so merely doing this doesn’t get a scrollPane and requires a getter/setter for the class MultiFriendSelectorAsset? If so I’ll gladly set that up, but i won’t be able to if it’s in the FacebookComponents.swc which i deduce is it’s location. Perhaps there’s a better way to do this? I’m just clueless to it since i don’t know what MultiFriendSelectorAsset looks like.
-
I don’t know what is in the facebook components.swc – But that is probably where the visual parts of the components come from.
Line 66 in the code says:
scrollPnae = child.content.scrollPane;
so if you add a getter to MultiFriendSelector for the private variable scrollPane (or just make it a public variable) you should have programatic access tot he scrollPane. That var is of type fl.containers.ScrollPane – so the getter should work. the Mutlifriend selector itself did not give me any runtime errors in a pure actionscript application.
-
I think we might have gotten our wires crossed. Line 66 (for you) line 67 (for me) is were the error occurs. child.content.scrollPane is not a ScrollPane. So when someone runs the MultiFriendSelector constructor a runtime error is thrown because private var scrollPane is a ScrollPane, but child.content.scrollPane is not. it’s a MovieClip.
I believe jrmorrill and myself got this error when we did this:
var mFriendSelect:MultiFriendSelector = new MultiFriendSelector(16,5,false);
and not when we were trying to do something like this (which i imagine is what you understood):
mFriendSelect.scrollPane;
You mentioned that you weren’t getting errors. Are you setting isAir to true? could there be a difference with ‘com.facebook.graph.FacebookDesktop’ and ‘com.facebook.graph.Facebook’?
-
Hmm,
I did only test the component in an AIR app – I usually develop on the desktop and then migrate to the web. So yes, I was setting isAir to true.
However, the actionscript graphAPI contains no visual components (unlike the old facebook API) so it *shouldn’t* matter which of those options is selected.
Are you certain you are including the FacebookComponents.swc as a library?
I just tried re-compiling the MultiFriendSelector.as file with mxmlc – it compiled just fine.
PPerhaps you can put a breakpoint into the program and see what type the child.content.scrollPane shows up as?
-
Is it possible to post an working example whith Facebook graphAPI?
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205package{
import com.facebook.graph.FacebookDesktop;
import com.facebook.graph.*;
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.net.*;
import flash.geom.*;
import com.milkisevil.ui.facebook.*;
import com.milkisevil.events.StatusEventEnhanced;
//import org.as3commons.collections.*;
import com.facebook.graph.core.AbstractFacebook;
import MySimpleButton;
public class CasterTest extends Sprite{
private var btn:MySimpleButton;
public var out:TextField;
private var face:Loader;
private var multiFriendSelector:MultiFriendSelector;
private var mfsOnStage:Boolean = false;
private var loggedIn:Boolean = false;
public function CasterTest():void{
out = new TextField();
out.text='\n';
addChild(out);
btn = new MySimpleButton("Login");
btn.x=200;btn.y=100;
addChild(btn);
out.multiline=true;
out.width=200;out.height=400;
out.x=200;
FacebookDesktop.init("ENTER YOUR FB APP ID HERE",onInit); //initialize
FacebookDesktop.manageSession=true;
//addEventListener(Event.ADDED_TO_STAGE, initFB);
}
private function onFBLogin(result:Object, fail:Object):void {
if (result) {
trace("onFBLogin succeeded\n");
this.loggedIn=true;
trace("Result = "+result.toString());
btn.label="Logout"
btn.addEventListener(MouseEvent.CLICK,logout);
createDialer();
} else {
this.loggedIn=false;
trace("onFBLogin: Login Failed\n");
btn.addEventListener(MouseEvent.CLICK,login); //addd the listener back to the button
trace(fail);
}
}
public function onInit(result:Object, fail:Object):void{
if (result) { //already logged in because of existing session
trace("onInit, Logged In\n");
this.loggedIn=true;
btn.label = "Logout"
btn.addEventListener(MouseEvent.CLICK,logout);
createDialer();
} else {
trace("onInit, Not Logged In - waiting for user to click login button\n");
btn.addEventListener(MouseEvent.CLICK,login);
//FacebookDesktop.login(onFBLogin);
}
}
private function login(evt:MouseEvent) :void{
FacebookDesktop.login(onFBLogin);
btn.removeEventListener(MouseEvent.CLICK,login);
}
private function logout(evt:MouseEvent) :void
{
FacebookDesktop.logout(); //add in your canvasl url to properly logout
btn.label="Login \n Again"
btn.removeEventListener(MouseEvent.CLICK,logout);
btn.addEventListener(MouseEvent.CLICK,login);
}
private function createDialer():void{
multiFriendSelector = new MultiFriendSelector( 10 );
showFriendSelector();
}
protected function getFriends(success:Object, fail:Object):void{
if (success){
var friendsIds:Array = [];
var friends:Array = success as Array;
var flist:String;
var l:uint=friends.length;
flist = 'friends list has'+l+' elements :\n';
var friend:Object;
for (var i:uint=0;i<l;i++) {
friend = friends[i];
flist+=friend.name+"\n";
}
//out.appendText(flist);
}
if (fail){
out.appendText("failed getting friends \n");
}
}
private function getPic():void{
face = new Loader();
var req:URLRequest = new URLRequest(FacebookDesktop.getImageUrl(FacebookDesktop.getSession().user.id,"small"));
face.load(req);
face.contentLoaderInfo.addEventListener(Event.COMPLETE, picLoaded)
//this.label.appendText("could not fetch user picture url");
//addChild(face);
//face.width=50;face.height=50;
}
private function picLoaded(e:Event):void{
var pic:Bitmap = Bitmap(face.content);
pic.smoothing=false;
pic.width=30;pic.height=30;
addChild(pic);
}
private function showFriendSelector():void
{
trace( "showFriendSelectorMethod Called" );
//multiFriendSelector = new MultiFriendSelector( 10 );
multiFriendSelector.title = 'Friend Dialer';
multiFriendSelector.subtitle = 'Choose up to 10 friends to Video Call';
multiFriendSelector.addEventListener( MultiFriendSelector.STATUS_EVENT, multiFriendSelectorStatus );
multiFriendSelector.width=500; multiFriendSelector.height=300;
multiFriendSelector.addEventListener(Event.ADDED_TO_STAGE,logStageAdditions);
if (!mfsOnStage){
addChild( multiFriendSelector );
}
multiFriendSelector.getFriends();
}
private function logStageAdditions(e:Event):void{
this.mfsOnStage=true;
trace("A multifriend selector was added to the stage");
}
private function hideFriendSelector(targ:Object):void
{
targ = targ as MultiFriendSelector;
var parent:DisplayObjectContainer = targ.parent as DisplayObjectContainer;
targ.parent.removeChild(targ);
trace("removed the multifriend selectors from it's parent");
multiFriendSelector = null;
}
private function multiFriendSelectorStatus(event:StatusEventEnhanced):void
{
trace('exec multiFriendSelectorStatus: ' + event.code);
switch(event.code)
{
case MultiFriendSelector.CLOSE:
hideFriendSelector(event.target);
break;
case MultiFriendSelector.SUBMIT:
var selectedUsers:Array = multiFriendSelector.getSelectedFriends();
printSelection(selectedUsers);
hideFriendSelector(event.target);
//FacebookDesktop.logout();
/* var uidList:Array = [];
for(var i:int = 0; i<selectedUsers.length; i++)
{
var facebookUser:FacebookUser = selectedUsers.getItemAt(i) as FacebookUser;
uidList.push( facebookUser.uid );
}*/
break;
}
}
//TODO: Remove this method once the MultiFriendSelector is stable and tested.
//traces out the names of the selected firends -- FOR TESTING PURPOSES ONLY
private function printSelection(users:Array):void{
var u:Object;
var names:String = "Selection was: \n";
for(var i:int=0;i<users.length;i++){
u = users[i];
names+=u.name+' id: '+u.uid+' pic: '+u.pic_square;
names+='\n';
}
trace(names);
}
}//class
}//package -
Hello again Letapjar,
yes i am including FacebookComponents.swc as a library.
I used DeMonsterDebugger to trace out chlid.content.scrollPane and it told me that child.content.scrollPane is not of type ScrollPane, but an object of type MovieClip with the name “scrollPane”. this must be the problem.
somewhere child.content is added an movieclip that has the name property set to scrollPane, but not cast as that. for example:
var _scrollPane:MovieClip = new MovieClip();
_scrollPane.name = “scrollPane”;addChild(_scrollPane);
i might be wrong about how that was added but perhaps a search in MultiFriendSelectorAsset for “scrollPane” may shed some light on why this is not the appropriate type?
is there any way i could help in the process? I’m more than happy to assist in the fixing of this issue.
-
Well,
It’s not my library to start – so I have no access to the facebook components.swc. All I can say is: 1) the child.content.scrollPane IS typed as a ScrollPane in it’s variable declaration – and 2) the component works – for me anyway – so I dunno where your error is coming from. I realize that doesn’t help much – but prhaps there is some error elsewhere? Have you tried writing a separate unit test? The code I posted erailer in this thread should work out of the box to generate a working multifriend selector.
-
Great work Philip and Letapjar, love your work.
Took a little fooling around:
I found that as3commons.reflect classes had a missing dependency of as3commons.lang classes.
Also a little bit working out how to translate the text(especially the submit and skip buttons – i have no idea where this MultiFriendSelectorAsset is coming from, but I managed to change the text of the buttons with a little digging aroune).
But all in all, appreciate your work, thanks guys. -
Hmm spoke to soon, was working fine in AIR app, but when i ported it to a web-based app, the pictures aren’t appearing.
After digging around, it seems that you need to now add a permission file, such as:
Security.loadPolicyFile(“https://graph.facebook.com/crossdomain.xml”);
