Asked  7 Months ago    Answers:  5   Viewed   32 times

I am creating a phonegap application for various mobile platforms and I was wondering what is a current best solution of browser/mobile phone detection?

Should I go with a server or a client side detection or could I use css solution through a media types screen width?

 Answers

22

Changes:

  • 06.03.2013 - Addad a few comments inside a WURFL chapter

Intro :

There are few available solutions but I will only name open-source ones, at least solutions mostly used with a jQuery/jQuery Mobile. Also be warned, this topic has the potential to start a war. On one side we have a proponents of server side detection with their community maintained databases and on the other side we have client side advocates with their browser sniffing.

Server side:

WURFL -

Created in 2002, WURFL (Wireless Universal Resource FiLe), is a popular open-source framework to solve the device-fragmentation problem for mobile Web developers and other stakeholders in the mobile ecosystem. WURFL has been and still is the de facto standard device-description repository adopted by mobile developers. WURFL is open source (AGPL v3) and a trademark of ScientiaMobile.

Good :

Very detailed detection, you would probably get more data then is really needed.

Good platform support, api's are available for Java, PHP and .Net.

Bad :

Not always up to date, heavy dependency on community

In case of iPhone there's no way of knowing an iOS version, so media type queries to detect pixel ratios.

Fee only for a non commercial usage, older version are still free for commercial usage but they can only use database updated up to WURFL EULA changes.

  • It can be found here: http://wurfl.sourceforge.net/apis.php

PHP example :

<?php
    // Include the configuration file
    include_once './inc/wurfl_config_standard.php';

    $wurflInfo = $wurflManager->getWURFLInfo();

    if (isset($_GET['ua']) && trim($_GET['ua'])) {
        $ua = $_GET['ua'];
        $requestingDevice = $wurflManager->getDeviceForUserAgent($_GET['ua']);
    } else {
        $ua = $_SERVER['HTTP_USER_AGENT'];
        // This line detects the visiting device by looking at its HTTP Request ($_SERVER)
        $requestingDevice = $wurflManager->getDeviceForHttpRequest($_SERVER);
    }
?>  
<html>
<head>
    <title>WURFL PHP API Example</title>
</head>
<body>
    <h3>WURFL XML INFO</h3>
    <ul>
        <li><h4>VERSION: <?php echo $wurflInfo->version; ?> </h4></li>
    </ul>
    <div id="content">
        User Agent: <b> <?php echo htmlspecialchars($ua); ?> </b>
        <ul>
            <li>ID: <?php echo $requestingDevice->id; ?> </li>
            <li>Brand Name: <?php echo $requestingDevice->getCapability('brand_name'); ?> </li>
            <li>Model Name: <?php echo $requestingDevice->getCapability('model_name'); ?> </li>
            <li>Marketing Name: <?php echo $requestingDevice->getCapability('marketing_name'); ?> </li>
            <li>Preferred Markup: <?php echo $requestingDevice->getCapability('preferred_markup'); ?> </li>
            <li>Resolution Width: <?php echo $requestingDevice->getCapability('resolution_width'); ?> </li>
            <li>Resolution Height: <?php echo $requestingDevice->getCapability('resolution_height'); ?> </li>
        </ul>
        <p><b>Query WURFL by providing the user agent:</b></p>
        <form method="get" action="index.php">
            <div>User Agent: <input type="text" name="ua" size="100" value="<?php echo isset($_GET['ua'])? htmlspecialchars($_GET['ua']): ''; ?>" />
            <input type="submit" /></div>
        </form>
    </div>
</body>
</html>

If you want to customize this code, change configuration parameters inside a wurfl_config_standard.php file.


Modernizr - Server -

Modernizr is a great way to find out about your user's browser capabilities. However, you can only access its API on the browser itself, which means you can't easily benefit from knowing about browser capabilities in your server logic. The modernizr-server library is a way to bring Modernizr browser data to your server scripting environment.

Good :

Like WURFL very detailed detection, but we need to take into consideration that it is build with a different purpose the WURFL.

Bad :

Only supported on PHP, but sometimes this will be enough.

Example :

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Modernizr Server Example</title>
</head>
<body>
<?php
    include('modernizr-server.php');

    print 'The server knows:';
    foreach($modernizr as $feature=>$value) {
        print "<br/> $feature: "; print_r($value);
    }
?>
</body>
</html>
  • It can be found here: https://github.com/jamesgpearce/modernizr-server

Client side:

Modernizer -

aking advantage of cool new web technologies is great fun, until you have to support browsers that lag behind. Modernizr makes it easy for you to write conditional JavaScript and CSS to handle each situation, whether a browser supports a feature or not. It’s perfect for doing progressive enhancement easily.

Good :

Only client side, server side component don't exist

Fast but still large for a javascript framework with its 12kb. Because of its modularity it can become smaller, depending on your needs.

Bad :

Can do only so much, less info then server side detection.

Modernizr itself is a great way to find out about your user’s browser capabilities. However, you can only access its API on the browser itself, which means you can’t easily benefit from knowing about browser capabilities in your server logic.

  • It can be found here: http://modernizr.com/

Example :

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>Modernizr Example</title>
      <script src="modernizr.min.js"></script>
    </head>
    <body>
      <script>
        if (Modernizr.canvas) {
          // supported
        } else {
          // no native canvas support available :(
        }  
      </script>
    </body>
    </html>

JavaScript based browser sniffing

It is arguable that this may be (academically) the worst possible way to detect mobile but it does have its virtues.

Good :

Simple

Bad :

Where to begin

Example :

<script type="text/javascript">     
    var agent = navigator.userAgent;      
    var isWebkit = (agent.indexOf("AppleWebKit") > 0);      
    var isIPad = (agent.indexOf("iPad") > 0);      
    var isIOS = (agent.indexOf("iPhone") > 0 || agent.indexOf("iPod") > 0);     
    var isAndroid = (agent.indexOf("Android")  > 0);     
    var isNewBlackBerry = (agent.indexOf("AppleWebKit") > 0 && agent.indexOf("BlackBerry") > 0);     
    var isWebOS = (agent.indexOf("webOS") > 0);      
    var isWindowsMobile = (agent.indexOf("IEMobile") > 0);     
    var isSmallScreen = (screen.width < 767 || (isAndroid && screen.width < 1000));     
    var isUnknownMobile = (isWebkit && isSmallScreen);     
    var isMobile = (isIOS || isAndroid || isNewBlackBerry || isWebOS || isWindowsMobile || isUnknownMobile);     
    var isTablet = (isIPad || (isMobile && !isSmallScreen));     

    if ( isMobile && isSmallScreen && document.cookie.indexOf( "mobileFullSiteClicked=") < 0 ) mobileRedirect(); 
</script>
Wednesday, March 31, 2021
 
kinske
answered 7 Months ago
32

I have tried a first solution for your problem by catching the resize event With that you can know the orientation and gest is the keyboard is visible

UPDATE : adding iOS mobile safari support with LKM solution

var is_keyboard = false;
var is_landscape = false;
var initial_screen_size = window.innerHeight;

/* Android */
window.addEventListener("resize", function() {
    is_keyboard = (window.innerHeight < initial_screen_size);
    is_landscape = (screen.height < screen.width);

    updateViews();
}, false);

/* iOS */
$("input").bind("focus blur",function() {
    $(window).scrollTop(10);
    is_keyboard = $(window).scrollTop() > 0;
    $(window).scrollTop(0);
    updateViews();
});

Now you can show and hide the logo and some line item

function updateViews() {
    $("li").hide();
    if (is_keyboard) {
        $("#logo").hide();
        if (is_landscape) {
            $("li").slice(0, 2).show();
        }
        else {
            $("li").slice(0, 4).show();
        }
    }
    else {
        $("#logo").show();
        $("li").show();
    }
}

For the JS based on this HTML

<div id="logo">Logo</div>
<input type="text"><input type="submit" value="search">
<ul>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
    <li>Item</li>
</ul>

Check out my example page

Sunday, August 1, 2021
 
Jon
answered 3 Months ago
Jon
99

I've rewritten the answer based on a better understanding of the question, but without losing any of my original answer for those who find this question.

Getting the size from code running on the device

The answer is simple: P/Invoke GetDiskFreeSpaceEx directly (example here) or use a third-party library that does it for you.

I'm also going to edit the post to make it seem like my assumptions are correct - change them to read otherwise if you need to.

You have a P/Invoke definition. This is simply a static method call. You put it in a class. Something like this:

public class MyClass
{
  [DllImport("coredll.dll", SetLastError=true, CharSet=CharSet.Auto)]
  [return: MarshalAs(UnmanagedType.Bool)]
  internal static extern bool GetDiskFreeSpaceEx(string lpDirectoryName,
    out ulong lpFreeBytesAvailable,
    out ulong lpTotalNumberOfBytes,
    out ulong lpTotalNumberOfFreeBytes);
}

Then you call it (no idea what you're trying to do with all of your marshaling stuff):

ulong GetDiskSize(string volumeName)
{
  ulong avail;
  ulong total;
  ulong totalfree;

  MyClass.GetDiskFreeSpaceEx(volumeName, out avail, out total, out totalFree);

  return total;
  // return others as desired
}

Then to use it it's something like this:

ulong diskSize = GetDiskSize("\Storage Card");

Getting the size from code running on the PC

While the device shows up in Explorer like a "drive", it is not a drive. A shell extension is used to get it to appear in Explorer. You cannot use any drive APIs, in the framework or via P/Invoke, to get information about the device.

If you need to get information about a device connected via ActiveSync (XP and earlier) or WMDC (Vista) then you have to use the Remote API, or RAPI. The specific API is CeGetStoreInformation, but you have to do some initialization before you can call it.

RAPI is a bit too complex to cover in an answer here, but it's well documented online, and there is a ready-made managed wrapper for it (free and open source) here. The specific call you are after in that library is RAPI.GetDeviceStoreInformation.

Saturday, August 21, 2021
 
Jakob Gade
answered 2 Months ago
40

Working example: http://jsfiddle.net/d9vzs/

This is not how you enable disable jQUery Mobile input elements.

It can be done with this functions:

$( "input" ).textinput( "disable" );


$( "input" ).textinput( "enable" );

Official documentation: http://api.jquerymobile.com/textinput/#method-disable

Saturday, September 18, 2021
 
Joel
answered 1 Month ago
99

In your examples, the derived table is not strictly necessary. There are numerous cases where you might need to join to an aggregate or similar, and a derived table is really the only way to handle that:

SELECT *
FROM A
LEFT JOIN (
    SELECT x, SUM(y)
    FROM B
    GROUP BY x
) AS B
    ON B.x = A.x

In addition, if expressions are used to derive columns from derived columns with a lot of shared intermediate calculations, a set of nested derived tables or stacked CTEs is the only way to do it:

SELECT x, y, z1, z2
FROM (
    SELECT *
           ,x + y AS z1
           ,x - y AS z2
    FROM (
        SELECT x * 2 AS y
        FROM A
    ) AS A
) AS A

As far as maintainability, using stacked CTEs or derived tables (they are basically equivalent) and can make for more readable and maintainable code, as well as facilitating cut-and-paste re-use and refactoring. The optimizer can typically flatten then very easily.

I typically use stacked CTEs instead of nesting for a little better readability (same two examples):

WITH B AS (
    SELECT x, SUM(y)
    FROM B
    GROUP BY x
)
SELECT *
FROM A
LEFT JOIN B
    ON B.x = A.x

WITH A1 AS (
    SELECT x * 2 AS y
    FROM A
)
,A2 AS (
    SELECT *
           ,x + y AS z1
           ,x - y AS z2
    FROM A1
)
SELECT x, y, z1, z2
FROM A2

Regarding your question about:

SELECT x, x * 2 AS y, x + x*2 AS z1, x - x*2 AS z2 
FROM A 

This has the x * 2 code repeated 3 times. If this business rule needs to change, it will have to change in 3 places - a recipe for injection of defects. This gets compounded any time you have intermediate calculations which need to be consistent and defined in only one place.

This would not be as much of a problem if SQL Server's scalar user-defined functions could be inlined (or if they performed acceptably), you could simply build your UDFs to stack your results and the optimizer would elimnate redundant calls. Unfortunately SQL Server's scalar UDF implementation cannot handle that well for large sets of rows.

Sunday, October 3, 2021
 
muncherelli
answered 3 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :