「Android」微信登錄,一篇文章搞定

鏈接:https://juejin.im/post/5d77b123f265da03970be35b

申請賬號

「Android」微信登錄,一篇文章搞定

使用方法是把這個APP安裝到手機,然後把要獲取簽名的APP使用發佈版簽名安裝到同一個手機,然後輸入包名點擊下圖的獲取。

「Android」微信登錄,一篇文章搞定

簽名和包名填寫到頁面底部的這裡↓

「Android」微信登錄,一篇文章搞定

然後在頁面頂部複製這個AppID,這個東西是不會變的,複製一次就行了,下面的AppSecret可用可不用。

因為微信的登錄回調寫得很智障,用戶暱稱頭像之類的東東,你和後臺,誰去管微信要,誰就要用到這個AppSecret

「Android」微信登錄,一篇文章搞定

自動給debug包簽名

如果不想每次都手動簽名,可以使用gradle腳本自動簽名。 在APP的build.gradle下android中加入

signingConfigs {
debug {
keyAlias 'aaa'//庫中對應的簽名文件
keyPassword '123456'//簽名密碼
storeFile file('D:/AndroidProjects/xxx.jks')//簽名庫文件路徑和名稱,強烈建議存在項目目錄裡
storePassword '123456'//簽名庫密碼
}
}

導入lib

跟我念:Gradle大法好!微信支付和微信登錄都在這一個包裡,導入就完事了

//微信SDK
implementation 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'

登錄代碼(寫到你的登錄界面裡)

Java

private IWXAPI api;
//實例化全局微信api對象,可以寫到Activity的onCreate裡也可以把整個對象放在Application裡全局使用
api = WXAPIFactory.createWXAPI(this, "你的AppID", false);
api.registerApp("你的AppID");

Kotlin

lateinit var api: IWXAPI
//實例化全局微信api對象,可以寫到Activity的onCreate裡也可以把整個對象放在Application裡全局使用
api = WXAPIFactory.createWXAPI(this, "你的AppID", false)
api.registerApp("你的AppID")
「Android」微信登錄,一篇文章搞定

然後是登錄方法

Java

private void login(IWXAPI api) {
if (!api.isWXAppInstalled()) {
ToastUtils.showShort("您還未安裝微信客戶端!");//這裡是一句Toast,可以用你自己的Toast工具類替換
return;
}
SendAuth.Req req = SendAuth.Req();
req.scope = "snsapi_userinfo";
req.state = "wechat_sdk_demo_test";
api.sendReq(req);
finish();
}

Kotlin

private fun login(api: IWXAPI) {
if (!api.isWXAppInstalled) {
ToastUtils.showShort("您還未安裝微信客戶端!")//這裡是一句Toast,可以用你自己的Toast工具類替換
return
}
val req = SendAuth.Req()
req.scope = "snsapi_userinfo"
req.state = "wechat_sdk_demo_test"
api.sendReq(req)
finish()
}

直接調用這個方法就可以請求微信登錄,回調寫的下面提到的Activtiy裡。

對,沒錯,回調寫到其他Activity裡,是不是很扯淡?不知道他微信的SDK開發人員腦子裡是不是進了硫酸(╯‵□′)╯︵┻━┻寫出這種神仙操作邏輯。

「Android」微信登錄,一篇文章搞定

創建wxapi的Activity

在你的包名下建一個子package叫wxapi,這個名字不能改,然後在裡面新建

WXEntryActivity -> 微信登錄/微信分享回調

WXPayEntryActivity -> 微信支付回調

他們都繼承Activity實現IWXAPIEventHandler接口

註冊回調Activity


<activity> android:name=".wxapi.WXEntryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />

<activity> android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleInstance"
android:theme="@style/AppSplash">

<intent-filter>
<action>
<category>
<data>
/<intent-filter>
/<activity>
/<activity>

style內容

 <style><br> <!-- 設置啟動背景透明 --><br> <item name="android:windowIsTranslucent">true</item><br> <!-- 設置啟動不要Title --><br> <item name="android:windowNoTitle">true</item><br> /<style> 

本篇講微信登錄,支付用的WXPayEntryActivity如果你的項目沒用到可以不寫也沒關係。

在WXEntryActivity和剛才一樣拿一個WXAPI對象,創建過程是一毛一樣的這裡就省略不寫了,如果你一開始是寫在Application裡面的現在直接拿來用就好了。

不同的是這次要在onCreate和onNewIntent里加上

setIntent(intent);//onNewIntent還要在前面加這句,onCreate不用
api.handleIntent(intent, this);

然後重寫onReq(請求發出)和onResp(請求返回)兩個方法

發出的地方(onReq)打個日誌就好

Toast.makeText(this, "openid = " + req.openId, Toast.LENGTH_SHORT).show();

接收返回的地方(onResp)我們來搞事情

「Android」微信登錄,一篇文章搞定

Java

@Override
private void onResp(BaseResp resp) {
String result = "";
switch (resp.errCode) {
case BaseResp.ErrCode.ERR_USER_CANCEL:
result = "操作取消";
break;
case BaseResp.ErrCode.ERR_AUTH_DENIED:
result = "請求被拒絕";
break;
default:
result = "未知錯誤";
break;
}
}
switch (resp.type) {
case 1:{
if (resp.errCode == BaseResp.ErrCode.ERR_OK) {
SendAuth.Resp resp2 = (SendAuth.Resp) resp;
val code = resp2.code;
result = "登錄成功";
getAccessToken(code);//如果你家後臺要暱稱頭像啥的用戶信息你還要用這個code去請求微信的接口,否則在這裡直接返回code給後臺即可
}
break;
}
case 2: {
if (resp.errCode == BaseResp.ErrCode.ERR_OK) {
result = "分享成功";
}
}
}
ToastUtil.showShort(result);
Logger.d(result);
}

Kotlin

override fun onResp(resp: BaseResp) {
when (resp.errCode) {
BaseResp.ErrCode.ERR_USER_CANCEL -> result = "操作取消"
BaseResp.ErrCode.ERR_AUTH_DENIED -> result = "請求被拒絕"
else -> {
result = "未知錯誤"
}
}
when (resp.type) {
1 -> {
if (resp.errCode == BaseResp.ErrCode.ERR_OK) {
val code = (resp as SendAuth.Resp).code
result = "登錄成功"
getAccessToken(code)//如果你家後臺要暱稱頭像啥的用戶信息你還要用這個code去請求微信的接口,否則在這裡直接返回code給後臺即可
}
}
2 -> {
if (resp.errCode == BaseResp.ErrCode.ERR_OK) {
result = "分享成功"
}
}
}
ToastUtil.showShort(result)
Logger.d(result)
}

如果你家後臺只要code的話,到這裡為止就結束了,把getAccessToken那個方法換成http請求發給你家後臺就行了。

如果你還想拿微信的暱稱和頭像的話,請繼續往下看。

Java+OkHttp3

private void getAccessToken(String code) {
// String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
String url = "https://api.weixin.qq.com/sns/oauth2/access_token";
OkHttpClient mOkHttpClient = new OkHttpClient();
///< Post方式也可以...
// RequestBody body = new FormBody.Builder()
// .add("appid", "替換為你的appid")
// .add("secret", "替換為你的app密鑰")
// .add("code", code)
// .add("grant_type", "authorization_code")
// .build();
url += "?appid=" + "替換為你的appid" + "&secret=xxxxxxxx"
+ "&code=" + code + "&grant_type=authorization_code";
final Request request = new Request.Builder()
.url(url)
//.post(body)
.build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
finish();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String json = response.body().string();
AccessToken accessToken = JSONObject.parseObject(json, new TypeReference<accesstoken>() {
});
getUserInfo(accessToken.getAccess_token(), accessToken.getOpenid());
}
});
}
/<accesstoken>

Kotlin+Kolley

/**
* @param code 根據code再去獲取AccessToken
*/
private fun getAccessToken(code: String) {
// String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
///< Post方式也可以...
// RequestBody body = new FormBody.Builder()
// .add("appid", "替換為你的appid")
// .add("secret", "替換為你的app密鑰")

// .add("code", code)
// .add("grant_type", "authorization_code")
// .build();
Http.post {
// url += ("?appid=" + "替換為你的appid" + "&secret=xxxxxxxx"
// + "&code=" + code + "&grant_type=authorization_code")
url = "https://api.weixin.qq.com/sns/oauth2/access_token"
params {
"appid" - "你的AppID"
"secret" - "你的Secret"
"code" - code//你拿到的code
"grant_type" - "authorization_code"
}
onSuccess { byts ->
var result = byts.toString(Charset.defaultCharset())
if (TextUtils.isNotEmpty(result)) {
val model: WXTokenModel = StringNullAdapter.gson.fromJson(result)
getUserInfo(model.access_token, model.openid)
}
}
onFail { error ->
var message = error.message
ToastUtil.showShort(message)
}
}
}

其中用到的

kolley是一個僅支持Kotlin的輕量級網絡請求框架

StringNuallAdapter是一個解析json時即使遇到空也不會崩潰的第三方庫僅支持Kotlin

implementation 'com.ohmerhe.kolley:kolley:0.3.1'
implementation 'com.github.mfangtao:FTLibary:2.0.2'

WXTokenModel

JavaBean

public class WXTokenModel{
private String access_token = "";
private int expires_in = 0;

private var openid: String = "";
private String refresh_token = "";
private String scope: = "";

//getter/setter略
}

Kotlin data class

data class WXTokenModel(
var access_token: String = "",
var expires_in: Int = 0,
var openid: String = "",
var refresh_token: String = "",
var scope: String = ""
)

Java+OkHttp3

private void getUserInfo(String access_token, String openid) {
// String url = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
String url = "https://api.weixin.qq.com/sns/userinfo";
OkHttpClient mOkHttpClient = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("access_token", access_token)
.add("openid", openid)
.build();
final Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
finish();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String json = response.body().string();
WXUserInfo wxUserInfo = JSONObject.parseObject(json, new TypeReference<wxuserinfo>() {
});//至此暱稱頭像全部到手,傳給你家後臺吧
finish();
}
});

}
/<wxuserinfo>

Kotlin+kolley

private fun getUserInfo(access_token: String, openid: String) {
// String url = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
Http.post {
url = "https://api.weixin.qq.com/sns/userinfo"
params {
"access_token" - access_token
"openid" - openid
}
onSuccess { byts ->
var result = byts.toString(Charset.defaultCharset())
if (TextUtils.isNotEmpty(result)) {
val model: WXUserInfo = StringNullAdapter.gson.fromJson(result)
sendThird(openid, model.headimgurl, model.nickname)//至此暱稱頭像全部到手,傳給你家後臺吧
}
}
onFail { error ->
var message = error.message
ToastUtil.showShort(message)
}
}
}

WXUserInfo

JavaBean

public class WXUserInfo(
private String city = "";
private String country = "";
private String headimgurl = "";
private String nickname = "";
private String openid= "";
private List<string> privilege = ArrayList();
private String province "";
private int sex 0;
private String unionid "";

//getter/setter略
)

/<string>

Kotlin data class

data class WXUserInfo(
var city: String = "",
var country: String = "",
var headimgurl: String = "",
var nickname: String = "",
var openid: String = "",
var privilege: MutableList<string> = ArrayList(),
var province: String = "",
var sex: Int = 0,
var unionid: String = ""
)
/<string>

這裡的調用鏈是你的登錄界面→微信的登錄界面→微信的回調界面,你會發現在這個跳轉中由於微信的登錄界面這個東東屁都不給你返回,你的登錄界面不能通過onActivtiyResult之類的方法去拿登錄結果,登錄結果被傳給了微信的回調界面。

你的登錄界面完完全全就是個請求發送器,發送請求之後就沒用了,所以在api.sendReq(req)這行下面通常都會加一句finish()讓登錄界面出棧,避免用戶在APP玩了一圈想退出的時候退回到了棧底的登錄界面。

當然這樣一來會導致一個問題,那就是用戶在微信授權的界面點退出直接就沒有棧底元素了直接回桌面了,但是這種情況一樣會走到WXEntryActivity裡,所以解決辦法就是在WXEntryActivity裡當resp.errCode != BaseResp.ErrCode.ERR_OK的時候手動去啟動一下我們自己的登錄界面。

關於集成友盟的登錄方案

如果你的項目使用了友盟分享的話,就不用導入一開始說的那個庫了,取而代之的是下面這個庫

implementation 'com.umeng.umsdk:share-wx:6.9.4'

然後在Application的onCreate中加上

UMConfigure.init(this, "友盟AppKey", "Umeng", UMConfigure.DEVICE_TYPE_PHONE, "友盟MessageSecret");
PlatformConfig.setWeixin("微信AppID", "微信AppSecret");

調用改為 Java

private UMShareAPI umShareAPI;
private UMAuthListener umAuthListener;//這東西的方法直接空實現即可,因為它的回調微信不會走。是方法空實現,不是對象留空
//onCreate中
umShareAPI = UMShareAPI.get(this);
//調用登錄
umShareAPI.getPlatformInfo(this, SHARE_MEDIA.WEIXIN, umAuthListener);//微信登錄

Kotlin

lateinit var umShareAPI: UMShareAPI
lateinit var umAuthListener: UMAuthListener//這東西的方法直接空實現即可,因為它的回調微信不會走。是方法空實現,不是對象留空
//onCreate中
umShareAPI = UMShareAPI.get(this)
//調用登錄

umShareAPI.getPlatformInfo(this, SHARE_MEDIA.WEIXIN, umAuthListener)//微信登錄

最後

謝謝大家閱讀都這裡,想看更多技術文章可以給我加個關、。

我從事Android開發快十年了,今年年初我花兩個月的時間收錄整理了一套知識體系,此外,還有面試專題、架構視頻,如果有想法深入的系統化的去學習的,可以關注我,我會把我收錄整理的資料都送給大家,幫助大家更快的提升。

私信【架構】

關注+轉發+私信,讓更多需要的朋友們都可以免費看到、領到。

「Android」微信登錄,一篇文章搞定

「Android」微信登錄,一篇文章搞定


「Android」微信登錄,一篇文章搞定


分享到:


相關文章: