Tuesday, August 26, 2014

AeroGear, iOS8 and Swift: Push happiness forward!

AeroGear iOS Push lib 1.0.0 , out this August, features iOS8 support and (in its preview) even offers a 'Swift' branch with the lib being rewritten "The Swift Way". Ready before the official iOS8 release, we hope you will enjoy it as much as we did :)

AeroGear Push notification on iOS8

AeroGear UnifiedPush Server is ready with updated payload. What does it mean for your app?
  • You can send longer messages.
  • You can use interactive notification.
  • If you want to dig deeper into interactive notifications please follow iOS8 interactive notification available in AeroGear with a step by step tutorial and videos.

    Get ready: Switch to Swift

    Getting ready before the iOS8 release got its price. It means some efforts to keep our demos and libraries up to the latest beta version and of course as it's beta, it takes some radars filling and workarounds. Currently all our Swift code compile against the latest Xcode6 beta6 (out the 18th August). Some workarounds are needed specially around framework build. I recommend you follow that mailing list thread for more details.

    Give Swift Push lib and demos a trial

    If you're all set up (latest Xcode6 and iOS8 device), give a spin to our HelloWorld Swift demo, you can use the OpenShift admin console to push messages. If you want to delve into more complete app, try our full blown server side and client side demo app Contact in its Swift branch.

    Going further into Swift

    AeroGear iOS team has chosen to go Swift first for the next releases.
    You can check out our roadmap and you'll see most of the upcoming tickets are Swift based ;)
    We've just baked aerogear-ios-httpstub, you can read more about its insights in my previous blog post. We're working on aerogear-ios-http a lightweight layer to take care of your http requests and our OAuth2 module is on its way.

    1
    2
    3
    ... Ready?
    Switch to Swift?

    Wednesday, July 30, 2014

    Http Stubs: let's go Swift Swizzling!

    Blog Update 20th August 2014: This initial post was tested using Xcode6 beta4, with Xcode beta5 Swizzling was broken. From release notes "Dynamic dispatch can now call overrides of methods and properties introduced in class extensions, fixing a regression introduced in Xcode 6 beta 5. (17985819)!"
    See stackoverflow question for more details

    Happy beta6 Swifting!
    Last weeks, I was delving into http and Swift with my friend Christos. To write robust code, we need unit tests of course and to isolate testing layer: you need a HTTP stub.

    When we worked with Objective-C, we used to mock http calls with OHTTPStubs. So we thought we could carry on using it with our brand new Swift code. After all, Swift and Objective-C are interoperable. However, there are subtle differences with iOS8 and when trying to use OHTTPSubs obj-c lib with Swift code, we ran into this issue (merged now!).

    But when you delve into some neat code, then the urge of writing your own is showing up... It wasn't long before my friend Christos came up with AGURLSessionStubs a http stub written entirely in Swift.

    With this blog post, I'd like to share with you the inside of stubbing http library. Let's dig under the hood to see how http mock are implemented in Objective-C and how we can apply the same concepts (with some restrictions) in Swift.

    Implementing NSURLProtocol

    As Mattt Thompson linked this excellent blog post on how to stub class method by registering a customized NSURLProtocol. All you have to do is implement your own mocked NSURLProtocol class. Let's see how to do it in Swift:
    class StubURLProtocol: NSURLProtocol {
        let stubDescr: StubDescriptor
    
        override class func canInitWithRequest(request: NSURLRequest!) -> Bool {
            return StubsManager.sharedManager.firstStubPassingTestForRequest(request) != nil
        }
        ...
        override func startLoading() {
            let request: NSURLRequest = self.request
            let client: NSURLProtocolClient = self.client;
    
            let responseStub: StubResponse = self.stubDescr.responseBlock(request)
    
            let urlResponse = NSHTTPURLResponse(URL: request.URL, statusCode: responseStub.statusCode, HTTPVersion: "HTTP/1.1", headerFields: responseStub.headers)
    
             client.URLProtocol(self, didReceiveResponse: urlResponse, cacheStoragePolicy: NSURLCacheStoragePolicy.NotAllowed)
             client.URLProtocol(self, didLoadData: responseStub.data)
             client.URLProtocolDidFinishLoading(self)
        }
    }
    
    And now we're left with registering. NSURLSession is initialised by passing it a configuration with a class method:
    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
    let session = NSURLSession(configuration: config)
    
    How can I switch between stub and real implementation? One way of doing it would be to inherit and implement NSURLSessionConfiguration, another way would be to swap method implementation of NSURLSessionConfiguration.defaultSessionConfiguration() with mock swizzle_defaultSessionConfiguration() which contains code to register our mocked NSURLProtocol class.

    Method swizzling

    The runtime dynamic method replacement technique known as method swizzling uses Objective-C runtime meta-programming to swap methods at runtime. Since we have interoperability Swift/Objective-C, if the object you want to mock inherits NSObject (in our scenario with NSURLSessionConfiguration, this is the case), you can use runtime meta-programming.
    Here is how to swap 2 methods contents.
       
    private class func swizzleFromSelector(selector: String!, toSelector: String!, forClass:AnyClass!) {
    
        var originalMethod = class_getClassMethod(forClass, Selector.convertFromStringLiteral(selector))
        var swizzledMethod = class_getClassMethod(forClass, Selector.convertFromStringLiteral(toSelector))
        method_exchangeImplementations(originalMethod, swizzledMethod)
    
    }
    
    In this example we simply swap the content of method from defaultSessionConfiguration to swizzle_defaultConfiguration. You can simply defined swizzle_defaultSessionConfiguration as an extension of NSURLSessionConfiguration:
       
    extension NSURLSessionConfiguration {    
        class func swizzle_defaultSessionConfiguration() -> NSURLSessionConfiguration! {
            // as we've swap method, calling swizzled one here will call original one
            let config = swizzle_defaultSessionConfiguration()
            
            var result = [AnyObject]()
            
            for proto in config.protocolClasses {
                result += proto
            }
    
            // add our stub
            result.insert(StubURLProtocol.classForCoder(), atIndex: 0)
            config.protocolClasses = result       
            return config
        }
    }
    
    The trick is when you call NSURLSessionConfiguration.defaultSessionConfiguration() you actually call NSURLSessionConfiguration.swizzle_defaultSessionConfiguration() and vice versa. So the first call line 5 is not a recursive call but the call to the original method! From a user point of view, here is the way to write a test:
    func testGETWithoutParametersStub() {
        func http_200(request: NSURLRequest!, params:[String: String]?) -> StubResponse {
            var data: NSData
            if (params) {
                data = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: nil)
            } else {
                data = NSData.data()
            }
            return StubResponse(data:data, statusCode: 200, headers: ["Content-Type" : "text/json"])
        }
        
        func http_200_response(request: NSURLRequest!) -> StubResponse {
            return http_200(request, params: ["key1":"value1"])
        }
        // set up http stub
        StubsManager.stubRequestsPassingTest({ (request: NSURLRequest!) -> Bool in
            return true
        }, withStubResponse:( http_200_response ))
            
        // async test expectation
        let getExpectation = expectationWithDescription("Retrieve data with GET without parameters");
            
        var url = "http://whatever.com"
        var http = AGSessionImpl(url: url, sessionConfig: NSURLSessionConfiguration.defaultSessionConfiguration())
        http.GET(nil, success: {(response: AnyObject?) -> Void in
           if response {
              XCTAssertTrue(response!["key1"] as NSString == "value1")
              getExpectation.fulfill()
           }
        }, failure: {(error: NSError) -> Void in
           XCTAssertTrue(false, "should have retrieved jokes")
           getExpectation.fulfill()
        })
            
        waitForExpectationsWithTimeout(10, handler: nil)
    }
    
    
    1. line16-19: you need to instantiate your stub and tell runtime: go swizzling from now on when you call NSURLSessionConfiguration.defaultSessionConfiguration() I really mean NSURLSessionConfiguration.swizzle_defaultSessionConfiguration() because this one instantiate my mock NSURLProtocol and put it before all the other protocols so i can stub http calls now.
    2. line 2-14: stub your response
    3. line 25-33: do you work with NSURLSession as usual
    4. line 27-28: assert
    5. in teardown method don't forget to remove your stub with StubsManager.removeAllStubs()

    Swizzling in Swift: is it needed?

    Yes, some would says.

    Matt says: this may not actually be necessary in Swift

    Although others ways exist (missing class variable in Swift though) I couldn't find an easy way to switch two methods content as shown in the previous example.

    Want to know more about AGURLSessionStubs

    Go and check AGURLSessionStubs, see how to use it with push registration lib or aerogear-ios-http lib.
    Special thanks to my friend Christos who shared with me most of the articles linked in the post and who is the creator of AGURLSessionStubs where code snippets comes from.

    Happy Swifting!
    Feedback welcome!

    Sunday, July 27, 2014

    How to support push notification for iOS7 and iOS8?

    iOS8 interactive notification

    The whole concept is to quickly respond to a notification without context switch. iOS8 interactive notification also called actionable notification allows you to respond to messages, reminders and invites without having to leave your app or unlock your phone.

    Deprecated API

    Since iO8, registerForRemoteNotificationTypes has been deprecated in favour of registerUserNotificationSettings: with registerForRemoteNotifications. The API unifies notification settings whether it's a remote or user notification.

    What about if...

    You want to register for remote notification and you ...
    use Xcode5 with iOS7
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    
    use Xcode6 with iOS8
        UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    
    use Xcode6 with iOS7
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    
    use Xcode6 with iOS7 or iOS8
    Testing wether or not the registerUserNotificationSettings: API is available at runtime, means you're running on iOS8.
        if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
            UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
            [[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
            [[UIApplication sharedApplication] registerForRemoteNotifications];
        } else {
            [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
        }
    use (Xcode6 with iOS8 or iOS7) and (Xcode5 with iOS7)
    The macro __IPHONE_OS_VERSION_MAX_ALLOWED conditionally compiles the code so that the new Xcode6 compiler won't complain about the deprecations and the XCode5 won't complain about nonexistent symbols. for Xcode6 running on iOS7 we use the trick explained in previous section.
    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0
        if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
            UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
            [[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
            [[UIApplication sharedApplication] registerForRemoteNotifications];
        } else {
            [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
        }
    #else
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    #endif
    

    Thursday, July 24, 2014

    iOS8 interactive notification available in AeroGear

    AeroGear UnifiedPush Server is ready for iOS8!
    Want to see how to create iOS8 interactive notifications? Follow me...

    AeroDoc push notification application revisited, step by step

    Last year, I blogged about AeroDoc, a demo app for AeroGear UnifiedPush Server (UPS). This is a very good entry point to get an overview on UPS. Here's the story:

    A sell agent can receive push notifications triggered by her admin. Upon notification, she has the option to accept the lead and add it to her personal list. But to accept the lead, you have to tap the notification and bring the app in the foreground. The whole purpose of interactive notification is to let you do action without context switch. No more app switching!
    Going back to AeroDoc tutorial, let's see how we can enhance the client app to accept a lead directly in the notification.

    What you need

  • iOS8+. At the time of writing, iOS8 beta4 is out.
  • Xcode6. Same here beta4
  • clone, build and deploy UPS or alternatively create a UPS on OpenShift
  • clone, build and deploy AeroDoc backend
  • clone, build AeroDoc iOS client

  • Steps by steps

    Step1: Create an Application on UnifiedPush Server

    Watch the screencast to learn how to:
  • create an OpenShift AeroGear UPS instance.
  • create a new backend app
  • associate an iOS variant with its APNs certificate



  • Step2: AeroDoc backend configuration

    Install AeroDoc backend following instructions.
    Go to configuration link and create a new configuration, entering:
  • UPS server URL
  • AppID
  • App Secret

  • Step3: AeroDoc backend app

    AeroDoc backend app uses unifiedpush-java-client to send push notification to UPS. Since 0.8.0, unifiedpush-java-client can send interactive notification in its payload. See the extra payload line 11. The category identifier "acceptLead" should be reused when implementing actions on client side. And that's all you need to do to support interactive notification server side!
        public void sendLeads(List users, Lead lead) {
                ...
                UnifiedMessage unifiedMessage = new UnifiedMessage.Builder()
                        .pushApplicationId(getActivePushConfig().getPushApplicationId())
                        .masterSecret(getActivePushConfig().getMasterSecret())
                        .categories("lead")
                        .actionCategory("acceptLead")
                        .aliases(users)
                        .simplePush("version=" + new Date().getTime())
                        .attribute("id", lead.getId().toString())
                        .attribute("messageType", "pushed_lead")
                        .attribute("name", lead.getName())
                        .attribute("location", lead.getLocation())
                        .attribute("phone", lead.getPhoneNumber()).sound("default")
                        .alert("A new lead has been created").build();
    
                javaSender.send(unifiedMessage, new LeadSenderMessageResponseCallback());
    
        }
    

    Note: APNs interactive notifications add category to its payload to associate a group of actions to a category. As UPS already uses the name 'categories' in its payload but for a different purpose, the name action-category was chosen instead.

    Step3: AeroDoc iOS app

    Watch it live coding:



    Or just follow these instructions:

    When registering for remote notification, provide a category (from the previous code we called it 'acceptLead'). To define a category, add all associated actions. Here we demo only one action but you can define a list. Depending on your notification setup, the list of visible actions can be limited. Using UIUserNotificationActionContextMinimal you can define which actions should be displayed in priority when space is limited.
    - (UIMutableUserNotificationCategory*)registerActions {
        UIMutableUserNotificationAction* acceptLeadAction = [[UIMutableUserNotificationAction alloc] init];
        acceptLeadAction.identifier = @"Accept";
        acceptLeadAction.title = @"Accept";
        acceptLeadAction.activationMode = UIUserNotificationActivationModeForeground;
        acceptLeadAction.destructive = false;
        acceptLeadAction.authenticationRequired = false;
        
        UIMutableUserNotificationCategory* category = [[UIMutableUserNotificationCategory alloc] init];
        category.identifier = @"acceptLead";
        [category setActions:@[acceptLeadAction] forContext: UIUserNotificationActionContextDefault];
        return category;
    }
    
    Once all actions are defined and wrapped into a category, inject category to UIUserNotificationSettings as shown below:
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    #ifdef __IPHONE_8_0
        UIUserNotificationCategory* category = [self registerActions];
        NSMutableSet* categories = [NSMutableSet set];
        [categories addObject:category];
        UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:categories];
        [[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    #else
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    #endif
    

    When an action has been selected in the interactive push notification, the callback application:handleActionWithIdentifier:forRemoteNotification:completionHandler: is called. To implement your action you need to check on which action was chosen:
    - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler {
        if([identifier isEqualToString: @"Accept"]) {
          ...
          ...
        }
        completionHandler();
    }
    
    You only left to implement the acceptLead logic within the if. If you want to see the full source code go to github.

    Enjoy !

    Friday, July 18, 2014

    Can I skip Optionals?

    TL;TR: NO!
    Working with Swift but using Cocoa/CocoaTouch API, you will have to get a good grasp on what they are and how to use them. When an Objective-C API returns nil, Swift will receive an Optional set to the value NONE.

    Quick definition

    A definition by example:
    var optionalString: String?
    optionalString == nil
    // Non optional values needs to be initialised before using them. 
    var string: String = "Test String"
    string == "Test String"
    
    Optionals is an enum to say "I have something" or "it's empty". You can picture it as a box which can be empty or contain something. It's just a box, to know what's inside you need to unwrap it. When defining an optional type, use ?, when unwrapping it, use !. Note that ? and ! are short name for Optional and ImplicitlyUnwrappedOptional.

    To unwrap or not to unwrap?

    When do we want to unwrap them? Work with them as much as you can in their Optional form, unwrap them when you need to work with their value.
    // An optional is sth or nothing, you can not compute operation with optional
    // you need to unwrap them
    var i: Int?
    var j: Int?
    //var k = i + j     // compilation issue
    //var k = i! + j!   // no compilation issue but runtime issue if i/j not initialised
    
    But the confusion is that most of the time, operating on optionals required unwrapping... except for println and string interpolation. the exception to confirm the rule, would say linguist ;)
     
    var kitty: String? = "Kitty"
    var greeting = "Hello \(kitty)"     // No compiler error!
    print("Hello"); println(kitty)      // Also fine.
    var nope = "Hello " + kitty         // Compiler error
    


    Different ways of unwrapping

    Several way of unwrapping:
    • either go the brute way, unwrap without checking and risk a runtime error
    • or check before with if statement, you can even use the if let or if var statement
    • or go with optional chaining with elvis operator ?. (turn your head left to see Elvis, remind me Groovy syntax here)
    // 1. force unwrapped
    var optionalValue: String?
    // optionalValue! // no compilation issue but runtime issue because optionaValue is nil
    
    // 2. if let: unwrap with
    var optionalName: String?
    var hello = "Hello!"
    if let name = optionalName {
        hello = "Hello, \(name)" // not executed
    }
    optionalName = "John Appleseed"
    hello = "Hello, \(optionalName)"
    
    if let name = optionalName {
        hello = "Hello, \(name)" // executed
    }
    
    // Same idea with for
    var jsonResponse: [String:String?] = ["one":"onevalue", "two":nil]
    var str:String?
    for (key, value) in jsonResponse {
        str = "key \(key) value \(value)"
    }
    str // Some "key one value onevalue"
    
    // 3. optional chaining
    // do not unwrap optionals if not needed, work with them 
    if let a = call1() {
        if let b = a.call2 {
            if let c = b.call3 {
                // do sth
            }
       }
    }
    let c = call1()?.call2?.call3
    


    Working with implicitly unwrapped optionals

    Implicitly unwrapped optionals can be nil same than normal optional, but they are automatically unwrapped when used. As per unwrap optional you may run into runtime error.
    func toInt(first:String!) -> Int! {
        return Int(first.toInt()!)
    }
    var myIn:Int = toInt("3")
    // var myIn:Int = toInt("3e") // runtime error
    


    Try it yourself

    Have a go with Optionals Playground format and Happy Swift coding!

    Tuesday, July 15, 2014

    Working with tuple

    Tuples are groups of values combined into a single, compound value. Brand new in Swift, they offer new approach on how to design and code, they particularly play well with functional programming. Very often used as return type of a function. For example, it allows you to return a value combined with an error code. Let's see how to use them with some playground examples:
    // Defining a Tuple using parenthesis around the comma-delimited list of values
    let httpError404 = (404, "Not found")
    let someOtherTuple2:(Double, Bool) = (100, false)
    
    // You can decompose a tuple very easily
    var (varStatusCode, varStatusMessage) = httpError404
    
    // Access tuple values with the dot operator followed by their index
    httpError404.0
    httpError404.1
    
    // Alternatively, you can name the elements of a Tuple
    let namedTuple = (statusCode: 404, message: "Not found")
    namedTuple.statusCode == namedTuple.0
    namedTuple.message == namedTuple.1
    
    I was surprised with Beta3 there are some lacking support for tuple an array/dictionary. In [1] like we define myArray, I'd expect the definition plus instantiation with tuple to work. In [2], not being to append a tuple.
    var myArray = [String]()
    // [1] Error in playground: invalid use of () to call a value of non-function type
    var array1 = [(String, String)]()
    
    var array1: [(String, String)] = []
    array1 +=  ("1", "2")
    array1
    
    var array2:[(String, String)] = []
    var tuple = ("fddfd", "fdfdf")
    // [2] Error in playgroungd: Missing argument #2 in call
    array2.append(tuple)
    array2 += tuple
    array2
    
    // Correct in playgroung
    var array3:[String] = []
    array3.append("ddd")
    
    Another good usage of tuple is with switch statement. You may need to differentiate switch cases depending on 2 criteria. Like in this sample code where the image name dependant on atmospheric measurement plus daylight factor. Tuple can also be used to enumerate through a dictionary
    var dict = ["onekey":"onevalue", "twokey":"twovalue"]
    
    for (key, value) in dict {
        dict[key] = "assign-me-sth"
        println("\(key):\(value)")
    }
    dict
    


    Let's keep an eye on tuple and array.
    Try it yourself on Playground format and Happy Swift coding!

    Thursday, July 10, 2014

    Markdown plays well with Playground

    Last blog post, I've told you about great learning resources with playgrounds. Searching github, you can have several example already available. I suggest you to build your own. Your playground will be your toolbox. Get inspired, create you own code snippets and ... share it!

    I started Swift with the Swift guided tour. I was impressed you could read and try code snippet at the same time with Xcode. Excellent idea! Googling around, I bumped into this nice project swift-playground-builder which takes markdown document and generate a playground. How does it do it? simple Playground is a folder with xml files... But it looks like magic, you can create your doc à la "guided tour".