Android探索與鞏固(微信QQ第三方登陸填坑)

Sparker發表於2019-02-22

@TOC

前言

​ 上個周到現在一直在忙年前的優化任務,領導都是越到年底越想激發你的潛力,任務一個一個地來,幹完了就能回家。作為一個剛剛進入這家公司的Android獨苗,接觸陌生的程式碼並且周圍人沒辦法提供幫助的情況下在這麼短時間開發幾個功能,還是挺費神的。等到現在才完全收工,有時間閒下來去總結一下上個周把我折磨得死去活來的小妖精們。(示例大部分依舊是kotlin)

微信三方登入

​ 整合微信的三方登陸過程不難,但是中間有好多大坑官方沒有說明白。我們先從頭看開始講,遇到的坑就放在後面詳細探討一下。

  1. 註冊微信開放平臺使用者,申請應用。

    這一步應該不用說太多,就是簡單的註冊流程。不過在Android應用這,app的簽名是通過微信提供的簽名工具獲取的:GenSignature,在這裡面輸入本機已經安裝的應用包名,就能獲取到這個應用的簽名。填上就行了。稽核上面說是七個工作日,其實幾個小時就行了。

  2. 引入第三方包,初始化

引入三方包,老規矩

com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+
複製程式碼

在專案的gradle檔案中引用這個地址,更新一下就可以使用了。

然後進行初始化,一般要放在Application裡面進行:

val appID = "wxecb9abc374b780c2"
val api: IWXAPI = WXAPIFactory.createWXAPI(this, appID, true)
private fun initWx() {
   api.registerApp(appID)
}
複製程式碼

當然這一步很多人直接放在需要呼叫登陸的Activity或者Fragment裡面進行,不過我們們這裡防止以後還需要加微信其他功能,就放在這裡了。

  1. 接下來就是在Activity或者Fragment裡面的操作。

    private fun startWxLogin() {
        val appID = "wxecb9abc374b780c2"
        val api: IWXAPI = WXAPIFactory.createWXAPI(this, appID, true)
        if (!api.isWXAppInstalled) {
            showShort("您還未安裝微信")
        } else {
            val req = SendAuth.Req()
            req.scope = "snsapi_userinfo"
            req.state = "zhys_wxlogin"
            api.sendReq(req)
        }
    }
    複製程式碼

    這個方法就是調起微信的操作,將這個方法放進相應的點選事件裡面就好了。req.scope固定為這個,req.state自定。

  2. 接下來需要新建一個類用於接收微信傳回來的資訊。因為在微信官網註冊了包名和簽名,所以微信是通過用絕對路徑的方式將資訊傳到這個類裡面,這個類有嚴格的命名規則。必須是包名的一級子目錄下新建一個資料夾:wxapi,在這個資料夾下新建名為WXEntryActivity的類,官網給出的規則必須是:包名.wxapi.WXEntryActivity,比如說官網註冊為com.androidproject.test,那麼這個類的包名就應該是com.androidproject.test.wxapi.WXEntryActivity。下面是這個類的基本寫法

class WXEntryActivity : Activity(), IWXAPIEventHandler {
    private var mWeixinAPI: IWXAPI? = null
    private val RETURN_MSG_TYPE_LOGIN = 1
    private val RETURN_MSG_TYPE_SHARE = 2

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mWeixinAPI = WXAPIFactory.createWXAPI(this, WEIXIN_APP_ID, true)
        mWeixinAPI!!.handleIntent(this.intent, this)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        setIntent(intent)
        mWeixinAPI!!.handleIntent(intent, this)//必須呼叫此句話
    }

    //微信傳送的請求將回撥到onReq方法
    override fun onReq(req: BaseReq) { LogUtils.d("onReq")
    }

    //傳送到微信請求的響應結果
    override fun onResp(resp: BaseResp) {
        LogUtils.d("onResp")
        when (resp.errCode) {
            BaseResp.ErrCode.ERR_OK -> {
                LogUtils.d("ERR_OK")
                //傳送成功
                val sendResp = resp as SendAuth.Resp
                val code = sendResp.code
                EventBus.getDefault().post(code,"wxCode")
                finish()
            }
            BaseResp.ErrCode.ERR_USER_CANCEL -> {
                if (resp.type == RETURN_MSG_TYPE_SHARE){
                    showShort("分享失敗")
                }else{
                    showShort("登陸失敗")
                }
                LogUtils.e("ERR_USER_CANCEL")
            }
            BaseResp.ErrCode.ERR_AUTH_DENIED -> LogUtils.e("ERR_AUTH_DENIED")
            else -> {
                showShort("微信登陸錯誤")
                LogUtils.d("微信登陸錯誤"+" "+resp.errCode+resp.errStr)
                finish()
            }
        }//傳送取消
        //傳送被拒絕
        //傳送返回

    }
    companion object {
        private val APP_SECRET = "305c1e604e79f7e9b4c9a617c67c345c"
        val WEIXIN_APP_ID = "wxecb9abc374b780c2"
        private val uuid: String? = null
    }

}
複製程式碼
  1. 這裡我們只用到了微信返回的code,然後傳送給後端,後端再整合微信三方登入的功能獲取我們的使用者資訊,如果是想取到相關使用者資訊也是可以取到的。

好了,到現在為止,微信的基本用法就這麼多,下面來講一下我在微信整合的時候遇到的

一開始,我按照官網一步步寫完執行之後發現微信調起介面只是一閃而過,調起瞬間又關閉,然後在WXEntryActivity這個類中debug也沒有觸發。顯然,微信沒有找到這個類。於是我檢查了包名,和官網一模一樣,然後我又檢查簽名,發現debug模式安裝和打包安裝的簽名是不一樣的。這就很坑,於是我得出結論,之後打包之後再測試吧。但是!!!!改了簽名之後還是不行,網上查詢解決辦法都說包名不對。可是我左看右看包名完全一致啊,然後這個問題困擾了我一天。到了晚上回到家精疲力盡的時候,想要做最後一博,就去試驗各種方法。然後我發現了這個程式碼之前設計的是在不同環境下打包新增不同的字尾,

applicationIdSuffix ".develop"
複製程式碼

這個時候你們肯定以為我在這個地方犯了低階錯誤,去找和官網註冊的相同字尾的包名問題就解決了(我倒是希望如此),事實證明問題並不是那麼簡單。

在這裡插入圖片描述

找到相同包名以為可以鬆一口氣的時候,絕望地發現還是不行。我這個時候就感覺肯定和這行程式碼有關係,網上成功的案例都是絕對固定的包名。於是我註釋掉這行程式碼,將微信註冊的包名換成沒有字尾的形式,果然成功了。(內心一萬個草泥馬奔騰而過)。雖然成功了,但是這個專案不能這麼繼續做下去,因為之後還要做QQ登陸,騰訊開放平臺的包名是不能修改的,而且還用了其他的第三方SDK,會影響其他功能。我就只能更改目錄結構,硬生生把那個字尾寫死在裡面。然後切出另外一個分支,維持原有的目錄結構,保證其他功能可以在測試環境測試。

微信登陸的坑

  1. 注意包名是否一致

  2. debug執行的簽名和打包簽名不一致(整合之後如果出現微信返回ERR=-6的錯誤,多半是簽名不一致,就是這個原因。也有可能是之前微信執行過錯誤的簽名,就會記錄到微信快取中,需要清除快取或者直接解除安裝重灌)

  3. //applicationIdSuffix ".develop"
    //signingConfig signingConfigs.release
    複製程式碼

不能使用這兩行程式碼(後面這個是我實驗出來的),比較懊惱的是至今不知道其原因,希望有緣人看到這篇文章可以解答一下。

QQ三方登入

接下來我們講一下QQ三方登入,QQ三方登入其實很簡單,我在這個地方絆倒純粹是經驗不足。

QQ三方登陸的SDK還是用的依賴lib包的形式實現。在官網下載它的lib包,引入後就可以使用了。

  1. 首先在你需要呼叫的地方進行例項化:

    val mTencent: Tencent = Tencent.createInstance("你的appid", applicationContext)
    複製程式碼

    然後進行拉起QQ登陸:

    mTencent.login(this, "all", BaseUiListener())
    複製程式碼

    這裡的BaseUiListener是自己去寫的接收qq的回撥。需要自己去寫一下.

  2. 編寫QQ回撥

    public class BaseUiListener implements IUiListener {
        //注意測試需要在騰訊開放平臺註冊除錯者QQ號
        @Override
        public void onComplete(Object response) {
            try {
    //            String openId = ((JSONObject) response).getString("openid");
    //            String expires = ((JSONObject) response).getString("expires_in");
                String token = ((JSONObject) response).getString("access_token");
                LogUtils.d(((JSONObject) response).getString("access_token"));
                EventBus.getDefault().post(token,"qqToken");
            } catch (JSONException e) {
                e.printStackTrace();
            }
    
        }
    
        @Override
        public void onError(UiError e) {
            LogUtils.d("code:" + e.errorCode + ", msg:"
                    + e.errorMessage + ", detail:" + e.errorDetail);
        }
    
        @Override
        public void onCancel() {
            LogUtils.d("onCancel");
        }
    
    }
    複製程式碼

這裡我只需要qq的accessToken,所有就取了這個值,其他的個人資訊也可以取到。

QQ需要注意的點就是在測試環境下需要去騰訊開放平臺註冊除錯者QQ號,不然的話只會不斷地重新拉起沒有反應。(奇怪的是,ios不用註冊也可以收到,因為這個我一直沒注意這個問題)。

至此,微信QQ三方登陸的坑就算填完了,這些坑耽誤了我太長時間,不過也值得。下面再講一個和主題無關的小坑:

我中間還用了百度的離線語音合成,但是出現一個問題,打正式的包的時候語音就無法讀出。我就去鎖定了打包的那幾行程式碼得出以下結論:

//            minifyEnabled false
//            shrinkResources false
複製程式碼

這兩行不能隨便加上,收縮資源和縮小檔案會去刪掉它認為沒用的資原始檔。極大可能會誤刪,所以導致了離線語音不可用。

最後總結

​ 前段時間時間太緊張了,部落格也沒更,自己維護的專案也沒做,後面再慢慢跟上吧。踩過的這些坑雖然耗時長,但是漲了不少經驗,以後就不會犯錯了。

相關文章