When I use XCode 11.1 to test my hybrid app using a WKWebView in the "iPhone 8" simulator and inspect the userAgent using Safari 13, I get the following string :
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
However when I test the app in the "iPad Pro (11-inch)" simulator, I have found that the userAgent is set to the following string :
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko)"
Note that this string does not contain the sub-string "iPad", nor the version of IOS in use, nor the fact that it is a Mobile app.
As my app examines userAgent to determine whether it is running under IOS, this works fine on the iPhone but presents me with a problem on how now to run this test on iPads that are running iPadOS 13. Please note that this is nothing to do with how the web view is displayed, it is to do with whether or not to establish communication between the javascript and Objective C.
My app worked fine on all iPads running IOS 12 as the userAgent is what I expected:
"Mozilla/5.0 (iPad; CPU OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16B92"
How should I now determine from inside Javascript whether my code is running on an iPad that is running iPadOS 13 or later?
There are a number of ways I could have solved this.
Not testing at all - and simply using evaluateJavascript after loading to tell the webview that it was IOS.
Detecting iPad using Objective C/swift and registering a custom user agent string in the user defaults containing the string "iPad: before creating the web view
// get original UserAgent string by using temporal webView
WKWebView *tmp = [[WKWebView alloc] init];
NSString *originalUA = [tmp stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
// create custom UserAgent string
NSString *customUA = [NSString stringWithFormat:@"%@ %@", originalUA, @" iPad"];
// set custom UserAgent as default
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:customUA , @"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
However and perhaps for the wrong reasons I decided to use a solution from Missing iPad tablet Web traffic
as follows
But it will incorrectly detect a new mac (with Apple m1 chip) as an iPad.
var agent = window.navigator.userAgent;
var d=document;
var e=d.documentElement;
var g=d.getElementsByTagName('body')[0];
var deviceWidth=window.innerWidth||e.clientWidth||g.clientWidth;
// Chrome
var IsChromeApp = window.chrome && chrome.app && chrome.app.runtime;
// iPhone
var IsIPhone = agent.match (/iPhone/i) != null;
// iPad up to IOS12
var IsIPad = (agent.match (/iPad/i) != null) || ((agent.match(/iPhone/i) != null) && (deviceWidth > 750)); // iPadPro when run with no launch screen can have error in userAgent reporting as an iPhone rather than an iPad. iPadPro width portrait 768, iPhone6 plus 414x736 but would probably always report 414 on app startup
if (IsIPad) IsIPhone = false ;
// iPad from IOS13
var macApp = agent.match (/Macintosh/i) != null;
if (macApp)
{
// need to distinguish between Macbook and iPad
var canvas = document.createElement ("canvas");
if (canvas != null)
{
var context = canvas.getContext ("webgl") || canvas.getContext ("experimental-webgl");
if (context)
{
var info = context.getExtension ("WEBGL_debug_renderer_info");
if (info)
{
var renderer = context.getParameter (info.UNMASKED_RENDERER_WEBGL);
if (renderer.indexOf ("Apple") != -1) IsIPad = true ;
};
};
};
};
// IOS
var IsIOSApp = IsIPad || IsIPhone ;
// Android
var IsAndroid = agent.match (/Android/i) != null;
var IsAndroidPhone = IsAndroid && deviceWidth <= 960 ;
var IsAndroidTablet = IsAndroid && !IsAndroidPhone ;