Skip to content

React Native Expo版本的微信SDK。 您可以基于此框架实现微信登录、微信支付、分享到微信、打开微信小程序,唤起客服聊天等功能。WeChat SDK for React Native Expo. You can implement WeChat login, WeChat Pay, sharing to WeChat, opening WeChat Mini Programs, and launching customer service chat based on this framework.

License

Notifications You must be signed in to change notification settings

likeSo/expo-wechat

Repository files navigation

expo-wechat

npm License: MIT

React Native Expo版本的微信SDK。 您可以基于此框架实现微信登录、微信支付、分享到微信、打开微信小程序,唤起客服聊天等功能。 WeChat SDK for React Native Expo. You can implement WeChat login, WeChat Pay, sharing to WeChat, opening WeChat Mini Programs, and launching customer service chat based on this framework.

🚀 主要特性

  • ✅完整的微信SDK功能。
  • ✅零原生代码配置。无需打开原生项目,无需修改原生代码,所有配置项均在app.json中完成。
  • ✅完整的TypeScript支持,完整的代码提示。
  • ✅跨平台支持。同时支持安卓和iOS。在web上你也可以调用,只是不会有任何效果,不会报错。
  • ✅售后保证。在使用过程中遇到任何问题都可以联系我,有Expo相关的技术问题也欢迎交流。

📦 安装

npx expo install expo-wechat

# 不带支付版本
# npx expo install expo-wechat-no-pay

🔧 配置

iOS需要配置通用链接和URL Scheme。安卓上需要配置混淆规则。这些都可以通过app.jsonapp.config.js来配置。

什么是URL Scheme和通用链接?简单来说这就是iOS上微信授权完成后,跳回你的app的两种途径。 URL Scheme用于给你的应用注册一个独一无二的链接,使别的软件可以通过这个链接直接唤起你的App。 是微信回调起你的App的保底方案,当通用链接唤起失败后,微信会尝试使用URL Scheme来唤起你的App。这个URL Scheme就是微信开放平台给你的微信id,类似于wx1234567890这种格式的。

通用链接是微信首推的唤起微信和你的App的方案,当通用链接没有配置好的时候,才会回退到URL Scheme方案。 通用链接允许你向苹果注册一个URL地址,当访问这个地址的时候,系统优先唤起你的App,而不是网页。简单来说,它是一种比URL Scheme更好的唤起App的解决方案。

通用链接如何生成,以及如何向苹果注册,也许你需要参照一下苹果官方文档

如果对于app.jsonapp.config.js有疑问,请参阅Expo Configure with app config 文档。其实都是一个东西,只是后者能让你写JS代码,更灵活一些。

app.jsonapp.config.js添加如下配置:

"expo": {
  "scheme": [
    // 微信开放平台给你的微信id,类似于wx1234567890这种格式的。
    "wx1234567890"
  ],
  "ios": {
    "associatedDomains": [
      // 你的通用链接地址,前缀applinks是固定的,需要保证后边的域名和苹果,以及微信上注册的一致。
        "applinks:example.com"
    ]
  },
  "plugins": [
    [
      // expo-build-properties是另外一个expo官方的插件,它能让你自定义很多构建阶段的参数,包括自定义混淆规则和maven仓库等。
      // 记得先npx expo install expo-build-properties
      "expo-build-properties",
      {
        "android": {
          "extraProguardRules": "把下面的混淆规则放到这里",
        },
      }
    ],
    "expo-wechat"
  ]
}
-keep class com.tencent.mm.opensdk.** {
    *;
}

-keep class com.tencent.wxop.** {
    *;
}

-keep class com.tencent.mm.sdk.** {
    *;
}

请注意,由于包含了自定义的原生代码,无法在expo go中直接使用。你应该使用npx expo run:android或者npx expo run:ios,编译原生app。详情参见官方DevClient文档

📝 初始化

import ExpoWeChat from 'expo-wechat'

/// 初始化微信SDK。一般都在用户接受了隐私政策后,调用此方法。
const result = await ExpoWeChat.registerApp(wechatAppId, universalLink);

📚 API文档

属性

属性名 类型 说明
isRegistered boolean 是否已经成功调用registerApp方法

初始化与检测

registerApp

registerApp(appId: string, universalLink: string): Promise<boolean>

初始化微信SDK。返回初始化结果。

参数:

  • appId: 微信App ID
  • universalLink: 通用链接地址(iOS必需)

返回值: Promise<boolean> - 初始化是否成功

isWXAppInstalled

isWXAppInstalled(): Promise<boolean>

检查用户是否已安装微信客户端。

返回值: Promise<boolean> - 是否已安装微信

getApiVersion

getApiVersion(): Promise<string>

获取微信SDK的版本号。

返回值: Promise<string> - SDK版本号

getWXAppInstallUrl

getWXAppInstallUrl(): Promise<string | null>

获取微信安装的URL。

返回值: Promise<string | null> - 安装URL或null

openWXApp

openWXApp(): Promise<boolean>

打开微信App。

返回值: Promise<boolean> - 打开是否成功

checkUniversalLinkReady

checkUniversalLinkReady(): Promise<void>

启动微信自检流程,打印自检日志。

注意: iOS Only

授权登录

sendAuthRequest

sendAuthRequest(
  scope: "snsapi_userinfo" | string,
  state: string
): Promise<boolean>

发送微信授权登录请求。

参数:

  • scope: 微信scope字段,如snsapi_userinfo
  • state: 微信state字段,用于维持请求和回调的状态

返回值: Promise<boolean> - 请求是否发送成功

注意: 此方法返回的是请求发送结果,不是授权结果。授权结果需通过监听onAuthResult事件获取。

sendAuthByQRRequest

sendAuthByQRRequest(options: AuthByQROptions): Promise<string>

发送微信扫码登录请求。

参数:

interface AuthByQROptions {
  appId: string;              // 微信App ID
  appSecret: string;          // 微信App Secret
  scope: "snsapi_userinfo" | string;  // 授权范围
  schemeData?: string;        // 可选的scheme数据
}

返回值: Promise<string> - 二维码base64编码的图片数据

分享功能

shareText

shareText(text: string, scene: ShareScene): Promise<boolean>

分享文字到微信。

参数:

  • text: 要分享的文字内容
  • scene: 分享目标场景 ('session' | 'timeline' | 'favorite' | 'status' | 'specifiedContact')

返回值: Promise<boolean> - 分享请求是否发送成功

shareImage

shareImage(options: ShareImageOptions): Promise<boolean>

分享图片到微信。

参数:

interface ShareImageOptions {
  base64OrImageUri: string;           // 图片内容(URI或base64)
  scene: ShareScene;                  // 分享场景
  thumbBase64OrImageUri?: string;     // 缩略图内容(可选)
  imageDataHash?: string | null;      // 图片哈希值(可选)
  miniProgramId?: string | null;      // 小程序原始id(可选)
  miniProgramPath?: string | null;    // 小程序路径(可选)
}

返回值: Promise<boolean> - 分享请求是否发送成功

shareFile

shareFile(
  base64OrFileUri: string,
  title: string,
  scene: ShareScene
): Promise<boolean>

分享文件到微信。

参数:

  • base64OrFileUri: 文件内容(URI或base64)
  • title: 文件标题
  • scene: 分享目标场景

返回值: Promise<boolean> - 分享请求是否发送成功

shareMusic

shareMusic(options: ShareMusicOptions): Promise<boolean>

分享音乐到微信。

参数:

interface ShareMusicOptions {
  musicWebpageUrl: string;                  // 音乐网页URL
  musicFileUri: string;                     // 音乐文件URI
  singerName: string;                       // 歌手名称
  duration: number;                         // 音乐时长(秒)
  scene: ShareScene;                        // 分享场景
  songLyric?: string;                       // 歌词(可选)
  hdAlbumThumbFilePath?: string;            // 高清专辑缩略图文件路径(安卓)
  hdAlbumThumbBase64OrImageUri?: string;    // 高清专辑缩略图(iOS)
  hdAlbumThumbFileHash?: string;            // 高清专辑缩略图文件哈希值
  albumName?: string;                       // 专辑名称
  title?: string;                           // 标题(可选)
  description?: string;                     // 描述(可选)
  thumbBase64OrImageUri?: string;           // 缩略图(可选)
}

返回值: Promise<boolean> - 分享请求是否发送成功

shareVideo

shareVideo(options: ShareVideoOptions): Promise<boolean>

分享视频到微信。

参数:

interface ShareVideoOptions {
  videoUri: string;                         // 视频文件URI
  scene: ShareScene;                        // 分享场景
  lowQualityVideoUri?: string;              // 低质量视频URI(可选)
  thumbBase64OrImageUri?: string;           // 缩略图(可选)
  title?: string;                           // 标题(可选)
  description?: string;                     // 描述(可选)
}

返回值: Promise<boolean> - 分享请求是否发送成功

shareWebpage

shareWebpage(options: ShareWebpageOptions): Promise<boolean>

分享网页到微信。

参数:

interface ShareWebpageOptions {
  url: string;                              // 网页URL
  scene: ShareScene;                        // 分享场景
  title?: string;                           // 标题(可选)
  description?: string;                     // 描述(可选)
  thumbBase64OrImageUri?: string;           // 缩略图(可选)
  extraInfo?: string;                       // 额外信息(可选)
}

返回值: Promise<boolean> - 分享请求是否发送成功

shareMiniProgram

shareMiniProgram(options: ShareMiniProgramOptions): Promise<boolean>

分享小程序到微信。

参数:

interface ShareMiniProgramOptions {
  id: string;                               // 小程序原始id
  type: WeChatMiniProgramType;              // 小程序类型 ('release' | 'test' | 'preview')
  path?: string;                            // 小程序路径(可选)
  scene: ShareScene;                        // 分享场景
  webpageUrl?: string;                      // 网页URL(可选)
  title?: string;                           // 标题(可选)
  description?: string;                     // 描述(可选)
  thumbBase64OrImageUri?: string;           // 缩略图(可选)
  withShareTicket?: boolean;                // 是否携带shareTicket(可选)
}

返回值: Promise<boolean> - 分享请求是否发送成功

小程序相关

launchMiniProgram

launchMiniProgram(options: LaunchMiniProgramOptions): Promise<boolean>

打开微信小程序。

参数:

interface LaunchMiniProgramOptions {
  id: string;                               // 小程序原始id
  type: WeChatMiniProgramType;              // 小程序类型
  path?: string;                            // 小程序路径(可选)
  extraData?: string;                       // 额外数据(可选)
}

返回值: Promise<boolean> - 打开请求是否发送成功

支付功能

pay

pay(options: PayOptions): Promise<boolean>

发起微信支付。

参数:

interface PayOptions {
  partnerId: string;                        // 商户号
  prepayId: string;                         // 预支付交易会话ID
  nonceStr: string;                         // 随机字符串
  timeStamp: number;                        // 时间戳
  sign: string;                             // 签名
  package: string;                          // 扩展字段
  extraData: string;                        // 额外数据
}

返回值: Promise<boolean> - 支付请求是否发送成功

客服与订阅消息

openWeChatCustomerServiceChat

openWeChatCustomerServiceChat(cropId: string, url: string): Promise<boolean>

打开微信客服聊天。

参数:

  • cropId: 企业ID
  • url: 客服URL

返回值: Promise<boolean> - 打开请求是否发送成功

sendSubscribeMessage

sendSubscribeMessage(
  scene: number,
  templateId: string,
  reserved: string
): Promise<boolean>

发送订阅消息。

参数:

  • scene: 场景
  • templateId: 模板ID
  • reserved: 保留字段

返回值: Promise<boolean> - 发送请求是否成功

openWebView

openWebView(url: string): Promise<boolean>

在微信内置 WebView 中打开指定链接。

参数:

  • url: 要打开的链接,建议使用有效的 http(s) URL

返回值: Promise<boolean> - 打开请求是否发送成功

事件监听

调用API返回的Promise仅仅代表调用的成功与否,不代表最终的微信返回结果。对于需要观测结果的API,应当使用事件监听的方式来实现:

支持的事件列表

事件名 说明 回调参数类型
onQRCodeAuthGotQRCode 二维码登录时,得到二维码图片 { image: string }
onQRCodeAuthUserScanned 二维码登录时,用户成功扫描二维码 void
onQRCodeAuthResult 二维码登录结果 { errorCode: number; authCode: string }
onShowMessageFromWeChat 从微信打开应用时收到的消息 ShowMessageFromWeChatPayload
onAuthResult 授权登录结果 AuthResultPayload
onPayResult 支付结果 PayResultPayload
onLaunchMiniProgramResult 打开小程序结果 { extraInfo?: string }

授权登录结果结构

export type AuthResultPayload = {
  code: string;         // 授权码
  state: string;        // 状态值
  url: string;          // 完整URL
  authResult: boolean;  // 授权是否成功
  lang: string;         // 语言
  country: string;      // 国家
  errorCode: number;    // 错误码
  errorMessage: string; // 错误信息
  openId: string;       // 开放ID
  transaction: string;  // 事务ID
};

支付结果结构

export type PayResultPayload = {
  prepayId?: string;    // 预支付ID
  returnKey?: string;   // 返回键
  extraInfo?: string;   // 额外信息
  errorCode: number;    // 错误码
  errorMessage: string; // 错误信息
  openId: string;       // 开放ID
  transaction: string;  // 事务ID
};

错误码说明

export enum ResultErrorCode {
  ok = 0,             // 成功
  common = -1,        // 普通错误
  userCancel = -2,    // 用户取消
  sentFailed = -3,    // 发送失败
  authDenied = -4,    // 授权被拒绝
  unsupported = -5,   // 不支持的操作
  ban = -6,           // 被禁止
}

使用示例

授权登录示例

import ExpoWeChat from 'expo-wechat'
import { useEvent, useEffect } from 'expo'

// 初始化
const initializeWeChat = async () => {
  const result = await ExpoWeChat.registerApp('wx1234567890', 'https://example.com/');
  console.log('微信SDK初始化结果:', result);
};

// 使用useEvent监听授权结果
const authResult = useEvent(ExpoWeChat, 'onAuthResult');

useEffect(() => {
  if (authResult) {
    if (authResult.errorCode === 0) {
      console.log('授权成功!');
      console.log('授权码:', authResult.code);
      console.log('状态:', authResult.state);
      // 在这里使用code向服务器换取token
    } else {
      console.log('授权失败:', authResult.errorMessage);
    }
  }
}, [authResult]);

// 发送授权请求
const handleWeChatLogin = async () => {
  // 检查微信是否安装
  const isInstalled = await ExpoWeChat.isWXAppInstalled();
  if (!isInstalled) {
    alert('请先安装微信');
    return;
  }
  
  // 发送授权请求
  const requestResult = await ExpoWeChat.sendAuthRequest('snsapi_userinfo', 'state123');
  console.log('授权请求发送结果:', requestResult);
};

二维码登录示例

import ExpoWeChat from 'expo-wechat'
import { useEvent, useEffect } from 'expo'

// 监听二维码相关事件
const qrCodeResult = useEvent(ExpoWeChat, 'onQRCodeAuthGotQRCode');
const qrCodeScanResult = useEvent(ExpoWeChat, 'onQRCodeAuthUserScanned');
const qrCodeLoginResult = useEvent(ExpoWeChat, 'onQRCodeAuthResult');

useEffect(() => {
  if (qrCodeResult) {
    console.log('二维码生成成功,可以显示了');
    // 这里可以使用qrCodeResult.image来渲染二维码
  }
}, [qrCodeResult]);

useEffect(() => {
  if (qrCodeScanResult) {
    console.log('用户已扫描二维码,请确认');
  }
}, [qrCodeScanResult]);

useEffect(() => {
  if (qrCodeLoginResult) {
    if (qrCodeLoginResult.errorCode === 0) {
      console.log('二维码登录成功!');
      console.log('授权码:', qrCodeLoginResult.authCode);
      // 在这里使用authCode向服务器换取token
    } else {
      console.log('二维码登录失败:', qrCodeLoginResult.errorCode);
    }
  }
}, [qrCodeLoginResult]);

// 生成登录二维码
const generateLoginQRCode = async () => {
  try {
    const qrCode = await ExpoWeChat.sendAuthByQRRequest({
      appId: 'wx1234567890',
      appSecret: 'your_app_secret',
      scope: 'snsapi_userinfo'
    });
    console.log('二维码生成成功');
  } catch (error) {
    console.error('二维码生成失败:', error);
  }
};

支付示例

import ExpoWeChat from 'expo-wechat'
import { useEvent, useEffect } from 'expo'

// 监听支付结果
const payResult = useEvent(ExpoWeChat, 'onPayResult');

useEffect(() => {
  if (payResult) {
    if (payResult.errorCode === 0) {
      console.log('支付成功!');
      // 支付成功后的处理逻辑
    } else {
      console.log('支付失败:', payResult.errorMessage);
      // 支付失败后的处理逻辑
    }
  }
}, [payResult]);

// 发起支付
const handlePay = async () => {
  try {
    // 从服务器获取支付参数
    const payParams = await getPayParamsFromServer();
    
    const result = await ExpoWeChat.pay({
      partnerId: payParams.partnerId,
      prepayId: payParams.prepayId,
      nonceStr: payParams.nonceStr,
      timeStamp: payParams.timeStamp,
      sign: payParams.sign,
      package: payParams.package,
      extraData: payParams.extraData
    });
    
    console.log('支付请求发送结果:', result);
  } catch (error) {
    console.error('支付失败:', error);
  }
};

分享示例

import ExpoWeChat from 'expo-wechat'

// 分享网页到微信会话
const shareToWeChat = async () => {
  try {
    const result = await ExpoWeChat.shareWebpage({
      url: 'https://example.com',
      title: '分享标题',
      description: '分享描述内容',
      thumbBase64OrImageUri: 'base64编码的图片或图片URI',
      scene: 'session'
    });
    console.log('分享请求发送结果:', result);
  } catch (error) {
    console.error('分享失败:', error);
  }
};

🔧 调试

开启日志调试,首先你需要调用ExpoWeChat.startLogByLevel('verbose')方法,即可打开全部日志。 为了将日志打印到JS控制台,你需要监听onLog事件,然后将其打印出来即可,具体可以参考example下的App.tsx文件。

注意: 所有API返回的Promise仅表示调用是否成功发送,不代表最终操作结果。需要通过相应的事件监听获取实际操作结果。 useEvent是expo提供的一个模块事件监听的工具,你完全可以使用ExpoWeChat.addListener('onAuthResult', (result) => {})这种语法来监听事件结果,但千万不要忘记在组件卸载时移除事件监听,否则会导致内存泄漏。

📱 例子项目

克隆本仓库,并启动Example示例项目的步骤如下

  • 克隆本仓库后,在根目录执行npm i
  • 在根目录执行npm run build plugin,然后按下ctrl + c退出命令即可。
  • 进入example文件夹,执行npm i安装依赖。
  • 启动之前,请在.env文件内配置微信AppId和Key,去app.json文件内配置scheme和associatedDomains,切记确保与微信后台配置的一致。

☎️ 联系方式

本框架积极维护,如有任何问题,欢迎提交issue或者PR。也欢迎进群交流:682911244。

🗺️ 线路图

  • 实现选择发票功能
  • 发布不带支付功能的SDK
  • 完善文档

🤔 常见问题

报错 could not find module ExpoModulesCore for target '86_64-apple-ios-simulator'; found: arm64-apple-ios-simulator

以下方案是我们的一些经验,你可以都试一下:

  • 启动Rosetta模拟器。
  • 使用真机运行项目。
  • 升级Xcode到16.4以及以后。
  • 使用expo-fix-ios-simulator-arch插件来自动帮你解决这个问题。

微信授权结束后,没有回到登录页面,而是跳到了404页面?

原因分析 微信授权结束后,会通过URL Scheme和通用链接来回到你的应用,并把授权结果带在路径上作为参数。比如/wxauth/wx1234567890/oauth 如果你使用了expo-router,或者配置好了React Navigation的deep linking,那么导航器会尝试跳转到这个URL对应的路由下,由于路由不存在,就会显示404页面。

解决方案1

既然这个问题产生的原因其实就是微信打开你的app的链接和你准备接收回调的链接没有“对准”,那么解决方案就是你想办法让它俩对准即可。在通用链接上和路由配置上想想办法。

解决方案2

expo-router提供了一个API,可以让你拦截所有deep link,并手动控制是否处理。详见Customizing links。 简单来说,你需要新建一个+native-intent.tsx文件,按照文档导出一个函数,并根据条件,重定向到你的登录页面即可。

🙏 鸣谢

本框架参考了许多react-native-wechat-lib的实现,实现了基本上所有的API的功能,在此基础上,极大的简化了配置流程,并使用了最新的微信SDK,感谢前人!

About

React Native Expo版本的微信SDK。 您可以基于此框架实现微信登录、微信支付、分享到微信、打开微信小程序,唤起客服聊天等功能。WeChat SDK for React Native Expo. You can implement WeChat login, WeChat Pay, sharing to WeChat, opening WeChat Mini Programs, and launching customer service chat based on this framework.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published