在我们公司的很多内部应用,都以钉钉为宿主环境。因此打开一个应用的里的某个功能,都至少要经过钉钉->从聊天切换到应用列表->打开应用->打开次级页面或功能,这样层层菜单区寻找。因此基于提高效率、方便使用的出发点,我们希望能够像微信小程序一样,借助于生成桌面快捷方式解决这个问题。
很可惜,钉钉H5微应用并没有像微信小程序那样提供添加到桌面的功能支持。但是我们发现微信小程序在IOS端创建桌面快捷方式的过程其实是以Safari浏览器的添加到桌面
的功能为媒介的。
PWA技术允许应用从设备主屏直接启动,而不需启动浏览器键入 URL。你的 Web 应用可以作为一等公民和原生应用肩并肩。这样可以使应用更易于访问,你还可以指定应用全屏运行,没有浏览器界面,这样看起来更像一个原生应用。该功能的操作步骤为:
我们也可以通过 “让 PWA 易于安装 - 渐进式 Web 应用(PWA) | MDN ”(https://developer.mozilla.org/zh-CN/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs)这篇文章来了解移动浏览器添加到主屏的具体信息。那么我们就对微信小程序的该功能进行详细的分解。
点击后安卓就直接在桌面生成了快捷方式,而IOS不一样。
以上是微信小程序添加到桌面
的用户最短路径,但是如果第二步里用户没有按照操作指引去生成快捷方式,而再次使用Safari打开短链会是怎样呢?试一下吧。
分析总结
添加到桌面
是分为以下几步:1、每次生成一个链接并启动Safari打开。
2、判断当前用户是否消费了该页面去生成了快捷方式:
a.已经生成了:则打开快捷方式落地页
b.未生成:则打开用户操作指引页
3、落地页自动/手动点击冷/热启动小程序
通过调研我们可以利用PWA里移动浏览器添加到主屏
的特性+钉钉微应用的AppLink能力(打开H5微应用 - 开放平台,https://open.dingtalk.com/document/isvapp/open-h5-micro-application)来实现桌面快捷方式
1.1. 由于钉钉微应用的看板我们无法定义进行控制,且没有添加到桌面的按钮。故我们退而求其次,通过在应用内指引用户去使用浏览器打开。如图:
1.2. 默认浏览器打开
的是当前页面地址,无法额外创建一个链接。因此我们要在项目里对入口进行拦截并区分是正常打开业务功能还是打开快捷方式功能。这里区分条件是:如果在手机浏览器打开则认定为展示用户操作指引页。
// 如果是 手机端非钉钉浏览器则默认打开的是快捷方式
const [isNeedAdddToDeskTop] = useState(isMobileUserAgent());
useJumpToDesktopPage();
if (isMobileUserAgent() && dd.env.platform === 'notInDingTalk') {
console.log('window.location.href 2', window.location.href);
// 添加到桌面场景时 拦截业务页面
if (window.location.href.indexOf('desktop') < 0) {
const newQuery: any = { ...(params || {}), time: new Date().getTime() };
const fullPath = `${path}?${Object.keys(newQuery)
.map((key) => `${key}=${newQuery[key]}`)
.join('&')}`;
console.log('fullPath', fullPath);
const redirectPath = `${encodeURIComponent(fullPath || '/')}`;
// 如果使用 next 跳转,由于next 是用hash替换,导致添加到桌面时是原路径而不是添加到桌面的路径
window.location.href = `/new/pages/package/desktop/index?redirect=${redirectPath}`;
}
}
const storeKey = `${redirectPath}`;
const storeValueObj = JSON.parse(localStorage.getItem(storeKey) || '{}');
const prevCount: number = storeValueObj?.count || 0;
const currentCount = `${prevCount * 1 + 1}`;
const isSamePage = storeKey === storeValueObj?.storeKey && storeValueObj?.time === queryObj?.time;
const isFirstVistRef = useRef(!isSamePage);
console.log('isFirstVist', isFirstVistRef.current);
localStorage.setItem(
storeKey,
JSON.stringify({
time: queryObj?.time,
count: isFirstVistRef.current ? 1 : currentCount,
storeKey,
})
);
{
isFirstVistRef.current ? (
<div className="guide-add-area">
<h3>添加伙伴通到主屏幕</h3>
<p>1、轻触底部「分享」</p>
<img src="//g.xxx.com/desktop-navigator.png" alt="伙伴通" />
<p>2、选择「添加到主屏幕」</p>
<img src="//g.xxx.com/desktop-add.png" alt="伙伴通" />
</div>
)
useDidShow(() => {
if (!isFirstVistRef.current) {
goDDpage(); // 利用钉钉微应用的AppLink打开H5
}
});
<link rel="manifest" href="https://g.xxx.com/manifest.json">
<link rel="manifest" href="https://g.gxxxxxx.com/manifest.webmanifest">
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="https://g.xxx.com/desk-icon.png">
<link rel="apple-touch-icon" sizes="72x72" href="https://g.xxx.com/desk-icon.png" />
<link rel="shortcut icon" href="https://g.xxx.com/desk-icon.png" />
在一些浏览器中,可以通过清单信息产生一个启动画面,当 PWA 启动时显示。
这个启动画面由给定的图标、主题和背景色生成。
以上我们详细阐述了如何实现钉钉H5微应用如何实现桌面快捷方式,但是我们还遗漏了一个问题
快捷方式打开微应用页面推进了一个路由,历史栈记录加一,而不是Relaunch
(调用reLaunch关闭当前所有页面,跳转到应用内的某个指定页面)。
我们翻阅了钉钉的开发者文档,对于微应用的打开方式,只有小程序类型的应用支持Relaunch,因此这个问题我们在技术侧目前没有太好的解决方法。目前的方案是在产品设计侧约定快捷方式打开的都是一级页面弱化次级页面要返回多层的弊端。