• Unity接入微信支付SDK 2022年版安卓篇


    最近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类,需要从你编辑器的这个路径里Editor\2020.3.24f1c2\Editor\Data\PlaybackEngines\AndroidPlayer\Source\com\unity3d\player拷贝出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 wxEntryActivityWeakReference;
    
            public MyHandler(WXEntryActivity wxEntryActivity){
                wxEntryActivityWeakReference = new WeakReference(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=%s\ntemplate_id=%s\nscene=%d\naction=%s\nreserved=%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=%s\nextMsg=%s\nerrStr=%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=%s\nextMsg=%s\nerrStr=%s\nbusinessType=%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=%d\nresultInfo=%s\nret=%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这样写

    
    
    <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("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/BV1Dr4y1T7nE/?spm_id_from=333.788.recommend_more_video.-1&vd_source=4f7f14539886b3de3b8a98d2e2b3c90d

    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

    https://blog.csdn.net/songyu_95/article/details/88248350

  • 相关阅读:
    Java:Session 会话详解
    一本通 1304:数的划分(线性DP)
    【知识地图】开发测试全栈 (未完待续)
    数据结构学习系列之顺序栈
    Python爬虫html网址实战笔记
    yarn包管理工具
    20240424 diary
    【前端基础】js 如何判断一个值是数组
    jvm-类加载
    6. MySQL 查询、去重、别名
  • 原文地址:https://www.cnblogs.com/Mr147/p/16711624.html