Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Sunday, September 29, 2013

How to Add Barcode Scanning to your Web App using Xamarin

Recently I had a client who wanted to add barcode scanning capabilities to their web app. Their web app was already responsive thanks to Bootstrap but there isn't a convenient way to scan a bar code from mobile Safari or Chrome.

This turned out to be fairly trivial thanks to Xamarin and two components in their Component Store:
JsBridge - eases Native to Javascript communication
ZXing.Net.Mobile - handles the barcode scanning

Here are some screenshots of what the web app looks like when accessed via the iOS app:



One of the requirements of the bar code scanning was to not show the Scan button if the user is not using the native app. To do this I customize the UserAgent of the UIWebView and then do UserAgent sniffing on the server side to hide or show the Scan button.

You'll notice if you view the web app in a browser the Scan button is not displayed:
http://xamarinbarcodesample.apphb.com/
To enable this functionality in the iOS app we append a XamarinBarcodeSampleApp string to the default UserAgent of the UIWebView:

Then in the web app we do UserAgent sniffing for this string.

To wire up the Scan button we take advantage of JsBridge. The first thing we do is register the mt.js library. Secondly we listen for the scanComplete event which is triggered on the iOS app side. Thirdly we handle the Scan button click event and let the iOS side know about it by firing the scanBarcode event.

On the iOS side we need to enable JsBridge, then listen for the scanBarcode event. When scanBarcode is fired we display the ZXing.Net.Mobile scanner. If the user successfully scans a barcode we fire the scanComplete event and pass the barcode string as an event parameter.

The native / hybrid iOS app source code can be downloaded here: 
https://github.com/crdeutsch/Xamarin.iOS.BarcodeSample

The web app source code is here:
https://github.com/crdeutsch/Xamarin.Web.BarcodeSample

Final thoughts:

Xamarin tools are flexible enough to handle the requirements of the Web Application developer dipping their toes into native development. 

In fact the Xamarin tools work so nicely with UIWebView based web apps that I'd urge any developer looking at PhoneGap or Titanium to add Xamarin to your review list and avoid the limitations you may run into. 

For instance, I built a series of HTML5 based game for a client that play audio via Flash in a desktop browser. To make them work on an iPad I used Titanium to martial the audio playback to native code. At the time I figured Titanium was the best solution since the bulk of the code was already Javascript. I eventually ran into limitations with Titanium when I wanted to detect custom gestures and realized they don't have a 1 to 1 mapping with the iOS API like Xamarin does. I plan on porting this app to Xamarin in the near future to take advantage of more advanced native iOS functionality.

In a future blog post I will demonstrate how to use JsBridge and another library I wrote to martial audio calls to the native side like I did for those HTML5 games.

DISCLAIMER: I've been work full time for Xamarin for about 3 weeks as a web developer. The following experiences and opinions were developed during my 3 years as a freelance consultant.

Sunday, May 13, 2012

Add support for LESS to Node.js connect-assetmanager package

The connect-assetmanager Node.js package allows you to combine multiple javascript and CSS files into one and also do other manipulations like minification.

It's part of Mathias Pettersson's (mape) excellent node-express-boilerplate template.

If you're also using LESS for CSS here is some code you can add to get connect-assetmanager to process you're LESS files:

var assetsSettings;
assetsSettings = {
  js: {
    route: /\/static\/js\/[a-z0-9]+\/.*\.js/,
    path: "./public/javascripts/",
    dataType: "javascript",
    files: ["libs/underscore-min.js" "libs/jquery.mobile-1.1.0.min.js", siteConf.uri + "/nowjs/now.js", "site.js"],
    debug: siteConf.debug,
    stale: !siteConf.debug
  },
  css: {
    route: /\/static\/css\/[a-z0-9]+\/.*\.css/,
    path: "./public/stylesheets/",
    dataType: "css",
    files: ["libs/jquery.mobile-1.1.0.min.css", "style.less"],
    debug: siteConf.debug,
    stale: !siteConf.debug,
    preManipulate: {
      "^": [
        function(file, path, index, isLast, callback) {
          var match;
          match = path.match(/\.less$/);
          if ((match != null) && match.length > 0) {
            return less.render(file, function(e, css) {
              return callback(css);
            });
          } else {
            return callback(file);
          }
        }
      ]
    }
  }
};

The import part is the preManipulate line under css but I include my entire assetsSettings from a project to make it easier to understand.

Tuesday, May 1, 2012

MonoTouch JsBridge - Communicate with the UIWebView

Today I'm open sourcing JsBridge for MonoTouch which allows for bidirectional communication between the javascript in your UIWebViews and your native C# code in your MonoTouch app. Go directly to GitHub for the documentation on how to use it.

This project was inspired by doing a project using Appcelerator's Titanium. In fact the javascript used in JsBridge was taken directly from that project, so if you're used to using Titanium you should be right at home using JsBridge.

At this time it requires MonoTouch 5.3.3, which as of 5/1/2012 is in Alpha, because JsBridge needs to register a custom url protocol using NSUrlProtocol.

I'm not 100% satisfied with the implementation of the event listeners on the native side, so I'm open to suggestions on how to make it better. Ideally some day the Xamarin team will implement something like this in a future version. ;)

I've already submitted my first app to use it the iOS AppStore and it relies heavily on bidirectional communication between javascript and native. The app is a remote control for Rdio's new UI. A nicely executed feature by Rdio (even if it came way after the chrome extension remote I made for their first UI ;) ), but unfortunately it doesn't work on iOS partially due to the Rdio servers not supporting the Websockets protocol that the UIWebView has. Using JsBridge I was able to implement the WebSocket connection on the native side and override the Rdio javascript calls that use WebSockets and pass them to the native side and vice versa. I'm quite pleased with the results so far. ;)

Wednesday, March 28, 2012

Solved: Video.Js Playback Error in IE9

TL;DR:

Make sure your server (including Amazon CloudFront) is setting the correct mime type when returning the video file.

For .mp4 files the mime type should be video/mp4

ISSUE:

I spent about an hour baffled why IE9 wouldn't play an H.264 video that Chrome and Firefox played fine.

The only lead I had was this message output by Video.js using console.log:

Video Error[object Object] 

What's more annoying is that IE9 doesn't let you inspect objects that are output by console.log. To get around that you can install the Firebug Lite bookmarklet. Unfortunately in this case the object doesn't give you much more to go on.

I tried swapping videos and found it worked with the sample Video.js video, which usually indicates a mime type issue (which seems to be a recurring issue with Microsoft products).

I was using Amazon CloudFront to server the videos (download style as opposed to streaming) and figured I couldn't set the mime type but it turns out you can:
  1. Go into S3 and find your video file.
  2. Right click and select Properties
  3. Select the Metadata tab
  4. In this case, set KeyContent-Type and Value = video/mp4
  5. Press Save button

Thursday, February 9, 2012

setTimeout Setting Mysterious Callback Parameters

I got burned by this twice in the last month.

Say you want to call the following function after 5 seconds.
function doSomething(optionalParam) {
  // check if optional param passed in.
  if (optionalParam) {
    optionalParam.foo(); // this is where the error sometimes happens.
  }
  // do more stuff.
}

// delay 5 seconds.
setTimeout(doSomething, 5000);

Periodically I was getting undefined errors when trying to call foo(). After some googling, it turns out Gecko browsers have setTimeout pass back an extra parameter indicating the "actual lateness" of the timeout in milliseconds.
https://developer.mozilla.org/en/DOM/window.setTimeout

I haven't run into this with other browsers but to avoid the issue it's best to do the following when your callback functions have optional params (Not having optional params would obviously be even safer).
// delay 5 seconds.
setTimeout(function() {
  doSomething();
}, 5000);

Wednesday, September 28, 2011

jQuery Mobile Displaying A Dialog

While working on a mobile web app that is using jQuery Mobile I wanted to display a dialog without making an Ajax call to the server to load it which is the "out of the box" way to do it.

Initially I couldn't figure out how to do this but after some reading and thinking it's ridiculously easy.

You have to use a multi-page template which means you have more then one jQuery Mobile "page" container. Example:
<div data-role="page" data-theme="a">
    <div data-role="header" class="header">
        <a href="#menu" data-icon="grid" data-theme="b" data-iconpos="notext" data-transition="pop">&nbsp;</a>
        <h1>My Web App</h1>
        
    </div>

    <div id="map" data-role="content" data-theme="d">
        <p>This is my main content</p>
    </div>
    
    <div data-role="footer">
        <div>
        by <a href="http://cdeutsch.com" rel="external">CDeutsch</a>
        </div>
    </div>
</div>

<!--start menu-->
<div id="menu" data-role="dialog" data-theme="a" data-url="menu">
    <div data-role="header" class="header">
        <h1>Main Menu</h1>
    </div>
    <div data-role="content" data-theme="d">
        <ul data-role="listview" data-theme="c">
            <li><a href="http://blog.cdeutsch.com" rel="external">My Blog</a></li>
            <li><a href="http://twitter.com/cdeutsch" rel="external">Twitter</a></li>
        </ul>
    </div>
</div>

I'm using a button on the left side of the header to trigger showing the dialog. Just set the href to the id of the dialog (in this case menu) and you're all set. No more repeatedly hitting the server for a frequently used resource.

See this jsfiddle for a working example.

Tuesday, April 19, 2011

Using RazorJS with MVC3

I've been working on a project where I've managed to accumulate 1200+ lines of javascript in my View file. There are two reasons for this:
  1. Since the application is still in development I don't have to worry about the browser caching JS files if the code is in the View.
  2. I often have Url.Action and other snippets of Razor mixed in with my javascript. 
I was just getting to the point where I was ready to move this code to its own .js file but I was worried about how to deal with the Razor that was mixed in. Thanks to John Katsiotis's (aka djsolid) RazorJS project I now have a solution!

Installation is easy, just use Nuget to add RazorJS to your solution in Visual Studio. The command line to do is:

Install-Package RazorJS

By default @Url.Action will not work and you'll get the error:
error CS0103: The name 'Url' does not exist in the current context

To get it to work add the following at the top of your javascript file.
@{
    var Url = new System.Web.Mvc.UrlHelper(System.Web.HttpContext.Current.Request.RequestContext);
}

If you run into other errors you should be able to use similar workarounds. If you do use other workarounds, let me know and I can add them to this post.

UPDATE: In version 0.4.2 you no longer need this work around for the UrlHelper. Thanks to John for adding this so fast!