【问题标题】:ios PWA How to open external link on mobile default safari(not In app browser)ios PWA 如何在移动默认 safari 上打开外部链接(不在应用浏览器中)
【发布时间】:2020-06-01 16:49:27
【问题描述】:

我正在 IOS 13.2 中制作 PWA。

我需要通过单击外部链接从我的应用启动另一个 PWA。

问题是我当前的 PWA 在应用内浏览器中打开所有外部链接,而不是常规 safari,并且在应用内浏览器中没有添加到主屏幕选项。

如何强制 PWA 在常规 safari 而不是应用内 safari 中打开外部链接?

不起作用的东西

  • 更改清单文件中的范围
  • 使用rel="noreferrer"
  • 使用target="_blank"

【问题讨论】:

  • 我的 safari 也有同样的问题,我想在另一个链接中使用 cameraAPI,但在独立模式下,我无法访问相机
  • 我找到了一种解决方法,但它很糟糕。从我的清单中删除“独立”以防止我的 PWA 作为 PWA 打开!!!您找到任何解决方案了吗? @Victor-Belashov
  • 这是一个使用 cordova 包装您的网络应用程序的“PWA”吗?就像您使用 PWABuilder 获得的一样。
  • 如果在href 上使用target="_blank 会发生什么?我没有要测试的设备。我假设 chromeless PWA 窗口无法处理该请求,它可能会触发 Safari。
  • @BryceHowitson target="_blank" 仍将使用应用内浏览器,而不是在正常的 safari 视图中打开。

标签: javascript html css ios progressive-web-apps


【解决方案1】:

这个问题(以及所有 cmets)有点难以回答,因为用例不是很清楚,但是这里......

在移动设备上,“应用内浏览器”与在全屏模式下运行的渐进式 Web 应用不同。

如果 iOS 应用程序运行并在其中显示 HTML 内容,则它使用的是 UIWebViewWKWebView。但是,对于 PWA,它已经在 Safari 中作为“全屏”体验运行。 定义您要从中断开链接非常重要,因为它们的功能不同。

target="_blank" 通常会使用 WebView 将链接从页面中断开。我相信这也是当前域外链接的默认功能。

“已安装”的 PWA 以一种称为“独立”的模式运行。这使它成为全屏并删除导航栏等。在撰写本文时,Safari 不支持其他浏览器正在实施的fullscreen API。 Chrome 使用应用清单文件来确定此功能。 Safari 基本上会忽略清单,而支持专有元标记。

在这种情况下,<meta name="apple-mobile-web-app-capable" content="yes"> 告诉 Apple 将页面设置为独立应用程序。尝试在应该脱离独立模式的页面上设置content="no"(Safari 会大量缓存内容,因此您可能需要强制刷新)。您可以使用此 javascript boolean window.navigator.standalone 来检查页面认为它处于什么模式。

或者您可以使用 javascript 在 Safari 中强制打开“新窗口”,只要您的目标是不同的子域或 HTTP 而不是 HTTPS

// if app is hosted from https://example.com
if (("standalone" in window.navigator) || window.navigator.standalone ) {
    window.open('http://example.com/page', '_blank');
}

最后,Apple 使用了一些 special URL strings 来让原生应用处理一些操作,例如电子邮件、电话号码和 youtube 视频。您或许可以“破解”该功能,让 Safari 浏览器打开您的链接。

【讨论】:

  • 这些是一些非常好的建议!不幸的是,window.openwindow.location.href 都打开了应用内浏览器。我不完全理解设置content="no" 的意思。如果在您链接的页面上完成,则该页面将停止处于全屏模式(至少如果 safari 识别出您进行了此更改)。如果您将其设置在您要链接到该页面的页面上,它将不再是一个全屏应用程序,这会破坏整个目的。
  • 关于 URL 方案我真的认为这是解决这个问题的一种方法,但似乎没有用于 safari 的 URL 方案:stackoverflow.com/a/22644889/7446618
  • @JensVæverHartfelt 我认为您应该提出一个完全描述您的用例的新问题。当您可能需要或不需要与 OP 相同的东西时,很难为您提供帮助。
  • 感谢您的反馈,但 OP 的问题与我的完全相同,因此新问题只会重复相同的内容。我已将 OP 的问题编辑得更简洁,并添加了一些无法解决问题的建议解决方案。我还添加了一个解决方法作为答案。
  • 嗯,我不知道如何进一步澄清它。也许通过将图像添加到 OP 的原始问题? Target="_blank" 听起来很适合原生应用程序,但它们的行为与 iOS 上的 PWA 不同。通过 PWA,我指的是从 iOS 的主屏幕打开的已安装 PWA。通过应用内浏览器,我指的是从 PWA 中打开任何指向外部域的链接时使用的浏览模式。转到本文中的标题“无法使用 Safari 打开链接”:medium.com/@firt/… 了解我的意思。
【解决方案2】:

经过相当彻底的调查,我认为目前(在 iOS 13.X 和 iOS 14.1 之间)这是不可能的。

以下 javascript API 将使用应用内浏览器:

  • window.open()
  • window.location.href =

使用锚标记也将使用应用内浏览器,无论它被分配什么属性。更改清单中的范围也无济于事。

但是我确实找到了一种方法,至少可以提示用户他们在应用内浏览器中,以使用户体验不那么混乱。

有两种方法(也许更多?)来检测浏览器是否独立:window.matchMedia("(display-mode: standalone)").matcheswindow.navigator.standalone 。这是奇怪的部分:

// regular safari
window.navigator.standalone -> false
window.matchMedia("(display-mode: standalone)").matches -> false

// full screen apps (only pwas, weirdly enough this doesn't apply to pre-pwa web apps on iOS)
window.navigator.standalone -> true
window.matchMedia("(display-mode: standalone)").matches -> true

// in-app browsers launched from within a PWA 
window.navigator.standalone -> true
window.matchMedia("(display-mode: standalone)").matches -> false

我假设 window.navigator.standalone 代表 pwa 的父上下文,window.matchMedia("(display-mode: standalone)").matches 代表应用内浏览器的上下文。

所以一个简单的实现来检查您的应用是否在 iOS 上的应用内浏览器中运行:

function isIOSInAppBrowser() {
  // Check if device is iPad, iPhone or iPod (this bit is naive and should probably check additional stuff)
  if (Boolean(window.navigator.userAgent.match(/iPad|iPhone|iPod/)) === false) return false;

  // Check if navigator is standalone but display-mode isn't
  if (window.navigator.standalone === true && window.matchMedia("(display-mode: standalone)").matches === false) {
    return true;
  } else {
    return false;
  }
}

请注意,此实现并不可靠,并且在未来的 iOS 版本中很容易产生误报

【讨论】:

  • isIOSInAppBrowser 功能对我不起作用。当我在应用内浏览器中打开它时,它返回 false。 iOS 14.2
  • 哦.. 也许他们在 14.1 之后改变了这种行为。我会尝试一下,看看我是否得到类似的结果
  • 我刚刚对其进行了测试,它似乎在 14.1 和 14.3 上对我有用(我目前没有要测试的 14.2 模拟器),但请记住,它只处理相当小众的问题- 全屏 Web 应用(pwa 或旧版主屏幕应用)在其上运行应用内浏览器的情况。我还没有针对此范围之外的应用内浏览器对其进行测试
【解决方案3】:
@IBAction func openURL(_ sender: Any) {
// check if website exists
guard let url = URL(string: "https://apple.com") else {
    return
}

let safariVC = SFSafariViewController(url: url)
    present(safariVC, animated: true, completion: nil)
}

【讨论】:

    【解决方案4】:

    我会亲自尝试target="_blank"href 链接。我还将添加一个rel="noreferrer external" 以确保这在不同的 webview 实现中是一致的。虽然我不完全确定它在 iOS 中是如何工作的,但也应该有一种方法可以通过清单文件执行此操作。

    【讨论】:

    • 从 iOS12.2 开始就不是这样了
    • reltarget 对此均无任何影响。清单文件中的范围将控制链接是使用应用内浏览器打开还是作为独立的“无铬”页面打开,但它对链接是否在应用内 safari 和常规 safari 中打开没有任何影响跨度>
    【解决方案5】:

    这将在所有支持 PWA 的 iOS 版本上完美运行。 (我知道这一点是因为我是 iOS 的老用户):

    target="_blank" 添加到您拥有的所有链接中。这将在移动默认 Safari 中打开它们。

    例如:

    <a href="/page" target="_blank">Page</a>

    【讨论】:

    • 这可能适用于某些但不是最近的应用程序浏览器中的功能障碍。这可能有一些好处(共享上下文以允许 oauth 工作),但它会在其他事情上中断(外部站点上的外部链接不起作用) - 相反,控制它会很有用,这样你可以将应用内的 oauth 和功能性应用用于其他人。
    • 您的评论不正确。这应该在所有设备上都可以正常工作
    • 很遗憾没有;现代 iOS 将您留在应用内浏览器中,您可能会将其误认为是 Safari,但并不完全相同。不过,我在外部网站评论上的外部链接不正确;使用 target="_blank" 的应用内浏览器中的链接不起作用(应用内浏览器似乎仅限于单个窗口),但其他链接可以,这意味着如果您控制外部站点,您可以解决它链接到。
    • 我没记错。问题是针对渐进式 Web 应用程序而不是应用程序
    • 是的,我的答案也适用于 PWA。 This article 可能会提供一些上下文。您的答案可能在某个时间点是正确的,并且对于较旧的 iOS 版本可能仍然正确,但对于更新的版本则不正确。
    【解决方案6】:

    您的应用的工作方式取决于您在 manifest.json 文件中的配置。

    manifest 文件中,scope 键将决定在 PWA 中打开哪个链接以及在浏览器中打开哪个链接。

    例如myapp 下的路由将在 PWA 内部打开,其他将在外部。

    {
      "name": "My App",
      "start_url": "/myapp",
      "scope": "/myapp",
      "display": "standalone"
    }
    

    【讨论】:

    • 这是真的,但 OP 要求在常规 safari 或应用内 safari 中打开链接,这对此没有影响
    猜你喜欢
    • 2017-11-26
    • 2021-04-02
    • 2018-11-03
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    • 1970-01-01
    • 1970-01-01
    • 2016-08-15
    相关资源
    最近更新 更多