When you are working on a Native Extension for iOS, as a rule, you don’t have direct access to your app’s AppDelegate class, which is how you control UIApplication.
Suppose you want to intercept events in your app either before they get to the ActionScrip (AIR) side or because they won’t get there in the first place. This tutorial will show you how to do it.
Replace AppDelegate’s didReceiveRemoteNotification method
We will do this in a function, called registerApplicationEventHandlers() which you implement in your native code. The idea here is that you get access to the AppDelegate that AIR created and trick it into accepting your implementation of one or more of its methods.
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 |
void registerApplicationEventHandlers() { // Get hold of the AppDelegate instance that AIR created: id delegate = [ [ UIApplication sharedApplication ] delegate ]; // Get its type: Class objectClass = object_getClass( delegate ); // Now create an alternative delegate class: NSString * newClassName = [ NSString stringWithFormat: @"Custom_%@", NSStringFromClass( objectClass ) ]; Class substituteDelegate = NSClassFromString( newClassName ); // If we haven't registered such a class yet, do it: if ( NULL == substituteDelegate ) { substituteDelegate = objc_allocateClassPair( objectClass, [ newClassName UTF8String ], 0 ); // But first, replace the default didReceiveRemoteNotification method replaceMethodImplementation( [ UIApplication class ], substituteDelegate, @selector(application:didReceiveRemoteNotification:), ( IMP ) didReceiveRemoteNotification ); // Do other method replacements, if you need to. // Register the new class with the runtime objc_registerClassPair( substituteDelegate ); } // Change the class of the original delegate object_setClass( delegate, substituteDelegate ); } |
Now implement replaceMethodImplementation(), which registerApplicationEventHandlers() calls.
1 2 3 4 5 6 7 8 |
void replaceMethodImplementation( Class class, Class modDelegate, SEL selectorToOverride, IMP newImplementation ) { // Get hold of the method we want to replace: Method m = class_getInstanceMethod( class, selectorToOverride ); // And insert our implementation in its place: class_addMethod( modDelegate, selectorToOverride, newImplementation, method_getTypeEncoding( m ) ); } |
Provide your custom implementation
Here you implement your own didReceiveRemoteNotification method that will be called instead of the default one.
1 2 3 4 |
void didReceiveRemoteNotification( id self, SEL _cmd, UIApplication * application, NSDictionary * userInfo ) { // Replace with your own implementation } |
Make sure the replacement method is called
When do you call registerApplicationEventHandlers()? Preferably before any of the methods you replace in it should be called, but after your AppDelegate has been created. In the context of an ANE the best place for that is in your extension context initializer:
1 2 3 4 5 6 7 8 9 10 11 |
void ParseAdaptorExtensionContextInitializer( void * extData, const uint8_t * ctxType, FREContext ctx, uint32_t * numFunctionsToSet, const FRENamedFunction ** functionsToSet ) { // Do the usual stuff with exposing functions to ActionScript // Then replace the event handlers in the AppDelegate: registerApplicationEventHandlers(); } |
Johan Degraeve
the didReceiveRemoteNotification implementation sample seems to have wrong code. It’s a copy/paste of the replacemethodimplementation.
Could you update the sample ?
Radoslava
Oops, it was a copy-paste. Thanks for calling it out, Johan!