Flex 4.5 Mobile with LeadBolt Ads
In a previous post, I showed how to load ads in your Flex Mobile application. After publishing my first Air Mobile app to the market using LeadBolt Ads, I can say that I am satisfied with their service.
They seem to have no issues with my Mobile Air application loading an html page for the ads. Unlike some reports from some people that Admob had issues with that. In fact, I emailed my LeadBolt rep asking about making a new ad request on every view. She replied within the hour… on a Saturday… and mentioned that is not a problem.
I was a little concerned that I had to get manual approval once my app was on the Android Market. I wasn’t sure how much time that would take. When came time to make it active, it was also done within the hour… on a Sunday.
All in all so far I am very pleased with LeadBolt. Especially their customer service and quick turn around times. I would recommend it to Air Mobile developers as an option.
For those interested in seeing the app and the ads in action , my app is called Time in Line and is available on the Android Market here: https://market.android.com/details?id=air.TimeInLine
Flex 4.5 – How to load ads from Admob and LeadBolt in your Air Mobile Application.
Here is the simplest way to load admob or leadbolt ads in your Air Mobile application using Flex 4.5.
If you choose Admod: Once you have an account, from the top menu create a Smartphone Web type: Sites & apps -> Add Site/App -> Smartphone Web
If you choose LeadBolt: Once you have registered , go to the apps tab and click Create New App. Make sure you select App Banner (HTML) for placement type. Get the HTML code and save it.
Here is an HTML template for AdMob.
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 | <html> <head> <title>Advertisement</title> <script type="text/javascript"> var admob_vars = { pubid: 'YOUR ID HERE', bgcolor: 'ffffff', text: '000000', test: false, manual_mode: true }; function showAd() { _admob.fetchAd(document.getElementById('adspace')); } </script> <script type="text/javascript" src="http://mm.admob.com/static/iphone/iadmob.js"></script> <style type="text/css"> body { margin-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; } </style> </head> <body onload="showAd()"> <div id="adspace"></div> </body> </html> |
Here is an HTML template for LeadBolt.
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 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/> <title>advertisement</title> <style type="text/css"> body,td,th { color: #FFF; } body { background-color: #000; margin-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; text-align: center; position: relative; } </style> </head> <body> <PUT YOUR LEADBOLT CODE HERE> </body> </html> |
Create a new Flex Mobile Project, and put these HTML files somewhere in your project, for example: “assets/admob.html” and “assets/leadbolt.html”
In your main view of the Flex Mobile Project, your code would look something like this:
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 | <?xml version="1.0" encoding="utf-8"?> <s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" viewActivate="init(event)" title="Ad Test" > <fx:Script> <![CDATA[ import mx.events.FlexEvent; import spark.events.ViewNavigatorEvent; protected var adArea:StageWebView; protected var adFile:File; protected function init(event:ViewNavigatorEvent):void { addEventListener(Event.ADDED_TO_STAGE, createAd); } protected function createAd(e:Event):void { removeEventListener(Event.ADDED_TO_STAGE, createAd); adArea = new StageWebView(); adArea.addEventListener(LocationChangeEvent.LOCATION_CHANGE, adAreaLocationChange); adArea.stage = stage; adArea.viewPort = new Rectangle(0, 80, stage.width, 75); var adTemplateFile:File = File.applicationDirectory.resolvePath("assets/leadbolt.html"); adFile = File.createTempFile(); adTemplateFile.copyTo(adFile, true); adArea.loadURL(adFile.url); } protected function adAreaLocationChange(event:LocationChangeEvent):void { if (adArea.location != adFile.url) { navigateToURL(new URLRequest(event.location)); adArea.loadURL(adFile.url); } } ]]> </fx:Script> </s:View> |
The main idea is to use StageWebView to display the html ads in our application. In the code we are waiting for the added to stage event to ensure we have all the information needed, like the stage. Once we have that, we can then create our StageWebView and position it. We then need to move our html in a temp directory so we can load it. When the user clicks on the banner, open the browser with the ad page.
One note about the location of the html file. You can host the html files on your server, Leadbolt seems to allow this. This means that every request will look like it is coming from one location. AdMob seems iffy about this and I’ve heard that some people got banned. It is probably better to have the html in your project, but you can experiment with this.
Here is a screenshot of the application:

Flex 3 – How can I make links inside a TextArea?
I was working on a project the other day that required me to take user input and parse out the links to make them clickable. For this particular project, I needed to create this as a method for my data class. I’ve stripped out the code for just the url parsing and made it just as a function.
CODE:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public function getUrlParsedMessage(msg:String):String { //Display message and fix links var isLink:RegExp = /(((http|https|ftp)\:\/\/)|(www\.))[a-z0-9.:\/]*/gi; //var msg:String = this.message; if(msg.match(isLink).length >= 1) { var t:String; var addHttp:String; for each (var match:String in msg.match(isLink)) { match.search("www.")?(addHttp=""):(addHttp="http://"); t = msg.replace(match,("<a href='event:"+ addHttp + match + "'>" + match + "</a>")); msg = t; } } return msg; } |
So, what I am doing here is creating a regular expression pattern that will pick out my link starting with http, https, ftp or www. Once I find a link, I look to see if it starts with http:// and add it if it doesn’t. In the TextArea’s HtmlText, flash needs event: in front of the url address hence why I am adding it in the msg.replace call. The function then returns the text with the url’s sorted out.
The TextArea and link function would look like this:
1 2 3 4 5 6 7 8 9 10 11 | <mx:Script> <![CDATA[ private function onLink( event : TextEvent ) : void { navigateToURL(new URLRequest(event.text)); } ]]> </mx:Script> <mx:TextArea link="onLink(event)" /> |
Keep in mind that I removed this from a member function and the parsing was called internally upon the object receiving a string. You have to wire this up the way you need.
Photographs – If Only They Could Speak
I really liked working on this project for its visual challenges. This doesn’t look like a Flex application at all.
I did not create the visual design but I implemented everything you see. I used Cairngorm and leveraged some webservices for the data. I liked working with the new Flash player 10 features like saving and encoding the images with a watermark.
Here is the link: http://culture.alberta.ca/archives/educationalresources/photographs/default.aspx
Flex 3 and Air application icon bugs [Error 303]
So there are lots of talk about this bug with “error 303” and the application icons. I read up a lot about it and I’ll share what worked for me.
1. First, I put all my icons in a directory under the src folder called assets.
2. Then, in the –app.xml file I added the paths to these icons
<icon>
<image16x16>assets/icon16.png</image16x16>
<image32x32>assets/icon32.png</image32x32>
<image48x48>assets/icon48.png</image48x48>
<image128x128>assets/icon128.png</image128x128>
</icon>
3. I then created a bin-release directory in my application folder.
4. Once that was done I exported the project by going to the project->Export Release Build… menu item. After entering the digital signature and hitting next flex starts building and brings me to a sreen that shows me the Air file contents.
5. This is where the bug happens for me. Flex Builder does not transfer the files over to the air file contents.
6. I then open windows explorer and manually copy my icon files over to the bin-release/assets directory. Back to flex builder, I have to hit the back button and go back to the digital signature.
7. Then I hit next again, and Flex start building again.
8. Once I am back on the Air File Contents window I now see my icons.
9. I make sure they are checked. Then I hit finish and get no more error 303…
This is lame, but that is the way it is for now until they fix it. Hope this will save you time.
Some more information about this:
http://bugs.adobe.com/jira/browse/FB-11712
http://chaos.corrupt.net/2009/01/06/avoiding-error-creating-air-file-303-when-compiling-a-flex-project-with-an-icon/
Augmented Reality comes to flash with FLARToolKit
Things like this is why I started programming, it is the endless possibilities and the fact that we can now merge the reality with virtality. While the idea of augmented reality has been around for a while, it is not until recently that we could really start working with it at a personal level. I’ve finally found the time to play around with it, and there are several great resources around to get you started too. I’ve started learning it and learning how to use FLARToolKit along with papervision3D. I can tell you that my mind is spinning with possibilities and that I will be looking more into this in the future.
First thing I thought of was this would be great for kids, seems like playstation thinks so too. And this guy as well. How about baseball cards? Look at this. How about adding air? No, not Adobe Air, but actually blowing into your microphone to make windmills spin! Check this out.
Augmented reality has arrived to flash and there is definitely some coolness, now let’s find the business to it. I’ll post future experiments and findings on this here, so stay tuned. I haven’t checked to see if the adult industry found this yet, they usually push technology advancements….
Here are links to get you started:
http://saqoosha.net/en/flartoolkit/start-up-guide/
http://saqoosha.net/en/2009/02/02/1694/
ARToolKit Marker Generator
Lee’s tutorial
Mikko’s tutorial
FMS 3.5 and Flex 3 – How do I record data over time with NetStream.send()?
After I learned how to work with remote objects, I learned something that I did not know existed. This is the ability to record data over time. This allows us to store user or application actions over time. This data is saved in an flv file on the server thru the NetStream object. Personally, I find this to be very powerfull and can think of several ways of using this. In the meantime, I’ve created a sample application that demonstates how this works in flex.
In fact, it is very similar to the remote objects example, and it starts by running the init function upon creation complete. We then create a NetConnection. Once it is established, we call the openNetstream function that instantiates a NetStream object and assigns it a generic object to store the callback aliases. Once that is all set up the netstream starts to record, the syntax is the same as if we were recording from the webcam.
At this point the stream is recording, you can click on the record button, which does nothing on the UI, but in the backend it is making calls to the sendValues function with the hello world argument. This information is “recorded” and saved into the stream to the flv file on the server. Once you’ve clicked a few times, you can click on the play button. This will load the flv file and play in real time the saved data, which makes calls to the function sendValues which in turn will trace “hello world” as many times as you previously clicked on the record button.
This example is very basic and only works one way, which means you have to start the app again to test it over, but it gives you a good idea on how this works. Check out the send method of the NetStream object in the help files for more ways to work with it. Powerful stuff!
Here is the code:
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 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()"> <mx:Script> <![CDATA[ import mx.controls.Alert; private var nc:NetConnection; private var ns:NetStream; private var serverURL:String = "rtmp://server/netstreamdata/myapp"; private var callBacks:Object = new Object() private function init():void { nc = new NetConnection(); nc.client = this; nc.addEventListener(NetStatusEvent.NET_STATUS, connectHandler); nc.connect(serverURL); } private function connectHandler(e:NetStatusEvent):void { if (e.info.code == "NetConnection.Connect.Success") { openNetStream(); } } private function openNetStream():void { ns = new NetStream(nc); ns.client = callBacks; callBacks.sendValues = sendValues; callBacks.onMetaData = ns_onMetaData; callBacks.onCuePoint = ns_onCuePoint; ns.publish("dataNetStream", "record"); } private function playStream():void { ns.close(); ns.play("dataNetStream", 0, -1); } //make sure this is public so others can access it public function sendValues(arg:String):void { //update all clients. trace(arg); } private function ns_onMetaData(item:Object):void { trace("meta"); } private function ns_onCuePoint(item:Object):void { //called when cuepoints are encountered trace("cue"); } public function onBWDone():void{ //called from asc trace("onBandwithDone"); } ]]> </mx:Script> <mx:HBox> <mx:Button id="btnSendValues" label="record" click="ns.send('sendValues','hello world');"/> <mx:Button id="btnPlayValues" label="play" click="playStream();"/> </mx:HBox> </mx:Application> |
FMS 3.5 and Flex 3 – How do I use remote shared objects?
As I am learning FMS 3.5, I’ve come across shared objects and wanted to give a working example of it in Flex 3. Client shared objects can be really useful and behave similar to cookies in the browser. Remote shared objects are even more useful because you can share them with other people and call methods on them. Below is a basic example of a remote object working with FMS 3.5, it shows how to set data and call methods on the remote shared object.
The application calls the init() function upon the creation complete event, which creates a Net Connection object that we can work with. Once the connection is established the connectHandler function calls the getSharedObject function where the share object is actually created.
Inside this function the sharedObj is declared and given the name of “so” on the server at the location “nc.uri” which is the net connection address. sharedObjSyncHandler is the function called when there is a sync event on the object, which means when the data of the object changes or when you connect to it etc… The SyncEvent object is what gets returned from this event containing some information. Look up the SyncEvent’s changeList in the help docs for more details. The sharedObj is persistant which means it will remain on the server and is not secure which means the object will not be served over https. This is set with the two last parameters on the getRemote method.
Now that we have an object ready and connected we can do stuff with it. The first thing I tested was to set data in the object. I created two buttons, one that calls the setData function and the other to get the data called getData. Notice that I had to use the setProperty on the object to set the color property in the object. In a real application, I would check to make sure we are connected to the object before trying to write to it by checking for “clear” on the sync handler. After setting the data, you can click on the get data button and see the data traced. Close the application and launch it again, then click the get data button to get the stored data from the server. Because we set the object as persistent, the shared object will remain on the server. It is stored under the application folder and the file extension is fso.
The other functionality of shared objects is the ability to call methods on it. I personally find this pretty powerful for several applications that I will one day share here. But for now, I show how to call a method on my shared object when clicking on the btnCallMethod. So, if you open two browsers with the application, click on the btnCallMethod in one application, you will see the text changing in the other browser. This demonstrates how both clients are sharing the object and update themselves when the data changes. I like it!
CODE:
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 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()"> <mx:Script> <![CDATA[ private var nc:NetConnection; private var ns:NetStream; private var serverURL:String = "rtmp://server/sharedObjects/myapp2"; private var callBacks:Object = new Object() private function init():void { nc = new NetConnection(); nc.client = this; nc.addEventListener(NetStatusEvent.NET_STATUS, connectHandler); nc.connect(serverURL); } private function connectHandler(e:NetStatusEvent):void { if (e.info.code == "NetConnection.Connect.Success") { openNetStream(); } } private function openNetStream():void { ns = new NetStream(nc); ns.client = callBacks; callBacks.sendValues = sendValues; callBacks.onMetaData = ns_onMetaData; callBacks.onCuePoint = ns_onCuePoint; ns.publish("dataNetStream", "record"); } private function playStream():void { ns.play("dataNetStream", 0, -1); } //make sure this is public so others can access it public function sendValues(arg:String):void { //update all clients. trace(arg); } private function ns_onMetaData(item:Object):void { trace("meta"); } private function ns_onCuePoint(item:Object):void { //called when cuepoints are encountered trace("cue"); } public function onBWDone():void{ //called from asc trace("onBandwithDone"); } ]]> </mx:Script> <mx:HBox> <mx:Button id="btnSendValues" label="record" click="ns.send('sendValues','hello world')"/> <mx:Button id="btnPlayValues" label="play" click="playStream();"/> </mx:HBox> </mx:Application> |
Flex 3 – Databinding
I’ve had this link for a while and never watched. I finally got around to it and I must say that it is very informative and thought I would pass it along.
Anything you ever wanted to know about how databinding in Flex works Michael Labriola covers it here.
FMS 3.5 and Flex 3 – How do I load a video in AS3 from FMS?
I’ve started to learn Flash Media Server 3.5 and so far I like it. I got FMS server running and started the tutorials and all is running well. I did have a bit of a hart time to find good examples that intergrated FMS, Flex and AS3. So, I gathered some examples from the docs and http://blog.flexexamples.com. I combined them to create my own class; hopefully this can be helpful to you.
My class extends the UIComponent, and I start by creating a NetConnection. I assign it the client as being “this”, so any callbacks from the server will know where to be directed to. onBWDone() is a callback made by default from FMS and the vod application. I then declare some event listeners as we do not want to go any further if there are issues with our server connection. If I wanted to http stream, I would have passed my connection’s method connect a value of “null”, however, I want to connect to FMS at this point. So, I pass the address of my server.
Now that we have called the server with a netConnection in the constructor, the application waits for a reply from the server. This comes in the form of NetStatusEvent and sent to my netStatusHandler method. The NetStatusEvent contains an info code. From here we know if the connection was successful or not by which code was returned. If the code returned is “NetConnection.Connect.Success” than we can proceed and create the NetStream and the Video object.
In the connectStream() method, I start by declaring an object that will hold the meta data and cuepoints should there be any. This could have been another class, like they did in the docs of Flex. I deciced to go with flexexamples’ way, and I created an object. The next step is to create the netStream, specify its client which is the nsClient object. The last step for the NetStream is to give it the stream name to get off the server.
I then create a video object and attach the stream to it. I decided to apply the smoothing now in case in the future I want to stretch the movie. Finally, I add the movie to the display list. Take note that the ns_onMetaData method is called when the stream gets metadata; this is where I resize the movie based on this information. Below is the complete code.
VideoExample.as:
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 | package com.alainthibodeau { import flash.events.NetStatusEvent; import flash.events.SecurityErrorEvent; import flash.media.Video; import flash.net.NetConnection; import flash.net.NetStream; import mx.controls.Alert; import mx.core.UIComponent; public class VideoExample extends UIComponent { private var serverURL:String = "rtmp://localhost/vod/"; private var streamName:String = "mp4:sample1_1500kbps.f4v"; private var connection:NetConnection; private var stream:NetStream; private var video:Video; private var meta:Object; public function VideoExample() { //First, create the netconnection, assign some listeners and connect to the server. connection = new NetConnection(); connection.client = this; connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); connection.connect(serverURL); } private function netStatusHandler(event:NetStatusEvent):void { //Lets make sure we have a connection before moving on. //We could also check here for other codes, check the docs for NetStatusEvent codes. switch (event.info.code) { case "NetConnection.Connect.Success": connectStream(); break; case "NetStream.Play.StreamNotFound": Alert.show("An error occurred while connectiing to the server: " + serverURL + "nCode: " + event.info.code,"Error"); break; case "NetConnection.Connect.Rejected": Alert.show("An error occurred while connectiing to the server: " + serverURL + "nCode: " + event.info.code,"Error"); break; } } private function securityErrorHandler(event:SecurityErrorEvent):void { trace("securityErrorHandler: " + event); } private function connectStream():void { //Create an object for the meta and cue points var nsClient:Object = {}; nsClient.onMetaData = ns_onMetaData; nsClient.onCuePoint = ns_onCuePoint; //Create the netstream object and pass it the client created above, and play the stream stream = new NetStream(connection); stream.client = nsClient; stream.play(streamName); //Create the video object and assign it our stream video = new Video(); video.attachNetStream(stream); video.smoothing = true; // put the video in the display list addChild(video); } private function ns_onMetaData(item:Object):void { //Once we know the dimensions, change the video to match it. video.width = item.width; video.height = item.height; } private function ns_onCuePoint(item:Object):void { //called when cuepoints are encountered trace("cue"); } public function onBWDone():void{ //called from asc trace("onBandwithDone"); } public function close():void { //called when the Netconnection is closed trace("close"); } } } |
Now in my MXML, all I have to do is add my tag. I could also declare it in AS3 should I ever want to change it. Depends how it will be implemented I guess.
VideoExample.mxml:
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:alainthibodeau="com.alainthibodeau.*"> <alainthibodeau:VideoExample width="100%" height="100%"/> </mx:Application> |