environmentDetector.ts 4.84 KB
/**
 * H5收银台环境检测工具 (TypeScript版本)
 * 用于识别当前运行环境:普通浏览器、微信浏览器、小程序webview等
 */

// 环境信息接口
interface EnvironmentInfo {
  isWeChat: boolean;
  isMiniProgram: boolean;
  isMiniProgramAsync: boolean | null;
  isAlipay: boolean;
  isAlipayMiniProgram: boolean;
  isNormalBrowser: boolean;
  os: string;
  browser: string;
}

// 微信小程序API类型声明
interface WxMiniProgram {
  getEnv: (callback: (res: { miniprogram: boolean }) => void) => void;
  navigateTo?: (options: { url: string }) => void;
  postMessage?: (options: { data: any }) => void;
}

interface WxNamespace {
  miniProgram: WxMiniProgram;
}

declare global {
  interface Window {
    wx?: WxNamespace;
  }
}

class EnvironmentDetector {
  public env: EnvironmentInfo;
  private ua: string;

  constructor() {
    this.ua = navigator.userAgent.toLowerCase();
    this.env = this.detect();
  }

  /**
   * 获取环境描述
   */
  public getEnvironmentDesc(): string {
    if (this.env.isMiniProgram || this.env.isAlipayMiniProgram) {
      return '小程序webview';
    }
    if (this.env.isWeChat) {
      return '微信浏览器';
    }
    if (this.env.isAlipay) {
      return '支付宝浏览器';
    }
    return '普通浏览器';
  }

  /**
   * 获取完整环境信息(包含异步检测结果)
   */
  public async getFullEnvironment(): Promise<EnvironmentInfo> {
    const isMiniProgramAsync = await this.isMiniProgramAsync();
    this.env.isMiniProgramAsync = isMiniProgramAsync;
    return this.env;
  }

  /**
   * 异步检测是否在微信小程序中(更准确)
   * 使用微信JSSDK的方法
   */
  public async isMiniProgramAsync(): Promise<boolean> {
    if (!this.isWeChat()) {
      return false;
    }

    return new Promise<boolean>((resolve) => {
      // 如果UA中已经有miniprogram标识,直接返回true
      if (this.isMiniProgram()) {
        resolve(true);
        return;
      }

      // 使用wx.miniProgram.getEnv检测
      if (window.wx !== undefined && window.wx.miniProgram) {
        window.wx.miniProgram.getEnv((res) => {
          resolve(res.miniprogram === true);
        });
      } else {
        // 如果wx对象不存在,可能还没加载,等待一下
        setTimeout(() => {
          if (window.wx !== undefined && window.wx.miniProgram) {
            window.wx.miniProgram.getEnv((res) => {
              resolve(res.miniprogram === true);
            });
          } else {
            resolve(false);
          }
        }, 300);
      }
    });
  }

  /**
   * 打印环境信息
   */
  public logEnvironment(): void {
    console.log('===== 环境检测结果 =====');
    console.log('环境描述:', this.getEnvironmentDesc());
    console.log('详细信息:', this.env);
    console.log('User Agent:', this.ua);
    console.log('======================');
  }

  /**
   * 检测当前环境
   * @returns {EnvironmentInfo} 环境信息对象
   */
  private detect(): EnvironmentInfo {
    return {
      isWeChat: this.isWeChat(),
      isMiniProgram: this.isMiniProgram(),
      isMiniProgramAsync: null,
      isAlipay: this.isAlipay(),
      isAlipayMiniProgram: this.isAlipayMiniProgram(),
      isNormalBrowser: this.isNormalBrowser(),
      os: this.getOS(),
      browser: this.getBrowser(),
    };
  }

  /**
   * 获取浏览器类型
   */
  private getBrowser(): string {
    if (this.isWeChat()) return 'WeChat';
    if (this.isAlipay()) return 'Alipay';
    if (/chrome/.test(this.ua)) return 'Chrome';
    if (/safari/.test(this.ua)) return 'Safari';
    if (/firefox/.test(this.ua)) return 'Firefox';
    return 'Other';
  }

  /**
   * 获取操作系统
   */
  private getOS(): string {
    if (/android/.test(this.ua)) return 'Android';
    if (/iphone|ipad|ipod/.test(this.ua)) return 'iOS';
    if (/windows/.test(this.ua)) return 'Windows';
    if (/mac/.test(this.ua)) return 'MacOS';
    return 'Unknown';
  }

  /**
   * 检测是否在支付宝中
   */
  private isAlipay(): boolean {
    return /alipayclient/.test(this.ua);
  }

  /**
   * 检测是否在支付宝小程序中
   */
  private isAlipayMiniProgram(): boolean {
    return /miniprogram/.test(this.ua) && this.isAlipay();
  }

  /**
   * 同步检测是否在小程序中(通过UA)
   * 注意:这个方法不够准确,建议配合异步方法使用
   */
  private isMiniProgram(): boolean {
    // 微信小程序webview会包含miniprogram标识
    return /miniprogram/.test(this.ua) && this.isWeChat();
  }

  /**
   * 检测是否在普通浏览器中(非微信、非支付宝等)
   */
  private isNormalBrowser(): boolean {
    return !this.isWeChat() && !this.isAlipay();
  }

  /**
   * 检测是否在微信中
   */
  private isWeChat(): boolean {
    return /micromessenger/.test(this.ua);
  }
}

export default EnvironmentDetector;
export type { EnvironmentInfo, WxMiniProgram, WxNamespace };