新手必看!帮你踩坑h5的微信生态~

H5 与 微信, 小程序 交互速查手册

适用端:H5(微信内 & 非微信内)、微信小程序;

关键词:(微信/非微信)微信支付、OAuth2、小程序跳转、微信 SDK、二维码扫码、h5链接卡片分享聊天/朋友圈;

微信支付:(微信环境/非微信环境 - 使用微信支付)

微信SDK:-API能力使用:扫码,分享,微信h5打开小程序 等...

非微信环境:H5打开小程序,通过明文 scheme 形式,最多携带512字符(纯前端完成)

微信内:扫码打开小程序指定页面(携带参数)


1. 环境判断

环境 UA 特征 判断示例
微信内 MicroMessenger const isWechat = /MicroMessenger/i.test(navigator.userAgent)

2. 微信支付

2.1 微信内(JSAPI)

1. 获取 code(静默授权)
js 复制代码
const appId = 'wx********';
const redirectUri = encodeURIComponent(window.location.href);
const authUrl =
  `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}` +
  `&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`;
// 微信授权
location.href = authUrl;
2. 调起支付
php 复制代码
// 拉起微信支付相关  - 详细见文档(签名等内容是 服务端调用wx接口拿到的)

WeixinJSBridge.invoke('getBrandWCPayRequest', {
    appId: payInfo.appId,
    timeStamp: payInfo.timeStamp,
    nonceStr: payInfo.nonceStr,
    package: payInfo.package,
    signType: payInfo.signType,
    paySign: payInfo.paySign
    }, (res) => {
    if (res.err_msg === 'get_brand_wcpay_request:ok') {
      // 支付成功
    }
});

2.2 非微信内(H5,MWEB)

js 复制代码
// 支付方式为 [tradeType: 'MWEB']: 
// 支付相关参数传给服务端 appid 还有业务相关参数 换取 'mweb_url' 地址 ,通过url 跳转到三方的支付链接,
// 支付完成后返回 'redirect_url' 
const url = `${payInfo.mweb_url}&redirect_url=${encodeURIComponent(window.location.href)}`;
window.location.href = url

3. 非微信环境 → h5跳转小程序

3.1 配置那些页面开启 scheme访问

js 复制代码
import pako from 'pako'; // 压缩库

const jumpMiniParams = { foo: 'bar' };

// 如需压缩
const compressed = pako.gzip(JSON.stringify(jumpMiniParams));
const zipText = btoa(String.fromCharCode(...compressed));
const encodedQuery = encodeURIComponent(`zipText=${zipText}`);

// 无需压缩
// const encodedQuery = encodeURIComponent(Object.entries(jumpMiniParams).map(([k, v]) => `${k}=${v}`).join('&'));

const appid = 'wx************';
const path = 'subPages/***/index';
const envVersion = 'trial'; // develop / trial / release
const deepLink = `weixin://dl/business/?appid=${appid}&path=${path}&query=${encodedQuery}&env_version=${envVersion}`;

window.location.href = deepLink;

3.2小程序端解析

js 复制代码
  // h5端无压缩则直接使用 小程序的携带参数解析即可 => 小程序 onLoad(options)
  const { zipText } = options;

  // window.atob 兼容性处理(解压场景 - 若h5端无压缩步骤无需关注下面的内容)
  const weAtob = (string: string): string => {
    const b64re =
      /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/;
    const b64 =
      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';

    // 去除空白字符
    string = String(string).replace(/[\t\n\f\r ]+/g, '');

    // 验证 Base64 编码
    if (!b64re.test(string)) {
      throw new TypeError(
        // eslint-disable-next-line quotes
        "Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded."
      );
    }

    // 填充字符
    string += '=='.slice(2 - (string.length & 3));

    let bitmap,
      result = '',
      r1,
      r2,
      i = 0;

    for (; i < string.length; ) {
      bitmap =
        (b64.indexOf(string.charAt(i++)) << 18) |
        (b64.indexOf(string.charAt(i++)) << 12) |
        ((r1 = b64.indexOf(string.charAt(i++))) << 6) |
        (r2 = b64.indexOf(string.charAt(i++)));

      if (r1 === 64) {
        result += String.fromCharCode((bitmap >> 16) & 255);
      } else if (r2 === 64) {
        result += String.fromCharCode(
          (bitmap >> 16) & 255,
          (bitmap >> 8) & 255
        );
      } else {
        result += String.fromCharCode(
          (bitmap >> 16) & 255,
          (bitmap >> 8) & 255,
          bitmap & 255
        );
      }
    }
    return result;
  };

  const unZip = (input) => {
    // 先解密
    const binaryString = weAtob(input)
    // 再解压
    const bytes = new Uint8Array(binaryString.length);
    for (let i = 0; i < binaryString.length; i++) {
      bytes[i] = binaryString.charCodeAt(i);
    }
    // 2. pako解压 -> 得到原始JSON字符串
    const decompressed = pako.ungzip(bytes, { to: 'string' });

    // 3. 解析回对象
    const originalData = JSON.parse(decompressed);
    
    console.log({originalData})
    return originalData
  }

4. 微信环境 → 扫码打开小程序

4.1 小程序后台配置「扫普通链接二维码打开小程序」

4.2 二维码内容示例:https://your-domain.com/path?foo=bar

  • 对应业务域名开放一个访问路径,如 /path
  • 将校验文件防止最后一级访问文件子目录下, 下载文件防止目录下

4.3 小程序对应页面接收参数

  • onLoad(options) 直接读取 options.foo

5. 微信 JS-SDK 能力

5.1 SDK引入 & SDK注册-准备

js 复制代码
/** SDK 引入*/
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
js 复制代码
/** SDK 注册*/
wx.config({
  debug: false,
  appId: conf.appId,
  timestamp: conf.timeStamp,
  nonceStr: conf.nonceStr,
  signature: conf.sign,
  jsApiList: [
    'scanQRCode',
    'updateAppMessageShareData',
    'updateTimelineShareData',
    'onMenuShareAppMessage',
    'onMenuShareTimeline'
  ],
  openTagList: ['wx-open-launch-weapp']
});

wx.ready(() => console.log('JSSDK ready'));
wx.error((e) => console.error('JSSDK error', e));

5.2 常用 API(SDK 对应API 使用举例)

微信扫码
js 复制代码
wx.scanQRCode({
    needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
    scanType: ['qrCode', 'barCode'], // 可以指定扫二维码还是一维码,默认二者都有
    success: function (res) {
        result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
        resolve(result);
    },
    fail(err) {
        console.log(err);
        reject(err);
    },
    // 取消扫码方法
    cancel() {

    }
});
h5链接进行卡片分享(聊天 / 朋友圈)
js 复制代码
// 注意: 使用前进行从服务端获取配置'conf',注册sdk, 在正式调用能力 之前 确保已经完成了 初始化 ready 好了, 与服务端交互的时候需要注意,如果服务端需要传 '当前地址', 记得使用 encodeURIComponent(url)
wx.onMenuShareAppMessage({
  title: '标题',
  desc: '描述',
  link: shareUrl, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
  imgUrl: iconUrl,
  success() {
    // 用户点击了分享
  }
});
微信环境下 - 通过微信提供的 按钮 - 打开小程序
js 复制代码
import { useEffect } from 'react';

const LaunchWeappButton = ({ btnText = '打开小程序', params }) => {
  useEffect(() => {
    const btn = document.getElementById('launch-btn');
    const onLaunch = (e) => console.log('launch success', e);
    const onError = (e) => console.log('launch fail', e);

    btn?.addEventListener('launch', onLaunch);
    btn?.addEventListener('error', onError);

    return () => {
      btn?.removeEventListener('launch', onLaunch);
      btn?.removeEventListener('error', onError);
    };
  }, []);

  return (
    <wx-open-launch-weapp
      id="launch-btn"
      appid="wx********"
      username="gh_********"
      path={`/pages/login/index?field=${encodeURIComponent(params)}`}
    >
      <script type="text/wxtag-template">
        <button style={{display:'block',width:'100%'}}>{btnText}</button>
      </script>
    </wx-open-launch-weapp>
  );
};

6. h5内嵌小程序webview - h5在小程序内跳转小程序指定页面

js 复制代码
 wx.miniProgram.navigateTo({
    url: `/subPages/pages/transferPage/index?fidle=${value}`,
    success: () => {
        console.log('成功的回调')
    }
})

7. 附录

相关推荐
北京_宏哥6 分钟前
🔥《刚刚问世》系列初窥篇-Java+Playwright自动化测试-32- 操作日历时间控件-下篇(详细教程)
java·前端·面试
王维志11 分钟前
⏱ TimeSpan:C#时间间隔结构
前端·后端·c#·.net
阿幸软件杂货间19 分钟前
【最新版】Edge浏览器(官方版)安装包_Edge浏览器(官方版)安装教程
前端·edge
RaidenLiu27 分钟前
Flutter 状态管理:Provider 入门与实战
前端·flutter
隔壁老王z32 分钟前
设计实现一个Web 终端:基于 Vue 3 和 Xterm.js 的实践
前端·iterm
中微子32 分钟前
简单介绍跨域资源共享(CORS)
前端
極光未晚36 分钟前
Vue 项目 webpack 打包体积分析:从 “盲猜优化” 到 “精准瘦身”
前端·vue.js·性能优化
刘小筛43 分钟前
Ant Design Vue (2x) 按钮(button)单击后离开,按钮状态无变化
前端
mogullzr1 小时前
4.1.ByteOJ用户模块——登录注册功能(RSA + TimeStamp加密过)
前端·后端
鹏多多.1 小时前
flutter-使用AnimatedDefaultTextStyle实现文本动画
android·前端·css·flutter·ios·html5·web