Android第三方登录_QQ

Question&Answer

1.QQ移动应用和Web应用openid不一样,可使用unionid,参考如下链接解决
https://blog.csdn.net/liuhuanchao/article/details/50527896

2.Android QQ第三方登录时有QQ客户端加载QQ客户端,没有则拉起网页登陆的解决办法
https://blog.csdn.net/yinzhong39/article/details/51774462

3.QQ拉起客户端提示非正式应用啥的
QQ互联的移动应用中的Android部分没有填写签名包名等数据,或者数据不正确导致的

4.QQ互联官方资料,基本按照官方教程就可实现基本功能
http://wiki.connect.qq.com/qq%E7%99%BB%E5%BD%95

代码

码云:https://gitee.com/zhangtao3/android_thirdlogin

准备

QQ互联申请移动应用,未通过审核也可进行登录开发,包名和签名有条件直接填写正确的,没有,后续也可添加
QQSDK没有找到直接的下载地址,只能通过下载demo,来拿到jar包

开始

1.sdk open_sdk_r5990_lite.jar导入

2.AndroidManifest.xml处理

    // 网络权限
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!-- QQ登录相关 start -->
        <activity
            android:name="com.tencent.tauth.AuthActivity"
            android:noHistory="true"
            android:launchMode="singleTask" >
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="tencent1106910756" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.tencent.connect.common.AssistActivity"
            android:configChanges="orientation|keyboardHidden"
            android:screenOrientation="behind"

            android:theme="@android:style/Theme.Translucent.NoTitleBar" />
        <!-- QQ登录相关 end -->

3.创建GlobalData,存放基础数据

    /** QQ相关 */
    public static final String QQ_APP_ID = "XXX";
    public static final String QQ_GET_USER_INFO = "https://graph.qq.com/user/get_user_info";

4.创建MyApplication全局类,并在AndroidManifest.xml添加android:name=”.MyApplication”,在这里初始化Tencent类,后续也会在这里初始化WeiXinApi

   // 初始化QQ
   private void initQQ() {
        // Tencent类是SDK的主要实现类,开发者可通过Tencent类访问腾讯开放的OpenAPI。
        mTencent = Tencent.createInstance(GlobalData.QQ_APP_ID, mAppContext);
        // QQ客户端和网页端登录处理,该方法就是用来处理吊起QQ客户端或者Web页登录,具体代码可参照以上网址,或者源码
        fixWebAuth(this, mTencent);
    }

5.参照官方教程,实现回调IUiListener,在onActivityResult方法中增加mTencent.onActivityResult(requestCode, resultCode, data);

public class BaseUiListener implements IUiListener {

    @Override
    public void onComplete(Object response) {
        Log.d(GlobalData.TAG, "qq_BaseUiListener_onComplete: " + response.toString());
        try {
            doComplete((JSONObject) response);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    protected void doComplete(JSONObject values) throws JSONException {
        Log.e(GlobalData.TAG, "qq_BaseUiListener_doComplete: " + values);
    }

    @Override
    public void onError(UiError e) {
        Log.e(GlobalData.TAG, "qq_BaseUiListener_onCancel: " + e.errorDetail);
    }

    @Override
    public void onCancel() {
        Log.e(GlobalData.TAG, "qq_BaseUiListener_onCancel: ");
    }
}

    //MainActivity
   // QQ登录回调
    private void initQQLoginListener() {
        qqLoginListener = new BaseUiListener() {
            @Override
            protected void doComplete(JSONObject values) throws JSONException {
                //{"auth_time":"1527600141911","ret":"0","pay_token":"","pf":"desktop_m_qq-10000144-android-2002-","page_type":"1",
                // "expires_time":1535376201953,"openid":"","expires_in":"7776000","pfkey":"8b372551e05c1b82a131de8d16cb691f",
                // "access_token":"DC92D06A6458A3CE2D54C343C61F9100"}
                if (values.getInt("ret") == 0) {
                    MyApplication.mTencent.setOpenId(values.getString("openid"));
                    MyApplication.mTencent.setAccessToken(values.getString("access_token"), values.getString("expires_in"));
                    // 保存QQToken
                    saveQQToken(values);
                    // 如需获取unionid,可getQQUnionId(values)
                    // 获取用户信息
                    getQQUserInfo();
                }else{
                    logoutQQ();
                    loginQQ();
                }
            }

            @Override
            public void onCancel() {
                ToastUtils.showShortToast("取消QQ登录");
                tv_result.setText("取消QQ授权");
            }
        };
    }

6.调用QQ登录接口,获取AccesToken,openid,unionid

 // QQ登录
    private void loginQQ() {
        if (!checkQQTokenValid()) {
            tv_result.setText("QQ登录授权...");
            MyApplication.mTencent.login(MainActivity.this, "", qqLoginListener);
        } else {
            SharedPreferences sp = getSharedPreferences("thirdlogin", Context.MODE_PRIVATE);
            MyApplication.mTencent.setOpenId(sp.getString("qq_openid", ""));
            MyApplication.mTencent.setAccessToken(sp.getString("qq_access_token", ""), sp.getString("qq_expires_in", ""));
            getQQUserInfo();
        }
    }

7.校验QQToken是否有效

    // 校验QQToken是否有效
    private boolean checkQQTokenValid() {
        SharedPreferences sp = getSharedPreferences("thirdlogin", Context.MODE_PRIVATE);
        String expires_time = sp.getString("qq_expires_time", "0");

        long var7 = Long.parseLong(expires_time);
        long var9 = System.currentTimeMillis();
        if (var9 < var7) {
            String access_token = sp.getString("qq_access_token", null);
            String expires_in = sp.getString("qq_expires_in", null);
            String openid = sp.getString("qq_openid", null);
            MyApplication.mTencent.setOpenId(openid);
            MyApplication.mTencent.setAccessToken(access_token, expires_in);
            return true;
        } else {
            return false;
        }
    }

8.存储QQToken

// 存储QQToken
    private void saveQQToken(JSONObject data) throws JSONException {
        SharedPreferences sp = getSharedPreferences("thirdlogin", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("qq_expires_time", data.getString("expires_time"));
        editor.putString("qq_access_token", data.getString("access_token"));
        editor.putString("qq_expires_in", data.getString("expires_in"));
        editor.putString("qq_openid", data.getString("openid"));
        editor.commit();
    }

9.QQ注销登录

// QQ注销登录
    private void logoutQQ() {
        MyApplication.mTencent.logout(MyApplication.getAppContext());
        tv_result.setText("QQ已注销");
        SharedPreferences sp = getSharedPreferences("thirdlogin", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.remove("qq_expires_time");
        editor.commit();
    }

10.获取QQ用户信息

// 获取QQ用户信息
    private void getQQUserInfo() {
        Map<String, String> params = new HashMap<>();
        params.put("access_token", MyApplication.mTencent.getAccessToken());
        params.put("oauth_consumer_key", GlobalData.QQ_APP_ID);
        params.put("openid", MyApplication.mTencent.getOpenId());

        OkHttpUtils.getInstance().getRequestAsync(GlobalData.QQ_GET_USER_INFO, params, new OkHttpUtils.MyOkHttpCall() {
            @Override
            public void success(Call call, Response response) throws IOException {
                // response.body()只可调用一次
                final String resultString = response.body().string();
                Log.d(GlobalData.TAG, "http_getuserinfo: " + resultString);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            JSONObject resultObj = new JSONObject(resultString);
                            if (resultObj.getInt("ret") == 0) {
                                tv_result.setText("QQ昵称:" + resultObj.getString("nickname"));
                            } else {
                                logoutQQ();
                                loginQQ();
                            }
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });
    }

11.获取QQ unionid

// 获取QQ unionid
    private void getQQUnionId(final JSONObject values) {
        // URL处理
        String url = "https://graph.qq.com/oauth2.0/me";
        Map<String, String> getParams = new HashMap<>();
        getParams.put("access_token", mTencent.getAccessToken());
        getParams.put("unionid", "1");
        // Get请求
        OkHttpUtils.getInstance().getRequestAsync(url, getParams, new OkHttpUtils.MyOkHttpCall() {
            @Override
            public void success(Call call, Response response) throws IOException {
                final String resultString = response.body().string();
                Log.d(GlobalData.TAG, "getQQUnionId_onResponse: " + resultString);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // TODO 获取unionid方法有待改善
                        String[] split = resultString.split(":");
                        String s = split[split.length - 1];
                        split = s.split("\"");
                        String unionid = split[1];
                        Log.d(GlobalData.TAG, "getQQUnionId_unionid: " + unionid);
                        try {
                            saveQQToken(values, unionid);
                            launcher.callExternalInterface("qqLogin", unionid);
                        } catch (JSONException e) {
                            e.printStackTrace();
                            ToastUtils.showShortToast("QQ登录数据异常");
                        }
                    }
                });
            }
        });
    }

12.OkHttp网络请求类简单封装

public class OkHttpUtils {

    private static final byte[] LOCKER = new byte[0];
    private static OkHttpUtils mInstance;
    private OkHttpClient mOkHttpClient;

    public static OkHttpUtils getInstance() {
        if (mInstance == null) {
            synchronized (LOCKER) {
                if (mInstance == null) {
                    mInstance = new OkHttpUtils();
                }
            }
        }
        return mInstance;
    }

    private OkHttpUtils() {
        OkHttpClient.Builder ClientBuilder = new OkHttpClient.Builder();
        ClientBuilder.readTimeout(20, TimeUnit.SECONDS);//读取超时
        ClientBuilder.connectTimeout(10, TimeUnit.SECONDS);//连接超时
        ClientBuilder.writeTimeout(60, TimeUnit.SECONDS);//写入超时
        //支持HTTPS请求,跳过证书验证
        ClientBuilder.sslSocketFactory(createSSLSocketFactory());
        ClientBuilder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
        mOkHttpClient = ClientBuilder.build();
    }

    /**
     * 自定义网络回调接口
     */
    public interface MyOkHttpCall {
        void success(Call call, Response response) throws IOException;
    }

    /**
     * Get异步请求
     *
     * @param url
     * @param getParams   get请求参数,可不传,直接将参数组合到url中
     * @param myOkHttpCall
     */
    public void getRequestAsync(String url, Map<String, String> getParams, final MyOkHttpCall myOkHttpCall) {
        //1 构造Request
        Request.Builder builder = new Request.Builder();
        // 处理Get参数
        String finalUrl = setGetParam(url,getParams);
        Request request = builder.get().url(finalUrl).build();
        //2 将Request封装为Call
        Call call = mOkHttpClient.newCall(request);
        //3 执行Call
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // 请求失败,统一处理
                Message message = new Message();
                message.what = GlobalData.NET_FAIL_CODE;
                MyApplication.handler.sendMessage(message);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                myOkHttpCall.success(call, response);

            }
        });
    }

    /**
     * Get请求拼接参数
     *
     * @param url
     * @param getParams
     */
    private String setGetParam(String url, Map<String, String> getParams) {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        if (getParams != null) {
            Iterator<String> iterator = getParams.keySet().iterator();
            String key = "";
            while (iterator.hasNext()) {
                key = iterator.next().toString();
                urlBuilder.addQueryParameter(key, getParams.get(key));
            }
        }
        Log.d(GlobalData.TAG, "http_get_url:" + urlBuilder.build().toString());
        return urlBuilder.build().toString();
    }

    /**
     * Post异步请求
     *
     * @param url
     * @param bodyParams
     * @param myOkHttpCall
     */
    public void postDataAsynToNet(String url, Map<String, String> bodyParams, final MyOkHttpCall myOkHttpCall) {
        Log.d(GlobalData.TAG, "http_post_url:" + url);
        //1构造RequestBody
        RequestBody body = setRequestBody(bodyParams);
        //2 构造Request
        Request.Builder requestBuilder = new Request.Builder();
        Request request = requestBuilder.post(body).url(url).build();
        //3 将Request封装为Call
        Call call = mOkHttpClient.newCall(request);
        //4 执行Call
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // 请求失败,统一处理
                Message message = new Message();
                message.what = GlobalData.NET_FAIL_CODE;
                MyApplication.handler.sendMessage(message);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                myOkHttpCall.success(call, response);

            }
        });
    }

    /**
     * post的请求参数,构造RequestBody
     *
     * @param BodyParams
     * @return
     */
    private RequestBody setRequestBody(Map<String, String> BodyParams) {
        RequestBody body = null;
        okhttp3.FormBody.Builder formEncodingBuilder = new okhttp3.FormBody.Builder();
        if (BodyParams != null) {
            Iterator<String> iterator = BodyParams.keySet().iterator();
            String key = "";
            while (iterator.hasNext()) {
                key = iterator.next().toString();
                formEncodingBuilder.add(key, BodyParams.get(key));
                Log.d(GlobalData.TAG, "http_post_key:" + key + ",post_value:" + BodyParams.get(key));
            }
        }
        body = formEncodingBuilder.build();
        return body;

    }


    /**
     * 生成安全套接字工厂,用于https请求的证书跳过
     *
     * @return
     */
    public SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory ssfFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
        }
        return ssfFactory;
    }

    /**
     * 用于信任所有证书
     */
    class TrustAllCerts implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

}

结束

QQ登录比较简单,参照文档基本就可以了

猜你喜欢

转载自blog.csdn.net/a564239493/article/details/80572399
今日推荐