如何从 iPadOS 13 上的 WKWebView 中的 javascript 测试正在使用的 IOS

How to test IOS in use from the javascript inside a WKWebView on iPadOS 13

当我使用 XCode 11.1 在 "iPhone 8" 模拟器中使用 WKWebView 测试我的混合应用程序并使用 Safari 13 检查 userAgent 时,我得到以下字符串:

"Mozilla/5.0 (iPhone; CPU iPhone OS 13_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148" 

然而,当我在 "iPad Pro (11-inch)" 模拟器中测试应用程序时,我发现 userAgent 设置为以下字符串:

"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko)"

请注意,此字符串不包含子字符串 "iPad",也不包含正在使用的 IOS 版本,也不包含它是移动应用程序这一事实。

当我的应用程序检查 userAgent 以确定它是否在 IOS 下 运行ning 时,这在 iPhone 上工作正常但给我带来了一个问题,现在如何 运行 此测试在 iPad 上 运行 宁 iPadOS 13. 请注意,这与 Web 视图的显示方式无关,它是与是否在 javascript 和 Objective C 之间建立通信有关。

我的应用程序在所有 iPads 运行ning IOS 12 上运行良好,因为 userAgent 是我所期望的:

"Mozilla/5.0 (iPad; CPU OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16B92"

我现在应该如何从内部 Javascript 确定我的代码是否 运行ning 在 iPad 上 运行ning iPadOS 13 或更高版本?

这不是任何类型的错误。这是一个非常好的功能,iOS 13 中的新功能。默认情况下,iPad 将自己显示为桌面浏览器,而不是移动浏览器。

我有很多方法可以解决这个问题。

  1. 根本没有测试 - 只是在加载后使用 evaluateJavascript 告诉 webview 它是 IOS。

  2. 使用 Objective C/swift 检测 iPad 并在包含字符串“iPad 的用户默认值中注册自定义用户代理字符串:在创建之前网络视图

     // 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];
    

然而,也许出于错误的原因,我决定使用 Missing iPad tablet Web traffic

中的解决方案

如下

但它会将新的 mac(使用 Apple m1 芯片)错误地检测为 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 ;