Monday, January 19, 2015

Using Ionic with Windows 8, Windows Phone + Cordova

Ionic has been gaining in popularity as a free and open source mobile development framework. It leverages AngularJS and SASS to provide a quick start to mobile development for iOS, Android and Windows.

But getting Ionic to work when targeting Windows 8 or Windows Phone apps with CTP3 of Visual Studio Tools for Apache Cordova isn't quite straightforward due to some security context restrictions in Windows 8 apps.

So here is a walk through for getting started with Ionic in VSCordova, along with the "gotchas" for Windows apps:
  1. First note that these steps are for CTP3 of VSCordova! Future releases will likely fix some of the issues presented here.
  2. Create a new Blank App (Apache Cordova) project:

  3. Install Ionic. Here we will use Nuget, but in the future you will likely be able to use Bower for JS packages.
    • Select Tools / NuGet Package Manager / Package Manager Console
    • type in:

      Install-Package ionic
    • be patient, this takes a bit

  4. Install JQuery 2. This is required because it fixes some security context restrictions in Win8 apps.
    • From the NuGet prompt, type in:

      Install-Package jQuery
  5. Let's replace the contents of index.html with a basic ionic template and the required includes:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
        <title>Ionic VSCordova</title>
        <link href="Content/ionic.css" rel="stylesheet" />
        <link href="css/index.css" rel="stylesheet" />
        <script src="cordova.js"></script>
        <script src="scripts/platformOverrides.js"></script>
        <script src="scripts/jquery-2.1.3.js"></script>
        <script src="scripts/ionic.bundle.js"></script> 
        <script src="scripts/index.js"></script>
    </head>
    <body ng-app="ionicApp" ng-csp>

        <ion-nav-bar class="bar-positive">
            <ion-nav-back-button class="button-icon ion-arrow-left-c">
            </ion-nav-back-button>
        </ion-nav-bar>

        <ion-nav-view></ion-nav-view>

        <script id="templates/tabs.html" type="text/ng-template">
            <ion-tabs class="tabs-icon-top tabs-positive">

                <ion-tab title="Home" icon="ion-home" href="#/tab/home">
                    <ion-nav-view name="home-tab"></ion-nav-view>
                </ion-tab>

                <ion-tab title="About" icon="ion-ios7-information" href="#/tab/about">
                    <ion-nav-view name="about-tab"></ion-nav-view>
                </ion-tab>

                <ion-tab title="Contact" icon="ion-ios7-world" ui-sref="tabs.contact">
                    <ion-nav-view name="contact-tab"></ion-nav-view>
                </ion-tab>

            </ion-tabs>
        </script>

    </body>

    </html>

  6. Now let's add in our Angular code to initialize our controller and set up our views. Open index.js and paste the following code right after the:

    "use strict";

     
       var app = angular.module('ionicApp', ['ionic'])

        app.config(function ($stateProvider, $urlRouterProvider) {

            $stateProvider
              .state('tabs', {
                  url: "/tab",
                  abstract: true,
                  templateUrl: "templates/tabs.html"
              })
              .state('tabs.home', {
                  url: "/home",
                  views: {
                      'home-tab': {
                          templateUrl: "partials/home.html",
                          controller: 'HomeTabCtrl'
                      }
                  }
              })
              .state('tabs.personnel', {
                  url: "/personnel",
                  views: {
                      'home-tab': {
                          templateUrl: "partials/personnel.html",
                          controller: 'PersonnelTabCtrl'
                      }
                  }
              })
              .state('tabs.about', {
                  url: "/about",
                  views: {
                      'about-tab': {
                          templateUrl: "partials/about.html"
                      }
                  }
              })
              .state('tabs.contact', {
                  url: "/contact",
                  views: {
                      'contact-tab': {
                          templateUrl: "partials/contact.html"
                      }
                  }
              });

            $urlRouterProvider.otherwise("/tab/home");

        })

        app.controller('HomeTabCtrl', function ($scope) {
            console.log('HomeTabCtrl');
        });

        app.controller('PersonnelTabCtrl', function ($scope) {
            $scope.items = [
                { id: 1, name: "Kirk, James T." },
                { id: 2, name: "McCoy, Leonard" },
                { id: 3, name: "Scott, Montgomery" },
                { id: 4, name: "Uhura, Nyota" },
                { id: 5, name: "Sulu, Hikaru" },
                { id: 6, name: "Chekov, Pavel" },
                { id: 7, name: "Chapel, Christine" },
                { id: 8, name: "Rand, Janice" }
            ];
        });



  7. The code above references four partials: about, contact, home, and personnel. Let's go ahead and create those. Create a new subfolder in the project named "partials" and add the following files:

    about.html
    contact.html
    home.html
    personnel.html


    Inside each of the four partials above, create an ionic view and add some content inside (it doesn't matter what, be creative)... and set the view-title to an appropriate string to display in the header.

  8. <
    ion-view view-title="About">
        <ion-content class="padding">
            <p>ABOUT: this is just a little demo of Ionic working in VSCordova!</p>
        </ion-content>
    </ion-view>
  9. For home.html, let's add a View that links to personnel.

  10. <
    ion-view view-title="Home">
        <ion-content class="padding">
             <a class="button icon icon-right ion-chevron-right" href="#/tab/personnel">Personnel List</a>
        </ion-content>
    </ion-view>
  11. For the personnel.html, let's show an ionic list:

  12. <
    ion-view view-title="Personnel">
        <ion-content class="padding">
            <p>This ion list directive is great, but be sure to also checkout the collection repeat directive when scrolling through large lists.</p>
            <ion-list>
                <ion-item ng-repeat="item in items"
                          item="item">
                    {{ item.id }}: {{ item.name }}
                </ion-item>
            </ion-list>
            <p>
                <a class="button icon ion-home" href="#/tab/home"> Home </a>
            </p>
        </ion-content>
    </ion-view>

  13. Run the project using the Windows or Windows Phone Emulator, and you'll get an ugly blank screen! If you look at the JavaScript Console in Visual Studio, you will see:

    Error: [$compile:tplrt] Template for directive 'ionTabNav' must have exactly one root element. 

    This error in CTP3 is due to an issue in winstore-jscompat.js, which is used by the Cordova tooling to wrap security context issues in Win8 Store apps. To fix this problem, open the following file in the project:

    \merges\windows\scripts\winstore-jscompat.js

    ... and replace it with the fork provided here:

    https://github.com/ClemMakesApps/winstore-jscompat/blob/master/winstore-jscompat.js
  14. Run the project again, and you should be good to go! Here is a screenshot of Ionic running in a Windows Phone 8 Emulator...



Sunday, January 18, 2015

Visual Studio Cordova "The certificate specified has expired"

If you have been using a recent CTP of Visual Studio Tools for Apache Cordova to target Windows 8 apps, you may have recently hit this error on build:

Error 104 The certificate specified has expired. For more information about renewing certificates, see http://go.microsoft.com/fwlink/?LinkID=241478.


It turns out that this is an issue with the underlying Cordova support for Windows 8, which contains a recently expired certificate - as explained here. The certifcate expired on 11/11/2014.

UPDATE 1/18/2015: It appears the issue appeared again with another expired certificate. Please see this post for details on how to correct the issue for a single project (option 1) and for all projects (option 2)

The VS Tools for Apache Cordova (CTP3) picks up this certificate file on build from a subfolder in the \Users\ directory, and this is what fixed the issue for me...
  1. For CTP3, go to the following directory:

    c:\users\{yourUsername}\.cordova\lib\npm_cache\cordova-windows\3.6.4\package\template\CordovaApp_TemporaryKey.pfx 

  2. Using Visual Studio, create a new Windows Store "Universal App" - this will provide you with an unexpired key file, which will be located in the \BlankShared.Windows subfolder of the project.

    Make a copy of this file:

    BlankSharedAppX_TemporaryKey.pfx 
    ... and rename it to

    CordovaApp_TemporaryKey.pfx
  3. Backup the following PFX file (just in case) and then copy over the newly created PFX file in its place -

    c:\users\{yourUsername}\.cordova\lib\npm_cache\cordova-windows\3.6.4\package\template\CordovaApp_TemporaryKey.pfx

  4. Back in VS, do a build / Clean and then a Rebuild. 
Anyway, that worked for me. Good luck!

Friday, January 9, 2015

Using a "Mac in the Cloud" for Visual Studio Cordova Dev

So you say you want to do iOS development using Visual Studio Tools for Apache Cordova (currently in CTP3)... but you don't actually own a Mac (like me)?

Well there is at least one option: use a "Mac in the Cloud!"

One service that allows "renting" a Mac in the Cloud is aptly named MacInCloud. And, Microsoft has published a nice walkthrough that can help you in getting started:

        Build and Simulate iOS in the Cloud

However, the initial setup can be a bit daunting due to some security and config issues - so I thought I would share my experiences here.

So here are the general steps - 
  1. Register as an iOS Developer

    I just want to mention this step in case you're totally new to iOS development. If you're not yet an iOS Developer, you will need to register and pay the mothership $99 per year. You can get started here.

  2. Get a MacInCloud account with the Remote Build Feature turned on.

    Since I was just dipping my toes into MacInCloud, I wanted to choose the most cost efficient plan, which ended up being their 
    PayAsYouGo plan, which is $1 per hour with a first time purchase of $30 (which covers your first 30 hours). 

    However, I later found out that this plan does not include the Remote Build Feature, which is required for Visual Studio remote deployment and debugging on a Mac. This feature will cost you an additional $5/month.

    If you choose the cheaper PayAsYouGo plan, you will need to contact MacInCloud support (here) to get the Remote Build Feature turned on for your account. (If you go with any of their higher end plans, then remote build will already be enabled). Before contacting support, read #4 below because you'll also want them to ensure vs-mda-remote is installed!

  3. Try Connecting to your Mac in the Cloud

    The MacInCloud service allows RDP access to your rented server in the cloud. Once your account is set up, you will download a series of RDP Configuration files in varying resolutions like so:



  4. Install the Visual Studio Remote Agent

    The Remote Agent (vs-mda-remote) allows Visual Studio to connect to a remote Mac and deploy, build and debug.

    There is a chance that vs-mda-remote will already be installed globally on your Mac server. To check this, open a Terminal window on your Mac and see if vs-mda-remote exists in the global node_modules directory (/usr/local/lib/node_modules/vs-mda-remote) like so:

    First, go to the global node modules dir and list the contents:

            cd /usr/local/lib/node_modules
            ls -l


    ... and if you see a directory named:

            vs-mda-remote

    ... then the VS Remote Agent is already installed on your Mac.

    If vs-mda-remote is NOT found in the global node modules, you can follow the instructions provided in this document: Build and Simulate iOS in the Cloud - HOWEVER, if you went with the PayAsYouGo plan, you will likely hit security issues with Homebrew and Node (which are used to install vs-mda-remote).  So again, it's back to MacInCloud support to help with installing vs-mda-remote.

  5. Do the iOS Developer Dance

    *Sigh* it is a twisted, awkward dance to begin Mac development. In order to allow your Mac In Cloud to develop iOS apps, you need to generate a certificate signing request, and then download the Cert and Provisioning Files from your Mac developer account.

    There are countless docs on how to do this, so I won't repeat all of the steps here but here is an "ok" walkthrough: Generating a certificate signing request

    Once you complete the request, you will be able to download the Certificate and Provisioning Profile from the Apple Dev Center.

  6. Setup XCode with your Dev Account Info

    On your remote Mac, you'll need to give XCode your dev account info. Start XCode from the Applications menu, and then from the system menu for XCode, select Preferences... and then go to the Accounts Tab and enter your apple dev account info:



  7. Start the Remote Agent, vs-mda-remote

    If everything is in place, then we should be able to use Visual Studio on our local machine to deploy and debug on the remote Mac in the cloud!

    Make a note of your Mac's IP Address, which you can get from the terminal window by looking at your shell's prompt (if you don't see it then just type in 
    ifconfig | grep "inet " )

    Next, on the Mac in the cloud, start the vs-mda-remote build agent:

    vs-mda-remote --secure false

    * IMPORTANT! by using secure==false, we are skipping the optional security feature of the server, which forces a Security PIN that changes every 10 minutes. If you are planning on keeping the remote agent running unmonitored for an extended period of time, then you should not do this!

    You should see something like so:

    Copyright (C) 2014 Microsoft Corporation. All rights reserved.
    0.2.5
    Loading resources for language en from /usr/local/lib/node_modules/vs-mda-remote/resources/en/resources.json
    Build Retention initialized with baseBuildDir /Users/userXXXXX/remote-builds/builds, maxBuildsToKeep 20
    Initialized BuildManager with installedCordovaVersion: 4.0.0; baseBuildDir /Users/userXXXX/remote-builds/builds; maxBuildsInQueue 10; deleteBuildsOnShutdown true; allowsEmulate true; nextBuildNumber XXXX
    Remote build Express server listening on [http] port 3000
    ios-sim is installed on path at: /usr/local/lib/node_modules/vs-mda-remote/node_modules/ios-sim/build/release/ios-sim

  8. Deploy and Debug from Visual Studio
    Back on your PC, open up Visual Studio and create or open an existing Apache Cordova App.

    Go to: Tools / Options / Tools for Apache Cordova / Remote Agent Configuration

            Set Enable remote iOS processing to True        Set Host to the IP address of your Mac in the cloud (found in previous step)
            For Security PIN, you can skip this if you started vs-mda-remote with secure false.

    From the Configuration Dropdowns, select Debug / iOS/ and then choose your favorite Simulator



    Now, debug by pressing F5. If there are any errors, you will see them in the VS Output Window (the server side vs-mda-remote has only limited error messaging).

  9. Setting Breakpoints

    I am amazed that setting breakpoints and debugging even works at all given all of the moving pieces here... But yes, there is some flakiness with debugging from VS to vs-mda-remote.

    If you see your breakpoint is not getting hit, first check the VS Output window and look for issues like "resource not found" - which would prevent your breakpoint from even being reached.

    Also there are also cases where a breakpoint is inside some initialization code, and was hit before vs-mda-remote was bootstrapped up. In these cases, you can go to the JavaScript Console inside Visual Studio (visible when debugging) and type in:

    window.location.reload()

Monday, November 24, 2014

Visual Studio Cordova: Black Screen/No Launch

If you are using the Visual Studio Tools for Apache Cordova and your app doesn't launch when debugging, take a look at the Output Windows in Visual Studio for some clues.

Recently I hit a case where the Output Window contained:

              CordovaWebView: TIMEOUT ERROR!

Which means that the app couldn't launch (and the debugger attach) within the allotted time.

You can increase the default launch time by adding an option to config.xml. However, since this option isn't yet supported in the VS Editor for config.xml, you need to edit the XML manually:

  • right-click config.xml and select "Open With..." and then "XML (Text) Editor"
  • below all of the existing <preference> nodes, add the following:

    <preference name="loadUrlTimeoutValue" value="120000" />
...which will increase the load time to 2 minutes. 


Friday, April 25, 2014

Physics Helper for Universal Windows apps

An update to the Physics Helper XAML project is now available with support for Universal Windows apps. There are several advantages to Universal apps:
  • simplified code (no more #if compiler directives)
  • increased re-use of both game assets and game logic
  • support both Windows 8.1 and Windows Phone 8.1, and eventually the XBOX One
  • if your assets use XAML vector graphics, they will be scaled to each screen size without any pixilation or loss of detail
Please watch this short video for details on the new Universal apps support:


Wednesday, March 26, 2014

babylon.js: physics and character animation


In this post we’ll see how we can create physics-enabled environments mixed with character animation for gaming using babylon.js and WebGL.
Kick around some boxes and beach balls in the demo

In previous posts, I showed how we can use babylon.js to create 3D Maps using Bing and share 3D Scans from Kinect. But the heart of babylon.js is all about games, and here we’ll talk about aspects of interactive, physics-based 3D games using the framework.

Skeletal Animation

Skeletal animation is used to animate meshes based on bones – such as the walking character animation shown here. Babylon.js supports skeletal animation, and will accept animations exported from Blender. When creating the animation for this demo, I needed separate animations for walking, kicking, jumping and standing. What I chose to do was just append all of these separate animations into a single group of 90 frames, which you can see in the image here.

To control this animation in babylon.js, we can pass in the start frame and end frame we wish to play back:

scene.beginAnimation(_skeletonRegularGuy, 31, 60, true, 1.0);

One important note when exporting animations from Blender: we need to bake the location, rotation and scaling for the animation before export! To do this, select your mesh in Object Mode and then press Ctrl+A and choose Location. Repeat this for Rotation (and Scale if you have any key frames affecting scale).



Keyboard Input

In this demo, I used a simple means of tracking which keys were down, first by adding standard event handlers:
        // key input
        window.addEventListener("keydown", this.handleKeyDown, false);        window.addEventListener("keyup", this.handleKeyUp, false);
… and then tracking the states of each key in a simple attribute:
this.handleKeyDown = function (evt) {
keyStates[evt.keyCode] = true;
};

To make things a bit easier to track, we can add an enumeration that equates key codes to directions for our character:
var enumDirectionKeys = {
    keyNone: 0,
    keyUp: 87,
    keyLeft: 65,
    keyRight: 68,
    keyDown: 83,
    keyJump: 32
}

Virtual (Touch) Joysticks

If you happen to try the demo on a touch-enabled device, you can use the left side of the screen to control a virtual joystick for movement, and the tapping anywhere on the right side of the screen makes the character kick. This is made possible by using the virtual joystick class from the GameFX library, which is included as babylon.virtualJoystick.js in the babylon source.
We can create an instance of the joystick with:
   joystick = new BABYLON.GameFX.VirtualJoystick(true);
… and then read the delta position of the joystick like so:
   var delta = (joystick.deltaJoystickVector);

Sound

For sound support, I used create.js. It’s pretty straight forward to use the sound library portion of create – first you initialize and add a manifest:
        // sound fx
        createjs.Sound.initializeDefaultPlugins();        var audioPath = "sounds/";
        var manifest = [            { id: "kick", src: "kick.mp3" },            { id: "wood", src: "wood.mp3" },            { id: "ball", src: "ball.mp3" },        ];
 createjs.Sound.registerManifest(manifest, audioPath);
… after which you can play any file by its id:

createjs.Sound.play(
"wood");

Adding Physics

Babylon.js uses Cannon.js to support 3D Physics, and it makes it very easy to do so through imposters. For example, to add physics to our “beach balls,” we can use the SphereImposter in a call to setPhysicsState like so:

ball.setPhysicsState({ impostor: BABYLON.PhysicsEngine.SphereImpostor, mass: 0.05, friction: 0.5, restitution: 0.9 });
However, there are some advanced scenarios where a simple imposter will not do – for example, in the picture to the right you see our “dude” physics in the demo. Since we want our dude character to walk around and move/kick the physics objects around him, we need to have a more advanced imposter. In this case, we can join a “wheel sphere” to  a “body box” and then apply impulse to the wheel to move the box around. Additionally, the “kick region” is used to detect collisions with other physics objects when the character performs his kick move.
To accomplish the character physics, three physics imposters are used.

Getting Help and Support

If you choose to use babylon.js for your next project, here are some resources that can get you started.
Babylon.js forums on HTML5 Game Devs – this is an awesome community of like-minded game devs using javascript frameworks such as babylon.
Babylon.js samples and source – if there is one thing babylon provides, it’s a lot of cool samples. Poking around through this code is invaluable in learning the ropes.
Babylon.js Wiki – full of some good tutorials to get started.