实现Unity接入安卓端的微信登录
分为五个大步骤
- 生成keystore安卓应用开发者签名
- 在微信开放平台申请移动应用接入
- 编写Java Android部分代码, 生成arr文件
- 编写 Unity C# 代码
- Unity打apk包, 安装到手机中进行测试
建议按照顺序逐步进行, 1, 2 步如果已经完成, 可直接跳过. 虽然步骤有些多, 但这些步骤只要做一次就好, 往后点击两个按钮就可以完成代码更新.
生成keystore安卓应用开发者签名
- 打开 IDEA , 新建项目
- 选择上方工具栏, Generate Signed Bundle/ APK生成密钥
- 点击 Create new
分别填入
- Password
- Confirm (再填一次密码)
- Alias
- Alias Password
- Alias Confirm
- Certificate 中填一个就好
keystore签名包含一个密钥与多个子签名. 密钥用于开启 keystore 文件, 而一个子签名Key Alias 可用于对一个 Android 应用加密.
- 这时可在 key store path 中看见文件
需要将该文件转为 .keystore 文件
我的testKey文件路径为 /Users/chenyuanzhen/Desktop/testKey
执行以下命令keytool -importkeystore -srckeystore /Users/chenyuanzhen/Desktop/testKey -srcstoretype JKS -deststoretype PKCS12 -destkeystore /Users/chenyuanzhen/Desktop/testKey.p12 keytool -v -importkeystore -srckeystore /Users/chenyuanzhen/Desktop/testKey.p12 -srcstoretype PKCS12 -destkeystore /Users/chenyuanzhen/Desktop/testKey.keystore -deststoretype JKS
在微信开放平台申请移动应用接入
-
需要注意的是, 接入的移动应用必须要有官网介绍这个应用或者已经上线....
-
应用签名需要填写 MD5 值, 而且只能有数字和字母, 其余需要去掉.
这个应用签名是从 keystore 文件中获取的. 获取方法需要执行以下指令.keytool -exportcert -rfc -keystore /Users/chenyuanzhen/Desktop/testKey.keystore -alias myKey | openssl x509 -inform pem -outform der -out testKey.der openssl md5 /Users/chenyuanzhen/Desktop/testKey.der
会得到如下输出
- 应用包名建议与刚在 IDEA 新建项目的包名一致
申请通过后, 到此第二步已经完成.
编写Java Android部分代码, 生成arr文件
从 Unity 中搬移文件到 Android 项目中.
点击任一一个 Copy Path 按钮, 目的是找到 Unity 的安卓环境路径.这个需要在 Unity Hub 中安装
- 将目录中的classes.jar文件复制到安卓项目下的 lib 目录下
/Applications/Unity/Hub/Editor/2021.3.23f1/PlaybackEngines/AndroidPlayer/Variations/il2cpp/Release/Classes
- 将位于下方目录的文件复制到安卓项目包内, 并将 package com.unity3d.player; 包名修改为你自己的包名
/Applications/Unity/Hub/Editor/2021.3.23f1/PlaybackEngines/AndroidPlayer/Source/com/unity3d/player/UnityPlayerActivity.java
编写模块内的 build.gradle 文件.
注意不是项目根目录的 build.gradle 文件
plugins { id 'com.android.library' } android { compileSdkVersion 33 buildToolsVersion "33.0.1" defaultConfig { minSdk 24 targetSdkVersion 33 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.9.0' compileOnly files('tempLibs/classes.jar') api 'com.tencent.mm.opensdk:wechat-sdk-android:+' testImplementation 'junit:junit:' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' } task copyPlugin(type: Copy) { dependsOn assemble from('build/outputs/aar') into('/Users/chenyuanzhen/UnityProject/projectname/Assets/Plugins/Android') include(project.name + '-release.aar') }
其中 copyPlugin 中的 into 里的文件目录为 Unity 项目目录
- 同步 gradle 文件
使用 IDEA 的话点击
按钮 新建两个包 (假设你的包名为 com.company.project, 在微信平台上登记的也是该包名)
com.company.project.wechatplugin
wechatplugin 可以随意取
com.company.project.wxapi
这个包名必须是 微信平台登记的包名 + wxapi
否则会出现微信没有回调信息的问题
- 将 UnityPlayerActivity.java 文件放置到 com.company.project.wechatplugin 下
在 com.company.project.wechatplugin 中创建 MainActivity 文件.
package com.company.project.wechatplugin; import android.os.Bundle; import android.util.Log; import com.tencent.mm.opensdk.modelmsg.SendAuth; import com.tencent.mm.opensdk.openapi.IWXAPI; import com.tencent.mm.opensdk.openapi.WXAPIFactory; import com.lingdong.drone.wechat.playerActivity.UnityPlayerActivity; public class MainActivity extends UnityPlayerActivity { public IWXAPI wxapi = null; // 这个 APPID 由 Unity 传入 public static String APPID; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } private void regWx(String appid){ APPID = appid; if (wxapi==null){ wxapi = WXAPIFactory.createWXAPI(this,APPID); // 将该app注册到微信 wxapi.registerApp(APPID); Log.e("myTencent", "监听注册到微信"); } Log.e("myTencent", "onCreate finished ! "); } public void Login(){ Log.e("myTencent", "Login!! "); SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; req.state = "wechat_sdk_demo_test"; wxapi.sendReq(req); Log.e("myTencent", "SendReq Finish"); } }
在 com.company.project.wxapi 下创建 WXEntryActivity.java 文件.
必须是这个名字
package com.company.project.wxapi; //com.lingdong.drone import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.widget.Toast; import com.lingdong.drone.wechat.MainActivity; import com.tencent.mm.opensdk.modelbase.BaseReq; import com.tencent.mm.opensdk.modelbase.BaseResp; import com.tencent.mm.opensdk.modelmsg.SendAuth; 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 WXEntryActivity extends Activity implements IWXAPIEventHandler { public IWXAPI wxapi = null; public static String gameObjectName = ""; // WXLoginCallBack public static String callBackFunctionName = ""; public static void setGameObjectName(String gameObjectName) { WXEntryActivity.gameObjectName = gameObjectName; } public static void setCallBackFunctionName(String callBackFunctionName) { WXEntryActivity.callBackFunctionName = callBackFunctionName; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // WXLoginObject Log.e("myTencent", "WxEntryActivity onCreate"); //初始化wxapi if (wxapi == null) { wxapi = WXAPIFactory.createWXAPI(this, MainActivity.APPID); } wxapi.registerApp(MainActivity.APPID); wxapi.handleIntent(getIntent(), this); } @Override public void onReq(BaseReq baseReq) { } @Override public void onResp(BaseResp baseResp) { Log.e("myTencent", "收到 resp "); if (baseResp.getType() == 1) {//微信登录 if (baseResp.errCode == BaseResp.ErrCode.ERR_OK) {//用户同意 UnityPlayer.UnitySendMessage(gameObjectName, callBackFunctionName, ((SendAuth.Resp) baseResp).code); } else if (baseResp.errCode == BaseResp.ErrCode.ERR_USER_CANCEL) {//用户取消 UnityPlayer.UnitySendMessage(gameObjectName, callBackFunctionName, "用户取消"); } else if (baseResp.errCode == BaseResp.ErrCode.ERR_AUTH_DENIED) {//用户拒绝 UnityPlayer.UnitySendMessage(gameObjectName, callBackFunctionName, "用户拒绝"); } else { UnityPlayer.UnitySendMessage(gameObjectName, callBackFunctionName, "其他错误"); } } else if (baseResp.getType() == 2) { } finish(); } }
修改项目内的 AndroidManifest.xml 文件
到此第三步完成.
编写 Unity C# 代码
在 Unity 项目中创建文件夹
/Assets/Plugins/Android
该文件夹路径必须是这样, Unity官方规定
打开安卓项目, 找到模块内build.gradle, 执行 copyPlugin 任务.
这时 /Assets/Plugins/Android 目录会出现一个 arr 文件
建议以后每次运行 copyPlugin 前, 先将旧的 arr 文件删除. 否则 Unity 可能会因缓存使用旧的 arr 文件.
- 将微信 sdk 的 jar 包移到 /Assets/Plugins/Android 目录中. 该 jar 包可在 idea 里的 External Libraries 中找到.
配置 Unity 设置
- 将安卓项目里的 AndroidManifest.xml 复制到 /Assets/Plugins/Android 目录中
对其进行修改
编写 C# 脚本
using UnityEngine; using UnityEngine.UI; public class WXLogin : MonoBehaviour { // public Button button_login, button_quit; // public Image image_head; public Text text_username, text_code; // public GameObject go_lobby; private AndroidJavaClass mainActivityClass = null; private AndroidJavaObject mainActivity = null; private AndroidJavaClass WXEntryActivityClass = null; private string APPID = "你的 APPID"; private string SECRET = "你的 APP 密钥"; // Start is called before the first frame update void Start() { // 配置 APPID mainActivityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); mainActivity = mainActivityClass.GetStatic
("currentActivity"); mainActivity.Call("regWx", APPID); // 配置 WXEntryActivity WXEntryActivityClass = new AndroidJavaClass("com.company.project.wxapi.WXEntryActivity"); WXEntryActivityClass.CallStatic("setGameObjectName", this.gameObject.name); WXEntryActivityClass.CallStatic("setCallBackFunctionName", "WXLoginCallBack"); } public void Onbutton_login() { mainActivity.Call("Login"); } public void WXLoginCallBack(string str) { if (str != "用户取消" && str != "用户拒绝" && str != "其他错误") { Debug.Log("微信登录成功,code是:" + str); text_code.text += "微信登录成功,code是:" + str + "\r\n"; } else { Debug.Log("微信登录失败,code是:" + str); text_code.text += "微信登录成功,code是:" + str + "\r\n"; } } } - 将WXLogin挂在一个 gameObject 下, 并将一个按钮 Onclick 事件触发 Onbutton_login 函数
到此第四步完成.
Unity打apk包, 安装到手机中进行测试
构建完成后会自动安装到手机中. 可从手机的日志查看是否登录成功.
执行流程
整个程序执行流程
- 用户在 Unity 中点击微信登录按钮
- Unity 中的 C# 代码, 使用 AndroidJavaClass 与 AndroidJavaObject 类调用 Android 代码
- Android 代码中调用微信 sdk, 并将应用向微信注册
- 跳转到微信程序
- 用户点击登录确认
- 微信程序跳转回 Android 代码, WXEntryActivity
Android 代码使用 UnityPlayer.UnitySendMessage 函数, 调用 Unity C#代码的函数, 并返回微信 code
UnityPlayer.UnitySendMessage(挂载的 gameObject 名字, 需要调用的函数名, 函数参数)
注意点
若出现问题, 先核查自己的 APPID 与 密钥 是否配置正确. 如果这两个东西不正确, 会报一些意想不到的错误. 例如
Uninitialized ActivityThread, likely app-created Instrumentation, disabling AppComponentFactory
很多问题都会报这个错, 例如 AndroidManifest.xml 配置错误也会报这个错.
- 若出现这个问题
那大概率是 arr 包里的文件与 Unity 里的配置冲突. - Unity 的 AndroidManifest.xml 配置与 arr 包里的AndroidManifest.xml 配置冲突
- arr 包名与 Unity 覆写的包名相同
具体可看构建时的报错 console