前提须知
笔者公司的我的项目在微信端的功能定位为根底性能交易及服务,告诉用户交易揭示、交易流水等,而 APP 为次要的交易性能。之前是在多个页面有引流按钮跳转至 App,性能点比拟粗犷,间接 location.href = 利用宝链接。当初产品有需要,说要用微信提供的标签来唤起 App

需要点:
所有跳转至 App 下载页面的局部,改成
Demo 后行
遇事不决,官网文档。查看后与微信 JS-SDK 性能点很像,这里我不废话,间接跳过。依照官网 demo,把示例写进业务代码中

import React, { useEffect, useRef } from 'react';import { toDownloadApp, isWechat, getWeixinVersion } from 'utils';const Download = () => {    const wxRef = useRef(null)    useEffect(() => {        if (wxRef.current) {            // @ts-ignore            wxRef.current?.addEventListener('launch', function (e: any) {                console.log('success');            });            // @ts-ignore            wxRef.current.addEventListener('error', function (e) {                console.log('fail', e.detail);                toDownloadApp()            });        }    }, [])    const onHandleClick = () => {         toDownloadApp()    }    return (        <div className="Download" onClick={onHandleClick}>            {/*  @ts-ignore */}            <wx-open-launch-app                ref={wxRef}                appid="XXXX"            >                <script type='text/wxtag-template'>                    <button>App内查看</button>                </script>                {/*  @ts-ignore */}            </wx-open-launch-app>        </div>    )}export default React.memo(Download);

测试胜利,demo 能跑通

组件试点
当初搞业务,以这个组件(Download)为试点开展,我要点击页面顶部的卡片(多个中央应用,抽离成 Download 组件),让其唤起 App,然而要判断其版本,如果版本过低,让其跳转至利用宝

import React, { useState, useEffect, useRef } from 'react';import LogoImg from '@/assets/images/logo.png';import { toDownloadApp, isWechat, getWeixinVersion } from 'utils';const Download = () => {    const wxRef = useRef(null)    const [enableLaunchWeapp, setEnableLaunchWeapp] = useState(false);    useEffect(() => {        const wxVersion = isWechat() && getWeixinVersion() || ''        if (wxVersion) {            let v = wxVersion.split('.')            if (Number(v[0]) >= 7) {                if (Number(v[1]) >= 0) {                    if (Number(v[2]) >= 12) {                        setEnableLaunchWeapp(true)                    }                }            }        }        if (wxRef.current) {            // @ts-ignore            wxRef.current?.addEventListener('launch', function (e: any) {                console.log('success');            });            // @ts-ignore            wxRef.current.addEventListener('error', function (e) {                console.log('fail', e.detail);                toDownloadApp()            });        }    }, [])    const onHandleClick = () => {        if (!enableLaunchWeapp) {            toDownloadApp()        }    }    return (        <div className="Download" onClick={onHandleClick}>            <div className="Download__logo">                <img src={LogoImg} alt="logo" />            </div>            <div className="Download__content">                <div className="Download__content-title">雅美App</div>                <div className="Download__content-desc">长泽雅美服务专区</div>            </div>            {/* <div>1</div> */}            <div className="Download__btn">立刻关上</div>            {/*  @ts-ignore */}            <wx-open-launch-app                ref={wxRef}                appid="XXXXX"                style={{ position: 'fixed', top: 0, left: 0, width: '100%', height: '60px', opacity: 0.3, background: 'blue' }}            >                <script type='text/wxtag-template'>                    <div style={{ position: 'fixed', top: 0, left: 0, width: '90%', height: '100%', opacity: 0.3, background: 'red' }} />                </script>                {/*  @ts-ignore */}            </wx-open-launch-app>        </div>    )}export default React.memo(Download);

成果如下所示:

思路逻辑参考:wx-open-launch-weapp 款式问题,我也给它配上色彩,不便后续察看

测试同步,能点击卡片跳转,好,下一步,在所有须要点击跳转页面的中央退出相似这样的代码

<wx-open-launch-app    ref={wxRef}    appid="XXXX"    style={{ position: 'fixed', top: 0, left: 0, width: '100%', height: '60px', opacity: 0.3, background: 'blue' }}    >    <script type='text/wxtag-template'>        <div style={{ position: 'fixed', top: 0, left: 0, width: '90%', height: '100%', opacity: 0.3, background: 'red' }} />    </script>    {/*  @ts-ignore */}</wx-open-launch-app>

封装组件 WxOpenLaunchApp
如果是这样,就能够将其封装成一个组件了,起个名吧: WxOpenLaunchApp

将唤起 App 的内容包装成一个组件,暴雷 children 和 style 两个 props,代码如下:

import React, { useEffect, useRef, forwardRef } from 'react';import { toDownloadApp } from 'utils';export interface WxOpenLaunchAppProps {    children: React.ReactNode;    style?: React.CSSProperties;}const WxOpenLaunchApp: React.FC<WxOpenLaunchAppProps> = props => {    const { style, children } = props;    const wxRef = useRef(null)    useEffect(() => {        if (wxRef.current) {            // @ts-ignore            wxRef.current?.addEventListener('launch', function (e: any) {                console.log('success');            });            // @ts-ignore            wxRef.current.addEventListener('error', function (e) {                console.log('fail', e.detail);                toDownloadApp()            });        }    }, [])    return (        <div className="wx-open-launch-app">            {/*  @ts-ignore */}            <wx-open-launch-app                ref={wxRef}                appid="XXXX"                style={style}            >                <script type='text/wxtag-template'>                    {children}                </script>                {/*  @ts-ignore */}            </wx-open-launch-app>        </div>    )}export default React.memo(WxOpenLaunchApp);

那么 Download 组件也就能够洁净很多

...const Download = () => {    ...    return (        ...            <div className="Download__btn">立刻关上</div>            {/*  @ts-ignore */}            <WxOpenLaunchApp style={{ position: 'fixed', top: 0, left: 0, width: '100%', height: '60px', opacity: 0.3, background: 'blue' }}>                <div style={{ position: 'fixed', top: 0, left: 0, width: '100%', height: '100%', opacity: 0.3, background: 'red' }} />            </WxOpenLaunchApp>        ...    )}...

业务组件 OpenAppPopup
回到需要点,每个点击的中央都要弹出弹出框,点击 关上 App ,再唤起 App,这样的话,弹出框 + WxOpenLaunchApp 就能够联合成一个组件,放进去供页面调用,名字就叫 OpenAppPopup ,代码如下:

import React, { FC } from 'react';import { Popup, WxOpenLaunchApp, Toast } from 'components'; // 此乃公司自研组件库export interface OpenAppPopupProps {    show: boolean;    onCancel: () => void;    onSubmit: () => void;}const OpenAppPopup: FC<OpenAppPopupProps> = (props) => {    const { show, onCancel, onSubmit } = props;    return (        <Popup.Group show={show}>            <Popup.Confirm                title="道歉,此性能需在雅美App中应用"                btnSubmitText={                    <div style={{ position: 'relative' }}>                        关上App                        <WxOpenLaunchApp style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', opacity: 0.3, background: 'blue' }}>                            <div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', opacity: 0.6, background: 'red' }} />                        </WxOpenLaunchApp>                    </div>                }                onCancel={onCancel}                onSubmit={onSubmit}            />        </Popup.Group>    )}export default React.memo(OpenAppPopup);

示意图如下:

接着在所有有跳转 App 的页面上用上这块逻辑即可

封装 HOOK
每个页面点击相似 下载App 按钮时,会弹出 OpenAppPopup,点击 关上App,须要判断你的微信版本,是否达到 7.0.12,如果每个页面都要加上这段

const wxVersion = (isWechat() && getWeixinVersion()) || ''if (wxVersion) {  let v = wxVersion.split('.')  if (Number(v[0]) >= 7) {    if (Number(v[1]) >= 0) {      if (Number(v[2]) >= 12) {        setEnableLaunchWeapp(true)      }    }  }}

真的太恶心了,果决抽离成 hook。代码如下:

import { useState, useEffect } from 'react';import { isWechat, getWeixinVersion } from 'utils';const useEnableLaunchWeapp = () => {    const [enableLaunchWeapp, setEnableLaunchWeapp] = useState(false);    useEffect(() => {        const wxVersion = isWechat() && getWeixinVersion() || ''        if (wxVersion) {            let v = wxVersion.split('.')            if (Number(v[0]) >= 7) {                if (Number(v[1]) >= 0) {                    if (Number(v[2]) >= 12) {                        setEnableLaunchWeapp(true)                    }                }            }        }    }, [])    return enableLaunchWeapp}export default useEnableLaunchWeapp;

逻辑也很简略,在刚加载时判断它是否能够点击,能够点击,就设置 enableLaunchWeapp 为 true。应用办法也很简略

import React, { useState, useEffect } from 'react';import { Dispatch, History } from 'umi';import {  OpenAppPopup } from 'components';+import { useEnableLaunchWeapp } from 'hooks';import { toDownloadApp } from 'utils';interface KVProps {    history: History;}const KV: React.FC<KVProps> = (props) => {    const { history } = props;    const [isShow, setIsShow] = useState(false);    +const enableLaunchWeapp = useEnableLaunchWeapp();    const onHandleClickToBuy = () => {        setIsShow(true);    };    const onHandleClickToSubmit = () => {        +if (!enableLaunchWeapp) {        +    toDownloadApp()        +}    }    return (        <div className="KV" style={{ background: kvBgColor }}>            <div className="KV__content">                <img src={img} alt="" />            </div>            <OpenAppPopup                show={isShow}                onCancel={() => {                    setIsShow(false);                }}                onSubmit={onHandleClickToSubmit}            />        </div>    );};export default React.memo(KV);

与 App 交互
需要点里说:要在所在页面跳转至 App 绝对页面,文档上写的很显著,能够传参数 extinfo="your-extinfo",轻易写了个让客户端同当时测试先

未唤醒 App
我手机是 IOS 的,是能够唤起的,然而安卓共事调试的时候说,后盾运行时,能够唤起 App,然而没有切换动作;如果杀掉过程,就无奈唤起。而这问题,大概率是 SDK 配置的问题,共事看了半天没解决,扔给他 Android 接入指南 。我又看不懂 Android,只能看他了

如果测试胜利,能跳过去,那么就把本页链接当作 extinfo 传过来,他那边接管到 extinfo 后,做个映射表,跳转至本身的页面即可,所以 WxOpenLaunchApp 须要革新,多一个 extinfo 参数。。。

后记
因为咱们用的是 flutter,共事说,因为引入的第三方库不反对,所以跳不过来,所以这个性能要后置,等他搞定了我再做更新
错误处理
除了在 WxOpenLaunchApp 组件中退出监听 error,谬误就让它跳转至 App 外,还要做当微信或者零碎版本不反对微信标签时,须要监听并进行回退兼容,代码如下:

document.addEventListener('WeixinOpenTagsError', function (e: any) {  console.error(e.detail.errMsg) // 无奈应用凋谢标签的谬误起因,需回退兼容。仅无奈应用开发标签,JS-SDK其余性能不受影响  toDownloadApp()})

总结
又复用就抽离成组件

必须要上生产环境,所以最好是有个预生产环境