Mobile Zone is brought to you in partnership with:

Matt Raible has been building web applications for most of his adult life. He started tinkering with the web before Netscape 1.0 was even released. For the last 16 years, Matt has helped companies adopt open source technologies (Spring, Hibernate, Apache, Struts, Tapestry, Grails) and use them effectively. Matt has been a speaker at many conferences worldwide, including Devoxx, Jfokus, ÜberConf, No Fluff Just Stuff, and a host of others. Matt is a DZone MVB and is not an employee of DZone and has posted 144 posts at DZone. You can read more from them at their website. View Full User Profile

Developing an iOS Native App with Ionic

04.07.2014
| 5258 views |
  • submit to reddit

Screenshots

After making all these changes, the app looks pretty good in Chrome.

Tips and Tricks

In additional to figuring out how to use Ionic, I discovered a few other tidbits along the way. First of all, we had a different default color for the header. Since Ionic uses generic color names (e.g. light, stable, positive, calm), I found it easy to change the default value for "positive" and then continue to use their class names.

Modifying CSS variable colors
To modify the base color for "positive", I cloned the source, and modified scss/_variables.scss.

$light: #fff !default;
$stable: #f8f8f8 !default;
-$positive: #4a87ee !default;
+$positive: #589199 !default;
$calm: #43cee6 !default;
$balanced: #66cc33 !default;
$energized: #f0b840 !default;

After making this change, I ran "grunt" and copied dist/css/ionic.css into our project.

iOS Native Integration
Our app uses a similar token-based authentication mechanism as x-auth-security, except its backed by Crowd. However, since users won't be logging directly into the Ionic app, we added the "else" clause in app.js to allow a token to be passed in via URL. We also allowed the backend API path to be overridden.

/* Try getting valid user from cookie or go to login page */
var originalPath = $location.path();
$location.path("/login");
var user = $cookieStore.get('user');
 
if (user !== undefined) {
    $rootScope.user = user;
    $http.defaults.headers.common[xAuthTokenHeaderName] = user.token;
    $location.path(originalPath);
} else {
    // token passed in from native app
    var authToken = $location.search().token;
    if (authToken) {
        $http.defaults.headers.common['X-Auth-Token'] = authToken;
    }
}
 
// allow overriding the base API path
$rootScope.apiPath = '/api/v1.0';
if ($location.search().apiPath) {
    $rootScope.apiPath = $location.search().apiPath;
}

By adding this logic, the iOS app can pull up any particular page in a webview and let the Ionic app talk to the API. Here's what the Objective-C code looks like:

NSString *versionNumber = @"v1.0";
NSString *apiPath = @"https://server.com/api/";
NSString *authToken = [TemporaryDataStore sharedInstance].authToken;
// webapp is a symbolic link to the Ionic app, created with Angular Seed
NSString *htmlFilePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:@"webapp/app"];
 
// Note: We need to do it this way because 'fileURLWithPath:' would encode the '#' to '%23" which breaks the html page
NSURL *htmlFileURL = [NSURL fileURLWithPath:htmlFilePath];
 
NSString *webappURLPath = [NSString stringWithFormat:@"%@#/news?apiPath=%@%@&token=%@",
                           htmlFileURL.absoluteString, apiPath, versionNumber, authToken];
 
// Now convert the string to a URL (doesn't seem to encode the '#' this way)
NSURL *webappURL = [NSURL URLWithString:webappURLPath];
[super updateWithURL:webappURL];

We also had to write some logic to navigate back to the native app. We used a custom URL scheme to do this, and the Ionic app simply called it. To override the default back button, I added an "ng-controller" attribute to <ion-nav-bar> and added a custom back button.

<ion-nav-bar class="bar-positive nav-title-slide-ios7" ng-controller="NavController">
    <ion-nav-back-button class="button-icon" ng-click="goBack()">
        <i class="ion-arrow-left-c"></i>
    </ion-nav-back-button>
</ion-nav-bar>

To detect if the app was loaded by iOS (vs. a browser, which we tested in), we used the following logic:

// set native app indicator
if (document.location.toString().indexOf('appName.app') > -1) {
    $rootScope.isNative = true;
}

Our Ionic app has three entry points, defined by "stateName1", "stateName2" and "stateName3" in this example. The code for our NavController handles navigating back normally (when in a browser) or back to the native app. The "appName" reference below is a 3-letter acronym we used for our app.

.controller('NavController', function($scope, $ionicNavBarDelegate, $state) {
    $scope.goBack = function() {
        if ($scope.isNative && backToNative($state)) {
            location.href='appName-ios://back';
        } else {
            $ionicNavBarDelegate.back();
        }
    };
 
    function backToNative($state) {
        var entryPoints = ['stateName1', 'stateName2', 'stateName3'];
        return entryPoints.some(function (entry) {
            return $state.current === $state.get(entry);
        });
    }
})

Summary

I've enjoyed working with Ionic over the last month. The biggest change I've had to make to our AngularJS app has been to integrate ui-router. Apart from this, the JavaScript didn't change much. However, the HTML had to change quite a bit. As far as CSS is concerned, I found myself tweaking things to fit our designs, but less so than I did with Bootstrap. When I've run into issues with Ionic, the community has been very helpful on their forum. It's the first forum I've used that's powered by Discourse, and I dig it.

You can find the source from this article in my boot-ionic project. Clone it and run "mvn spring-boot:run", then open http://localhost:8080.

If you're looking to create a native app using HTML5 technologies, I highly recommend you take a look at Ionic. We're glad we did. Angular 2.0 will target mobile apps and Ionic is already making them look pretty damn good.

Published at DZone with permission of Matt Raible, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)