【Android】微信登陸,一篇文章搞定

申請帳號

微信開放平臺申請帳號
添加應用後在底部填寫Android包名應用簽名,填寫Android的就完了,iOS咱無論
簽名使用Gensignature獲取 java

Gensignature下載位置
使用方法是把這個APP安裝到手機,而後把要獲取簽名的APP 使用發佈版簽名安裝到同一個手機,而後輸入包名點擊下圖的獲取。
獲取簽名
簽名和包名填寫到頁面底部的這裏↓
填寫包名和簽名

而後在頁面頂部複製這個 AppID,這個東西是不會變的,複製一次就好了,下面的 AppSecret可用可不用。
由於微信的登陸回調寫得很智障,用戶暱稱頭像之類的東東,你和後臺,誰去管微信要,誰就要用到這個AppSecret
AppID

自動給debug包簽名

若是不想每次都手動簽名,可使用gradle腳本自動簽名。 在APPbuild.gradleandroid中加入android

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

導入lib

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

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

登陸代碼(寫到你的登陸界面裏)

先實例化一個微信API對象
Javagithub

private IWXAPI api;

//實例化全局微信api對象,能夠寫到Activity的onCreate裏也能夠把整個對象放在Application裏全局使用
        api = WXAPIFactory.createWXAPI(this, "你的AppID", false);
        api.registerApp("你的AppID");
複製代碼

Kotlinjson

lateinit var api: IWXAPI

//實例化全局微信api對象,能夠寫到Activity的onCreate裏也能夠把整個對象放在Application裏全局使用
        api = WXAPIFactory.createWXAPI(this, "你的AppID", false)
        api.registerApp("你的AppID")
複製代碼

而後是登陸方法
Javaapi

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();
    }
複製代碼

Kotlinbash

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開發人員腦子裏是否是進了硫酸(╯‵□′)╯︵┻━┻寫出這種神仙操做邏輯。微信

建立wxapi的Activity

你的包名下建一個子package叫wxapi這個名字不能改,而後在裏面新建
WXEntryActivity -> 微信登陸/微信分享回調
WXPayEntryActivity -> 微信支付回調
他們都繼承Activity實現IWXAPIEventHandler接口網絡

註冊回調Activity

<!-- 微信回調STRART -->
        <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 android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="在這裏填寫AppID" />
            </intent-filter>
        </activity>
        
複製代碼

style內容app

<style name="AppSplash" parent="Theme.AppCompat.Light.NoActionBar"> <!-- 設置啓動背景透明 --> <item name="android:windowIsTranslucent">true</item> <!-- 設置啓動不要Title --> <item name="android:windowNoTitle">true</item> </style>
複製代碼

本篇講微信登陸,支付用的WXPayEntryActivity若是你的項目沒用到能夠不寫也不要緊。
WXEntryActivity和剛纔同樣拿一個WXAPI對象,建立過程是一毛同樣的這裏就省略不寫了,若是你一開始是寫在Application裏面的如今直接拿來用就行了。
不一樣的是此次要在onCreateonNewIntent里加上

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

而後重寫onReq(請求發出)和onResp(請求返回)兩個方法
發出的地方(onReq)打個日誌就好

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

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

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請求發給你家後臺就好了。
若是你還想拿微信的暱稱和頭像的話,請繼續往下看。

用code調微信接口拿token

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());
            }
        });
    }

複製代碼

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的輕量級網絡請求框架
StringNullAdapter是一個解析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 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 = ""
)
複製代碼

用token調微信接口拿用戶信息

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();
            }
        });
    }
複製代碼

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略
)
複製代碼

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 = ""
)
複製代碼

微信登陸奇怪的調用鏈致使的問題

這裏的調用鏈是你的登陸界面→微信的登陸界面→微信的回調界面,你會發如今這個跳轉中因爲微信的登陸界面這個東東屁都不給你返回,你的登陸界面不能經過onActivtiyResult之類的方法去拿登陸結果,登陸結果被傳給了微信的回調界面。
你的登陸界面完徹底全就是個請求發送器,發送請求以後就沒用了。
WXEntryActivity一般是一個空的界面,沒有layout,由於絕大多數APP微信登陸以後都是直接進主頁的,而不是有一個專門的登陸成功界面,因此WXEntryActivity在不少APP中都是透明的。
因而在api.sendReq(req)這行下面一般都會加一句finish()讓登陸界面出棧,避免用戶在APP玩了一圈想退出的時候退回到了棧底的登陸界面。
固然這樣一來會致使一個問題,那就是用戶在微信受權的界面點退出直接就沒有棧底元素了直接回桌面了(實際上是走到了WXEntryActivity,可是因爲它是透明的,因此看起來像是APP退出了同樣),因此解決辦法就是在WXEntryActivity裏當resp.errCode != BaseResp.ErrCode.ERR_OK的時候手動去啓動一下咱們本身的登陸界面。

關於集成友盟的登陸方案

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

implementation 'com.umeng.umsdk:share-wx:6.9.4'
複製代碼

而後在ApplicationonCreate中加上

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)//微信登陸
複製代碼

其餘部分和官方SDK相同

參考文獻

部分代碼來自Android-微信登陸坑(+友盟微信登陸)

相關文章
相關標籤/搜索