8

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

 1 year ago
source link: https://www.cnblogs.com/Mr147/p/16711624.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

新建工程

1520764-20220920155905396-379536784.png

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

1520764-20220920160033391-621652067.png

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

1520764-20220920160122079-1925881982.png

保持包名一致

1520764-20220920160358291-1765462113.png

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

1520764-20220920160648320-978866434.png

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

1520764-20220920160847909-607604502.png

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

1520764-20220920161104732-763800559.png

新版的classes.jar文件里不包含UnityPlayerActivity类,需要从你编辑器的这个路径里Editor\2020.3.24f1c2\Editor\Data\PlaybackEngines\AndroidPlayer\Source\com\unity3d\player拷贝出UnityPlayerActivity.java文件

然后回到编辑器中,取消勾选图片中的选线,可以让包名文件夹分级

1520764-20220920161639179-1020430134.png

新建一级微信package

1520764-20220920161755106-192078105.png

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

1520764-20220920161854384-1012512824.png

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

1520764-20220920162135195-687293005.png

这样方便安卓工程集成,但是我们要打出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包下载到本地

1520764-20220920162858403-918152198.png
1520764-20220920162947931-1515792364.png

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

1520764-20220920163213956-451730499.png

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

1520764-20220920163405308-14078635.png

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

1520764-20220920163530620-464951523.png

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

1520764-20220920163704505-2067843893.png

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

1520764-20220920164126433-1664229245.png

代码在这里,记住,别忘了把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=%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丢到图中位置

1520764-20220920170823905-1738313971.png

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

1520764-20220920170511172-1238216590.png

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里面大概就是这个样子,自己给按钮绑定好对应事件

1520764-20220920171920216-1583929650.png

然后就可以打包了,签过名打出包来以后装在手机上,要再下载微信的签名获取工具:https://res.wx.qq.com/wxdoc/dist/assets/media/Gen_Signature_Android.e481f889.zip
在里面输入包名获取签名,把签名填在微信开平平台对应的app信息里面,否则无法正常调起

平台上更新好签名后(审核要半天左右),再重新运行app,就可以调用微信支付了,我目前还没接后端服务器部分,所以还没有真实的微信支付参数,但传入app_id后就可以正常调微信(但是没调起来,需要支付相关参数正确),以及接收到安卓传来的支付回调给Unity端,所以还不算完整流程,后面有机会再详细补充下

1520764-20220920173815514-1074310374.png

完毕,喜欢的同学请三连支持,谢谢~

感谢以下博主的分享:

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK