miniProgram.js 2.48 KB
const WECHAT_JS_SDK_URL = 'https://res.wx.qq.com/open/js/jweixin-1.6.0.js'

let wechat_bridge_loading_promise = null

const isBrowserEnv = () => typeof window !== 'undefined' && typeof document !== 'undefined'

const getWechatBridge = () => {
  if (typeof window === 'undefined') {
    return null
  }

  return window.wx || window.jWeixin || null
}

const getMiniProgramBridge = () => getWechatBridge()?.miniProgram || null

export const isH5Env = () => isBrowserEnv()

const ensureWechatBridge = async () => {
  if (!isH5Env()) {
    return null
  }

  const current_bridge = getWechatBridge()

  if (current_bridge) {
    return current_bridge
  }

  if (!wechat_bridge_loading_promise) {
    wechat_bridge_loading_promise = new Promise((resolve, reject) => {
      const script = document.createElement('script')

      script.src = WECHAT_JS_SDK_URL
      script.async = true
      script.onload = () => resolve(getWechatBridge())
      script.onerror = () => reject(new Error('微信 JS SDK 加载失败'))

      document.head.appendChild(script)
    })
  }

  try {
    return await wechat_bridge_loading_promise
  } catch (error) {
    wechat_bridge_loading_promise = null
    throw error
  }
}

export const isWechatMiniProgramWebview = () => new Promise((resolve) => {
  const check_env = async () => {
    if (!isH5Env()) {
      resolve(false)
      return
    }

    try {
      await ensureWechatBridge()
    } catch (error) {
      console.error('微信 JS SDK 初始化失败:', error)
      resolve(false)
      return
    }

    const mini_program_bridge = getMiniProgramBridge()

    if (!mini_program_bridge) {
      resolve(false)
      return
    }

    if (typeof mini_program_bridge.getEnv !== 'function') {
      resolve(true)
      return
    }

    mini_program_bridge.getEnv((result = {}) => {
      resolve(!!result.miniprogram)
    })
  }

  check_env().catch(() => {
    resolve(false)
  })
})

export const navigateToMiniProgramPage = async (url = '') => {
  const normalized_url = String(url || '').trim()

  if (!normalized_url) {
    return false
  }

  const is_supported_webview = await isWechatMiniProgramWebview()

  if (!is_supported_webview) {
    return false
  }

  const mini_program_bridge = getMiniProgramBridge()

  if (typeof mini_program_bridge?.navigateTo !== 'function') {
    return false
  }

  return new Promise((resolve, reject) => {
    mini_program_bridge.navigateTo({
      url: normalized_url,
      success: () => resolve(true),
      fail: (error) => reject(error),
    })
  })
}