简体   繁体   中英

Detect model of iOS device using Javascript or HTML?

So I'm serving H.264 .mp4 video on my website. I'm using open source HTML5 video player http://mediaelementjs.com/ . Some visitors are viewing from Safari for iPhone. The iPhone 4 supports video playback only up to 720p, so if I make my videos smaller than that, they work on the 4 and the 4S. But the 4S supports video up to 1080p. So how would I serve a larger video to the 4S and a smaller video to the 4? I tried this:

<video width="640" height="400" id="player" controls="controls" preload="auto">
    <source src="https://s3.amazonaws.com/my-big-1080p-video.mp4" type="video/mp4">
    <source src="https://s3.amazonaws.com/my-small-720p-video.mp4" type="video/mp4">
</video>

But it didn't work. The iPhone 4 isn't smart enough to try the second source. How can I make my website serve the correct video to the different devices?

Play 720p video on iPhone 4 — 1080p video on iPhone 4S

Try this on an iPhone 4 and a 4S ( jsfiddle )

 <video src="http://file.brow.sr/1080p.mp4" onerror="this.src='http://file.brow.sr/720p.mp4';" controls loop width="320" height="180"> </video> 

Explanation

Load the 1080p video, then use Javascript's onError to fall back to 720p.

Safari will sniff the header of the 1080p file to determine if it's playable, and if it's too big to decode it will throw an error. We then catch that error to provide the 720p video.

By using this kind of feature detection, the fallback will not only work on one device (iPhone 4) but probably on a lot of different capable browsers.

Why multiple <source> 's won't work

When using multiple <source> tags with the same MIME types , the browser will load the first source that has a compatible MIME type and discard the others, even if that video is not playable. That's because source elements are expected to provide alternative video codecs (eg. ogg, webm, mp4), not alternative frame sizes / file sizes.

Here is how to go about it:

1) Retrieve the device model by using wurfl

<script type='text/javascript' src=“//wurfl.io/wurfl.js"></script>

You can either use HTTP or HTTPS (both are are supported) If you plan to use the device information provided by the script to make rendering decisions, then you might want to include the script in the element. Otherwise, you can load it asynchronously. Now you have access to the WURFL object within JavaScript.

Sample response looks something like:

{ complete_device_name:"Apple iPhone 5", form_factor:"Smartphone", is_mobile:true }

off course you can(and should)

console.log(WURFL);

to find out the rest of the properties you can use.

2) Now that you know which exactly which device model your users are on, you can switch the video players configs.

How about something like?

<video width="IPHONE5_VIDEO_WIDTH"
       height="IPHONE5_VIDEO_HEIGHT"
       id="player" controls="controls"
       preload="auto">
       <source src="IPHONE5_VIDEO_URL" type="video/mp4">
</video>

super clean and readable right? Hope that helps.

I have a php script that does this. I got it here - http://detectmobilebrowsers.com/ - and yes, there is a javascript, JQuery, etc. versions. It's worked quite well for us and it has the benefit of seeming to stay fairly updated. The only issue we've run into was an iPad that had been deliberate set not to identify itself as a mobile device.

尝试链接库应该能够检测用户代理,您可以相应地提供适当的文件。

I cannot offer sample code since I am not an Apple geek, but I can tell you based off of my experience trying to make sites compatible between XHTML and HTML5 that it is better to check for browser capability than browser version.

The reason for this is that there are too many browser versions to justify the upkeep, and also the user agent string can be modified. I recommend that you write a script that checks for HTML5 video capabilities with a simple if statement, and then render either one video or the other depending upon the results.

A mobile device detection database like WURFL (Wireless Universal Resource File - http://wurfl.sourceforge.net/ ) or DeviceAtlas may be overkill if video is the only capability you're checking for. But it is a quick way to get robust capabilities detection for a vastly larger range of devices than you would be able to feasibly compile checks for, and would come in handy if your site ever needs to verify other capabilities besides video support.

Your solution don't work because of the reason mentioned by dear @Duvrai. I've searched to attain a right way to meet your purpose and it seemed we have no choice unless using some javascript code (here without considering server side programming) to make a decision which source should be delivered. The bellow snippet detects the browser Type and its Version :

 navigator.sayswho= (function(){ var ua= navigator.userAgent, tem, M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\\/))\\/?\\s*(\\d+)/i) || []; if(/trident/i.test(M[1])){ tem= /\\brv[ :]+(\\d+)/g.exec(ua) || []; alert('IE '+(tem[1] || '')); } if(M[1]=== 'Chrome'){ tem= ua.match(/\\bOPR\\/(\\d+)/) if(tem!= null) alert('Opera '+tem[1]); } M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?']; if((tem= ua.match(/version\\/(\\d+)/i))!= null) M.splice(1, 1, tem[1]); alert( M.join(' ')); })(); 

Now you can write some lines of code in javascript and decide to change video sources based on browser Type and Version .

MEJS player does not handle errors correctly, I'd to add more support to be able to detect what actually happened. On iPhone it even sometimes throws an error event but there is no actual error and you can play the video correctly.

Open mediaelement-and-player.js and look for

        // error handling
        media.addEventListener('error',function() {
            loading.hide();
            controls.find('.mejs-time-buffering').hide();
            error.show();
            error.find('mejs-overlay-error').html("Error loading this resource");
        }, false);

Then use this code:

        // error handling
        media.addEventListener('error',function() {
            var
                videoError = error.closest('.mejs-inner').find('video,audio')[0].error,
                msg = 'Error loading this resource.';

            if (!videoError) { //webkit sometimes throws error event but video has no actual error and can play the video correctly - ignore the event
                console.log('MEJS event: error throws but no error found - ignored');
                return;
            }

            //hide elements visible while loading and playing - cannot play after error
            loading.hide();
            controls.addClass('hidden'); //controls are automatically displayed when mouse hover is detected - must hide it permanently using class with !important
            error.closest('.mejs-inner').find('.mejs-overlay-play').hide(); //also hide overlay with play button
            error.show();

            //get relevant error message
            switch(videoError.code) { //see http://www.w3.org/TR/html5/embedded-content-0.html#error-codes
                case videoError.MEDIA_ERR_ABORTED: //loading stopped (by user, e.g. by pressing ESC or Back)
                    msg = 'Video loading aborted';
                    break;
                case videoError.MEDIA_ERR_DECODE: //invalid format (actually presumed format is OK, but the data does not correspond with the defined format - probably corrupted file of data transfer)
                    msg = 'Video file is broken';
                    break;
                case videoError.MEDIA_ERR_NETWORK: //network problem (was able to connect to the provided URL but could not get the video data)
                    msg = 'Network connection lost';
                    break;
                case videoError.MEDIA_ERR_SRC_NOT_SUPPORTED: //invalid source URL (url provided does not lead to a supported video file)
                    msg = 'Video not supported';
                    break;
            }

            //display error
            console.log('Video error: ' + msg + ', code: ' + videoError.code);
            error.find('.mejs-overlay-error').html(msg);
        }, false);

If you need to you can add your own handling that will switch to 720p in case of unsupported video.

And in mediaelementplayer.css add this (not sure if actually required or just improvement for my theme):

/* Display errors */
.mejs-overlay-error {
    color: white;
    background: black;
    text-align: center;
    font-size: 1.2EM;
}
.mejs-controls.hidden {
    display: none !important;
}
/* End: Display errors */

This is for version 2.13.1, not sure if newer version is better.

Update: newest version 2.16.3 contains exactly same useless error handler.

This will detect the iOS version. Maybe it can be useful:

if (navigator.userAgent.indexOf('5_0') != -1) {
    alert('IOS 5');
} else {
    alert('Other');
}

Edit: I have have ajusted and tested the script.

Put this in your tags:

<meta name="viewport" content="initial-scale=1.0">
<meta name="viewport" content="width=320.1">    
<script>
if (window.screen.height==568) { // iPhone 5
                    document.querySelector("meta[name=viewport]").content="width=320.1";
                  // your code here
                }
</script>

I use this code:

    // iPhone 3
    if (window.screen.height==480 && window.screen.width==320 && window.devicePixelRatio==1)
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:300px;width:500px;"></div>');
    } 
    // iPhone 4, this is Retina
    else if (window.screen.height==480 && window.screen.width==320 && window.devicePixelRatio==2) 
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:300px;width:500px;"></div>');
    } 
    // iPhone 5
    else if (window.screen.height==568 && window.screen.width==320 && window.devicePixelRatio==2) 
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:400px;width:600px;"></div>');
    } 
    // iPad
    else if (window.screen.height==1024 && window.screen.width==768 && window.devicePixelRatio==1) 
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:425px;width:680px;"></div>');
    } 
    // iPad Retina
    else if (window.screen.height==1024 && window.screen.width==768 && window.devicePixelRatio==2) 
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:425px;width:680px;"></div>');
    } 
    // all other, this was before for all 
    else  
    { 
        $('#chartDivWrapper').html('<div id="chartdiv" style="height:400px;width:600px;"></div>');
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM