cover_image

钉钉H5微应用实现桌面快捷方式

章文亮 Goodme前端团队 2024年07月23日 00:02

一、背景

在我们公司的很多内部应用,都以钉钉为宿主环境。因此打开一个应用的里的某个功能,都至少要经过钉钉->从聊天切换到应用列表->打开应用->打开次级页面或功能,这样层层菜单区寻找。因此基于提高效率、方便使用的出发点,我们希望能够像微信小程序一样,借助于生成桌面快捷方式解决这个问题。

二、调研

很可惜,钉钉H5微应用并没有像微信小程序那样提供添加到桌面的功能支持。但是我们发现微信小程序在IOS端创建桌面快捷方式的过程其实是以Safari浏览器的添加到桌面的功能为媒介的。

PWA(Progress Web Application)

PWA技术允许应用从设备主屏直接启动,而不需启动浏览器键入 URL。你的 Web 应用可以作为一等公民和原生应用肩并肩。这样可以使应用更易于访问,你还可以指定应用全屏运行,没有浏览器界面,这样看起来更像一个原生应用。该功能的操作步骤为:

  • 当用户使用支持的移动浏览器访问 PWA 时,浏览器会显示一条横幅信息表示可以安装这个应用。
  • 在用户单击这个横幅后,安装横幅信息会显示出来。它是浏览器基于网页清单信息创建的,名字和图标可以在提示中看到。
  • 如果用户单击安装到主屏按钮,会显示应用图标的样子,让用户确认是否安装这个应用。
  • 确认之后,应用就安装到主屏上了。

图片

我们也可以通过 “让 PWA 易于安装 - 渐进式 Web 应用(PWA) | MDN ”(https://developer.mozilla.org/zh-CN/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs)这篇文章来了解移动浏览器添加到主屏的具体信息。那么我们就对微信小程序的该功能进行详细的分解。

微信小程序添加到桌面过程分解

  • 点击微信通过右上角的胶囊,打开的看板里添加到桌面的图标,如下图:

图片

点击后安卓就直接在桌面生成了快捷方式,而IOS不一样。

  • IOS启动Safari浏览器,并打开用户操作引导页,如下图:

                                                                   

 图片

 图片


  • 用户根据操作指引页添加了快捷方式,点击快捷方式后,打开落地页

图片

  • 点击前往微信打开,冷/热启动微信小程序

以上是微信小程序添加到桌面的用户最短路径,但是如果第二步里用户没有按照操作指引去生成快捷方式,而再次使用Safari打开短链会是怎样呢?试一下吧。

  • 未添加到桌面前,再次Safari打开生成的链接,仍然展示操作指引页。
  • 添加到桌面后,再次Safari打开生成的链接,展示为落地页。
  • 将该链接分享给别人打开,展示为操作指引页。

分析总结

  • 通过以上分析我们不难理解微信小程序添加到桌面是分为以下几步:

1、每次生成一个链接并启动Safari打开。

2、判断当前用户是否消费了该页面去生成了快捷方式:

      a.已经生成了:则打开快捷方式落地页

      b.未生成:则打开用户操作指引页

3、落地页自动/手动点击冷/热启动小程序

三、方案设计

通过调研我们可以利用PWA里移动浏览器添加到主屏的特性+钉钉微应用的AppLink能力(打开H5微应用 - 开放平台,https://open.dingtalk.com/document/isvapp/open-h5-micro-application)来实现桌面快捷方式

1. 生成链接并启动浏览器打开

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}`;
  }
}

2. 判断该链接是否被当前客户端消费过

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,
  })
);

3. 如果没被消费过,则展示用户操作指引页


  {
    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>
  )

4. 如果被消费过了,则展示快捷方式落地页,并自动跳转到应用

useDidShow(() => {
  if (!isFirstVistRef.current) {
    goDDpage(); // 利用钉钉微应用的AppLink打开H5
  }
});

5. 利用设备清单信息在主屏上显示应用图标和文字,启动画面

<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关闭当前所有页面,跳转到应用内的某个指定页面)。

  1. 如 钉钉 -> 微应用首页 -> 列表页 【添加到桌面快捷方式】 此时页面堆栈为 :首页 + 列表页
  2. 使用桌面快捷方式自动打开列表页 :此时页面堆栈为 :首页 + 列表页 + 列表页
  3. 再次使用桌面快捷方式自动打开列表页 :此时页面堆栈为 :首页 + 列表页 + 列表页 + 列表页

我们翻阅了钉钉的开发者文档,对于微应用的打开方式,只有小程序类型的应用支持Relaunch,因此这个问题我们在技术侧目前没有太好的解决方法。目前的方案是在产品设计侧约定快捷方式打开的都是一级页面弱化次级页面要返回多层的弊端。



继续滑动看下一个
Goodme前端团队
向上滑动看下一个