公司动态
Unity接入微信与支付宝SDK实战:登录、分享与支付全流程填坑指南
简介这是一份面向Unity开发者的第三方服务接入整合包覆盖微信登录、微信分享、微信支付与支付宝SDK的Unity端集成方案适合需要在iOS/Android项目中快速接入支付与社交能力的团队或个人。压缩包共7322个文件包含约3000个C#脚本、2100余个bin数据文件、114个DLL动态库以及XML配置、预制体和场景资源整体约465MB目录结构基本对应SDK、示例工程与平台配置模块。已有2236人学习下载。资料中详细给出了微信SDK在IL2CPP后端下的配置方式涉及登录、分享、支付的核心管理类调用以及支付宝订单参数构造与结果监听等关键环节同时涵盖微信分享中文本、图片、网页链接对象的构造预支付订单处理支付回调状态判断多平台差异兼容、常见异常排查和日志记录等实战细节。资源保留了Unity工程、Android/iOS配置参考和脚本注释便于直接对照验证和二次开发适合刚接触SDK接入的初级开发者也能帮助统一管理多端服务的团队查漏补缺。 做了几年Unity开发只要做过国内发行基本都躲不过这两座大山微信全家桶登录、分享、支付和支付宝支付。尤其是做社交类、工具类或者带内购的游戏渠道方动不动就要求接微信登录和分享支付环节又是微信支付支付宝双通道一起上。这个项目本身不复杂但坑是真的多藏得也深。我把整个接入过程、踩过的坑、以及排查思路完整梳理一遍包括很多官方文档里没写清楚但实际开发中绕不开的细节希望能帮后面接的人少走弯路。1. 为什么国内发布绕不开这几套SDK1.1 微信生态其实是三套独立的能力很多人第一次接的时候会误以为微信登录、分享、支付是一套SDK包打天下其实在工程结构上它们是高度耦合的微信OpenSDK统一提供但在开放平台的能力配置上完全是三个独立的应用能力。你在微信开放平台创建的应用可以只申请登录权限也可以同时把分享和支付都开通。这导致一个非常常见的现象代码写好了、测试跑通了但正式环境一调就报错最后排查半天发现是开放平台对应的权限没开通。微信登录走的是OAuth 2.0的授权码模式。客户端发起授权请求拿到一个临时code然后由你的服务端拿这个code去微信的API换取access_token和用户的openid。这里面有个特别容易误解的地方客户端永远只能拿到code不应拿token更不能直接在客户端调微信的接口换取用户信息。我看到过不少新手把AppSecret放到客户端代码里这是非常危险的做法AppSecret一旦被反编译出来等于把你的微信应用完全暴露给别人。微信分享则是另一套逻辑——构建一个WXMediaMessage塞进去文本、图片、网页链接等不同类型的媒体内容然后调SendMessageToWXReq。这里需要注意的是你要区分清楚是分享给会话还是分享到朋友圈两者的场景值WXSceneSession / WXSceneTimeline不一样而且每种分享类型对缩略图的大小都有严格的限制32KB以内超了就直接分享失败没有任何提示。微信支付是最大的一块硬骨头。它的完整链路是服务端调用微信支付统一下单接口拿到prepay_id再按规则生成客户端调起支付所需的参数客户端拿到参数后调WXPayEntryActivity唤起微信支付支付完成后微信会回调客户端同时微信服务器也会异步通知你的服务端。这中间涉及两套回调一套给客户端一套给服务端很多人只处理了客户端回调结果订单状态一直没更新。1.2 支付宝是另一套独立的体系支付宝SDK和微信SDK完全不互通SDK不同、签名算法不同、回调机制也不同。支付宝的核心链路是服务端用支付宝的私钥生成订单字符串客户端拿到这个字符串后直接调支付宝SDK的支付接口用户完成支付后支付宝通过URL Scheme回调你的App。支付宝最大的特点是它在客户端层面的接入比微信简单——不需要像微信那样配置微信回调所需的WXEntryActivity只需要在AndroidManifest里注册一个回调Activity并配置好URL Scheme就能收到支付结果。但支付宝在服务端的要求反而更高它要求你的服务端必须用RSA2SHA256WithRSA做敏感信息签名而且所有订单信息都要严格按支付宝的字段规范拼装拼错一个字段就可能支付失败或者验签失败。2. 接入前的准备AppID、包名、签名这三样是命根子2.1 开放平台申请与权限开通微信这边需要去微信开放平台open.weixin.qq.com注册开发者账号并创建移动应用。审核通过后你会拿到AppID和AppSecret。AppSecret只能看一次务必立刻保存到服务端配置里以后要重置只能重新生成。创建应用之后不要以为就完事了还需要去接口权限里确认一下登录、分享、支付这几个能力是否已经开通很多人的应用创建时默认只开了登录分享和支付要去单独申请。支付宝这边需要去支付宝开放平台open.alipay.com创建一个应用然后配置应用公钥。支付宝走的签名机制是商户自己生成一对RSA密钥把公钥上传给支付宝私钥自己保存。这里有个非常反直觉的细节支付宝不是简单的公钥加密私钥解密而是你用自己的私钥对订单信息签名支付宝拿着你上传的公钥去验签支付宝返回的异步通知则用支付宝的公钥验签。所以你要保存两个东西自己的应用私钥绝对不能泄露和支付宝的公钥从开放平台复制。2.2 Android端最关键的包名与签名配置微信和支付宝在开放平台配置的包名必须和你Unity最终打包出的APK包名完全一致不允许有任何偏差。但很多人在Unity里改包名后忘了同步到开放平台或者反过来。这里我建议一开工就把包名定死先在开放平台配置好再去Unity Player Settings里设置避免后期返工。签名也是重灾区。微信登录和支付都依赖签名校验APK的签名信息必须和开放平台配置的MD5签名一致。很多人在开发阶段用的是Unity默认的debug.keystore调试签名上线打包时换成了正式签名结果开放平台里还是调试签名的MD5——线上环境微信支付直接就调不起来。我的经验是申请微信应用时如果项目已经确认了正式签名的keystore那就直接填正式签名如果还在开发期也要记得在最终发版前把开放平台的签名配置改成正式签名然后重新提交审核。开发阶段用AndResGuard或者360加固这些工具时也要注意有些加固会改变签名也需要重新同步。支付宝对签名的校验主要是在服务端完成的。客户端只需要配置好支付宝SDK不涉及签名校验但支付宝的SDK会校验你APK的包名是否与传入的URL Scheme前缀匹配不匹配就直接回调失败。2.3 iOS端的配置也不能漏iOS端没有包名和签名的概念取而代之的是URL Scheme。微信需要你在Info.plist里配置一条URL Scheme格式是wx AppID比如wx1234567890abcdef。支付宝需要配置一条你自己的自定义URL Scheme一般建议命名规范和业务相关比如alipay1234或者你的应用名称拼音。iOS端如果用的是Unity 2019及以上版本还需要注意LSApplicationQueriesSchemes这个字段微信和支付宝的SDK需要查询系统里是否安装了对应App所以必须在Info.plist里声明weixin和alipays这两个查询Scheme否则调起来会直接报not installed。3. 微信登录和分享的接入流程3.1 第一步永远是初始化IWXAPI在Unity里接入微信SDK最稳妥的做法是使用官方提供的OpenSDK Android和iOS原生库然后自己封装C#接口通过UnitySendMessage做桥接。也有第三方插件平台做了一体化封装但我个人更建议自己用Android Native和iOS Native封装因为微信SDK版本更新频繁第三方插件往往跟不上。初始化时调用IWXAPI.registerApp(appId)这个接口会校验appId与AndroidManifest里声明的WXEntryActivity包路径是否匹配。这里有个新手容易忽略的点WXEntryActivity所在的包路径不能随便写必须是你的应用包名.wxapi.WXEntryActivity不能多一层目录也不能少一层。Unity打包时如果你的包名是com.example.game那WXEntryActivity就必须放在com.example.game.wxapi包下面AndroidManifest里声明为com.example.game.wxapi.WXEntryActivity。3.2 发起登录请求微信登录的调用很简单构建一个SendAuth.Req设置scope为snsapi_userinfo然后调用iwxapi.sendReq(req)。微信客户端接收请求后会弹出授权页面用户点击同意后微信会回调你的WXEntryActivity把授权结果带回。这里的关键在于code的有效期和一次性使用。微信返回的code只能用一次你用它在服务端换取access_token之后这个code就作废了。如果服务端换取失败不要试图用同一个code重试而是应该让用户重新发起登录。另外code的有效期大概5分钟服务端要尽快处理。登录态过期是另一个容易被忽略的问题。access_token有效期一般是2小时refresh_token有效期是30天。在实际项目中我建议把openid和refresh_token缓存起来access_token过期后用refresh_token刷新尽量避免用户频繁重新授权。3.3 处理回调——WXEntryActivity里的门道Unity接入微信登录最绕不开的就是这个WXEntryActivity。它在原生层接收微信的回调然后通过UnitySendMessage把结果转发给Unity场景中的GameObject。我在项目中通常会做一个专门的类放在Android原生工程里public class WXEntryActivity extends Activity implements IWXAPIEventHandler { Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); api WXAPIFactory.createWXAPI(this, Constants.WX_APP_ID, false); api.handleIntent(getIntent(), this); } Override public void onReq(BaseReq req) { // 微信侧请求App通常SDK启动时会调用 } Override public void onResp(BaseResp resp) { switch (resp.getType()) { case ConstantsAPI.COMMAND_SEND_AUTH: SendAuth.Resp authResp (SendAuth.Resp) resp; String code authResp.code; UnitySendMessage(WXManager, OnAuthResp, code); break; case ConstantsAPI.COMMAND_SENDMESSAGE_TO_WX: UnitySendMessage(WXManager, OnShareResp, String.valueOf(resp.errCode)); break; } finish(); } }这里有个非常容易踩的坑WXEntryActivity必须设置启动模式为singleTask否则在微信回调你的App时系统会重新创建一个Activity实例导致onResp收不到回调。实际上微信官方要求WXEntryActivity使用singleTask启动模式。另外一个坑是WXEntryActivity的onCreate里调用了handleIntent但微信的回调是通过底层Activity的onNewIntent触发的所以onNewIntent也要重写Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); api.handleIntent(intent, this); }这就意味着不能只处理onCreateonNewIntent同样必须处理否则在部分手机上登录后回调会莫名丢失。3.4 登录后的用户信息获取拿到code之后服务端要去https://api.weixin.qq.com/sns/oauth2/access_token换取access_token和openid再拿着access_token去https://api.weixin.qq.com/sns/userinfo获取用户昵称、头像、性别等信息。可以看到这一步必须放到服务端完成因为要使用AppSecret。这里我建议一个更安全的做法服务端换到access_token后不要直接返回给客户端而是由服务端自己再去调userinfo接口把需要的昵称头像等字段过滤后再返回给客户端。这样客户端的网络层完全接触不到access_token安全性会好很多。3.5 分享内容与缩略图的坑微信分享支持文本、图片、音乐、视频、网页等类型。Unity游戏里最常用的是网页分享和图片分享。分享网页时必须要设置title、description、thumbData缩略图和网页URL。thumbData这个字段有32KB的大小限制超过就会分享失败。很多Unity开发者直接把一张高清图压缩成base64的byte数组扔进去结果分享失败最后发现是缩略图超过了限制。正确做法是设置缩略图前先做等比缩放把最长边控制在100像素以内然后通过Bitmap.compress(Bitmap.CompressFormat.JPEG, 85, baos)或者WebP格式压缩到32KB以下。我一般在Unity侧就把纹理缩放到合适尺寸再传给Android层这样iOS和Android都能复用。4. 微信支付的接入流程4.1 先理清支付链路的职责边界微信支付最容易让人懵的地方是职责切分不清晰。客户端负责三件事发起支付、接收支付结果回调、把结果展示给用户服务端负责三件事调用统一下单接口拿到prepay_id、生成客户端支付参数、接收微信的异步通知并更新订单状态。很多人会问为什么客户端不能直接调统一下单因为统一下单需要商户号API密钥这个密钥放在客户端就是自爆。所以正确流程是客户端请求自家服务端下单接口服务端调微信统一下单返回随机字符串、时间戳、nonceStr、package固定值SignWXPay、signType和paySign签名这六个参数给客户端客户端用这些参数调起微信支付。4.2 服务端统一下单与参数生成服务端调微信统一下单接口/pay/unifiedorder时需要传的参数非常细碎但核心就几个appid、mch_id、out_trade_no商户订单号、total_fee金额单位是分、body商品描述、notify_url异步通知地址、trade_type这里用APP。这里有几个极其容易忽略的细节金额单位是分不是元。下单接口传的是整数分很多服务端同学直接把前端传的12.5传上去了微信直接报金额格式错误。notify_url必须是公网能访问的HTTPS地址不能是IP也不能带query参数。out_trade_no需要保证唯一性不能用时间戳当订单号并发下单时很容易撞车。我一般会采用日期业务前缀随机数的方式生成。服务端拿到prepay_id后需要再按微信支付文档生成APP调起支付的参数。这个过程不需要再调接口只要在本地用MD5或HMAC-SHA256按字典序拼接参数生成paySign就行。签名字段包括appid、partnerid、prepayid、package、noncestr、timestamp这六个参数。其中package固定是SignWXPay这个很多人容易写错可能是少了大写S或者把等号写错导致支付调起时一直报参数错误。4.3 Unity客户端拉起支付的代码逻辑在Unity侧我通常把Activity的回调结果通过UnitySendMessage转发给C#层然后在C#里封装一个PayManagerpublic class PayManager : MonoBehaviour { private static PayManager instance; public void WxPay(string partnerId, string prepayId, string nonceStr, string timeStamp, string sign) { // 通过Android原生桥接传入参数 AndroidJavaObject activity new AndroidJavaClass(com.unity3d.player.UnityPlayer) .GetStaticAndroidJavaObject(currentActivity); activity.Call(wxPay, partnerId, prepayId, nonceStr, timeStamp, sign); } public void OnWxPayResult(string result) { // 处理支付结果 // 0 表示支付成功但这里仅做UI提示真正的订单确认看服务端 } }客户端收到支付成功errCode为0的回调后注意一个核心原则支付成功不等于订单完成。客户端回调只能用来刷新UI或跳转结果页订单的最终确认必须依赖服务端收到微信异步通知后更新订单状态再由服务端告诉客户端或者客户端主动轮询服务端订单状态。4.4 回调Activity配置与常见失败微信支付在Android端需要两个回调入口一个是WXPayEntryActivity另一个是WXEntryActivity。WXPayEntryActivity同样必须放在包名.wxapi包下名字必须是WXPayEntryActivity。很多人在接支付时只配置了WXEntryActivity结果支付完成后点返回按钮没有反应或者游戏一直停在那里不动。WXPayEntryActivity的处理逻辑和WXEntryActivity基本一样都继承IWXAPIEventHandlerpublic class WXPayEntryActivity extends Activity implements IWXAPIEventHandler { Override public void onResp(BaseResp resp) { if (resp.getType() ConstantsAPI.COMMAND_PAY_BY_WX) { int errCode resp.errCode; String errStr resp.errStr; // 0成功-1错误-2用户取消 UnitySendMessage(PayManager, OnWxPayResult, String.valueOf(errCode)); } finish(); } }一个常见现象是支付后微信转圈一直不回调App或者WXPayEntryActivity收到了回调但Unity侧没反应。这种问题八成是UnitySendMessage的对象名或方法名不匹配。UnitySendMessage的第一个参数必须是当前场景里真实存在的GameObject名第二个参数是挂在它身上的组件方法名而且方法必须是public的。很多人在场景里改过GameObject名忘记同步原生层的UnitySendMessage调用名结果回调就静默丢失了。5. 支付宝支付的接入流程5.1 支付宝SDK与Unity的集成方式支付宝SDK在Unity里的集成方式相对简单因为支付宝官方提供的AAR包可以直接放到Assets/Plugins/Android目录下。客户端侧不需要像微信那样处理复杂的回调Activity只需要配置好URL Scheme然后调支付宝SDK的支付接口。支付宝官方的接入方式有两种老版的PayTask.payV2接口和新版的AlipaySDK.defaultService.payOrder接口。在Unity里我会用AndroidJavaObject来反射调用public void AlipayPay(string orderInfo) { using (AndroidJavaClass unityPlayer new AndroidJavaClass(com.unity3d.player.UnityPlayer)) { AndroidJavaObject activity unityPlayer.GetStaticAndroidJavaObject(currentActivity); AndroidJavaObject alipayClass new AndroidJavaObject(com.alipay.sdk.app.PayTask, activity); // payV2 返回的是MapString, String AndroidJavaObject resultMap alipayClass.CallAndroidJavaObject(payV2, orderInfo, true); // 解析resultMap AndroidJavaObject resultStatus resultMap.CallAndroidJavaObject(get, resultStatus); string resultStatusStr resultStatus.Callstring(toString); // 9000 表示支付成功 } }注意payV2的第二个参数是isShowLoading如果传true会弹出一个正在支付的加载框。这个加载框在某些定制ROM上可能会出现显示异常我一般传false自己在Unity侧做一个加载UI。5.2 订单串生成与签名支付宝客户端的orderInfo是一个很长的字符串包含partner、seller_id、out_trade_no、subject、total_amount、notify_url、charset、sign_type、sign等字段。服务端把各个字段按支付宝要求拼成请求串然后按照app_id、biz_content等新规范把核心参数封装成JSON格式再签名。这里要特别提醒RSA2签名时参数内容必须和实际发送的值完全一致多一个空格、少一个逗号都会导致验签失败。而且支付宝的biz_content里是一个JSON字符串这个JSON的字段顺序是否会被调整、是否有转义都会影响验签结果。我在实际项目中遇到过多次服务端签名成功但客户端验签失败的问题排查到最后都是服务端拼字符串时多了不可见字符比如BOM头或者换行符。5.3 支付成功后的服务端验证支付宝支付完成后客户端会返回一个resultStatus9000表示支付成功。但和微信支付的原则一样客户端结果不可信必须等支付宝服务器异步通知你的服务端服务端收到通知后验签、核对金额、核对订单号确认无误后才给客户端发确认消息。支付宝的异步通知是个POST请求会对你的notify_url以application/x-www-form-urlencoded格式POST一堆参数其中有个trade_status字段只有TRADE_SUCCESS才是真正支付成功。很多人以为收到通知就算成功了但如果是WAIT_BUYER_PAY这种状态用户未支付就不能更新订单状态。验签时要注意支付宝异步通知验签需要把收到的POST参数中除了sign和sign_type以外的所有参数按字典序拼接后用支付宝公钥验签。不要使用自己的应用私钥去验签这是很多新手搞错的点——签名方向反了。5.4 iOS端支付宝的特殊处理iOS端支付宝接入比Android更简单但有个绕不开的配置需要留意。支付宝SDK采用URL Scheme回调你需要在Info.plist的URL Types中加一条identifier填alipayURL Schemes填你要用的scheme这个scheme必须以字母开头推荐用应用的拼音或者英文名。如果这个scheme配置不规范比如以数字开头支付宝支付完成后就回不来你的App。支付宝SDK在iOS端没有微信那么严格的包路径要求但如果你同时接了微信和支付宝要注意两个回调URL Scheme不能冲突。微信的scheme是wxAppID支付宝的是自定义字符串一般不会有冲突但都放在一个Info.plist里时顺序有讲究——同一个key下多个URL Type不会互相影响但LSApplicationQueriesSchemes里必须把weixin和alipays都声明好。6. 联调经验与上线前检查清单6.1 联调阶段最折磨人的几个问题问题一登录成功后拿不到用户信息。授权、拿code、换access_token都成功了但调userinfo接口返回48001错误码。这个错误码的含义是api功能未授权。十有八九是开放平台应用的获取用户基本信息权限没有开通去开放平台把权限补上重新审核通过后再试。问题二微信分享图片变形。缩略图在会话里显示模糊或者被拉伸是因为thumbData和message的图片尺寸比例不一致。微信要求缩略图和正式图片最好是等比例的我一般用统一尺寸模板生成分享图保证正常图片是120x120、缩略图按等比压缩到对应的宽高。问题三支付成功后微信图标一直转圈。这个非常经典。原因几乎都在WXPayEntryActivity的AndroidManifest声明或者singleTask配置上。检查一下android:exportedtrue是否加了从Android 12开始没有显式声明exported的Activity在接收外部Intent时会被系统拦截直接导致微信无法拉起回调。问题四iOS登录时跳转到微信后立即返回没有任何回调。这种大概率是APKApp和开放平台配置的Universal Links不一致或者Universal Links文件没有放到正确的域名路径上。微信iOS SDK从1.8.6版本开始强依赖Universal Links做登录和支付的回调只配置URL Scheme已经不够。6.2 我整理的上线前自检清单根据这几个项目的经验我每次发版前都会过一遍以下检查项开放平台的应用包名是否与最终APK包名完全一致大小写、下划线都算应用签名MD5是否与正式签名keystore一致而不是调试签名WXEntryActivity和WXPayEntryActivity的包路径是否放在包名.wxapi下且导出了AndroidManifest里微信相关的Activity是否设置了singleTaskiOS端Info.plist里是否配置了微信URL Scheme、Universal Links、LSApplicationQueriesSchemesiOS端支付宝URL Scheme是否可以正常回调服务端统一下单的金额单位是否使用分支付通知的notify_url是否可以从外网访问服务端微信支付签名和支付宝RSA2签名是否已切换成正式密钥空间沙箱密钥和正式密钥经常混加固后的APK是否跑过一遍完整的登录→分享→支付流程我以前就吃过一次亏开发期一直在真机上用沙箱环境联调上线前换了正式环境却只改了下单接口的url忘了切换服务端的商户号和密钥结果正式用户支付时全部报签名错误。从那以后我每次发版都把环境配置核验列到自检清单的最前面。6.3 个人心得把SDK封装层做厚最后分享一个比较实用的工程经验不要在游戏逻辑里直接散落微信和支付宝的原生调用代码。我会在C#层做一个统一的SocialPlatformManager和PayManager把微信登录、微信分享、微信支付、支付宝支付全部封装起来。这样游戏业务层的调用只面对一套接口接入方可以统一处理loading、错误码映射和流程跳转。这样封装的另一个好处是测试起来方便。联调阶段我直接通过封装层注入假的登录和支付结果来验证游戏逻辑等Native部分完全验证通过后再把假数据开关关掉游戏的每个阶段到底卡在业务逻辑还是SDK层一测便知。如果你也是长期维护多个渠道包的项目建议尽早把这一层做厚后面接华为、小米、OPPO等渠道SDK的时候也能省下很多重复工。本文还有配套的精品资源点击获取