Cordova 应用程序无法在 iPhone X(模拟器)上正确显示

Cordova app not displaying correctly on iPhone X (Simulator)

我昨天在 Xcode X Simulator Xcode 9.0 (9A235) 上测试了我基于 Cordova 的应用程序,它看起来不太好。 首先,应用内容的上方和下方没有填满整个屏幕区域,而是黑色区域。 更糟糕的是,在应用程序内容和黑色之间是两个白色条。

添加 cordova-plugin-wkwebview-engine 以便 Cordova 使用 WKWebView(而非 UIWebView)呈现修复白条。 由于使用 cordova-plugin-wkwebview-engine 时的性能和内存泄漏问题,我的应用程序未从 UIWebView 迁移到 WKWebView,这发生在将从 Inapp Purchase 托管内容下载的图像加载到 HTML5 canvas(直接 file:// 由于 WKWebView 的安全限制,无法通过 Webview 访问,因此必须通过 cordova-plugin-file).

加载图像数据

这些屏幕截图显示了在 <body> 上设置了蓝色背景的测试应用。 UIWebView的上下可以看到白条,WKWebView看不到:


(来源:pbrd.co


(来源:pbrd.co

与填充全屏区域的本机应用程序相比,两种 Cordova Webview 都显示黑色区域:

我找到了解决白条的办法here:

在视口 <meta> 标签上设置 viewport-fit=cover,即:

<meta name="viewport" content="initial-scale=1, width=device-width, height=device-height, viewport-fit=cover">

然后 UIWebView 中的白条消失:

去除黑色区域的解决方案(由@dpogue in a comment below) is to use LaunchStoryboard images提供,用cordova-plugin-splashscreen替换遗留启动图像,Cordova默认使用。为此,将以下内容添加到iOS 平台在 config.xml:

<platform name="ios">    
    <splash src="res/screen/ios/Default@2x~iphone~anyany.png" />
    <splash src="res/screen/ios/Default@2x~iphone~comany.png" />
    <splash src="res/screen/ios/Default@2x~iphone~comcom.png" />
    <splash src="res/screen/ios/Default@3x~iphone~anyany.png" />
    <splash src="res/screen/ios/Default@3x~iphone~anycom.png" />
    <splash src="res/screen/ios/Default@3x~iphone~comany.png" />
    <splash src="res/screen/ios/Default@2x~ipad~anyany.png" />
    <splash src="res/screen/ios/Default@2x~ipad~comany.png" />   

    <!-- more iOS config... -->
</platform>

然后在 res/screen/ios 中创建具有以下尺寸的图像(删除任何现有的):

Default@2x~iphone~anyany.png - 1334x1334
Default@2x~iphone~comany.png - 750x1334
Default@2x~iphone~comcom.png - 1334x750
Default@3x~iphone~anyany.png - 2208x2208
Default@3x~iphone~anycom.png - 2208x1242
Default@3x~iphone~comany.png - 1242x2208
Default@2x~ipad~anyany.png - 2732x2732
Default@2x~ipad~comany.png - 1278x2732

删除黑条后,iPhone X 的另一个不同之处在于:由于 "notch",状态栏大于 20px,这意味着任何内容都位于您的 Cordova 应用程序的最顶部将被它遮挡:

而不是 hard-coding 以像素为单位的填充,您可以使用 iOS 中的新 safe-area-inset-* 常量在 CSS 中自动处理此问题 11.

注意: 在 iOS 11.0 中处理这些常量的函数被称为 constant() 但在 iOS 11.2 Apple 将其重命名为 env() (see here), 因此,要涵盖这两种情况,您需要同时重载 CSS 规则,并依赖 CSS fallback mechanism 来应用适当的规则:

body{
    padding-top: constant(safe-area-inset-top);
    padding-top: env(safe-area-inset-top);
}

结果如愿:应用内容覆盖了整个屏幕,但没有被 "notch":

遮挡

我创建了一个 Cordova 测试项目来说明上述步骤:webview-test.zip

备注:

页脚按钮

  • 如果您的应用有页脚按钮(就像我的一样),您还需要应用 safe-area-inset-bottom 以避免它们被 iPhone X 上的虚拟主页按钮重叠。
  • 在我的例子中,我无法将它应用到 <body>,因为页脚是绝对定位的,所以我需要将它直接应用到页脚:

.toolbar-footer{
    margin-bottom: constant(safe-area-inset-bottom);
    margin-bottom: env(safe-area-inset-bottom);
}

cordova-plugin-statusbar

  • iPhone X 上的状态栏大小已更改,因此 cordova-plugin-statusbar 的旧版本在 iPhone X
  • 上显示不正确
  • Mike Hartington has created this pull request 应用必要的更改。
  • 这已合并到 cordova-plugin-statusbar@2.3.0 版本中,因此请确保您至少使用此版本以应用于 safe-area-insets

启动画面

  • LaunchScreen 故事板约束在 iOS 11/iPhone X 上发生了变化,这意味着当使用现有版本的插件时启动画面出现 "jump"( ).
  • 这是在错误报告 CB-13505, fixed PR cordova-ios#354 and released in cordova-ios@4.5.4 中捕获的,因此请确保您使用的是 cordova-ios 平台的最新版本。

设备方向

  • 在iOS 11.0上使用UIWebView时,从纵向>横向>纵向旋转导致safe-area-inset不是re-applied,导致内容再次被缺口遮挡(正如下面评论中 jms 突出显示的那样)。
  • 如果应用程序以横向启动然后旋转为纵向,也会发生这种情况
  • 通过 cordova-plugin-wkwebview-engine 使用 WKWebView 时不会发生这种情况。
  • 雷达报告:http://www.openradar.me/radar?id=5035192880201728
  • 更新:这似乎已在 iOS 11.1
  • 中修复

作为参考,这是我打开的原始 Cordova 问题,其中包含以下内容:https://issues.apache.org/jira/browse/CB-13273

手动修复现有的 cordova 项目

黑条

将此添加到您的 info.plist 文件中。修复启动图像是一个单独的问题,即

<key>UILaunchStoryboardName</key>
<string>CDVLaunchScreen</string>

白条

在元标记中设置 viewport-fit=cover

<meta name="viewport" content="initial-scale=1, width=device-width, height=device-height, viewport-fit=cover">

请注意,对于 11.2 beta+

,用于安全区域边距的 constant 关键字已更新为 env

https://webkit.org/blog/7929/designing-websites-for-iphone-x/

如果您在全局安装 ionic 的较新版本,您可以 运行 ionic cordova resources 它将为您生成所有启动画面图像以及正确的尺寸。

您需要执行 3 个步骤

对于 iOs 11 状态栏 & iPhone X header 问题


1.视口适合覆盖

viewport-fit=cover 添加到 <header>

中的视口元
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0,viewport-fit=cover">

演示: https://jsfiddle.net/gq5pt509 (index.html)


  1. <platform name="ios">
  2. 中的 config.xml 添加更多启动图像

不要跳过此步骤,这是获得屏幕适合 所需的 iPhone X 工作

<splash src="your_path/Default@2x~ipad~anyany.png" />   <!-- 2732x2732 -->
<splash src="your_path/Default@2x~ipad~comany.png" />   <!-- 1278x2732 -->
<splash src="your_path/Default@2x~iphone~anyany.png" /> <!-- 1334x1334 -->
<splash src="your_path/Default@2x~iphone~comany.png" /> <!-- 750x1334  -->
<splash src="your_path/Default@2x~iphone~comcom.png" /> <!-- 1334x750  -->
<splash src="your_path/Default@3x~iphone~anyany.png" /> <!-- 2208x2208 -->
<splash src="your_path/Default@3x~iphone~anycom.png" /> <!-- 2208x1242 -->
<splash src="your_path/Default@3x~iphone~comany.png" /> <!-- 1242x2208 -->

演示: https://jsfiddle.net/mmy885q4 (config.xml)


  1. 修正你的风格 CSS

使用 safe-area-inset-leftsafe-area-inset-rightsafe-area-inset-topsafe-area-inset-bottom

示例:(根据您的情况使用!)

#header {
   position: fixed;
   top: 1.25rem; // iOs 10 or lower
   top: constant(safe-area-inset-top); // iOs 11
   top: env(safe-area-inset-top); // iOs 11+ (feature)

   // or use calc()
   top: calc(constant(safe-area-inset-top) + 1rem);
   top: env(constant(safe-area-inset-top) + 1rem);
  
   // or SCSS calc()
   $nav-height: 1.25rem;
   top: calc(constant(safe-area-inset-top) + #{$nav-height});
   top: calc(env(safe-area-inset-top) + #{$nav-height});
}

奖励: 您可以在 deviceready[= 上添加 body class,例如 is-androidis-ios 28=]

var platformId = window.cordova.platformId;
if (platformId) {
   document.body.classList.add('is-' + platformId);
}

所以你可以在 CSS

上做这样的事情
.is-ios #header {
 // Properties
}

在我的情况下,每个初始屏幕都是单独设计的,而不是自动生成的或以故事板格式布置的,我不得不坚持我的旧版启动屏幕配置并添加纵向和横向图像以针对 iPhoneX 1125×2436 方向config.xml 像这样:

<splash height="2436" src="resources/ios/splash/Default-2436h.png" width="1125" />
<splash height="1125" src="resources/ios/splash/Default-Landscape-2436h.png" width="2436" />

将这些添加到 config.xml 后("viewport-fit=cover" 已在 index.hml 中设置)我使用 Ionic Pro 构建的应用程序会填满 iPhoneX 设备上的整个屏幕。

修复 iPhone X/XS 屏幕旋转问题

在 iPhone X/XS 上,屏幕旋转将导致 header 条高度使用不正确的值,因为 safe-area-inset-* 的计算没有反映出来新值及时 UI 刷​​新。即使在最新的 iOS12 中,UIWebView 中也存在此错误。解决方法是插入 1px 顶部边距,然后快速反转它,这将触发 safe-area-inset-* 为 re-calculated 立即。一个有点难看的修复程序,但如果您出于某种原因必须使用 UIWebView,它会起作用。

window.addEventListener("orientationchange", function() {
    var originalMarginTop = document.body.style.marginTop;
    document.body.style.marginTop = "1px";
    setTimeout(function () {
        document.body.style.marginTop = originalMarginTop;
    }, 100);
}, false);

代码的目的是使document.body.style.marginTop稍微改变然后反转它。它不一定必须是“1px”。您可以选择一个不会导致 UI 闪烁但达到其目的的值。

我开发 cordova 应用程序已有 2 年时间,我花了数周时间来解决相关问题(例如:键盘打开时 webview 滚动)。这是针对 ios 和 android

的经过测试和验证的解决方案

P.S.: 我正在使用 iScroll 滚动内容

  1. 切勿在 index.html 的元标记中使用 viewport-fit=cover,让应用远离状态栏。 iOS 将为所有 iPhone 变体处理适当的区域。
  2. 在XCode中取消选中隐藏状态栏需要全屏并且不要忘记select启动屏幕文件为 CDVLaunchScreen
  3. 在config.xml中设置全屏false
  4. 最后,(感谢 Eddy Verbruggen 提供了很棒的插件)添加他的插件 cordova-plugin-webviewcolor 来设置状态栏和底部区域的背景颜色。这个插件可以让你设置任何你想要的颜色。
  5. 在下面添加到config.xml(x 后的第一个 ff 是不透明度)

    <preference name="BackgroundColor" value="0xff088c90" />
    
  6. 通过向输入元素添加焦点事件来自行处理滚动位置

    iscrollObj.scrollToElement(elm, transitionduration ... etc)
    

对于 android,执行相同操作,但安装 cordova-plugin-statusbar 而不是 cordova-plugin-webviewcolorcordova-plugin-navigationbar-color

这是使用这些插件在 ios 和 android 上工作的 javascript 代码:

function setStatusColor(colorCode) {
    //colorCode is smtg like '#427309';
    if (cordova.platformId == 'android') {
        StatusBar.backgroundColorByHexString(colorCode);
        NavigationBar.backgroundColorByHexString(colorCode);
    } else if (cordova.platformId == 'ios') {
        window.plugins.webviewcolor.change(colorCode);
    }
}

看看这个 link,有时可能会有帮助。我可以使用下面提供的解决方案解决问题。 https://github.com/apache/cordova-plugin-wkwebview-engine/issues/108

添加

[wkWebView.scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];

在wkWebView.UIDelegate之前=self.uiDelegate;在 CDVWebViewEngine.m