How to create a native window in Xcode and integrate it with a Mobile Flex application. The native window should act similar as the StageWebView component whereby the native con
Being a flex programmer, this was a tedious process that took me weeks to figure out. Hope this will helps some other Xcode newbies.
First of all, you must have a basic understanding of Objective-C and Xcode. You should be able to create a simple Hello World Xcode program. Once you know how to do this, you'll see that for each visual window you'll typically have a xib file, a header file and an implementation file. I found that it is easier to start of writing a normal Xcode application, and then once it is working and looking like it should, you manually pull these 3 files (and of course the helper files) over to your Xcode static library project. So, moving on, I'm going to assume that you're past this step. Here are some step by step instructions on how to integrate Xcode and Flex mobile, using ANE:
Delete FWAne.h file. Replace contents of FWAne.m file with the following:
'#import "FloatingWindow.h" '#import "FlashRuntimeExtensions.h" FREObject openFloatingWindow(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[] ) { uint32_t parm0Length, parm1Length, parm2Length, parm3Length, parm4Length, parm5Length, parm6Length, parm7Length, parm8Length, parm9Length, parm10Length, parm11Length, parm12Length, parm13Length; const uint8_t *uparm0, *uparm1, *uparm2, *uparm3, *uparm4, *uparm5, *uparm6, *uparm7, *uparm8, *uparm9, *uparm10, *uparm11, *uparm12, *uparm13; FREGetObjectAsUTF8(argv[0], &parm0Length, &uparm0); NSString* parm0 = [NSString stringWithUTF8String:(char*)uparm0]; // FREGetObjectAsUTF8(argv[1], &parm1Length, &uparm1); // NSString* parm1 = [NSString stringWithUTF8String:(char*)uparm1]; // FREGetObjectAsUTF8(argv[2], &parm2Length, &uparm2); // NSString* parm2 = [NSString stringWithUTF8String:(char*)uparm2]; // FREGetObjectAsUTF8(argv[3], &parm3Length, &uparm3); // NSString* parm3 = [NSString stringWithUTF8String:(char*)uparm3]; // FREGetObjectAsUTF8(argv[4], &parm4Length, &uparm4); // NSString* parm4 = [NSString stringWithUTF8String:(char*)uparm4]; // FREGetObjectAsUTF8(argv[5], &parm5Length, &uparm5); // NSString* parm5 = [NSString stringWithUTF8String:(char*)uparm5]; // FREGetObjectAsUTF8(argv[6], &parm6Length, &uparm6); // NSString* parm6 = [NSString stringWithUTF8String:(char*)uparm6]; // FREGetObjectAsUTF8(argv[7], &parm7Length, &uparm7); // NSString* parm7 = [NSString stringWithUTF8String:(char*)uparm7]; // FREGetObjectAsUTF8(argv[8], &parm8Length, &uparm8); // NSString* parm8 = [NSString stringWithUTF8String:(char*)uparm8]; // FREGetObjectAsUTF8(argv[9], &parm9Length, &uparm9); // NSString* parm9 = [NSString stringWithUTF8String:(char*)uparm9]; // FREGetObjectAsUTF8(argv[10], &parm10Length, &uparm10); // NSString* parm10 = [NSString stringWithUTF8String:(char*)uparm10]; // FREGetObjectAsUTF8(argv[11], &parm11Length, &uparm11); // NSString* parm11 = [NSString stringWithUTF8String:(char*)uparm11]; // FREGetObjectAsUTF8(argv[12], &parm12Length, &uparm12); // NSString* parm12 = [NSString stringWithUTF8String:(char*)uparm12]; // FREGetObjectAsUTF8(argv[13], &parm13Length, &uparm13); // NSString* parm13 = [NSString stringWithUTF8String:(char*)uparm13];} // ContextFinalizer(). void ContextFinalizer(FREContext ctx) { NSLog(@"ContextFinalizer"); //Cleanup Here. return; } // ContextInitializer() void ContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet) { NSLog(@"ContextInitializer"); *numFunctionsToTest = 1;NSLog(@"Initializing delegate and window"); id delegate = [[UIApplication sharedApplication] delegate]; UIWindow *window = [delegate window]; NSLog(@"Creating FloatingWindow"); FloatingWindow* fw = [[FloatingWindow alloc] initWithNibName:@"FloatingWindow" bundle:nil]; NSLog(@"Adding FloatingWindow"); [window addSubview:fw.view]; NSLog(@"Setting frame size"); fw.view.frame = CGRectMake(100, 100, 200, 200); NSLog(@"Done openFloatingWindow"); return NULL;
} // ExtInitializer() void ExtInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet, FREContextFinalizer* ctxFinalizerToSet) { NSLog(@"ExtInitializer"); *extDataToSet = NULL; *ctxInitializerToSet = &ContextInitializer; *ctxFinalizerToSet = &ContextFinalizer; } // ExtFinalizer() void ExtFinalizer(void* extData) { NSLog(@"ExtFinalizer"); // Do Cleanup here. return; }FRENamedFunction* func = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * 1); func[0].name = (const uint8_t*) "openFloatingWindow"; func[0].functionData = NULL; func[0].function = &openFloatingWindow; *functionsToSet = func;
Add the FlashRuntimeExtensions.h to your Xcode project. This file exists under the /Applications/Adobe Flash Builder 4.6/sdks/4.6.0/include folder
Create your class that will use ExtensionContext to wire the Flex code to your Xcode code like so:
package fwane { import flash.events.EventDispatcher; import flash.events.StatusEvent; import flash.external.ExtensionContext;}public class FWAne { private static const EXTENSION_ID : String = "fwane.FWAne"; private var context : ExtensionContext; public function FWAne() { context = ExtensionContext.createExtensionContext( EXTENSION_ID, null ); if (context == null) { trace("WARNING: ExtensionContext cannot initialize"); } } public function openFloatingWeendow(fileName : String) : void { trace("Calling openFloatingWeendow"); context.addEventListener( StatusEvent.STATUS, onAneWinHander ); trace("Invoking native call"); context.call( "openFloatingWindow", fileName); trace("Returning from openFloatingWeendow"); } private function onAneWinHander( event : StatusEvent ) : void { trace(event.level); } }
Build the FWAne swc
Next, you are going to require a build script to compile your ANE. Here's my build.sh script:
export XLIB="/Users/christo.smal/Library/Developer/Xcode/DerivedData/wherever-lib.a" export CERT="/wherever/if/you/want/to/sign/ane.p12" export FLEXLIBPATH="../Path/of/flex/library/project" export XIBPATH="/Path/of/where/xib/files/are" export SWCFNAME="FWAne.swc" export ANEFNAME="FWAne.ane" ls -la $XLIB echo Copying files ... rm -rf debug/* cp $FLEXLIBPATH/src/extension.xml . cp $FLEXLIBPATH/bin/$SWCFNAME . cp $XLIB ./debug '# copy resource files such as images to debug folder cp /path/to/my/images/referenced/from/xcode/*.png ./debug echo Compiling xib''s cp $XIBPATH/*.xib ./debug cp /wherever/FloatingWindow.xib ./debug /Developer/usr/bin/ibtool --errors --warnings --notices --output-format human-readable-text --compile debug/FloatingWindow.nib debug/FloatingWindow.xib --sdk /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk rm -rf debug/*.xib echo Extracting library.swc ... cp $SWCFNAME kak cd kak unzip -xo $SWCFNAME cp -X library.swf ../debug cd .. echo Copying some more files ... rm -rf debug/*.ane cp extension.xml debug echo Building ANE ... '# -package -target ane / extension.xml -swc -platform -C . /Applications/Adobe\ Flash\ Builder\ 4.6/sdks/4.6.0/bin/adt -package -target ane debug/unsigned.ane extension.xml -swc $SWCFNAME -platform iPhone-ARM -platformoptions ios-platformoptions.xml -C debug . echo Signing ANE ... '#/Applications/Adobe\ Flash\ Builder\ 4.6/sdks/4.6.0/bin/adt -sign -storetype pkcs12 -keystore $CERT -storepass password -target ane debug/unsigned.ane $ANEFNAME cp debug/unsigned.ane $ANEFNAME echo done
Important to note about my build script: The xibs are compiled to nibs, and then these nibs together with other resource files (such as images) are then included in the ANE. Remember that static libs cannot contain resource files.
You would also require an ios-platformoptions.xml file. This is to include all frameworks you require. You can also include any additional 3rd party libs with their search paths here:
<platform xmlns="http://ns.adobe.com/air/extension/3.1"> <sdkVersion>5.0</sdkVersion> <linkerOptions> <option>-framework Foundation</option> <option>-framework UIKit</option> <option>-framework QuartzCore</option> <option>-framework CoreGraphics</option> <!--option>-lthirdparty</option> <option>-L/searhPath/for/thirdlibrary</option--> </linkerOptions> </platform>
Now, in FlashBuilder, create a sample test application project. Go to project properties. In Flex build path, make sure the ane is added. Also under Flex Build Packaging -> Apple iOS -> Native extensions the ANE is added there and package is checked. Also add the Apple iOS SDK folder under native extensions. Finally, check that the extension is added in the -app.xml file.
Hope this helps
C