SDK准备

微信Android接入指南:

接入指南 / Android接入指南 (qq.com)

首先在Android Studio的build.gradle里面添加:

1
2
3
dependencies {
implementation 'com.tencent.mm.opensdk:wechat-sdk-android:+'
}

等待Android Studio出现的提示并点击“sync now”,等待gradle自动添加完成依赖。

下载的jar包位置:在Project资源管理模式下——点击External Libraries——找到Gradle: com.tencent.mm.opensdk:wechat-sdk-android——classes.jar。选中classes.jar——右键Open In——Explorer,将文件夹内的jar包复制粘贴到Unity的Assets——Plugins——Android——libs文件夹下,注意将此jar包的名称修改为wechat-sdk-android

TencentWX类

在之前的文件夹内新建TencentWX类,提供的方法内容基本上和TenecntQQ类相同,但是具体细节上有所不同:

GetAccessToken方法类似于TencentQQ.LoginCallBack方法,但是微信这个回调需要我们发送https请求来获取用户信息,而不是直接返回。注意,微信的回调方法和QQ的都需要开启一个新线程,因为这两个地方都需要在安卓底层发送http请求。而微信下面介绍的方法也是发送http请求,但是不需要开启新线程,因为它们不是安卓底层调用的,而是Unity需要调用的,会自动在新线程中请求。

使用SaveRefreshTokenGetRefreshToken来保存和获取refreshtoken,这个token就是用来缓存用户信息的,QQ提供了缓存token的API,而微信没有,所以我们这里需要自己写保存和读取的方法。微信每次使用https登录请求都会获得两个token,一个是accesstoken,一个是refreshtoken,前者只有2小时有效时间,所以我们只保存后者。

使用CheckAuthorValid方法检查refreshtoken票据,和QQ也不一样,QQ已经封装好了一个方法,而微信需要自己发起一个获取token的http请求,得到新的accesstoken

使用RefreshSession方法刷新accesstoken,也是发起一次获取token的http请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
package com.DefaultCompany.ResLoadPrg;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
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 org.json.JSONObject;

import java.io.InputStream;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

public class TencentWX {
public static IWXAPI WXapi;
private static Activity m_MainActivity;
private static final String TAG = "TencentWX";
private static final String APP_ID = "wxfin458bf9gt";//替换成自己的APPID
private static final String APP_Secret = "jncnignaondh364b58EW7ng84hag";//替换成自己的App Secret

/**
* 初始化方法
*/
public static void Init(Activity activity){
Log.i(TAG, "Init: ");
m_MainActivity = activity;
WXapi = WXAPIFactory.createWXAPI(activity,APP_ID,true);
WXapi.registerApp(APP_ID);
}
/**
* 登录函数
*/
public static void Login(){
Log.i(TAG, "WXLogin");
SendAuth.Req req = new SendAuth.Req();
//应用授权域,这里的“snsapi_userinfo”表示获取用户个人信息
req.scope = "snsapi_userinfo"; // 只能填 snsapi_userinfo
//用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf(跨站请求伪造)攻击。
//可设置为简单的随机数和session进行校验
req.state = "resloadprg_wx_test";
WXapi.sendReq(req);
}

/**
* 注销函数
*/
public static void Logout(){
Log.i(TAG,"WXLogout");
WXapi.unregisterApp();
}
/**
* 判断授权是否有效
* @return 授权是否有效
*/
public static boolean CheckAuthorValid(){
try {
String refreshToken = GetRefreshToken();
if(refreshToken == null || refreshToken.equals("")){
return false;
}
URL url = new URL("https://api.weixin.qq.com/sns/oauth2/refresh_token?appid="+APP_ID+
"&grant_type=refresh_token&refresh_token=" + refreshToken);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();//打开连接
connection.setRequestMethod("GET");//打开连接之后,使用GET头来获取
connection.setConnectTimeout(5000);//设置链接请求延时
connection.setReadTimeout(5000);//设置获取数据延时

int code = connection.getResponseCode();
if(code == HttpsURLConnection.HTTP_OK){
InputStream is = connection.getInputStream();
byte[] data = TencentQQ.ReadStream(is);
String json = new String(data);
JSONObject jsonObject = new JSONObject(json);
if(jsonObject.has("errcode")){
Log.e(TAG, "CheckAuthorValid: 授权无效,需要重新授权");
return false;
}
else {
Log.i(TAG, "CheckAuthorValid: 授权有效,不需要再授权");
return true;
}
}
}
catch (Exception e){
Log.e(TAG, "CheckAuthorValid: 检测是否授权错误!" + e.toString());
}
return false;
}

/**
* 刷新票据
* @return 格式化后的token数据
*/
public static JSONObject RefreshSession(){
try{
String refreshToken = GetRefreshToken();
if(refreshToken == null || refreshToken.equals("")){
return null;
}
URL url = new URL("https://api.weixin.qq.com/sns/oauth2/refresh_token?appid="+APP_ID+
"&grant_type=refresh_token&refresh_token=" + refreshToken);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();//打开连接
connection.setRequestMethod("GET");//打开连接之后,使用GET头来获取
connection.setConnectTimeout(5000);//设置链接请求延时
connection.setReadTimeout(5000);//设置获取数据延时

int code = connection.getResponseCode();
if(code == HttpsURLConnection.HTTP_OK){
InputStream is = connection.getInputStream();
byte[] data = TencentQQ.ReadStream(is);
String json = new String(data);
JSONObject jsonObject = new JSONObject(json);
if(!jsonObject.has("errcode")){
return SetSelfData(jsonObject);
}
}
}
catch (Exception e){
Log.e(TAG, "RefreshSession: 刷新票据错误:" + e.toString());
}
return null;
}
/**
* 保存refreshtoken
* @param token token内容
*/
private static void SaveRefreshToken(String token){
//可以理解为创建一个表,Wxcache是表名
SharedPreferences sharedPreferences = m_MainActivity.getSharedPreferences("Wxcache", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
//下面就是向Wxcache表添加键值对
editor.putString("refreshtoken",token);
//提交保存
editor.apply();
}

/**
* 获取保存的refreshtoken
* @return refreshtoken
*/
private static String GetRefreshToken(){
SharedPreferences sharedPreferences = m_MainActivity.getSharedPreferences("Wxcache",Context.MODE_PRIVATE);
return sharedPreferences.getString("refreshtoken","");
}
/**
* 登录回调获取数据
* @param wxcode 回调来的代码
*/
public static void GetAccessToken(final String wxcode){
new Thread(new Runnable() {
@Override
public void run() {
try{
URL url = new URL("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + APP_ID +
"&secret=" + APP_Secret +
"&code=" + wxcode +
"&grant_type=authorization_code");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();//打开连接
connection.setRequestMethod("GET");//打开连接之后,使用GET头来获取
connection.setConnectTimeout(5000);//设置链接请求延时
connection.setReadTimeout(5000);//设置获取数据延时

int code = connection.getResponseCode();
if(code == HttpsURLConnection.HTTP_OK){
InputStream is = connection.getInputStream();//获取流
byte[] data = TencentQQ.ReadStream(is);
String json = new String(data);//通过byte创建字符串
JSONObject jsonObject = new JSONObject(json);
JSONObject jsonData = SetSelfData(jsonObject);
GameHelper.SendPlatformMessageToUnity(GameHelper.PLATFORM_MSG_WXLOGINCALLBACK,0,0,0,jsonData.toString(),"","");
}
}
catch (Exception e){
Log.e(TAG, "GetAccessToken: 获取登录票据错误"+e.toString());
}
}
}).start();
}
/**
* 格式化为和Unity通信的Json
* @param data 源Json
* @return 格式化好的Json
*/
private static JSONObject SetSelfData(JSONObject data){
JSONObject jsonObject = new JSONObject();
try {
String token = data.getString("access_token");
String expires = data.getString("expires_in");
String openid = data.getString("openid");
String refreshtoken = data.getString("refresh_token");
String expirestime = data.getString("expires_in");
String unionid = GetUnionId(token,openid);

jsonObject.put("openid",openid);
jsonObject.put("token",token);
jsonObject.put("unionid",unionid);
jsonObject.put("refreshtoken",refreshtoken);
jsonObject.put("expires",expires);
jsonObject.put("paytoken","");
jsonObject.put("pf","");
jsonObject.put("pfkey","");
jsonObject.put("expirestime",expirestime);
SaveRefreshToken(refreshtoken);
}
catch (Exception e){
Log.e(TAG, "SetSelfData: 设微信统一票据失败" + e.toString() );
}
return jsonObject;
}

/**
* 获取微信unionid
*/
private static String GetUnionId(String token,String openid){
String unionId = "";
try{
URL url = new URL("https://api.weixin.qq.com/sns/userinfo?access_token="+token+"&openid=:" + openid);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);

int code = connection.getResponseCode();
if(code == HttpsURLConnection.HTTP_OK){
InputStream is = connection.getInputStream();
byte[] data = TencentQQ.ReadStream(is);
String json = new String(data);
json = json.replace("(","").replace(")","").replace("callback","");
JSONObject jsonObject = new JSONObject(json);
unionId = jsonObject.getString("unionid");
}
}
catch (Exception e){
Log.e(TAG, "GetUnionId: 失败!" + e.toString() );
}
return unionId;
}
}

注意将此类在MainActivity中初始化

GameHelper中调用Tencent的LoginLogoutCheckAuthorValidRefreshSession方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public static final int PLATFORM_MSG_QQLOGIN = 1;//QQ登录
public static final int PLATFORM_MSG_QQLOGOUT = 2;//QQ注销
public static final int PLATFORM_MSG_WXLOGIN = 3;//微信登录
public static final int PLATFORM_MSG_WXLOGOUT = 4;//微信注销
//Unity发送消息到Android
public static void SendUnityMessageToPlatform(
int iMsgId,
int iParam1,
int iParam2,
int iParam3,
int iParam4,
String strParam1,
String strParam2,
String strParam3,
String strParam4
){
//...
switch (iMsgId){
case PLATFORM_MSG_QQLOGIN:
TencentQQ.Login();
break;
case PLATFORM_MSG_QQLOGOUT:
TencentQQ.Logout();
break;
case PLATFORM_MSG_WXLOGIN:
TencentWX.Login();
break;
case PLATFORM_MSG_WXLOGOUT:
TencentWX.Logout();
break;
}
}
public static final int PLATFORM_MSG_QQ_AUTHORVALID = 1;
public static final int PLATFORM_MSG_QQ_REFRESHSESSION = 2;

public static final int PLATFORM_MSG_WX_AUTHORVALID = 3;
public static final int PLATFORM_MSG_WX_REFRESHSESSION = 4;
//Unity从Android获取String
public static String GetStringFromPlatform(int type){
switch (type){
case PLATFORM_MSG_QQ_AUTHORVALID:
return String.valueOf(TencentQQ.CheckAuthorValid());
case PLATFORM_MSG_QQ_REFRESHSESSION:
return TencentQQ.RefreshSession().toString();
case PLATFORM_MSG_WX_AUTHORVALID:
return String.valueOf(TencentWX.CheckAuthorValid());
case PLATFORM_MSG_WX_REFRESHSESSION:
return TencentWX.RefreshSession().toString();
}
return "";
}

WXAPI

com.DefaultCompany.ResLoadPrg文件夹内新建wxapi文件夹(如果不能在Android Studio内新建就在Windows资源管理器内新建)。

在这个文件夹内新建几个类

WXEntryActivity

这个类相当于QQ接入时的BaseUiListener,用来获取回调,和QQ不同的是,微信获取回调的这个类必须属于Activity子类。

还有和QQ不同的是,在QQ中的回调会直接传回包含用户信息的json。而微信在登录回调成功后需要再次发送Https请求来得到用户信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.DefaultCompany.ResLoadPrg.wxapi;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

import com.DefaultCompany.ResLoadPrg.GameHelper;
import com.DefaultCompany.ResLoadPrg.TencentWX;
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.IWXAPIEventHandler;

public class WXEntryActivity extends Activity implements IWXAPIEventHandler {

private static final String TAG = WXEntryActivity.class.getName();

@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//使用这句将安卓句柄注册到微信,否则收不到下面的回调
TencentWX.WXapi.handleIntent(getIntent(),this);
}
/**
* 微信发送请求到第三方应用时,会回调该方法
*/
@Override
public void onReq(BaseReq baseReq) {

}

/**
* 第三方应用发送消息到微信,处理返回的回调
*/
@Override
public void onResp(BaseResp baseResp) {

int type = baseResp.getType();

switch (baseResp.errCode){
case BaseResp.ErrCode.ERR_AUTH_DENIED:
Log.d(TAG, "onResp: 拒绝微信授权登录");
GameHelper.SendPlatformMessageToUnity(GameHelper.PLATFORM_MSG_WXLOGINCALLBACK,1,0,0,"","","");
break;
case BaseResp.ErrCode.ERR_USER_CANCEL:
Log.d(TAG, "onResp: 用户取消登录");
GameHelper.SendPlatformMessageToUnity(GameHelper.PLATFORM_MSG_WXLOGINCALLBACK,2,0,0,"","","");
break;
case BaseResp.ErrCode.ERR_OK:
if(type == 1){
String code = ((SendAuth.Resp)baseResp).code;
Log.d(TAG,"onResp: 微信登录成功");
TencentWX.GetAccessToken(code);
}
else if(type == 2){//返回的是2代表微信分享成功
Log.i(TAG, "onResp: 微信分享成功");
}
break;
}
}
}