当前位置: 首页 > news >正文

Unity集成微信支付全流程实战:从Android原生模块到C#桥接

1. 项目概述

如果你正在用Unity开发一款面向国内市场的Android应用,并且需要接入支付功能,那么微信支付几乎是绕不开的一环。我最近刚在一个商业项目中完整走通了Unity集成微信支付的流程,从Android Studio的aar打包,到Unity端的C#桥接,再到微信开放平台的配置,整个过程踩了不少坑,也积累了一些实战经验。这篇文章就是一份详细的踩坑指南,我会把每一步的操作、背后的原理,以及那些官方文档里不会写的“坑点”都讲清楚。无论你是独立开发者还是团队中的技术负责人,这篇指南都能帮你节省大量东拼西凑查资料的时间,快速、稳定地实现Unity应用的微信支付功能。

2. 核心原理与架构设计

2.1 为什么Unity集成微信支付这么“麻烦”?

很多刚接触的开发者会疑惑,为什么不能像用C#插件一样,直接拖一个DLL到Unity里就完事了?这得从微信支付SDK的调用机制和Android平台特性说起。

微信支付本质上是一个跨应用通信的过程。你的Unity应用(我们称之为“商户应用”)需要调起微信客户端,用户在微信内完成支付授权后,微信客户端需要将支付结果回调给你的应用。在Android上,这种跨应用回调通常通过特定的Activity来实现。微信SDK规定,接收回调的Activity必须放在固定的包路径[你的应用包名].wxapi下,并且命名为WXPayEntryActivity。这个Activity就像一个“接待处”,专门处理从微信客户端跳转回来的信息。

Unity打包的APK,其入口Activity默认是com.unity3d.player.UnityPlayerActivity。我们的任务,就是在这个标准的Unity应用框架里,插入微信SDK要求的“接待处”,并建立一条从C#脚本到Java层,再到微信客户端,最后再返回C#脚本的完整通信链路。这涉及到Android原生开发(Java)、Unity与Android的交互(AndroidJavaClass/AndroidJavaObject)、以及微信开放平台的配置,三者缺一不可,因此步骤显得繁琐。

2.2 整体技术架构与数据流

理解整个数据流,对接下来的每一步操作至关重要。下图清晰地展示了从用户点击支付到收到回调的完整过程:

sequenceDiagram participant U as Unity C#脚本 participant A as Android Java层 (MainActivity) participant W as 微信客户端 participant S as 商户服务器 participant WX as 微信支付后台 U->>A: 1. 调用支付方法,传入订单参数 A->>W: 2. 调起微信支付界面 W->>用户: 3. 展示支付确认界面 用户->>W: 4. 输入密码/确认支付 W->>WX: 5. 提交支付请求 WX->>S: 6. 异步通知支付结果 (可选) W-->>A: 7. 支付结果回调至 WXPayEntryActivity A->>U: 8. 通过 UnitySendMessage 通知C# U->>S: 9. 向自家服务器查询/验证最终订单状态

流程关键点解析:

  1. 参数准备(步骤1):Unity C#脚本需要从你自己的业务服务器获取一组支付参数(包括prepay_id,nonceStr,timeStamp,sign等)。这些参数由你的服务器向微信支付后台发起统一下单API获得。C#脚本将这些参数传递给Android Java层。
  2. 调起支付(步骤2):Java层的MainActivity使用微信SDK的IWXAPI.sendReq(PayReq)方法,将支付参数封装成一个请求,发送给微信客户端。如果微信已安装且参数正确,系统会弹出微信支付界面。
  3. 回调与通知(步骤7, 8, 9):这是最容易出错的部分。支付完成后,微信客户端会跳转回你应用中指定的WXPayEntryActivity。该Activity的onResp方法会收到一个BaseResp对象,其中errCode表示支付结果(0成功,-2用户取消)。注意:这个回调仅代表用户支付动作的完成,不代表资金已结算。为了确保安全,你必须在此处通过UnityPlayer.UnitySendMessage将结果告知Unity,然后Unity再通知你的业务服务器。你的服务器应当以微信支付后台发来的异步通知(步骤6)作为最终入账依据,或者主动调用微信的查询订单API进行二次确认。

3. 环境准备与前置条件

3.1 账号与密钥申请

在写第一行代码之前,你需要准备好以下“门票”:

  1. 微信开放平台账号与应用:前往微信开放平台注册并完成开发者认证。创建一个移动应用,获取应用的唯一标识AppID。这个AppID是后续所有调用的关键。
  2. 微信支付商户号:如果你还没有,需要在开放平台内申请开通微信支付功能,审核通过后你会获得一个MCHID(商户号)。
  3. API密钥:在微信支付商户平台设置API密钥。这是一个32位的字符串,用于生成支付签名,务必妥善保管,不要泄露到客户端。签名是在服务端生成的。

重要提示:确保开放平台应用填写的包名应用签名与你最终发布的Unity应用完全一致。应用签名需要使用微信提供的“签名生成工具”获取,而不是直接用Android Studio或Unity的调试密钥。包名不一致或签名不匹配,会导致无法调起微信。

3.2 本地开发环境配置

  • Unity版本:建议使用稳定的LTS版本,如2020.3.x或2021.3.x。我使用的是2020.3.24f1c2。确保在Unity Hub中安装了对应的Android Build Support模块。
  • Android Studio:用于开发和编译包含微信SDK的Android Library(aar包)。版本无严格要求,能正常构建即可。
  • JDK:确保已安装Java Development Kit (JDK 8或11),并配置好环境变量JAVA_HOME
  • Unity工程设置:在Player Settings > Android > Other Settings中,正确设置Package Name(包名),并与你在开放平台注册的包名一致。同时准备好你的发布密钥库(Keystore),因为调试版和发布版的签名不同,测试时建议直接使用发布签名进行调试,避免签名问题。

4. Android原生模块开发详解

这是整个集成过程中最核心、也最容易出错的一步。我们的目标是在Android Studio中创建一个Android Library模块,它封装了微信SDK的调用逻辑,并编译成.aar文件供Unity使用。

4.1 创建Android Library工程

  1. 打开Android Studio,新建一个Empty Activity项目。在配置页面,Package name必须填写与你的Unity工程完全一致的包名,例如com.yourcompany.yourapp
  2. 项目创建后,切换到Project视图(左上角下拉菜单)。右键点击项目根目录,选择New > Module
  3. 选择Android Library,模块名称可以定为unitywechatpay,包名会自动继承主项目,确认与Unity包名一致(例如com.yourcompany.yourapp.wx)。这样创建出来的library,其命名空间就与你的主应用一致了。

4.2 引入依赖库:微信SDK与Unity Classes.jar

Library需要两个关键的依赖:微信支付SDK和Unity的Java交互接口。

1. 引入微信SDK:微信官方推荐使用Maven Central仓库依赖。在你的library模块的build.gradle文件的dependencies块中添加:

dependencies { implementation 'com.tencent.mm.opensdk:wechat-sdk-android:6.8.0' // 使用当时最新稳定版 }

但是,这里有个大坑:如果你直接这样依赖,然后打包aar,这个aar文件不会包含微信SDK的代码。它只会在gradle配置中声明依赖。当这个aar被放入Unity工程时,Unity的构建系统无法解析这个Maven依赖,导致最终APK中缺少微信SDK的类,运行时就会报ClassNotFoundException

解决方案有两种:

  • 方案A:使用Unity的依赖解析插件(推荐):谷歌提供了External Dependency Manager for Unity(原名Play Services Resolver)。你可以在Unity Asset Store下载或通过Package Manager添加。这个插件可以识别aar中的Maven依赖,并在Unity构建时自动下载并合并到APK中。这是最接近原生Android开发体验的方式。
  • 方案B:手动下载并嵌入SDK(本文采用,更直观):我们从Maven Central手动下载微信SDK的aar包。可以访问https://search.maven.org/搜索com.tencent.mm.opensdk:wechat-sdk-android,选择版本,下载.aar文件。然后用解压软件(如7-Zip)打开,将其中的classes.jar提取出来,重命名为wechat-sdk-android.jar,放入library模块的libs目录下。最后在build.gradle中改为依赖本地jar:
    dependencies { implementation files('libs/wechat-sdk-android.jar') }

2. 引入Unity Classes.jar:为了让我们的Java代码能回调到Unity的C#脚本,我们需要Unity提供的Java类。这个jar文件位于你的Unity安装目录下:[Unity安装路径]\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono或il2cpp\Release或Development\Classes\classes.jar。 根据你的Unity脚本后端(Mono或IL2CPP)和构建类型(Release或Development)选择对应的jar。通常开发期选择mono/Development/classes.jar。同样,将其复制到library模块的libs目录,并在build.gradle中添加依赖:

dependencies { implementation files('libs/wechat-sdk-android.jar') compileOnly files('libs/classes.jar') // 注意是 compileOnly }

这里使用compileOnly而不是implementation,是因为这个jar只在编译时需要,我们不希望将它打包进最终的aar。因为Unity在构建APK时,会自己注入这个jar,如果aar里也有一份,就会导致类冲突,引发Duplicate class错误。

4.3 编写核心Java代码

我们需要创建三个关键的Java类。

1. WXPayEntryActivity.java - 支付回调接收器这个类必须放在[你的包名].wxapi包下。在Android Studio中,在java目录下右键,依次新建包com.yourcompany.yourapp.wxapi,然后在该包下新建类WXPayEntryActivity

package com.yourcompany.yourapp.wxapi; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import com.tencent.mm.opensdk.constants.ConstantsAPI; import com.tencent.mm.opensdk.modelbase.BaseReq; import com.tencent.mm.opensdk.modelbase.BaseResp; import com.tencent.mm.opensdk.openapi.IWXAPI; import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; import com.tencent.mm.opensdk.openapi.WXAPIFactory; import com.unity3d.player.UnityPlayer; public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler { private static final String TAG = "MicroMsg.WXPayEntry"; private IWXAPI api; // 这两个静态变量用于接收Unity传过来的GameObject和Method名 public static String unityGameObjectName; public static String unityCallbackMethodName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 这里不设置ContentView,我们不需要界面 api = WXAPIFactory.createWXAPI(this, null); // AppID可以从Manifest读取或由MainActivity设置 api.handleIntent(getIntent(), this); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); api.handleIntent(intent, this); } @Override public void onReq(BaseReq baseReq) { // 微信发送请求到第三方应用时,会回调此方法。支付场景一般不需要处理。 } @Override public void onResp(BaseResp baseResp) { Log.d(TAG, "onPayFinish, errCode = " + baseResp.errCode); // 判断回调类型是否为支付 if (baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { String resultMsg; switch (baseResp.errCode) { case BaseResp.ErrCode.ERR_OK: resultMsg = "PAY_SUCCESS"; break; case BaseResp.ErrCode.ERR_USER_CANCEL: resultMsg = "PAY_CANCEL"; break; default: resultMsg = "PAY_FAILED_" + baseResp.errCode; break; } // 关键步骤:将支付结果发送回Unity if (unityGameObjectName != null && unityCallbackMethodName != null) { UnityPlayer.UnitySendMessage(unityGameObjectName, unityCallbackMethodName, resultMsg); } else { Log.e(TAG, "Unity callback target not set!"); } } finish(); // 关闭这个临时Activity } }

2. MainActivity.java - 继承UnityPlayerActivity并封装支付调用我们需要替换Unity默认的Activity。在com.yourcompany.yourapp.wx包下创建MainActivity

package com.yourcompany.yourapp.wx; import android.os.Bundle; import com.tencent.mm.opensdk.modelpay.PayReq; import com.tencent.mm.opensdk.openapi.IWXAPI; import com.tencent.mm.opensdk.openapi.WXAPIFactory; import com.unity3d.player.UnityPlayerActivity; public class MainActivity extends UnityPlayerActivity { private IWXAPI wxApi; public static final String WX_APP_ID = "你的微信AppID"; // 建议从C#传入或读取配置 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initWXApi(); } private void initWXApi() { if (wxApi == null) { wxApi = WXAPIFactory.createWXAPI(this, WX_APP_ID, true); wxApi.registerApp(WX_APP_ID); } } /** 检查微信是否安装 */ public boolean isWeChatInstalled() { return wxApi != null && wxApi.isWXAppInstalled(); } /** 发起微信支付请求 */ public void requestWeChatPay(String appId, String partnerId, String prepayId, String packageValue, String nonceStr, String timeStamp, String sign, String callbackGameObject, String callbackMethod) { // 设置回调目标 WXPayEntryActivity.unityGameObjectName = callbackGameObject; WXPayEntryActivity.unityCallbackMethodName = callbackMethod; PayReq request = new PayReq(); request.appId = appId; request.partnerId = partnerId; request.prepayId = prepayId; request.packageValue = packageValue; request.nonceStr = nonceStr; request.timeStamp = timeStamp; request.sign = sign; if (wxApi != null) { wxApi.sendReq(request); } } }

3. 处理UnityPlayerActivity类缺失问题新版本的Unity(大约2018以后),classes.jar中可能不再包含UnityPlayerActivity的源码。如果你在编译时遇到这个类找不到的错误,需要手动添加。从Unity安装目录Editor\Data\PlaybackEngines\AndroidPlayer\Source\com\unity3d\player找到UnityPlayerActivity.java文件,复制到你的Android Studio工程中,放在与MainActivity相同的包 (com.yourcompany.yourapp.wx) 下。然后在MainActivity中继承它即可。

4.4 生成AAR文件并解决依赖问题

完成代码编写后,点击Android Studio右侧Gradle面板,找到你的library模块,依次展开Tasks > build,双击assembleassembleRelease。编译成功后,aar文件会生成在模块目录/build/outputs/aar/下。

关键检查点:打开生成的aar文件(用解压软件),检查libs/目录下是否包含了wechat-sdk-android.jar,但不应该包含classes.jar。如果包含了classes.jar,说明之前的compileOnly依赖没有生效,需要检查gradle配置,或者手动从aar中删除这个jar,否则Unity打包时会冲突。

5. Unity工程配置与C#桥接

5.1 导入AAR与配置AndroidManifest

  1. 在Unity项目中,创建文件夹Plugins/Android。将上一步生成的.aar文件(以及可能用到的其他aar,如微信SDK的aar,如果你用方案B手动引入了)复制到这个文件夹。Unity在构建Android APK时,会自动处理该目录下的原生插件。
  2. 配置自定义AndroidManifest.xml:Unity默认会生成一个AndroidManifest。为了注册我们的MainActivityWXPayEntryActivity,我们需要提供一个自定义的。在Plugins/Android下创建AndroidManifest.xml文件。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yourcompany.yourapp" <!-- 替换为你的包名 --> xmlns:tools="http://schemas.android.com/tools"> <!-- 对于 Android 11 (API 30) 及以上,必须添加此 queries 声明,才能正常检测和调起微信 --> <queries> <package android:name="com.tencent.mm" /> </queries> <application> <!-- 替换Unity默认的Activity为我们自定义的MainActivity --> <activity android:name="com.yourcompany.yourapp.wx.MainActivity" android:exported="true" android:theme="@style/UnityThemeSelector" android:launchMode="singleTask" tools:replace="android:theme"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="unityplayer.UnityActivity" android:value="true" /> </activity> <!-- 微信支付回调Activity,必须放在.wxapi包下 --> <activity android:name="com.yourcompany.yourapp.wxapi.WXPayEntryActivity" android:exported="true" android:launchMode="singleTask" /> <!-- 如果你还需要微信登录等功能,也需要对应的WXEntryActivity --> <!-- <activity android:name=".wxapi.WXEntryActivity" ... /> --> </application> </manifest>

重要提示android:exported="true"是必须的,否则其他应用(微信)无法启动这个Activity。<queries>段落是针对Android 11以上包可见性限制的解决方案,没有它,isWXAppInstalled()会返回false,且无法调起微信。

  1. 在Unity Editor中,打开Player Settings > Android > Publishing Settings,勾选Custom Main ManifestCustom Main Gradle Template(如果需要修改Gradle配置)。确保我们自定义的Manifest文件被使用。

5.2 编写C#调用脚本

在Unity中创建一个C#脚本,例如WeChatPayManager.cs,负责与Android Java层通信。

using UnityEngine; using System; public class WeChatPayManager : MonoBehaviour { private static AndroidJavaObject _currentActivity; private static AndroidJavaObject CurrentActivity { get { if (_currentActivity == null) { AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); _currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); } return _currentActivity; } } /// <summary> /// 检查设备是否安装微信 /// </summary> public static bool IsWeChatInstalled() { try { return CurrentActivity.Call<bool>("isWeChatInstalled"); } catch (Exception e) { Debug.LogError("[WeChatPay] Check installation failed: " + e.Message); return false; } } /// <summary> /// 调用微信支付 /// </summary> /// <param name="payParams">从服务器获取的支付参数对象</param> /// <param name="callbackGameObject">接收回调的GameObject名称</param> /// <param name="callbackMethod">接收回调的方法名称</param> public static void RequestPayment(WeChatPayParams payParams, string callbackGameObject, string callbackMethod) { if (payParams == null) { Debug.LogError("[WeChatPay] Payment parameters are null."); return; } if (!IsWeChatInstalled()) { Debug.LogError("[WeChatPay] WeChat is not installed."); // 可以在这里触发一个失败回调 GameObject.Find(callbackGameObject)?.SendMessage(callbackMethod, "NOT_INSTALLED"); return; } try { CurrentActivity.Call("requestWeChatPay", payParams.appId, payParams.partnerId, payParams.prepayId, payParams.package, payParams.nonceStr, payParams.timeStamp, payParams.sign, callbackGameObject, callbackMethod); Debug.Log($"[WeChatPay] Payment request sent. PrepayId: {payParams.prepayId}"); } catch (Exception e) { Debug.LogError($"[WeChatPay] Failed to call native method: {e.Message}"); GameObject.Find(callbackGameObject)?.SendMessage(callbackMethod, "NATIVE_CALL_FAILED"); } } /// <summary> /// 支付参数结构体,应与服务端返回的JSON对应 /// </summary> public struct WeChatPayParams { public string appId; // 微信开放平台AppID public string partnerId; // 商户号 MCHID public string prepayId; // 预支付交易会话ID,由统一下单接口返回 public string package; // 固定值 "Sign=WXPay" public string nonceStr; // 随机字符串 public string timeStamp; // 时间戳(秒) public string sign; // 签名 } } // 示例:挂载在场景中的回调处理脚本 public class PaymentHandler : MonoBehaviour { void Start() { // 示例:从服务器获取支付参数(这里需要网络请求) // StartCoroutine(FetchPaymentParams("order_123")); } // 这个函数名需要和调用RequestPayment时传入的callbackMethod一致 public void OnWeChatPayCallback(string result) { Debug.Log($"[PaymentHandler] WeChat Pay Callback: {result}"); switch (result) { case "PAY_SUCCESS": // 支付成功,但此时仅代表用户支付动作完成。 // 必须通知服务器,让服务器查询微信支付后台确认最终订单状态。 StartCoroutine(ConfirmOrderWithServer("order_123")); break; case "PAY_CANCEL": // 用户取消支付 UIManager.Instance.ShowToast("支付已取消"); break; default: // 支付失败,result可能包含错误码,如 "PAY_FAILED_-1" UIManager.Instance.ShowToast("支付失败,请重试"); break; } } // 模拟调用支付 public void OnPayButtonClicked() { // 1. 先检查是否安装微信 if (!WeChatPayManager.IsWeChatInstalled()) { UIManager.Instance.ShowToast("请先安装微信客户端"); return; } // 2. 模拟从服务器获取到的参数(实际项目中需网络请求) WeChatPayManager.WeChatPayParams mockParams = new WeChatPayManager.WeChatPayParams { appId = "wx1234567890abcdef", partnerId = "1900000109", prepayId = "wx20250410123456abcdef", package = "Sign=WXPay", nonceStr = "5K8264ILTKCH16CQ2502SI8ZNMTM67VS", timeStamp = "1712731200", sign = "C380BEC2BFD727A4B6845133519F3AD6" // 示例签名,切勿直接使用 }; // 3. 调用支付,指定本GameObject和回调方法名 WeChatPayManager.RequestPayment(mockParams, this.gameObject.name, "OnWeChatPayCallback"); } private System.Collections.IEnumerator ConfirmOrderWithServer(string orderId) { // 向你的服务器发起请求,验证订单最终状态 // yield return ... yield return null; } }

6. 打包、签名与平台配置的终极陷阱

代码写完了,但距离成功调起支付还有最后,也是最关键的几步。

6.1 获取并配置应用签名

这是导致“无法调起微信”最常见的原因。微信开放平台需要验证调用方的身份,验证方式就是应用签名

  1. 不要使用调试签名:Unity在Editor中运行或打Debug包时使用的调试密钥(debug.keystore)的签名,与发布包(使用你自己的.keystore文件)的签名完全不同。
  2. 获取发布版签名
    • 用你的发布密钥库(.keystore文件)打包一个正式的APK(或Android App Bundle)。
    • 将这个APK安装到你的测试手机上。
    • 在手机上安装微信官方提供的“签名生成工具”(可在微信开放平台文档中找到下载链接)。
    • 打开工具,输入你的应用包名(如com.yourcompany.yourapp),点击“获取签名”。工具会计算并显示一个32位的MD5签名(不带冒号)。
  3. 配置开放平台:登录微信开放平台,进入你的应用详情页,找到“修改”应用签名的地方,将上一步获取的签名字符串填写进去。注意:这个修改可能需要一段时间(通常是几个小时)审核生效。在生效前,你用该签名打包的APK依然无法调起微信。

6.2 打包流程与关键设置

  1. Player Settings:
    • Other Settings > Package Name: 必须与开放平台注册的包名、AndroidManifest中的包名、Android Studio工程包名完全一致
    • Other Settings > Minimum API Level: 建议设置为21(Android 5.0)或更高,但需注意<queries>标签要求API Level 30+,如果设低了,需要额外的兼容性处理。
    • Publishing Settings > Keystore: 选择你用于发布签名的.keystore文件,并填写正确的alias和密码。
  2. 构建:在Build Settings中选择Android平台,进行构建。建议先打一个Development Build并勾选Autoconnect Profiler,方便在真机上通过Logcat查看日志。

6.3 真机调试与日志查看

连接Android手机,开启USB调试。打包并安装APK。

  • 使用Android Studio的Logcat:这是最强大的调试工具。在Android Studio中连接设备,选择你的应用进程,过滤Tag为MicroMsg.WXPayEntry或你自定义的TAG,可以清晰地看到支付回调的日志。
  • 使用adb logcat命令:如果你习惯命令行,adb logcat -s MicroMsg.WXPayEntry可以起到同样的过滤效果。
  • 常见错误日志
    • registerApp fail, appId is invalid:AppID填写错误,或该AppID与当前应用包名/签名不匹配。
    • sendReq fail, not registered:没有成功调用wxApi.registerApp
    • 没有任何错误日志,但微信没反应:大概率是签名未配置或未生效,或者<queries>标签在低版本Android上缺失导致无法找到微信包。

7. 服务端交互与安全实践

客户端集成只是半边天,一个健壮的支付系统离不开服务端的配合。

7.1 支付流程中的服务端职责

你的服务器需要至少实现两个接口:

  1. 统一下单接口:当客户端发起支付请求时,客户端不应直接接触微信支付API密钥。应由你的服务器接收订单信息(金额、商品描述、用户IP等),然后使用商户密钥(MCHKEY)按照微信V3或V2 API的规则生成签名,调用微信的统一下单API。微信服务器会返回一组支付参数(prepay_id,nonce_str等),你的服务器将这些参数返回给Unity客户端。签名过程必须在服务端完成!
  2. 支付结果通知/查询接口:客户端收到支付成功回调(errCode=0)后,应立刻通知你的服务器:“用户可能支付成功了”。你的服务器需要做两件事之一:
    • 处理异步通知:微信支付后台会在支付成功后,主动向你服务器配置的notify_url发送一个POST请求,携带加密的支付结果。这是最权威的支付成功凭证。你的服务器需要验证签名、解密数据、处理业务逻辑(如给用户加钻石),并返回成功响应给微信。
    • 主动查询订单:如果担心异步通知丢失,可以在收到客户端通知后,由服务器主动调用微信的查询订单API,根据返回的订单状态进行最终确认。

7.2 客户端-服务端交互示例

// 在PaymentHandler.cs中补充 private System.Collections.IEnumerator StartPaymentFlow(string productId) { // 1. 向自家服务器请求支付参数 string orderUrl = $"https://yourserver.com/api/createOrder?product={productId}&userId={UserManager.Instance.UserId}"; using (UnityWebRequest request = UnityWebRequest.Get(orderUrl)) { yield return request.SendWebRequest(); if (request.result == UnityWebRequest.Result.Success) { // 解析服务器返回的JSON,得到 WeChatPayParams WeChatPayManager.WeChatPayParams payParams = JsonUtility.FromJson<WeChatPayParams>(request.downloadHandler.text); // 2. 调用原生支付 WeChatPayManager.RequestPayment(payParams, gameObject.name, "OnWeChatPayCallback"); } else { Debug.LogError("Failed to create order: " + request.error); } } } public void OnWeChatPayCallback(string result) { if (result == "PAY_SUCCESS") { // 3. 通知服务器支付成功(让服务器去验证) StartCoroutine(NotifyServerPaymentResult("orderId_from_payParams")); } // ... 其他结果处理 } private System.Collections.IEnumerator NotifyServerPaymentResult(string orderId) { string notifyUrl = $"https://yourserver.com/api/confirmOrder?orderId={orderId}"; using (UnityWebRequest request = UnityWebRequest.Post(notifyUrl, "")) { yield return request.SendWebRequest(); if (request.result == UnityWebRequest.Result.Success) { // 服务器确认成功,更新本地状态 Debug.Log("Order confirmed by server!"); } } }

8. 进阶问题与性能优化

8.1 多场景与GameObject生命周期管理

如果你的支付调用和回调处理分布在不同的场景或GameObject上,需要谨慎管理。UnitySendMessage要求接收消息的GameObject在场景中处于活动状态。如果支付发起后用户切换了场景,原来的GameObject被销毁,回调就会丢失。

解决方案

  • 使用单例或持久化GameObject:创建一个名为PaymentCallbackManager的GameObject,挂载一个DontDestroyOnLoad脚本,专门用于处理支付回调。所有支付请求都指定这个GameObject为回调目标。
  • 使用事件/委托系统:构建一个全局的事件管理器。支付回调脚本收到UnitySendMessage后,不直接处理业务逻辑,而是触发一个全局的支付结果事件。其他模块(如UI、数据管理器)订阅这个事件。这样解耦了回调接收者和业务处理者。

8.2 支付参数缓存与重试机制

网络不稳定时,从服务器获取支付参数可能失败。可以考虑在本地缓存一份有效的支付参数(注意预支付IDprepay_id有有效期,通常2小时)。当支付因网络问题失败时,可以尝试使用缓存的参数直接发起支付,避免再次请求服务器。

8.3 减少包体积

微信SDK的aar/jar文件有一定体积。如果对包体敏感,可以考虑使用ProGuard或R8代码混淆(在Android Studio的library模块中配置minifyEnabled true),移除无用的代码。但务必做好测试,确保混淆后与微信SDK的交互正常。

8.4 兼容性处理

  • Android 12+ 的PendingIntent可变性:如果你的targetSdkVersion设置为31或更高,在创建通知等相关功能时,如果涉及微信支付结果的PendingIntent,需要声明其可变性FLAG_IMMUTABLEFLAG_MUTABLE。虽然支付回调本身不直接涉及,但若你的应用有相关功能需注意。
  • 备用支付方式:始终检查IsWeChatInstalled()。如果未安装,应有友好的UI提示,并引导用户使用其他支付方式(如支付宝、银联)或引导安装微信。

9. 常见问题排查速查表

下表汇总了集成过程中最常见的问题、可能原因和解决方案:

问题现象可能原因排查步骤与解决方案
点击支付无任何反应,微信未启动1. 应用签名未在开放平台配置或错误。
2. 包名不一致。
3. Android 11+ 缺少<queries>声明。
4.MainActivity未成功替换Unity默认Activity。
1. 用发布签名打包APK,安装后使用微信签名工具获取签名,与开放平台配置比对。
2. 检查Unity、AndroidManifest、开放平台三处包名是否完全一致。
3. 确认AndroidManifest.xml中已添加<queries>段落。
4. 检查Logcat,查看应用启动时运行的Activity是否是自定义的MainActivity
调起微信后,显示“商家参数格式错误”支付参数(appId,partnerId,prepayId,sign等)有误或缺失。1. 检查所有支付参数是否从服务器正确获取并完整传递到Java层。
2.重点检查签名(sign):确保是服务端用商户密钥对指定参数生成的正确签名。客户端不能参与签名生成。
3. 检查timeStamp是否为字符串格式的秒数。
支付完成后,无法返回原应用,或回调不执行1.WXPayEntryActivityandroid:exported未设为true
2.WXPayEntryActivity未在AndroidManifest.xml中正确声明。
3. 包名路径错误,不是[包名].wxapi.WXPayEntryActivity
4. 回调的GameObject不存在或方法名错误。
1. 确认Manifest中该Activity的exported="true"
2. 确认Manifest中该Activity的声明路径完全正确。
3. 在WXPayEntryActivity.onResp开始处加Log,确认是否被调用。
4. 检查C#调用RequestPayment时传入的callbackGameObjectcallbackMethod名称是否准确,且该GameObject在场景中激活。
Logcat报错:ClassNotFoundExceptionNoClassDefFoundError1. 微信SDK的jar/aar未正确打包进APK。
2. Unity的classes.jar冲突。
1. 如果用方案B(手动jar),检查aar的libs/目录下是否有微信SDK的jar。
2. 如果用方案A(EDM),检查Unity Console,看External Dependency Manager是否成功解析并添加了依赖。
3. 检查aar中是否错误地包含了classes.jar,如果有,修改gradle为compileOnly并重新打包aar。
在Editor中运行正常,打包后失败1. 使用了调试签名,与开放平台配置的发布签名不符。
2. Development Build和Release Build的代码优化/混淆导致问题。
3. 依赖的.so库未包含在发布包中。
1.永远使用发布签名进行最终测试
2. 关闭代码优化(Scripting Backend为Mono时)或关闭混淆再试。
3. 检查Player Settings > Publishing Settings > Split Application Binary是否被误勾选,这可能导致原生库丢失。
支付成功,但服务器未收到异步通知1. 服务器notify_url未正确配置或不可访问。
2. 服务器处理通知后,未按规定返回成功的XML/JSON给微信。
3. 网络延迟或微信通知重试机制尚未触发。
1. 登录微信商户平台,检查支付配置中的通知URL。
2. 检查服务器端通知处理逻辑,确保在验证签名和解密后,返回<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>(V2)或{“code”: “SUCCESS”, “message”: “成功”}(V3)。
3. 商户平台有通知查询工具,可以手动补发通知。

整个集成过程就像搭积木,每一步都要严丝合缝。最关键的三个匹配:包名、签名、回调Activity路径,只要有一个对不上,支付流程就通不了。多利用Logcat和真机调试,耐心比对每一步的输出,问题总能定位。当你第一次成功看到微信支付界面弹出来的时候,那种感觉,之前的折腾都值了。

http://www.cnnetsun.cn/news/3332801.html

相关文章:

  • Hadoop 3.3.6 MapReduce 性能调优实战:Shuffle 阶段 3 大参数优化与吞吐量提升 40%
  • 操作系统 I/O 软件 4 层架构:从用户请求到硬件中断的 5 个关键步骤拆解
  • MobaXterm 连接 Ubuntu 22.04 失败:3 种网络模式(NAT/桥接)配置与端口映射详解
  • 纽扣电池供电优化:NBM5100A与STM32F042K6的低功耗方案
  • Git 分支命名与版本号映射:基于 4 种主流工作流的实战对比与选择指南
  • 工业信号采集系统设计与抗干扰优化实践
  • Java中public class与class的区别详解
  • 题解:Atcoder Beginner Contest abc466 A~D
  • FastAPI核心原理:契约驱动的现代Web架构设计
  • 俩个指令完成VMwareTool的安装
  • DAVE 4 环境配置:Windows/Linux 双平台安装与 3 个常见报错解决
  • PyTorch深度学习框架完整学习路径:从核心概念到实战项目
  • Perplexity搜索效率提升300%:从新手到高手的5步实战工作流(附真实数据对比)
  • 模板驱动型文档自动化:结构化组装替代手工写作
  • 直流有刷电机控制系统设计与H桥驱动器应用
  • 终极指南:使用OpenCore Legacy Patcher让老旧Mac重获新生,完整实战教程深度揭秘
  • Cisco IOS 交换机 VLAN 批量配置:3种端口范围语法与 5 个实战场景解析
  • ROS 2 Humble 坐标变换实战:3种TF2库方法对比与性能实测
  • Tushare接口文档:ST风险警示板股票(st)
  • BepInEx框架解析:解决Unity插件开发三大痛点与实战优化
  • Hyperledger Fabric 2.5 构建成绩管理系统:3节点联盟链部署与性能实测
  • 2026 无人机培训行业洗牌复盘:千余家机构出局,拆解成都先飞智能长期存活的合规与技术底层优势
  • 连续统假设:为什么实数的个数无法被数学公理判定
  • 专业的那曲野生虫草供应商
  • 深入解析C++循环结构:while与do...while的本质差异与应用场景
  • iCloud Drive 同步异常排查:从网络诊断到缓存清理的 4 层检查法
  • 渗透测试实战:从弱口令到内网漫游的5个关键步骤与工具链
  • Python实时数据流处理管道构建:从文件监听、日志解析到结果输出
  • C++实战:LSB规则下十六进制字节流到有符号整数的解码指南
  • 费马大定理的现代证明:从弗雷曲线到模形式的桥梁