在Android原生浏览器上检测作为主屏幕应用运行的Web应用程序

7
我们正在构建一个Web应用程序,该应用程序必须作为独立的/主屏幕应用程序使用。在Chrome和Safari中,我们可以使用window.navigator.standalonewindow.matchMedia('(display-mode: standalone)')来检测是从浏览器还是本地类似于浏览器的容器中查看它。但是,在默认的Android股票浏览器/Samsung Internet中,这两个选项似乎都不起作用。此外,我们也不能使用manifest.json中的start_url,因为我们需要向主屏幕应用程序传递每个用户唯一的令牌。
是否可能检测当使用Android股票浏览器添加应用时,是否从主屏幕打开应用?
相关:

嗯...三星浏览器是否支持您的 manifest.json?除非您专门针对三星手机,否则我希望大多数人都会安装Chrome或Firefox - 否则,看起来您在这里无能为力。您能详细说明一下 start_url 的问题吗?为什么不能使用 user_token=xxx&pwa=true 生成清单,然后使用JavaScript解析它呢? - sheng
用户收到包含用户令牌的链接的电子邮件。这意味着在那个时候,用户令牌只在客户端知道。从技术上讲,我可以在服务器端使用php从查询字符串中获取用户令牌,并在客户端请求时将其返回到自定义manifest.json中 - 或者甚至更糟糕的是,设置一个cookie,然后将其与manifest.json调用一起发送回来。我认为这两个选项都不是很好 - 也不是非常可靠。目前,所有用户的manifest.json都是相同的。 - Sumurai8
有趣的是,它不是书签,因为如果是书签,它就会有地址栏。浏览器的显示模式设置存在问题,这导致了我们遇到的问题,但除此之外,我还没有发现其他问题。 - Sumurai8
这可能会引起您的兴趣。https://github.com/SamsungInternet/support/issues/45 - sheng
如果您在三星文档中搜索“渐进式Web应用程序”,它保证支持,所以一定要支持它... https://developer.samsung.com/internet/android/web-guide - sheng
显示剩余2条评论
3个回答

5
据我所知,目前没有直接检测应用程序是否在三星浏览器中运行或作为独立应用程序在三星浏览器中运行的方法。我能找到的唯一区别是 window.innerHeight,因为它不包括地址栏。通过使用 window.screen.height 可以计算出比例。由于该浏览器可用于许多不同的设备,这并不能真正帮助您。对于独立应用程序,window.innerHeight 应该更大,但您并不一定知道独立应用程序与浏览器体验相比有多大。
// Imperfect solution
if ((window.innerHeight / window.screen.height) > 0.9) {
  // Some probability of this being a standalone app.
}

我发现的另一种解决方案是通过JavaScript设置清单文件,使我们能够为每个用户的起始URL设置唯一令牌。但是这种方法有几个缺点。通过JavaScript设置清单文件在技术上是不受支持的,如果您以这种方式创建清单文件,则您的应用程序将永远不会安装为Web APK。Firefox根本不支持动态生成的清单文件,而iOS缓存清单文件可能会引起自身的问题。Chrome开发工具也无法始终显示您清单文件中的内容。以下是部分内容来自这篇中等文章
// This approach has many caveats. Be aware of all of them before using this solution
import manifestBase from '../manifest.json';

const myToken = window.localStorage.getItem('myToken');
const manifest = { ...manifestBase };
manifest.start_url = `${window.location.origin}?standalone=true&myToken=${myToken}`;
const stringManifest = JSON.stringify(manifest);
const blob = new Blob([stringManifest], {type: 'application/json'});
const manifestURL = URL.createObjectURL(blob);
document.querySelector('meta[rel=manifest]').setAttribute('href', manifestURL);

您可以通过将manifest元标记的href属性设置为合理的默认值来解决FireFox的问题。如果您的唯一信息经常更改,甚至根本没有办法在iOS中解决这个问题。如果您的起始URL不是动态的,请根本不要通过JavaScript设置清单文件,而是使用一些信息(例如上面的standalone=true查询字符串)设置起始URL,以便区分独立应用程序和浏览器URL。
另外一个我发现的问题是,将浏览器模式设置为其他任何模式,如全屏模式,并不能“修复”Samsung Browser的错误。它永远不会将显示模式设置为除浏览器之外的任何东西,因此无法通过这种方式检测它。

1

今晚我想出了以下解决方案,经过尝试了许多不起作用的“解决方案”。我的理论是,手机上的任务栏高度为30px或更低,因此从屏幕高度中减去html的内部高度,如果剩余的高度为30像素或更低,则创建全屏规则,例如...

     var flScrn = (screen.height - innerHeight );
        if (flScrn < 30) {
            $('.installprompt').css("display","none");
        }

0

我遇到了同样的问题。在清单的start_url参数中提供参数的所有解决方案都不起作用,因为:

  • 清单中的start_url参数将被忽略(没有找到这个文档在哪里记录,但在我所有的测试中都是如此)
  • 如果url参数仍然传递给PWA,在Android上的Chrome浏览器中,您无法将该值存储在cookie中,以便仅对PWA可用,因为PWA的cookie将与浏览器共享,如下所述:

[如何使用独立浏览器分离PWA会话和cookie?][1] [1]: 如何使用独立浏览器分离PWA会话和cookie?(PWA作为私密标签)

(忘记尝试使用子域或类似方法的变通办法,因为PWA只能在安装它的完全相同的域上正常工作)。

我想出了一个变通办法,也适用于Android原生浏览器(在三星Galaxy S7 Edge上尝试过):

在清单中,为 PWA 指定一个唯一的起始 URL(因为 URL 参数将被忽略):
``` ... "start_url": "/pwa_start", ... ```
在定义 start_url 的页面上,使用如下带有 URL 参数的重定向来调用实际页面(示例为 PHP):
``` ```
使以下 JavaScript 函数成为您检查网站是否作为 PWA 运行的唯一方法,并确保它在您网站的所有页面上都可用并且至少在您正在重定向到的页面上被调用一次:
``` // 如果网站当前正以 PWA 应用程序方式运行,则返回 true,否则返回 false function isPWA() { // 尝试默认方法(仅在支持且以 PWA 方式运行时才为 true) if (window.matchMedia('(display-mode: standalone)').matches) return true;
// 另一种方法: if (!(window.sessionStorage || false)) return false; // 不支持会话存储 if (self.location.href.indexOf('?is_pwa=1') >= 0) { window.sessionStorage.setItem('isPWA', '1'); } return window.sessionStorage.getItem('isPWA') == '1'; } ```
如果页面作为 PWA 运行,则可以使用 JavaScript 向您的 `` 标签添加 CSS 类。这样,您就可以创建和使用 CSS 类“hidden-pwa”或“visible-pwa”,以在 PWA 和浏览器中显示不同的内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接