Categories

Archives

Integrating native iOS applications with Flash Media Server

The Communication Library for iOS which we have recently released enables developers to integrate native iPhone and iPad applications with various server-side technologies. Since the library implements the RTMP protocol, it can easily connect the iOS applications with any RTMP-enabled media server. One of the most popular media servers is Adobe Flash Media Server. The video below provides an overview of the integration. Specifically, it demonstrates ability to do invocations of the server-side ActionScript running in FMS from the iOS apps using the library. Additionally, there is an example of the FMS data push implemented as an invocation of the client-side Objective-C functions from the code running in FMS.

In addition to the features reviewed in the video, the same library supports Remote Shared Objects. Currently, the integration enables data messaging, but we’re also working on adding support for video and audio broadcast and server-side recording. This new functionality will enable any iOS application to broadcast or record video stream from the device’s camera and audio from the microphone.

Enjoy!

Follow the steps below to configure your own FMS installation to run the same examples:

  1. Download and install Flash Media Server
  2. Create “CallbackDemo” folder under [FMS-INSTALL]/applications
  3. Download and extract CallbackDemo-servercode.zip into [FMS-INSTALL]/applications/CallbackDemo
  4. Create “MethodInvocation” folder under [FMS-INSTALL]/applications
  5. Download and extract MethodInvocation-servercode.zip into [FMS-INSTALL]/applications/MethodInvocation
  6. Download Communication Library for iOS, extract and the examples and open the examples project in XCode

“Hello, World!” screencast

Below, please find the screencast version of this “Hello, World!” blarticle.

It’s not the spiffiest screencast I’ve ever seen. I made it using TechSmith’s Camtasia, which has far more features than I know how to use. As I learn more about Camtasia, these screencasts will improve accordingly. Lots of new stuff to learn!

Whee!   ;-)

Hello, World!

My first WebORB for .NET app, as is traditional, simply displays the message “Hello, World!” — but with a client/server twist.

The server side code is implemented as a C# class library:

using System;
using System.Web;

namespace HelloWorldServer
{
    public class HelloWorldService
    {
        public string getHelloString()
        {
            return "Hello, World!";
        }
    }
}

Compiling that in VisualStudio 2008 produces an assembly called “HelloWorldServer.dll”, at \Visual Studio 2008\Projects\samples\HelloWorldServer\HelloWorldServer\bin\Debug.

[Why VisualStudio 2008 instead of VisualStudio's new, über-cool 2010 version? Because, as a former Microsoft employee, I can buy Visual Studio 2010 Professional super-cheap through the Microsoft Company Store...but it's on back-order there now. Until it's back in stock, I'll stick with the older version.]

One way to make this service available to WebORB for .NET clients is to copy the service’s DLL into WebORB’s \bin directory. For my installation, that’s C:\Program Files\WebORB for .NET\4.0.0.5\bin; your mileage may vary, depending on where you’ve installed WebORB for .NET and what version you have installed.

To verify that the service is exposed properly, I can then launch WebORB for .NET’s management console,
…click in its SERVICES tab,
…click on .NET Assemblies, and click through to the method getHelloString(), which is exposed by WebORB for .NET as a service.

Note that the console’s Test Drive tab is selected, exposing (among other things) a button labelled “Invoke”. In the list control at the left of the screen, select the getHelloString() method. Then, click on the “Invoke” button to invoke getHelloString().

As you can see, the “Name,” “Type,” and “Value” columns’ first row contain, respectively,

  • “Result” (the name of getHelloString()’s result),
  • “String” (the type of getHelloString()’s result), and
  • “Hello, World!” (the value of getHelloString()’s result).

This simple test verifies that:

  • getHelloString() is deployed where WebORB for .NET can find it, and
  • getHelloString() is returning the value I intended (that is, “Hello, World!”).

…which is a good “reality check” before starting to work on the client-side code.

Now, in the DEPLOYED ASSEMBLIES area on the upper-left corner of the console, go up one level to select HelloWorldService.

This automatically selects the console’s “Generate Code” tab, which, IMHO, is one of the coolest features of WebORB, because it can save an incredible amount of time writing, testing, and debugging code.

It’s not just that WebORB generates code for you; it’s not just that generating code saves you time; and it’s not just that time is money, so that using generated code saves you money — although all of that is true, and important. Even more important, however, is that the generated code encapsulates years of experience in client/server software development. Every time The Midnight Coders’ resident geniuses figure out how to handle another kind of bug, that handling goes into the code generator, so that you don’t have to deal with it yourself.

I’m not saying that WebORB generates perfect code; not at all. Indeed, this blarticle will expose a significant imperfection in WebORB’s code generation….but not quite yet.

Look at the right-hand side of the console. It should look like the image at right. Note that, of the set of “Code format/style” radio buttons, the one for “Flex Remoting/AS3″ is selected, indicating that Flex-compatible code will be generated. Try selecting other radio buttons. The generated code, shown in the middle of the console, changes to reflect the “Code format/style” radio button currently selected, changes as you select different radio buttons.

Below the stack of radio buttons is another UI section, entitled “Generated code structure:”. It lists the folder(s) and files(s) that can be generated. Select one file, and you’ll see its code appear in the console’s central box. Select a different file, and its code will appear in that box instead.

Now, you could just copy the generated code out of that box and then paste it into your own project. That would be pretty cool. In this blarticle, however, we’re going to do something even cooler.

First, make sure that the “Flex Remoting/AS3″ radio button is selected. Next, look right below the stack of radio buttons. See the checkbox labelled “Generate project files”? Click on it, so that it is checked. Now, press the “Download Code” button.

Windows will throw up a “File Download” dialog, asking you to select the location at which to save the file “weborb.codegen.zip”. Save it wherever is convenient (once you unzip it, you can throw it away, so it doesn’t much matter where you save it).


Now comes the fun part. Open up Flex Builder 4, and in the “File” menu, choose “Import…”. That will bring up the Import screen shown at left.

Find the entry named “Flash Builder”, as highlighted at left. Click on the little ‘+’-sign to its left to reveal more choices.

Select “Flash Builder Project”, as highlighted at right.

Press the “Next” button and you’ll be taken to the “Import Flash Builder Project” screen, shown below.

Wow, these images are really overwhelming this blarticle.  I like to use lots of graphics, though, because I find it hard to follow other people’s instructions if they leave steps out, or don’t make them brain-dead simple to follow (which tells you more about my brain than about their instructions, I fear).

In the “Import Flash Builder Project” screen above, click on the upper “Browse…” button at right. That will bring up the standard “Open” directory browser. Use it to navigate to the “weborb.codegen.zip” file you downloaded a couple of steps ago. Select it; press the “Open” button; and you’ll be taken back to the “Import Flash Builder Project” screen above…but this time, the “Finish” button is enabled. Click “Finish”.

That will bring you to yet another screen, this one entitled “Choose Flex SDK Version”. All of my sample apps will use Flex SDK 4 unless otherwise noted (until a future major upgrade is released, anyway) — so be sure that you choose Flex SDK 4 in this screen, too. Click the screen’s “OK” button.

Yet another screen appears — this one entitled “Project Will Be Upgraded,” informing me that “Project HelloWorldService was created with a previous version of Flash Builder. If you save it, you will no longer be able to open this project with older versions of Flash Builder. Continue?” It offers two choices, “OK” and “Cancel”. Click “OK”. That ends the importation of the generated project.

The generated project is shown in Flex Builder’s “Package Explorer” window, as shown at left. (The project HelloWorldClient1, above it, is local to my machine; you won’t see it on yours.)

As you can see, WebORB’s generated source files — HellowWorldService.as and HelloWorldServiceModel.as — are in the HelloWorldServer package, which is as it should be.

However, I’m not super-happy with the name of the generated project. It’s “HelloWorldService”, but this Flex app is the client-side app. I’d rather name it HelloWorldClient. So I’ll select it, right-click it, and choose “Rename…” from the resulting pop-up menu, renaming it to “HelloWorldClient”. Much better.

Let’s look at HelloWorldClient’s main.mxml, generated by WebORB:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="onLoad()">
<mx:Script>
<![CDATA[

  public function onLoad():void
  {

  }
]]>
</mx:Script>
</mx:Application>

This code was generated for Flex SDK 3.5, but I’m using Flex SDK 4.0. At present, WebORB for .NET does not have the capability of generating code for Flex SDK 4.That’s on the “to-do” list, and should be supported Real Soon Now. Bummer. (See? I told you that WebORB generated less-than-perfect code. We are but mortal.)

No worries, though — the changes are simple enough to make. Here’s the revised code:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   initialize="onLoad()">
	<fx:Script>
		<![CDATA[

		public function onLoad():void
		{

		}
		]]>
	</fx:Script>
</s:Application>

The changes I made were:

  • defining the fx and s namespaces
  • re-defining the mx namespace
  • changing the Application tags from mx to s
  • changing the Script tags from mx to fx
  • removing the “layout=absolute” phrase from the Application’s declaration
  • changing the indentation in the Application’s declaration to make it easier to read

What is the next step? The source code in HelloWorldService.as, generated by WebORB for .NET, provides a clue. Its header comment says:

/***********************************************************************
The generated code provides a simple mechanism for invoking methods
on the HelloWorldServer.HelloWorldService class using WebORB.
You can add the code to your Flex Builder project and use the
class as shown below:

import HelloWorldServer.HelloWorldService;
import HelloWorldServer.HelloWorldServiceModel;

[Bindable]
var model:HelloWorldServiceModel = new HelloWorldServiceModel();
var serviceProxy:HelloWorldService = new HelloWorldService( model );

// make sure to substitute foo() with a method from the class
serviceProxy.foo();

Notice the model variable is shown in the example above as Bindable.
You can bind your UI components to the fields in the model object.
************************************************************************/

OK, let’s do that! Fleshing out the CDATA block as described above gives us the following:

	<fx:Script>
		<![CDATA[
			import HelloWorldServer.HelloWorldService;
			import HelloWorldServer.HelloWorldServiceModel;

			[Bindable]
			private var model:HelloWorldServiceModel
								= new HelloWorldServiceModel();
			private var serviceProxy:HelloWorldService
								= new HelloWorldService( model );

			public function onLoad():void
			{
				serviceProxy.getHelloString();
			}
		]]>
	</fx:Script>

Cool! Let’s run it! …and absolutely nothing is visible on screen. Doh! I kinda forgot to add a UI.

Let’s add a couple of labels below the Script block:

	<s:Label id="helloLabel"
			 horizontalCenter="0" verticalCenter="0"
			 text="{model.getHelloStringResult}" />

	<s:Label y="34" horizontalCenter="0" text="Result is..."/>

The only interesting bit here is the binding of helloLabel’s text field to model.getHelloStringResult, as suggested by the comment in HelloWorldService.as. When did this property get set? Let’s look at the whole main.mxml file:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   width="282" height="150"
			   initialize="onLoad()">

	<fx:Script>
		<![CDATA[
			import HelloWorldServer.HelloWorldService;
			import HelloWorldServer.HelloWorldServiceModel;

			[Bindable]
			private var model:HelloWorldServiceModel
								= new HelloWorldServiceModel();
			private var serviceProxy:HelloWorldService
								= new HelloWorldService( model );

			public function onLoad():void
			{
				serviceProxy.getHelloString();
			}
		]]>
	</fx:Script>

	<s:Label id="helloLabel"
			 horizontalCenter="0" verticalCenter="0"
			 text="{model.getHelloStringResult}" />

	<s:Label y="34" horizontalCenter="0" text="Result is..."/>
</s:Application>
  • On line 06, we ensure that onLoad() gets called when the application is initialized.
  • On line 21, onLoad() calls serviceProxy.getHelloString().
  • On line 16, serviceProxy is declared to be of class HelloWorldService.

…so let’s take a look at HelloWorldService.as.

      public function getHelloString( responder:IResponder = null ):void
      {
        var asyncToken:AsyncToken = remoteObject.getHelloString();

        if( responder != null )
            asyncToken.addResponder( responder );
      }

      public virtual function getHelloStringHandler(event:ResultEvent):void
      {
          var returnValue:String = event.result as String;
          model.getHelloStringResult = returnValue;
      }

The flow of control is:

  • onLoad() calls serviceProxy.getHelloString();
  • serviceProxy.getHelloString() calls remoteObject.getHelloString();
  • WebORB calls the C# service we defined earlier;
  • If the magic is successful, then the C# service’s return value is stuffed into the “result” field of a ResultEvent;
  • getHelloStringHandler() is called asynchronously with that ResultEvent object as a parameter;
  • model’s getHelloStringResult property is set to event.result (that is, to “Hello, World!”);
  • and, finally, because helloLabel’s text field is bound to model.getHelloStringResult,
  • helloLabel’s text field is updated to match model.getHelloStringResult, which, deep in the bowels of Flex
  • forces helloLabel to be redrawn with its new contents: “Hello, World!”

Now, I would not claim that this is the simplest “Hello, World!” application ever written — far from it. It include four source code files: one on the server, and three on the client. Together, these files contain something like 170 lines of code. That’s not counting WebORB for .NET’s code, or Flex’s code. All together, we’re talking quite a bit of code.

But the thing is, I wrote hardly any of it. A few lines on the server, a few lines on the client, and — presto-chango! — I’ve got a (trivial) client-server application up and running.

I left programming for nearly a decade in the late 1990’s, in part because COM and — shudder! — DCOM made programming so complicated. I did not want to spend my hours tracking down reference counting errors, for example, or bugs in a class’ marshalling/unmarshalling. Blech. That simply wasn’t fun. I got into programming because people paid me to have fun doing it, which is a pretty awesome way to make a living…until it got so complicated that it wasn’t fun anymore.

Now, with .NET, Flex, and WebORB, programming has become fun again — so I’m delighted to get back into coding. Still, I’ve missed a lot, so if you see me making a coding mistake, or a design error, a pattern violation, a smell fault, or somesuch, please don’t hesitate to let me know. By helping me, you’ll be helping lots of other people, too; we can all learn together. You can reach me at jim [att] themidnightcoders [dott] com.

P.S.:  Before you ask…Why haven’t I included a link to this sample application’s HelloWorldService.as and HelloWorldServiceModel.as files? Because they are both generated by WebORB. You can generate them for yourself, using WebORB’s management console, as described above. That’s kinda the whole point of this blarticle. ;-)

WebORB Plugin for Flash Builder (Video)

One of the new features in the WebORB v.4 for .NET release is a plugin for Flash Builder. This video reviews the plugin and the features it provides. The direct link to the video on YouTube is:

http://www.youtube.com/watch?v=gSHpzsTJpRM&hd=1

Enjoy!

What should Adobe do now or getting Flash to iPhone

Flash-on-iPhoneCS5 is hours away from being released and I am sure a lot of people are wondering what Adobe is going to do with the much anticipated feature allowing Flash apps to be compiled to the native iPhone binary format. Clearly the changes in section 3.3.1 of the iPhone SDK licensing agreement seem to be  a big blow for Adobe. The new feature was marketed to be a new, cool way to leverage one’s Flash development skills and get Flash-compiled apps directly into the Apple’s AppStore. So what’s going to happen now? No one really knows until CS5 is released, but here’s what I would love Adobe to do:

  1. Definitely keep the feature in. In fact, continue marketing it to establish Flash as a fresh, new, intuitive framework for building apps for mobile devices. Enhance the framework with new components, wizards, cool interfaces. One might ask ‘why??’, the reason is in item #2:
  2. Create an alternative, open and community-driven AppStore where developers can post their applications. It should not be focused on iPhone, but be open for Flash-based apps for all types of devices: iPhone, IPod Touch, iPad, Android and Blackberry. Use the same principle to monetize it as done by Apple – get a piece of the action from the apps offered for a fee, but let the free one be distributed for free with no string attached. You might ask, how would the iPhone users be able to get those apps? The answer for that question is item #3:
  3. Get completely behind the iPhone/iPod Touch/iPad jailbreaking software. Publicize it on the new AppStore. Include it as an extension directly into Flash Player and Acrobat Reader. Someone wants to unlock their iPhone or iPad, the software to do it is right there! It is not clear whether this would be entirely legal, however it is very likely it might be (see this section on Legal Issues of Jailbreaking on Wikipedia).
  4. Enable the feature in CS5 to compile the Flash apps to run on other devices in addition to iPhone/iPad (Android, Blackberry, etc).
  5. Figure out how to generate pure Objective-C code rather than binary compilation. This is easier said than done, but it would allow some really cool things to happen, for example item #6:
  6. Create a Mac-based cloud which would allow Flash developers to upload their Flash/AS code, generate Obj-C code and then compile it into a native app. The result of this would eliminate anyone from buying Apple’s hardware and you can still get around the limitations of 3.3.1. I bet Apple would hate it!

I know some of these suggestions are a bit far fetched, but I believe all of it is doable and could lead to many positive developments.