Yeoman

A new project with PhoneGap and AngularJS

This is part of a series posts relating to PhoneGap. PhoneGap is an open source framework for quickly building cross-platform mobile applications using HTML5 and Javascript, allowing you to make use of the many open licensed Javascript libraries available on the internet. You also get the benefits of the native features on the targeted device and the simplicity and quick development cycle of a web page. You can write the application once and deploy it to multiple targets with ease.

What is AngularJS?

AngularJS is an open source javascript framework maintained by Google. It allows you to develop static web application using a MVC software architectural pattern. It’s a perfect companion framework for building powerful PhoneGap applications quickly while maintaining organized and reusable code.

AngularJS is perfect for a PhoneGap application where the device might not always be online. In today’s article I will be demonstrating how to setup and build a new AngularJS / PhoneGap project.

Creating a new AngularJS / PhoneGap Project

We will be using Yeoman for generating our project. Yeoman provides a generator ecosystem – a plugin that when run with the `yo` command will scaffold complete projects to create a robust workflow. Read more about Yeoman.

First make sure you have the required software installed: PhoneGap, npm, Ruby, and Compass.

Install the required npm modules.

npm –g install grunt grunt-cli bower yo generator-karma generator-angular 

Use PhoneGap to create a new project and then create a new AngularJS project using Yeoman inside the same folder.

phonegap create new-project
cd new-project
yo angular "New Project"

PhoneGap expects your application to live in the www folder while AngularJS expects the application to live in the app folder. It is easier to change grunt’s application folder than it is to change PhoneGap. In Gruntfile.js, add the following variable to your appConfig declaration.

  // Configurable paths for the application
  var appConfig = {
    app: require('./bower.json').appPath || 'app',
    dist: 'dist',
    phonegap: 'www'
  };

Add a new clean task for PhoneGap:

    // Empties folders to start fresh
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '.tmp',
            '<%= yeoman.dist %>/{,*/}*',
            '!<%= yeoman.dist %>/.git{,*/}*'
          ]
        }]
      },
      phonegap: ['<%= yeoman.phonegap %>/*', '!<%= yeoman.phonegap %>/config.xml', '!<%= yeoman.phonegap %>/res'],
      server: '.tmp'
    },

This will clean all of the files in the PhoneGap folder but will leave the res folder with the project’s icons and splash screen images. Now modify the copy task:

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          dest: '<%= yeoman.dist %>',
          src: [
            '*.{ico,png,txt}',
            '.htaccess',
            '*.html',
            'views/{,*/}*.html',
            'images/{,*/}*.{webp}',
            'styles/fonts/{,*/}*.*'
          ]
        }, {
          expand: true,
          cwd: '.tmp/images',
          dest: '<%= yeoman.dist %>/images',
          src: ['generated/*']
        }, {
          expand: true,
          cwd: '.',
          src: 'bower_components/bootstrap-sass-official/assets/fonts/bootstrap/*',
          dest: '<%= yeoman.dist %>'
        }]
      },
      phonegap: {
        expand: true,
        cwd: '<%= yeoman.dist %>',
        dest: '<%= yeoman.phonegap %>',
        src: '**'
      },
      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },

Modify the build task. We will be configuring this task in the style of ‘grunt build:target’ so that you can just run ‘grunt build:phonegap’ to build for PhoneGap.

grunt.registerTask('build', 'build task', function(target) {
      target = target || 'dev';
      if (target === 'phonegap') {
          
          grunt.task.run([
            'clean:phonegap',
            'clean:dist',
            'wiredep',
            'useminPrepare',
            'concurrent:dist',
            'autoprefixer',
            'concat',
            'ngAnnotate',
            'copy:dist',
            'preprocess:phonegap',
            'cdnify',
            'cssmin',
            'uglify',
            'filerev',
            'usemin',
            'htmlmin',
            'copy:phonegap'
          ]);
      } else {
          grunt.task.run([
            'clean:dist',
            'wiredep',
            'useminPrepare',
            'concurrent:dist',
            'autoprefixer',
            'concat',
            'ngAnnotate',
            'copy:dist',
            'preprocess:dist,
            'cdnify',
            'cssmin',
            'uglify',
            'filerev',
            'usemin',
            'htmlmin'
          ]);
      }
  });

Now we can build a web version (grunt build) or a PhoneGap version (grunt build:phonegap) from the command line.

In order for your application to make use of the device’s mobile features we will need to include PhoneGap’s cordova.js file and not bootstrap AngularJS until after the device is ready.

We will use grunt-preprocess to provide different a conditional index.html depending on if your project is built for web or for PhoneGap.

Add the following to Gruntfile.js.

    preprocess: {
        options: {
            context: {
            }
        },
        dist: {
            src: '<%= yeoman.app %>/index.html',
            dest: '<%= yeoman.dist %>/index.html'
        },
        phonegap: {
            options: {
                context: {
                    phonegap: true
                }
            },
            src: '<%= yeoman.app %>/index.html',
            dest: '<%= yeoman.dist %>/index.html'
        }
    },

In index.html, we will need to remove the ng-app directive so that we can control when AngularJS will bootstrap. In the <head> section we will load cordova.js for PhoneGap. The ng-app directly have been removed from the <body> tag and javascript has been added above the </body> closing tag that will wait for PhoneGap to report the device as ready before bootstrapping.

Make the following changes to index.html.

<!doctype html>
<html class="no-js">
  <head>
    <meta charset="utf-8">
    <title></title>
    <meta name="description" content="">
    
    <!-- @ifdef phonegap -->
    <script type="text/javascript" src="cordova.js"></script>
    <meta name="format-detection" content="telephone=no" />
    <meta name="msapplication-tap-highlight" content="no" />
    <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
    <!-- @endif -->
    <!-- @ifndef phonegap -->
    <meta name="viewport" content="width=device-width">
    <!-- @endif -->
    
    <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
    <!-- build:css(.) styles/vendor.css -->
    <!-- bower:css -->
    <!-- endbower -->
    <!-- endbuild -->
    <!-- build:css(.tmp) styles/main.css -->
    <link rel="stylesheet" href="styles/main.css">
    <!-- endbuild -->
  </head>
  <body>
    <!--[if lt IE 7]>
      <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
    <![endif]-->

    <!-- Add your site or application content here -->
    <div class="header">
      <div class="navbar navbar-default" role="navigation">
        <div class="container">
          <div class="navbar-header">

            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#js-navbar-collapse">
              <span class="sr-only">Toggle navigation</span>
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
            </button>

            <a class="navbar-brand" href="#/">newProject</a>
          </div>

          <div class="collapse navbar-collapse" id="js-navbar-collapse">

            <ul class="nav navbar-nav">
              <li class="active"><a href="#/">Home</a></li>
              <li><a ng-href="#/about">About</a></li>
              <li><a ng-href="#/">Contact</a></li>
            </ul>
          </div>
        </div>
      </div>
    </div>

    <div class="container">
    <div ng-view=""></div>
    </div>

    <div class="footer">
      <div class="container">
        <p><span class="glyphicon glyphicon-heart"></span> from the Yeoman team</p>
      </div>
    </div>


    <!-- Google Analytics: change UA-XXXXX-X to be your site's ID -->
     <script>
       !function(A,n,g,u,l,a,r){A.GoogleAnalyticsObject=l,A[l]=A[l]||function(){
       (A[l].q=A[l].q||[]).push(arguments)},A[l].l=+new Date,a=n.createElement(g),
       r=n.getElementsByTagName(g)[0],a.src=u,r.parentNode.insertBefore(a,r)
       }(window,document,'script','//www.google-analytics.com/analytics.js','ga');

       ga('create', 'UA-XXXXX-X');
       ga('send', 'pageview');
    </script>

    <!-- build:js(.) scripts/vendor.js -->
    <!-- bower:js -->
    <script src="bower_components/jquery/dist/jquery.js"></script>
    <script src="bower_components/angular/angular.js"></script>
    <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap.js"></script>
    <script src="bower_components/angular-animate/angular-animate.js"></script>
    <script src="bower_components/angular-cookies/angular-cookies.js"></script>
    <script src="bower_components/angular-resource/angular-resource.js"></script>
    <script src="bower_components/angular-route/angular-route.js"></script>
    <script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
    <script src="bower_components/angular-touch/angular-touch.js"></script>
    <!-- endbower -->
    <!-- endbuild -->

        <!-- build:js({.tmp,app}) scripts/scripts.js -->
        <script src="scripts/app.js"></script>
        <script src="scripts/controllers/main.js"></script>
        <script src="scripts/controllers/about.js"></script>
        <!-- endbuild -->
        
    <script>


    window.isPhoneGap = function() {
            return (document.URL.indexOf( 'http://' ) === -1 && document.URL.indexOf( 'https://' ) === -1) || document.location.port == 3000;
        };

        // This is a function that bootstraps AngularJS, which is called from later code
        function bootstrapAngular() {
            console.log("Bootstrapping AngularJS");
            // This assumes your app is named "app" and is on the body tag: <body ng-app="app">
            // Change the selector from "body" to whatever you need
            var domElement = document.querySelector('html');
            // Change the application name from "app" if needed
            angular.bootstrap(domElement, ['newProjectApp']);
        }

        // This method of user agent detection also works, though it means you might have to maintain this UA list
        if (window.isPhoneGap()) {
            console.log("UA: Running in Cordova/PhoneGap");
            document.addEventListener('deviceready', bootstrapAngular, false);
        } else {
            console.log("UA: Running in browser");
            jQuery(function($){
                bootstrapAngular();
            });

        }
    </script>
        
</body>
</html>

Using this workflow you can create and test your AngularJS application using your browser by running:

grunt serve

You can test your AngularJS/PhoneGap app by running:

grunt build:phonegap
phonegap build android
If everything worked as expected your device should show the Yeoman scaffold boilerplate.

PhoneGap AngularJS scaffold

Hutz Media Logo

Bryan Wiebe is a web developer and mobile developer located in the Okanagan, British Columbia. He works for Hutz Media Ltd. This post is an entry in a blog series covering development with PhoneGap.

PhoneGap

PhoneGap Developer App

In our previous post I demonstrated how to install PhoneGap, create your first project, and compile and run it on an Android device. Continuing a series of PhoneGap posts, I’m going to demonstrate the most useful PhoneGap tool at your disposal; the PhoneGap Developer App.

What is the PhoneGap Developer App?

PhoneGap Developer App allows you to develop locally and then see the changes on your mobile device instantly. There is no need to re-sign, re-compile, and reinstall your app on a mobile device just to test your code. It even provides access to the device APIs that you can’t test in a web browser.

Downloading the mobile app

The PhoneGap Developer App is available on Android, iOS, and Windows Phone. Download the app to your mobile devices to get started.

The Android version is available in the Google Play Store. It requires Android 4.1+.

The iOS version is available in the App Store. It requires iOS 6.0 or later.

The Windows Phone version is available in the Windows Phone Store. It requires Windows Phone 8.0 or later.

Connect the app with your desktop

Open up a command prompt or shell and change directories to your PhoneGap application and type “phonegap serve”. Take note of the IP address that the server is listening on.

> cd hello-world-app
> phonegap serve
[phonegap] starting app server...
[phonegap] listening on 192.168.1.199:3000
[phonegap]
[phonegap] ctrl-c to stop the server
[phonegap]

Open the PhoneGap developer app on your mobile device. Enter in the IP address the server is listening on and press “Connect”. In this example, 192.168.1.199:3000.

Connect with developer app

The server will wait for any IO changes on your project directory and will automatically send a refresh to the mobile device. Open up your project index.html and make some changes.

<div id="deviceready" class="blink">
    <p class="event listening">Connecting to Device</p>
    <p class="event received">This line will change when saved.</p>
</div>

Automatically updated

Hutz Media LogoBryan Wiebe is a web developer and mobile developer located in the Okanagan, British Columbia. He works for Hutz Media Ltd. This post is an entry in a blog series covering development with PhoneGap.
PhoneGap

Setting up Phone Gap

PhoneGap is an open source framework for quickly building cross-platform mobile applications using HTML5 and Javascript, allowing you to make use of the many open licensed Javascript libraries available on the internet. You also get the benefits of the native features on the targeted device and the simplicity and quick development cycle of a web page. You can write the application once and deploy it to multiple targets with ease.

In this post I will show you how to setup and configure a simple “hello world” PhoneGap application and test it on an android device. If you want to test it on an iOS device you will need to run these commands from a MacOS X computer.

Getting Started

If you haven’t done so already, download NodeJS at http://nodejs.org/. NodeJS includes npm, a package manager for Javascript that allows you to download and install phonegap from the command line.

You will also need to have Apache Ant and Android SDK installed and properly configured with the correct environment path variables.

After you have installed NodeJS run the following command line:

npm install –g phonegap

Now run the following command line to create a new phonegap project:

phonegap create hello-world-app
cd hello-world-app

Making Some Changes

Let’s make some changes. Open up the HTML file located at: ./hello-world-app/www/index.html.

<div id="deviceready" class="blink">
<p class="event listening">Connecting to Device</p>
<p class="event received">Device is Ready</p>
</div>

Change the HTML to:

<div id="deviceready" class="blink">
    <p class="event listening">Connecting to Device</p>
    <p class="event received">Hello World</p>
</div>

Compile and Deploy to Device

You’re project is now ready to compile and deploy to your test device. PhoneGap does all the work for you so you just need to run a few commands.

If you are working on a Windows or Linux machine you probably use an Android device for testing applications. If you are testing on a MacOS with an iOS device just change “android” to “ios”.

Connect your android device to your computer making sure that it’s in development mode. In your command prompt, run the following command:

phonegap run android

The project will now be compiled and deployed. If you run into problems just run the command with the –d flag (phonegap run android –d) and check the output.

PhoneGap deployed

Hutz Media LogoBryan Wiebe is a web developer and mobile developer located in the Okanagan, British Columbia. He works for Hutz Media Ltd. This post is an entry in a blog series covering development with PhoneGap.

App Store 64-bit required

As of February 1, 2015, Apple requires that all apps submitted to the App Store need to be built with the iOS 8 software development kit and include 64-bit support. Furthermore, on June 1, 2015, all app updates submitted to the App Store will need to be built in the same way.

17-64bit_required

The spirit of this change is to force developers to release apps that take advantage of 64-bit support and are iOS 8 compliant. Apple is hoping that this will improve the app performance and experience of their new iOS 8 compliant devices.

This has created a headache for developers who have applications that were built using 32-bit libraries many years before there was even a 64-bit iPhone. It might mean the end of updates for some projects because their linked libraries no longer work and the cost of upgrading won’t bring enough ROI.

In my opinion, this change is unnecessary and is just another way for Apple to make their older devices obsolete much faster. Why do you really need to buy the next new iPhone when the performance differences between each version is marginal or exactly the same.