Determining platform

Although obviously the point of Enyo is to be multiplatform, there come times when we need to use platform-specific codes to achieve some things. I've been doing some research into how to determine what platforms we are on, and would appreciate any more tips from anyone else.

To determine if we are in webOS, we can check window.PalmSystem: if(window.PalmSystem) webOSFunction();
To determine if we are running in Phonegap, we can check PhoneGap: if(PhoneGap) phoneGapFunction();

PhoneGap has a "device.platform" property that should return an operating system name, however, it is perhaps less than reliable: it's returns are not completely valid, or necessarily documented -- it returns "iPhone" for all iOS devices, and on several Blackberry devices, it apparently returns a version number of the operating system rather than the name of the system.

Comments

  • Put the PalmSystem check first, just in case you're running in PhoneGap on webOS :)
  • Checking the presence of the PhoneGap object will be confusing, because this object is present as soon as you load the phonegap javascript file. You can not use it to determine whether the phonegap API services are available. If you only want to check for a phonegap project its ok (but i think then you would know it anyway?!).
  • I had problems with if (PhoneGap) since (I guess) the auto caster has a problem with undeclared variables. I use if (typeof PhoneGap != 'undefined'). Also you can use if (typeof chrome != 'undefined') to check if the chrome extension api is available.
  • I'm not certain what if any advantages would come to running with PhoneGap included also on webOS, my first thought, is that I would use this to not include PhoneGap on webOS :) and then to come up with alternatives to the various PalmService and other calls that don't make sense elsewhere.

    Of course, please add if anyone has ways to specifically determine iOS, Android, Blackberry, possibly as well as determining other metrics that might be really important to cross platform things. I'll continue adding as I find them.
  • This is how I handle platform determination:
    try{
    this.platform=device.platform.toLowerCase();
    }catch(e){
    if(window.PalmSystem){
    this.platform="webos";
    }else{
    this.platform="web";
    }
    }
    Basically, it attempts to ask PhoneGap what the device's platform is (and convert to lowercase). If we're not running under PhoneGap, the device object is undefined, and therefore accessing the platform property of it throws an exception.

    If that Exception is thrown, we assume no PhoneGap and check for the PalmSystem object. If it's there, then we know we're on webOS.

    I assume that if we're not using PhoneGap or webOS, that we're running in the browser.

    So far everything seems to be working. There may be a more elegant solution, but this works for me since I only include PhoneGap if I'm building for iOS or Android.
  • Actually, this brings up a curious Javascript question, that the answer doesn't seem to be an easy google for .. In Python, things are typically done with the try..catch type of construct, the "Python Way" is to perform the operation and if it errors deal with it, whereas most every other language I've ever used, even if it had try..catch, it was preferred (usually from a performance standpoint, wrt to setting up all the stacks and such, it's been so long i can't even remember the name of the issue) to do:

    if(device && device.platform) { xxx } else { yyy }

    I wonder if there's any reason to do it one way or the other in Javascript.

    Anyway, on topic, I wonder if there's a way to determine more specifically, such as in the case of device.platform returning a version # instead of a name, as is described in the docs.
  • In .Net, you should never rely on a try/catch unless it is a last resort, something truly exceptional.

    An exception would have to walk the stack trace and gather memory dumps for the exception handler, a very slow process indeed.

    I would assume that try/catch is much more expensive even in Javascript vs. just handling it properly
    if( window.PalmSystem ){
    this.platform = "webos";
    } else if( device == undefined || device.platform == undefined ){
    this.platform = "web";
    } else {
    this.platform = device.platform.toLowerCase( );
    }
    This should almost work, I sometimes encounter a problem with checking 'device == undefined' unless I set it to null during initialization before PhoneGap runs.
  • I'm super lazy, so try/catch requiring fewer keystrokes appealed to me. It works. Maybe not awesomely, but, as I said, I'm lazy,
  • Apparently, accessing "device" is an error on some platforms, rather than it just returning null. So, that's not really reliable, and you kind of have to do the try..catch if you're not positive that it's there.

    Many scripting languages that I have used do have exception handling, but it's usually quite slow compared to just checking it. Doesn't look like that's always possible here, though, unless you know the vars are set somewhere.
  • That's why I initialize 'device' in my main kind. Otherwise, causes very nasty errors.

    device = {};
  • In which case do you initialize 'device' with {}?
  • what about
    device = device || {};
  • I always initialize device to null, and let PhoneGap set it to the correct value as it runs.

    The problem sugardave is that just accessing the 'device' property will crash Enyo.
  • As I mentioned earlier you can use
    if (typeof device != "undefined")
    Also if you check for window.device you wont get an error if it has not been declared.
  • Based on complete lack of desire to go to sleep (until now), and wanting to catalog a lot of what I spent my weekend learning into a short space, I just banged this out . . I honestly have no idea if it works, I'm going to catch some sleep before I go through the long process of testing on at least 8 different OS/version combinations that I have access to at the moment...

    http://pastebin.com/wkdsDduX

  • Wow! Thanks Ekdikeo for taking the time to create the kind. I'll be adding it to all my apps.

    I'm tempted to break OOP and make it a bit more global and use enyo.application.platform over this.platform.

    And yup! You're right MaKleSoft, I completely missed your post the first time. Thanks for pointing that out. I wondered how to do that properly.
  • Might want to test that it works before adding it to everything ;) I'll get to that here in a little while, I don't like to put out untested code, but I figured people smarter than me might look it over and point out some fatal flaw or ways to improve upon it before I managed to get a test built.
  • Absolutely will! My apps are now out on three platforms, so at least I have some test cases.
  • Nice! Adapted it to a global version but haven't tested it in any real fashion. Seems to work, though.

    http://pastebin.com/g1PLaAi0
  • I just discovered that Playbook has a standard UI for opening a menu, the swipe-down-from-top gesture:

    http://supportforums.blackberry.com/t5/tkb/articleprintpage/tkb-id/browser_dev@tkb/article-id/88

    so that might make some changes to the hasMenu() function. Need to figure out if there's a similar thing for other BlackBerries
  • Hmm, your code does not detect Android for me. It detects "web" instead. Apparently, "PhoneGap" does not exist at this time. I am using an index.html for Android + PhoneGap like James posted here. It seems to be a timing problem, because later, PhoneGap is defined. Trying on Android 3.2 emulator.
  • BTW, using the global version by @ryanjduffy.
  • OK, I got it. I added a Platform.setup() function, which I call in index.html, ondeviceReady() before creating my main kind, so PhoneGap is already initialized.
    Also, the var "platform" for the whole object collided with the "platform" string and destroyed it, so I changed that.
    Also added a getVersion() function.

    http://pastebin.com/uEeByGhZ
  • hmm. I haven't actually got to doing anything Android yet, planning on looking at that this evening. In the meantime, however, I have managed to get around to beating up on the rest of it, on webOS and WebWorks .. and have a new updated version:

    http://pastebin.com/Qyp8PyDf

    ... maybe one of these days I'll get around to getting a github or something .. but, anyway, this adds a "thisObj" parameter to the browser() function, as I discovered that the "bind" implementation I used isn't well supported, and I was using it incorrectly anyway, so I just switched to enyo.bind() .. adds support for webOS using the browser() function, calls BlackBerry's web invoke on WebWorks with or without PhoneGap, and works in Chrome.

    Also adds a getReviewURL function which will return the URL to open for the HP App Catalog, Android Market, or iTunes store. To get the iTunes one to work, you'll need to add a new field to your appinfo.json: iTunesAppId, which would be your application id from the Apple Dev Portal.
  • ok, i'm going to make sure I get setup with github or something this week, because this is turning out to be a much more involved thing than I started with :)

    http://pastebin.com/6ATAiEhH

    PhoneGap device detection should work, so long as you make sure you don't call into this before the "deviceready" event.

    Rather than directly calling setup(), the first call that you make into any function in the kind will cause it to configure. If you ARE using PhoneGap, but are not waiting until "deviceready" is fired, results are undefined and untested, but the first call to it after deviceready will initialize it.

    Added getPlatformName(), identify "webworks" is valid for isBlackBerry(), add useHTMLAudio() boolean function, browser() takes 2 arguments as described above and now works with webOS, Android 4.0, and WebWorks out-of-the-"box", no plugins required .. getReviewURL() as above ..

    Also, this one includes a new helper kind: PlatformSound. It works sort of like a cross between the Enyo 1.0 Sound kind, and the PhoneGap Media API. It encapsulates and extends both of them, giving a unified interface to both the HTML5 audio API and the PhoneGap Media API.

    This one has been pretty thoroughly tested in webOS, Android CM7, Android CM9, and on the PlayBook 1.0.8 emulator. I haven't touched anything in iOS, it's too much of a pain in the butt to deploy to until I get a personal developer account with Apple.
  • GitHub has a "gist" feature at https://gist.github.com/ that's like pastebin but with comments, forking, and tracking. I really like it.
  • ok, got around to putting this into a seperate git:

    https://github.com/ericblade/EnyoPlatform

    Not only Platform detection, but useful tools for cross platform development, encapsulating some UI features and device functions, a browser call that works pretty much everywhere, and adding cross-platform versions of other things, too, such as the PlatformSound component that wraps enyo.Sound allowing for mostly full function for both HTML and PhoneGap audio.

    Next project is to see if I can get Dashboard running on PlayBook and Chrome :)

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Twitter