乘风破浪,遇见最美Windows 11之新微软商店(Microsoft Store)生态 - 通过渐进式Web应用(PWA)技术上架商店应用锦囊

什么是渐进式Web应用

image

渐进式Web应用(Progressive Web Apps, PWA)是指运用现代的Web API以及传统的渐进式增强策略来创建跨平台Web应用程序。这些应用无处不在、功能丰富,使其具有与原生应用相同的用户体验优势。

https://docs.microsoft.com/zh-cn/windows/uwp/publish/pwa/turn-your-website-pwa

基于现有Web网站对PWA特性支持的成果,可实现快速打包并完成Microsoft Store商店上架,这成为由Web驱动的应用上架商店的首选方式。

image

给现有Web网站添加PWA支持

image

给现有Web网站添加PWA支持主要是完成四大技术改造:

  1. 添加PWA图标。
  2. 准备并引入PWA清单文件。
  3. 注册并激活ServiceWorkerJs。
  4. 提供HTTPS安全环境。

生成PWA所需图标和清单文件

最佳途径:https://www.pwabuilder.com/imageGenerator

备用途径:

image

image

Web App清单文件示例

{
    "description": "someting description",
    "display": "standalone",
    "name": "product name",
    "short_name": "product name",
    "start_url": "/",
    "theme_color": "#ffffff",
    "icons": [
        {
            "src": "/images/logo-512.png",
            "type": "image/png",
            "sizes": "512x512",
            "purpose": "any"
        }
    ]
}

其中较为关键的几个元素包括:

  • 应用名称(name),这个用于确定应用的名称。
  • 应用短名称(short_name),这个用于当没有足够空间展示应用名称时备用。
  • 启动入口(start_url),这个用于用户启动应用的第一个页面位置。
  • 显示模式(display),这个用于定制应用的窗口显示模式,比如standalone就是独立窗口模式。
  • 主题颜色(theme_color),这个用于定制应用的在系统运行的主题色,比如Windows中窗体标题栏的颜色。
  • 图标素材组(icons),这个用于描述应用的素材,这个决定了应用安装和运行的图标,其中512x512是必须的。

更多细节定制可以参考文档:https://developer.mozilla.org/zh-CN/docs/Web/Manifest

更多图标素材组定制可以参考文档:https://github.com/pwa-builder/pwabuilder-windows-chromium-docs/blob/master/image-recommendations.md

引入PWA清单文件

在Web网站的Header中,可以以Link的方式直接引入它。

<!DOCTYPE html>
<html>

<head>
    <link rel="manifest" href="./manifest.webmanifest" />
</head>

</html>

或者

<!DOCTYPE html>
<html>

<head>
    <link rel="manifest" href="./manifest.json" />
</head>

</html>

注册PWA的ServiceWorker

<script type="text/javascript" async>
    if ("serviceWorker" in navigator) {
        window.addEventListener("load", function () {
            navigator.serviceWorker
                .register("/serviceWorker.js")
                .then(res => console.log("service worker registered"))
                .catch(err => console.log("service worker not registered", err));
        })
    }
</script>

那么serviceWorker.js内容是什么呢?

/* eslint-disable consistent-return */
// cache名, 在控制台Application的CaChe下可以看到
const cacheName = 'xxxxxxxxxxxxx';
// cache文件
const cacheFiles = ["/", "/index.html"];

/**
 * 安装 Service Worker
 * install事件是 Service Worker 执行的第一个事件,同一个 Service Worker 只会调用一次,
 * 即使 Service Worker 脚本文件只有一个字节不同,浏览器也将视为一个新的 Service Worker。
 */
// eslint-disable-next-line no-restricted-globals
self.addEventListener('install', (e) => {
    console.log('install');
    // eslint-disable-next-line no-restricted-globals
    self.skipWaiting();
    e.waitUntil(
        caches.open(cacheName).then((cache) => cache.addAll(cacheFiles)),
    );
});

/**
 * 激活 Service Worker
 * Service Worker 安装成功之后,会触发activate事件
 * 在这个阶段我们一般做一些清理旧缓存相关的工作
 */
// eslint-disable-next-line no-restricted-globals
self.addEventListener('activate', (e) => {
    console.log('activate');
    // e.waitUntil(caches.delete(cacheName));
    e.waitUntil(
        caches
            .keys()
            .then((keys) => Promise.all(
                // eslint-disable-next-line array-callback-return
                keys.map((key) => {
                    // 清理缓存
                    if (cacheName !== key) {
                        return caches.delete(key);
                    }
                }),
            ))
            .then(() => {
                console.log('cache deleted');
            }),
    );
});

// service worker发生更新后,刷新页面
// eslint-disable-next-line no-restricted-globals
self.addEventListener('controllerchange', () => {
    console.log('controllerchange');
    window.location.reload();
});


// eslint-disable-next-line no-restricted-globals
self.addEventListener('fetch', (e) => {
});

生成并测试商店包

生成本地测试包

打开微软官方的制作网站PWABuilder,把确定好并支持PWA的网站入口填写到输入框中,点击Start开始按钮。

image

等待分析结果。

image

这里每一项的检查结果都是以10分满分制,如果拿到10分说明没有问题,如果丢分了,就是可以优化的选项。

image

点击Next下一步按钮,就会进入最终的发布选择界面,排在前面的就是Microsoft Store的选项,这里我们可以点击Test Package按钮就可以获取到本地测试的商店包

image

image

点击Store Package按钮,它会要求我们填写我们在商店的一些应用信息,我们根据已知信息完成填写即可,填写完成后点击Generate按钮即可生成最终上架的商店包。

image

image

本地测试商店包

解压从PWABuilder获取的商店测试包,发现里面包含了几个文件,默认情况下,其中install.ps1是安装脚本,其中xxxxx.classic.appxbundle是Win10版本的传统商店包,其中xxxxxx.msixbundle是新式打包格式MSIX的商店包,其中xxxxx.sideload.msix是用于旁加载的安装包。

image

install.ps1安装脚本文件上右键,选择"使用PowerShell运行"

image

但是,这时候会遇到权限错误,这是因为根据系统本地的Powershell默认安全策略,是不允许直接运行这种不安全的脚本的。

image

这时候我们需要修改下Powershell默认安全策略,在开始菜单上右键,找到并进入"Windows终端(管理员)"选项,执行如下命令以便解除安全限制:

Set-ExecutionPolicy bypass -Scope CurrentUser

即可,可以通过如下命令确认权限是否完成修改:

Get-ExecutionPolicy -List

完成之后,我们再次重复在install.ps1安装脚本文件上右键,选择"使用PowerShell运行"

image

会看到,它正在使用xxxxx.sideload.msix包完成安装,完成成功之后,在开始菜单就可以看到应用图标了。

image

image

上架到Microsoft Store

创建MSIX or PWA类型应用

image

进入应用概况页面,前往左侧的产品管理-产品标识页面,这个页面里面包标识名称对应的就是Package Id,包标识发行商对应的是Publish ID,包发布者显示名称对应的是Publisher Display Name

image

填写应用商店资料

之前的上架指南填写应用相关商店资料并提交认证

受限功能

在完成提交之前,您必须执行的一个重要步骤是解释Windows应用程序所需的本机功能,称为"runFullTrust"。它由转换器工具自动添加并标记为"受限功能"。要通过审核,您必须导航到您的提交,然后打开"提交选项"并向审核团队提供注释。只需评论一下,此功能是由该工具自动添加的,一切都应该没问题 - 不再需要额外的工作。

runFullTrust权限要求是由PWABuilder转换工具自动添加的。

识别来自Microsoft Store的流量

https://stackify.dev/485391-detect-if-web-app-is-running-as-pwa-through-the-microsoft-store

方案1

正确的官方方法是检查.NET应用程序。当作为一个商店应用程序运行时,整个WinRT API表面被注入。因此,你可以(而且应该)做以下事情,而不是嗅探用户代理:window.Windows

if (window.Windows) {
  // running as a Windows app
}
else {
  // running in browser
}

方案2

我意识到,用户代理毕竟不是那么含糊的。

Microsoft Edge确实通过在其用户代理中添加MSAppHost/<WebView Rev>来表明它何时作为应用程序主机运行。

例如

在我的机器上,我托管的PWA的用户代理列出了 "MSAppHost/3.0"。

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; MSAppHost/3.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063

方案

对字符串MSAppHost/的测试揭示了网络应用程序是否以托管应用.navigator.userAgent的方式运行。

我现在在我的服务器端和客户端渲染中使用这个检查,以剥离任何链接到外部商店的内容。

方案3

你可以检查. 如果它等于app-info://platform/microsoft-store,你的网络应用就是从微软商店安装的。这个功能在Edge 91 document.referrer版本中首次引入。

<script>
    if(document.referrer === 'app-info://platform/microsoft-store')
    {
        // 代表当前运行来自微软商店,仅在Edge v91及其以上版本生效
    }
</script>

上面的实现会存在刷新后丢失判断的情况,因为页面刷新之后,document.referrer会发生变化,建议采用下面的实现方式:

<script>
    // Compatible with ms store
    const fromMsStore = document.referrer === 'app-info://platform/microsoft-store' || localStorage.getItem('referrer-ms-store')

    localStorage.setItem('referrer-ms-store', fromMsStore)

    if (fromMsStore)
    {
        // 代表当前运行来自微软商店,仅在Edge v91及其以上版本生效
    }
</script>

参考

posted @   TaylorShi  阅读(411)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示