收藏
回答

Bug:H5 JSSDK微信分享功能异常:微信浏览器中,无法以图文卡片形式分享H5页面。

框架类型 问题类型 API/组件名称 终端类型 微信版本 基础库版本
小程序 Bug updateAppMessageShareData/updateTimelineShareData 微信安卓客户端 8.0.61 是H5页面问题,不涉及Java基础库

https://developers.weixin.qq.com/doc/service/guide/h5/ 无法支持图文卡片式分享给朋友和朋友圈:

wechatshare hook代码:

import { useEffect, useState, useRef } from 'react';

declare global {
  interface Window {
    wx: any;
  }
}

interface WechatShareConfig {
  title: string;
  desc: string;
  link: string;
  imgUrl: string;
  success?: () => void;
  cancel?: () => void;
  fail?: (error: any) => void;
  // 新增:分享类型相关的回调
  onFriendsShareSuccess?: () => void;
  onTimelineShareSuccess?: () => void;
  onFriendsShareCancel?: () => void;
  onTimelineShareCancel?: () => void;
  onFriendsShareFail?: (error: any) => void;
  onTimelineShareFail?: (error: any) => void;
}

interface WechatSignature {
  appId: string;
  timestamp: number;
  nonceStr: string;
  signature: string;
}

export default function useWechatShare() {
  const [isWechatReady, setIsWechatReady] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [isInitialized, setIsInitialized] = useState(false); // 新增:标记是否已初始化
  const initPromiseRef = useRef<Promise<boolean> | null>(null); // 新增:保存初始化Promise


  // 检测是否在微信浏览器中
  const isWechatBrowser = () => {
    if (typeof window === 'undefined') return false;
    const ua = window.navigator.userAgent.toLowerCase();
    return ua.includes('micromessenger');
  };

  // 加载微信JS-SDK
  const loadWechatSDK = () => {
    return new Promise((resolve, reject) => {
      if (window.wx) {
        resolve(window.wx);
        return;
      }

      const script = document.createElement('script');
      script.src = 'https://res.wx.qq.com/open/js/jweixin-1.6.0.js';
      script.onload = () => resolve(window.wx);
      script.onerror = reject;
      document.head.appendChild(script);
    });
  };

  // 获取微信签名
  const getWechatSignature = async (url: string): Promise<WechatSignature> => {
    const response = await fetch(`/api/wechat/signature?url=${encodeURIComponent(url)}`);
    if (!response.ok) {
      throw new Error('获取微信签名失败');
    }
    return response.json();
  };

  // 初始化微信JS-SDK
  const initWechatSDK = async () => {
    if (!isWechatBrowser()) {
      console.log('非微信浏览器环境');
      return false;
    }

    // 如果已经在初始化中,返回现有的Promise
    if (initPromiseRef.current) {
      console.log('SDK正在初始化中,等待完成...');
      return initPromiseRef.current;
    }

    // 如果已经初始化完成,直接返回结果
    if (isInitialized) {
      console.log('SDK已初始化,当前状态:', isWechatReady);
      return isWechatReady;
    }

    // 创建新的初始化Promise
    initPromiseRef.current = (async () => {
      try {
        setIsLoading(true);
        console.log('开始初始化微信SDK...');
        
        // 加载微信SDK
        await loadWechatSDK();
        
        // 获取当前页面URL(去掉hash部分)
        const currentUrl = window.location.href.split('#')[0];
        
        // 获取签名
        const signature = await getWechatSignature(currentUrl);
        
        // 配置微信SDK
        window.wx.config({
          debug: process.env.NODE_ENV === 'development', // 开发环境自动开启调试
          appId: signature.appId,
          timestamp: signature.timestamp,
          nonceStr: signature.nonceStr,
          signature: signature.signature,
          jsApiList: [
            'updateAppMessageShareData', // 分享给朋友
            'updateTimelineShareData'    // 分享到朋友圈
          ]
        });

        // 配置成功回调
        return new Promise<boolean>((resolve) => {
          window.wx.ready(() => {
            console.log(`${new Date().toString()} wx.config ready`);
            console.log('微信JS-SDK配置成功');
            setIsWechatReady(true);
            setIsInitialized(true);
            resolve(true);
          });

          // 配置失败回调
          window.wx.error((res: any) => {
            console.error(`${new Date().toString()} wx.config error:`, res);
            console.error('微信JS-SDK配置失败:', res);
            // 更详细的错误信息
            if (res.errMsg) {
              console.error('错误详情:', res.errMsg);
              if (typeof window !== 'undefined' && window.console) {
                console.warn('微信分享功能暂时不可用,请确保在微信浏览器中打开');
              }
            }
            setIsWechatReady(false);
            setIsInitialized(true); // 即使失败也标记为已初始化,避免重复尝试
            resolve(false);
          });
        });

      } catch (error) {
        console.error('初始化微信SDK失败:', error);
        setIsWechatReady(false);
        setIsInitialized(true); // 标记为已初始化,避免重复尝试
        return false;
      } finally {
        setIsLoading(false);
        initPromiseRef.current = null; // 清除Promise引用
      }
    })();

    return initPromiseRef.current;
  };

  // 配置分享内容
  const configShare = (config: WechatShareConfig) => {
    if (!isWechatReady || !window.wx) {
      console.warn('微信SDK未准备就绪,当前状态:', { isWechatReady, hasWx: !!window.wx });
      return false;
    }

    try {
      console.log('配置微信分享内容:', config.title);
      
      // 确保图片URL是绝对路径
      const getAbsoluteImageUrl = (imageUrl: string) => {
        if (!imageUrl) return '';
        if (imageUrl.startsWith('http')) return imageUrl;
        return `${window.location.origin}${imageUrl.startsWith('/') ? '' : '/'}${imageUrl}`;
      };

      const absoluteImgUrl = getAbsoluteImageUrl(config.imgUrl);

      
      // 检查当前客户端版本是否支持分享接口
      window.wx.checkJsApi({
        jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'],
        success: function(res: any) {
          console.log('分享接口支持情况:', res.checkResult);
          if (!res.checkResult.updateAppMessageShareData) {
            console.warn('当前微信版本不支持updateAppMessageShareData接口');
          }
          if (!res.checkResult.updateTimelineShareData) {
            console.warn('当前微信版本不支持updateTimelineShareData接口');
          }
        }
      });

      // 配置分享给朋友
      console.log(`${new Date().toString()} wx.updateAppMessageShareData begin`);
      console.log({
        title: config.title,
        desc: config.desc,
        link: config.link,
        imgUrl: absoluteImgUrl
      });
      
      window.wx.updateAppMessageShareData({
        title: config.title,
        desc: config.desc,
        link: config.link,
        imgUrl: absoluteImgUrl,
        success: () => {
          console.log(`${new Date().toString()} wx.updateAppMessageShareData success - 配置成功`);
          // 这个success回调表示配置成功,不是分享成功
          // 可以统计为"分享配置成功"或"分享意图"
          config.onFriendsShareSuccess?.();
          config.success?.(); // 保持向后兼容
        },
        cancel: () => {
          console.log('取消分享给朋友');
          config.onFriendsShareCancel?.();
          config.cancel?.(); // 保持向后兼容
        },
        fail: (error: any) => {
          console.error('分享给朋友失败:', error);
          config.onFriendsShareFail?.(error);
          config.fail?.(error); // 保持向后兼容
        }
      });
      console.log(`${new Date().toString()} wx.updateAppMessageShareData end`);

      // 配置分享到朋友圈
      console.log(`${new Date().toString()} wx.updateTimelineShareData begin`);
      console.log({
        title: config.title,
        link: config.link,
        imgUrl: absoluteImgUrl
      });
      
      window.wx.updateTimelineShareData({
        title: config.title,
        link: config.link,
        imgUrl: absoluteImgUrl,
        success: () => {
          console.log(`${new Date().toString()} wx.updateTimelineShareData success - 配置成功`);
          // 这个success回调表示配置成功,不是分享成功
          // 可以统计为"分享配置成功"或"分享意图"
          config.onTimelineShareSuccess?.();
          config.success?.(); // 保持向后兼容
        },
        cancel: () => {
          console.log('取消分享到朋友圈');
          config.onTimelineShareCancel?.();
          config.cancel?.(); // 保持向后兼容
        },
        fail: (error: any) => {
          console.error('分享到朋友圈失败:', error);
          config.onTimelineShareFail?.(error);
          config.fail?.(error); // 保持向后兼容
        }
      });
      console.log(`${new Date().toString()} wx.updateTimelineShareData end`);

      return true;
    } catch (error) {
      console.error('配置分享失败:', error);
      config.fail?.(error);
      return false;
    }
  };

  // 一步配置分享(改进版)
  const setupShare = async (config: WechatShareConfig) => {
    console.log('setupShare调用,当前状态:', { isWechatReady, isInitialized, isLoading });
    
    // 如果SDK已就绪,直接配置
    if (isWechatReady) {
      return configShare(config);
    }
    
    // 如果未初始化,先初始化
    if (!isInitialized && !isLoading) {
      const initialized = await initWechatSDK();
      if (initialized) {
        return configShare(config);
      }
    }
    
    // 如果正在加载中,等待加载完成
    if (isLoading && initPromiseRef.current) {
      const initialized = await initPromiseRef.current;
      if (initialized) {
        return configShare(config);
      }
    }
    
    console.warn('setupShare失败,SDK未能初始化成功');
    return false;
  };

  // 页面加载时自动初始化(只初始化一次)
  useEffect(() => {
    if (isWechatBrowser() && !isInitialized && !isLoading) {
      console.log('页面加载,自动初始化微信SDK');
      initWechatSDK();
    }
  }, []); // 空依赖数组,只在组件挂载时执行一次

  return {
    isWechatBrowser: isWechatBrowser(),
    isWechatReady,
    isLoading,
    isInitialized, // 新增:暴露初始化状态
    initWechatSDK,
    configShare,
    setupShare
  };
} 

全页面的日志信息是如下,显示:

页面的日志信息是如下,显示
[id]-557c3938a7c7903c.js:1 
更新作者资料: 
{id: 24, created_at: "2025-05-07T19:45:48.475157+08:00", updated_at: "2025-07-17T18:14:58.808494+08:00", username: "sally 妈妈", email: "skynet2050@163.com", …}
[id]-557c3938a7c7903c.js:1 
准备配置微信分享,当前状态: 
{isWechatReady: false, isInitialized: false}
[id]-557c3938a7c7903c.js:1 
等待SDK自动初始化完成...
[id]-557c3938a7c7903c.js:1 
Post data: 
{id: 2324, created_at: "2025-06-22T13:05:03.456553+08:00", updated_at: "2025-07-16T21:03:44.87702+08:00", user_id: 24, user: {…}, …}
[id]-557c3938a7c7903c.js:1 
User data in post: 
{id: 24, created_at: "2025-05-07T19:45:48.475157+08:00", updated_at: "2025-07-17T18:14:58.808494+08:00", username: "sally 妈妈", email: "skynet2050@163.com", …}
[id]-557c3938a7c7903c.js:1 
Display username: 赫尔弥斯
[id]-557c3938a7c7903c.js:1 
Display avatar: https://image.inteducom.com/user_uploads/24/e257fe42-f966-453a-818a-df56c3acc9eb/edited-avatar.webp
_app-cafb680d520d278c.js:1 
[useAuth checkAuth] Current login status: false
_app-cafb680d520d278c.js:1 
[auth.ts] 正在设置Axios拦截器...
_app-cafb680d520d278c.js:1 
[auth.ts] Axios拦截器设置完成
_app-cafb680d520d278c.js:1 
[axios拦截器] 请求 GET /api/posts/2324/comments - 无token可用
_app-cafb680d520d278c.js:1 
[axios拦截器] 响应成功: GET /api/posts/2324/comments - 状态 200
3
_app-cafb680d520d278c.js:1 
[useAuth checkAuth] Current login status: false
[id]-557c3938a7c7903c.js:1 
准备配置微信分享,当前状态: 
{isWechatReady: false, isInitialized: false}
[id]-557c3938a7c7903c.js:1 
等待SDK自动初始化完成...
_app-cafb680d520d278c.js:1 
[useAuth checkAuth] Current login status: false
[id]-557c3938a7c7903c.js:1 
准备配置微信分享,当前状态: 
{isWechatReady: false, isInitialized: false}
[id]-557c3938a7c7903c.js:1 
等待SDK自动初始化完成...
index.js:9 
Fri Jul 18 2025 01:19:53 GMT+0800 (中国标准时间) wx.config begin
index.js:9 
{appId: "wxd20e798f1bb60259", jsApiList: Array(2), nonceStr: "8h5gA6wHZAUM8g6V", signature: "0c40ca0cb9886d8a6032fda15f74da3bf27a2705", timestamp: "1752772794"}
[id]-557c3938a7c7903c.js:1 
准备配置微信分享,当前状态: 
{isWechatReady: false, isInitialized: false}
[id]-557c3938a7c7903c.js:1 
等待SDK自动初始化完成...
index.js:9 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.config end
index.js:9 
{errMsg: "config:ok", jsApiList: Array(2)}
index.js:9 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) 当前页面通过 wx.config 获取到的 JSSDK 权限如下
index.js:9 
(index)
	
0
	
1
		
0	"updateAppMessageShareData"	"updateTimelineShareData"
		
Array(1)
[id]-557c3938a7c7903c.js:1 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.config ready
[id]-557c3938a7c7903c.js:1 
微信JS-SDK配置成功
[id]-557c3938a7c7903c.js:1 
准备配置微信分享,当前状态: 
{isWechatReady: true, isInitialized: true}
[id]-557c3938a7c7903c.js:1 
SDK已就绪,直接配置分享
[id]-557c3938a7c7903c.js:1 
配置微信分享内容: 数学建模竞赛与3D建模竞赛全面对比解析 - IntEdu 国际社区
index.js:9 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.checkJsApi begin
[id]-557c3938a7c7903c.js:1 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateAppMessageShareData begin
[id]-557c3938a7c7903c.js:1 
{title: "数学建模竞赛与3D建模竞赛全面对比解析 - IntEdu 国际社区", desc: "很多家长一听“建模竞赛”就头大,不知道是数学的建模,还是画图的建模。↵其实,“数学建模”和“3D建模…完全不同。↵这篇文章,帮你一文读懂两类建模的本质区别、适合人群及升学价值,帮助孩子选对适合自己的成", link: "https://www.inteducom.com/posts/2324", imgUrl: "https://image.inteducom.com/user_uploads/24/93894c8e-5f72-4e35-a685-451c4b45e5bf/1.webp"}
index.js:9 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateAppMessageShareData begin
index.js:9 
{title: "数学建模竞赛与3D建模竞赛全面对比解析 - IntEdu 国际社区", desc: "很多家长一听“建模竞赛”就头大,不知道是数学的建模,还是画图的建模。↵其实,“数学建模”和“3D建模…完全不同。↵这篇文章,帮你一文读懂两类建模的本质区别、适合人群及升学价值,帮助孩子选对适合自己的成", link: "https://www.inteducom.com/posts/2324", imgUrl: "https://image.inteducom.com/user_uploads/24/93894c8e-5f72-4e35-a685-451c4b45e5bf/1.webp"}
[id]-557c3938a7c7903c.js:1 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateAppMessageShareData end
[id]-557c3938a7c7903c.js:1 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateTimelineShareData begin
[id]-557c3938a7c7903c.js:1 
{title: "数学建模竞赛与3D建模竞赛全面对比解析 - IntEdu 国际社区", link: "https://www.inteducom.com/posts/2324", imgUrl: "https://image.inteducom.com/user_uploads/24/93894c8e-5f72-4e35-a685-451c4b45e5bf/1.webp"}
index.js:9 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateTimelineShareData begin
index.js:9 
{title: "数学建模竞赛与3D建模竞赛全面对比解析 - IntEdu 国际社区", link: "https://www.inteducom.com/posts/2324", imgUrl: "https://image.inteducom.com/user_uploads/24/93894c8e-5f72-4e35-a685-451c4b45e5bf/1.webp"}
[id]-557c3938a7c7903c.js:1 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateTimelineShareData end
index.js:9 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.checkJsApi end
index.js:9 
{errMsg: "checkJsApi:ok", checkResult: {…}}
[id]-557c3938a7c7903c.js:1 
分享接口支持情况: 
{updateAppMessageShareData: true, updateTimelineShareData: true}
index.js:9 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateTimelineShareData end
index.js:9 
{errMsg: "updateTimelineShareData:ok"}
[id]-557c3938a7c7903c.js:1 
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateTimelineShareData success - 配置成功
[id]-557c3938a7c7903c.js:1 
配置分享到朋友圈成功 - 这不是实际分享
[id]-557c3938a7c7903c.js:1 
微信分享成功

​
​



回答关注问题邀请回答
收藏
登录 后发表内容