最近1年转了UE开发,博客更新的比较少,技术栈宽了不少,以后有空尽量多更新,也方便总结记忆
Unity接入微信支付整个过程坑比较多,网上之前的教程要么比较老,要么比较零碎,只能东拼西凑摸索,跑通后还是总结记录下吧
开发环境,Windows11,Unity2020.3.24f1c2,Android Studio2021.2.1 Patch2
1.注册微信开放平台,注册应用,申请微信支付,来获取调取SDK的必要参数,此处不展开了(https://open.weixin.qq.com/)
2.确保开发环境装好,jdk,sdk等,Unity的安卓环境可以用Unity Hub自带的装好,也可以用全局环境变量的
3.Android Studio端的开发,导出aar
新建工程

设置包名,注意要和unity工程的包名一致

切换到Project视图,新建module,要选择Android Library

保持包名一致

需要将微信的库和Unity(微信支付成功后需要安卓端主动通知Unity端)的库都加入到工程中的lib文件夹中

Unity的库在这个位置,classes.jar文件,根据自己的需求来选择il2cpp还是mono,release还是dev,一共四种

将Unity的库照图右键添加到gradle配置中

新版的classes.jar文件里不包含UnityPlayerActivity类,需要从你编辑器的这个路径里Editor2020.3.24f1c2EditorDataPlaybackEnginesAndroidPlayerSourcecomunity3dplayer拷贝出UnityPlayerActivity.java文件
然后回到编辑器中,取消勾选图片中的选线,可以让包名文件夹分级

新建一级微信package

直接把UnityPlayerActivity.java文件拖到wx下面

然后我们开始引入微信的库,微信官方已经不直接提供jar或者aar的下载,已改用 gradle 形式,发布到 Maven Central

这样方便安卓工程集成,但是我们要打出aar包给unity使用,直接导出aar的话并不包含微信的库,有两种方法来解决
1)是谷歌出的一款插件,通过Unity插件Play Services Resolver for Unity在Unity端补全aar库的依赖关系,这个甚至可以补全ios平台的依赖,但我用的不多,引路官方仓库:https://github.com/googlesamples/unity-jar-resolver
2)通过Google Maven下载,搜索wechat,然后选择版本,选择aar包下载到本地


aar包中是包含jar的,我们需要用解压软件把jar包提取出来,然后改好名字

最后将微信的jar包放到lib下面并右键添加到工程中

这时我们rebuild工程,就可以看到打出的aar包了,在这个路径下

还有一点,这个aar包中包含unity的库,我们不需要,这会导致我们打包报错,修改build.gradle,将unity的库改为只引用,打包不包含

至此我们的lib依赖部分完成,下面开始添加Java的逻辑,首先是两个微信的Activity,用于安卓到Unity端的调用,一个登录,一个支付

代码在这里,记住,别忘了把APP_ID换成你们自己申请的
WXEntryActivity
package com.myvision.myapp.wxapi; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.widget.Toast; 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.modelbiz.SubscribeMessage; import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram; import com.tencent.mm.opensdk.modelbiz.WXOpenBusinessView; import com.tencent.mm.opensdk.modelbiz.WXOpenBusinessWebview; import com.tencent.mm.opensdk.modelmsg.SendAuth; import com.tencent.mm.opensdk.modelmsg.ShowMessageFromWX; import com.tencent.mm.opensdk.modelmsg.WXAppExtendObject; import com.tencent.mm.opensdk.modelmsg.WXMediaMessage; import com.tencent.mm.opensdk.openapi.IWXAPI; import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; import com.tencent.mm.opensdk.openapi.WXAPIFactory; import java.lang.ref.WeakReference; public class WXEntryActivity extends Activity implements IWXAPIEventHandler{ private static String TAG = "MicroMsg.WXEntryActivity"; private IWXAPI api; private MyHandler handler; public static String wxAPPID = "换成你们自己"; private static class MyHandler extends Handler { private final WeakReference<WXEntryActivity> wxEntryActivityWeakReference; public MyHandler(WXEntryActivity wxEntryActivity){ wxEntryActivityWeakReference = new WeakReference<WXEntryActivity>(wxEntryActivity); } @Override public void handleMessage(Message msg) { int tag = msg.what; } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); api = WXAPIFactory.createWXAPI(this, wxAPPID, false); handler = new MyHandler(this); try { Intent intent = getIntent(); api.handleIntent(intent, this); } catch (Exception e) { e.printStackTrace(); } } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); api.handleIntent(intent, this); } @Override public void onReq(BaseReq req) { switch (req.getType()) { case ConstantsAPI.COMMAND_GETMESSAGE_FROM_WX: goToGetMsg(); break; case ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX: goToShowMsg((ShowMessageFromWX.Req) req); break; default: break; } finish(); } @Override public void onResp(BaseResp resp) { int result = 0; switch (resp.errCode) { case BaseResp.ErrCode.ERR_OK: break; case BaseResp.ErrCode.ERR_USER_CANCEL: break; case BaseResp.ErrCode.ERR_AUTH_DENIED: break; case BaseResp.ErrCode.ERR_UNSUPPORT: break; default: break; } Toast.makeText(this, getString(result) + ", type=" + resp.getType(), Toast.LENGTH_SHORT).show(); if (resp.getType() == ConstantsAPI.COMMAND_SUBSCRIBE_MESSAGE) { SubscribeMessage.Resp subscribeMsgResp = (SubscribeMessage.Resp) resp; String text = String.format("openid=%sntemplate_id=%snscene=%dnaction=%snreserved=%s", subscribeMsgResp.openId, subscribeMsgResp.templateID, subscribeMsgResp.scene, subscribeMsgResp.action, subscribeMsgResp.reserved); Toast.makeText(this, text, Toast.LENGTH_LONG).show(); } if (resp.getType() == ConstantsAPI.COMMAND_LAUNCH_WX_MINIPROGRAM) { WXLaunchMiniProgram.Resp launchMiniProgramResp = (WXLaunchMiniProgram.Resp) resp; String text = String.format("openid=%snextMsg=%snerrStr=%s", launchMiniProgramResp.openId, launchMiniProgramResp.extMsg,launchMiniProgramResp.errStr); Toast.makeText(this, text, Toast.LENGTH_LONG).show(); } if (resp.getType() == ConstantsAPI.COMMAND_OPEN_BUSINESS_VIEW) { WXOpenBusinessView.Resp launchMiniProgramResp = (WXOpenBusinessView.Resp) resp; String text = String.format("openid=%snextMsg=%snerrStr=%snbusinessType=%s", launchMiniProgramResp.openId, launchMiniProgramResp.extMsg,launchMiniProgramResp.errStr,launchMiniProgramResp.businessType); Toast.makeText(this, text, Toast.LENGTH_LONG).show(); } if (resp.getType() == ConstantsAPI.COMMAND_OPEN_BUSINESS_WEBVIEW) { WXOpenBusinessWebview.Resp response = (WXOpenBusinessWebview.Resp) resp; String text = String.format("businessType=%dnresultInfo=%snret=%d",response.businessType,response.resultInfo,response.errCode); Toast.makeText(this, text, Toast.LENGTH_LONG).show(); } if (resp.getType() == ConstantsAPI.COMMAND_SENDAUTH) { SendAuth.Resp authResp = (SendAuth.Resp)resp; final String code = authResp.code; } finish(); } private void goToGetMsg() { // Intent intent = new Intent(this, GetFromWXActivity.class); // intent.putExtras(getIntent()); // startActivity(intent); finish(); } private void goToShowMsg(ShowMessageFromWX.Req showReq) { WXMediaMessage wxMsg = showReq.message; WXAppExtendObject obj = (WXAppExtendObject) wxMsg.mediaObject; StringBuffer msg = new StringBuffer(); msg.append("description: "); msg.append(wxMsg.description); msg.append("n"); msg.append("extInfo: "); msg.append(obj.extInfo); msg.append("n"); msg.append("filePath: "); msg.append(obj.filePath); // Intent intent = new Intent(this, ShowFromWXActivity.class); // intent.putExtra(Constants.ShowMsgActivity.STitle, wxMsg.title); // intent.putExtra(Constants.ShowMsgActivity.SMessage, msg.toString()); // intent.putExtra(Constants.ShowMsgActivity.BAThumbData, wxMsg.thumbData); // startActivity(intent); finish(); } }
WXPayEntryActivity
package com.myvision.myapp.wxapi; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.widget.Toast; 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{ public static String GameObjectName; public static String CallBackFuncName; private static final String TAG = "WXPayEntryActivity"; private IWXAPI api; public static String wxAPPID = "换成你们自己"; // 在调用微信支付处,设置该变量值 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // setContentView(R.layout.wx_pay_result); // api = WXAPIFactory.createWXAPI(this, wxAPPID); api.handleIntent(getIntent(), this); //UnityPlayer.UnitySendMessage(GameObjectName,CallBackFuncName,"微信API_ING"); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); api.handleIntent(intent, this); } @Override public void onReq(BaseReq req) { } /** 微信返回支付结果,会调用该函数*/ @Override public void onResp(BaseResp resp) { showText("onPayFinish, errCode = " + resp.errCode); if (resp.errCode != 0 && resp.errCode != -2) { showToast(this, "微信支付失败, errCode:" + resp.errCode); } if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { // AlertDialog.Builder builder = new AlertDialog.Builder(this); // builder.setTitle("提示"); // builder.setMessage("微信支付结果:" + resp.errCode); // builder.show(); if(resp.errCode == 0) { // PaySuccess(this); // 可在此处,添加应用自己的支付结果统计相关逻辑 showToast(this, "微信支付成功"); } else if(resp.errCode == -2) showToast(this, "用户取消支付"); else showToast(this, "支付失败,其他异常情形" ); } showToast(this, GameObjectName+","+CallBackFuncName ); UnityPlayer.UnitySendMessage(GameObjectName,CallBackFuncName,"支付回调:"+resp.errCode); this.finish(); } /** 输出log信息 */ public static void showText(final String info) { Log.d(TAG, info); } /** 输出Toast消息 */ private void showToast(Context context, final String info) { Toast.makeText(context, info, Toast.LENGTH_SHORT).show(); Log.d(TAG, info); } }
然后我们需要新建一个继承自UnityPlayerActivity的MainActivity,里面目前只实现的创建wxapi和一个支付逻辑
package com.myvision.myapp.wx; import android.os.Bundle; import com.myvision.myapp.wxapi.WXPayEntryActivity; import com.tencent.mm.opensdk.modelpay.PayReq; import com.tencent.mm.opensdk.openapi.IWXAPI; import com.tencent.mm.opensdk.openapi.WXAPIFactory; public class MainActivity extends UnityPlayerActivity { public static String APP_ID; private PayReq req = new PayReq(); private IWXAPI wxAPI = null; @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); APP_ID = "换成你们自己"; WechatInit(APP_ID); } public void WechatInit(String appid){ APP_ID = appid; if(wxAPI==null){ wxAPI = WXAPIFactory.createWXAPI(this,appid); wxAPI.registerApp(appid); } } public boolean IsWechatInstalled(){ return wxAPI.isWXAppInstalled(); } public void WeChatPayReq(String APP_ID,String MCH_ID,String prepayid,String packageValue,String noncestr,String timestamp,String sign,String callBackObjectName,String CallBackFuncName) { WXPayEntryActivity.GameObjectName = callBackObjectName; WXPayEntryActivity.CallBackFuncName = CallBackFuncName; req.appId = APP_ID; req.partnerId = MCH_ID; req.prepayId = prepayid; req.packageValue =packageValue; req.nonceStr = noncestr; req.timeStamp = timestamp; req.sign = sign; wxAPI.sendReq(req); } }
坚持住伙计!Rebuild Project!我们的aar就新鲜出炉了!我为你感到自豪!
4.Unity端的开发
首先新建好unity工程,确保包名一致,把我们的aar丢到图中位置

切换到安卓平台,设置下你的keystore签名,没有这个的话不能正常唤起微信(关联Tip1),勾选Custon Main Manifest,我们需要创建一个自定义的AndroidManifest.xml文件

AndroidManifest这样写
<?xml version="1.0" encoding="utf-8"?> <!-- GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN--> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.myvision.myapp" xmlns:tools="http://schemas.android.com/tools"> <queries> <package android:name="com.tencent.mm" /> // 指定微信包名 </queries> <application> <activity android:name="com.myvision.myapp.wx.MainActivity" android:exported="true" android:theme="@style/UnityThemeSelector"> <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 android:name="com.myvision.myapp.wxapi.WXEntryActivity" android:exported="true" android:launchMode="singleTask"> </activity> <activity android:name="com.myvision.myapp.wxapi.WXPayEntryActivity" android:exported="true" android:launchMode="singleTask"> </activity> </application> </manifest>
注意安卓11以上,一定要加这段,否则无法调起微信(落泪)
<queries> <package android:name="com.tencent.mm" /> // 指定微信包名 </queries>
最后一的C#做一个简单的调用
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class Test : MonoBehaviour { public Text ui; public Text ui2; private AndroidJavaObject jo= null; // Start is called before the first frame update public void Init() { AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); jo = jc.GetStatic<AndroidJavaObject>("currentActivity"); } public void CheckWX() { bool bo = true; bo = jo.Call<bool>("IsWechatInstalled"); ui.text = bo.ToString(); } public void WXPay() { jo.Call("WeChatPayReq", "你的APP_ID", "", "", "com.myvision.myapp", "", "", "", "Test", "WXCallback"); } public void WXCallback(string str) { print("WXCallback"); ui2.text = str; } }
Editor里面大概就是这个样子,自己给按钮绑定好对应事件

然后就可以打包了,签过名打出包来以后装在手机上,要再下载微信的签名获取工具:https://res.wx.qq.com/wxdoc/dist/assets/media/Gen_Signature_Android.e481f889.zip
在里面输入包名获取签名,把签名填在微信开平平台对应的app信息里面,否则无法正常调起
平台上更新好签名后(审核要半天左右),再重新运行app,就可以调用微信支付了,我目前还没接后端服务器部分,所以还没有真实的微信支付参数,但传入app_id后就可以正常调微信(但是没调起来,需要支付相关参数正确),以及接收到安卓传来的支付回调给Unity端,所以还不算完整流程,后面有机会再详细补充下

完毕,喜欢的同学请三连支持,谢谢~
感谢以下博主的分享:
https://www.bilibili.com/video/BV1Rq4y1S7qP?p=10&vd_source=4f7f14539886b3de3b8a98d2e2b3c90d
https://blog.csdn.net/linxinfa/article/details/117083637
https://blog.csdn.net/weixin_45724919/article/details/126139229
https://blog.csdn.net/Sun_XiaoChuan/article/details/110118309
https://blog.csdn.net/weixin_42414707/article/details/93844385