In the past year, I switched to UE development. The blog update is relatively small, and the technology stack is much wider. I will update as much as I can in the future, and it is also convenient to summarize and remember.
There are many pitfalls in the whole process of Unity’s access to WeChat payment. The previous tutorials on the Internet are either old or fragmented.
Development environment, Windows11, Unity2020.3.24f1c2, Android Studio2021.2.1 Patch2
1. Register the WeChat open platform, register the application, and apply for WeChat payment to obtain the necessary parameters for calling the SDK, which will not be expanded here ( https://open.weixin.qq.com/)
2. Make sure that the development environment is installed, jdk, sdk, etc. Unity's Android environment can be installed with the one that comes with Unity Hub, or you can use the global environment variable
3.Android Studio side development, export aar
New Construction
Set the package name, pay attention to the same as the package name of the unity project
Switch to the Project view, create a new module, and select Android Library
Keep the package name the same
Both the WeChat library and the Unity library (the Android side needs to actively notify the Unity side after WeChat payment is successful) need to be added to the lib folder in the project
Unity's library is in this location, classes.jar file, according to your own needs to choose il2cpp or mono, release or dev, a total of four
Right-click Unity's library image and add it to the gradle configuration
The new version of classes.jar file does not contain the UnityPlayerActivity class, you need to copy the UnityPlayerActivity.java file from the path of your editor Editor\2020.3.24f1c2\Editor\Data\PlaybackEngines\AndroidPlayer\Source\com\unity3d\player
Then go back to the editor, uncheck the selection line in the picture, you can make the package name folder hierarchical
Create a new first-level WeChat package
Drag the UnityPlayerActivity.java file directly under wx
Then we started to introduce the library of WeChat. WeChat officially no longer provides jar or aar downloads directly, and has changed to gradle and released it to Maven Central
This is convenient for Android project integration, but we need to type out the aar package for use by unity. If we directly export aar, it does not include the WeChat library. There are two ways to solve it.
1) It is a plug-in from Google. The Unity plug-in Play Services Resolver for Unity is used to complete the dependencies of the aar library on the Unity side. This can even complete the dependencies of the ios platform. https://github.com/googlesamples/unity-jar-resolver
2) Download through Google Maven, search for wechat, then select the version, select the aar package to download locally
The aar package contains jar, we need to extract the jar package with decompression software, and then change the name
Finally, put the WeChat jar package under lib and right-click to add it to the project
At this time, when we rebuild the project, we can see the aar package that was typed, under this path
Another point, this aar package contains the unity library, we don't need it, this will cause us to pack an error, modify the build.gradle, change the unity library to only reference, the package does not contain
At this point, our lib dependency part is completed. Let's start adding Java logic. First, there are two WeChat activities, which are used for calling from Android to Unity, one for login and one for payment.
The code is here, remember, don't forget to replace the APP_ID with your own application
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 = "replace yourself"; 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 = "replace yourself"; // When calling WeChat Pay, set the variable value @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,"WeChat API_ING"); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); api.handleIntent(intent, this); } @Override public void onReq(BaseReq req) { } /** WeChat returns the payment result and will call this function*/ @Override public void onResp(BaseResp resp) { showText("onPayFinish, errCode = " + resp.errCode); if (resp.errCode != 0 && resp.errCode != -2) { showToast(this, "WeChat payment failed, errCode: " + resp.errCode); } if (resp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) { // AlertDialog.Builder builder = new AlertDialog.Builder(this); // builder.setTitle("Title"); // builder.setMessage("WeChat payment result: " + resp.errCode); // builder.show(); if(resp.errCode == 0) { // PaySuccess(this); // You can add the application's own payment result statistics related logic here showToast(this, "WeChat payment success"); } else if(resp.errCode == -2) showToast(this, "User cancels payment"); else showToast(this, "Payment failure, other abnormal situations" ); } showToast(this, GameObjectName+","+CallBackFuncName ); UnityPlayer.UnitySendMessage(GameObjectName,CallBackFuncName,"Payment callback:"+resp.errCode); this.finish(); } /** output log information */ public static void showText(final String info) { Log.d(TAG, info); } /** Output Toast message */ private void showToast(Context context, final String info) { Toast.makeText(context, info, Toast.LENGTH_SHORT).show(); Log.d(TAG, info); } }
Then we need to create a new MainActivity that inherits from UnityPlayerActivity, which currently only implements the creation of wxapi and a payment logic
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 = "replace yourself"; 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); } }
Hold on mate! Rebuild Project! Our aar is freshly baked! I am so proud of you!
4.Unity side development
First, create a new unity project, make sure the package name is the same, and throw our aar into the position in the figure
Switch to the Android platform, set your keystore signature, without this, you can't call up WeChat normally (associated with Tip1), check Custon Main Manifest, we need to create a custom AndroidManifest.xml file
AndroidManifest writes like this
<?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" /> // Specify the WeChat package name </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>
Pay attention to Android 11 and above, you must add this paragraph, otherwise you will not be able to tune up WeChat (tears)
<queries> <package android:name="com.tencent.mm" /> // Specify the WeChat package name </queries>
The last C# makes a simple call
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", "yours APP_ID", "", "", "com.myvision.myapp", "", "", "", "Test", "WXCallback"); } public void WXCallback(string str) { print("WXCallback"); ui2.text = str; } }
This is probably what the Editor looks like. Bind the corresponding events to the buttons by yourself.
Then you can pack it, sign it and type it out and install it on your phone. You need to download the WeChat signature acquisition tool: https://res.wx.qq.com/wxdoc/dist/assets/media/Gen_Signature_Android.e481f889.zip
Enter the package name in it to get the signature, and fill in the signature in the app information corresponding to the WeChat Kaiping platform, otherwise it will not be able to be activated normally
After updating the signature on the platform (it takes about half a day for the review), and then re-run the app, you can call WeChat Pay. I haven't connected the back-end server part yet, so there is no real WeChat payment parameters, but after passing in the app_id, WeChat can be adjusted normally (but it has not been adjusted, and the relevant payment parameters need to be correct), and the payment callback from Android is received to the Unity side, so it is not a complete process, and I will have the opportunity to add more details later.
It's over, the students who like it, please support three consecutive times, thank you~
Thanks to the following bloggers for sharing:
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