微信、QQ、微博第三方登录

                     微信、QQ、微博第三方登录与分享

    最近项目终于要完结了,甲方可能是觉得这个项目做得不错,准备推广,说他们的boss要开发布会了,我听后内心偷偷一笑,这种傻b系统还开发布会,别逗我笑,我的小心脏受不了。于是他们又过来了几次,说加个第三方登录与分享功能。嗯,加个第三方登录与分享,说得轻巧,可苦了我。而且啊,第三方登录,是要做iOS端和Android端的,还要做服务器端,忧伤。

    新来的妹子电脑太卡了,帮她调了个bug,intellij IDEA卡到爆炸,实在受不了了,就把唯一一台imac让给她了,又抄起自己的小macbook pro,虽然屏幕小了点,但好在敲敲代码啥的性能上没问题,就是同时开着xcode、as、intellij IDEA和网易云音乐时风扇转得太厉害,怕把本本烧坏,有点小心烦。记录一下集成三大平台的登录与分享。

    首先,肯定是马上上CSDN博客找解决方案,不负希望,找到了不少前辈分享的博客。在此分享一下

史上最详细Android集成QQ,微信,微博分享(不用第三方)持续更新中

Android开发第三方登录--微博登录

iOS 第三方登录(QQ 微信 新浪微博)

基于Swift语言开发微信、QQ跟微博的SSO授权登录代码分析

对比着几个博客和官网文档,嗯,其实也不太难,不过腾讯开发平台和微博的文档是真的有点那啥,特别是微博的,sdk托管在github上,文档解释也是少得可怜,而微信最坑的是就算你完全按步骤集成了,你也是跑不通的,因为你要清除微信的缓存,或者说自己重装一遍微信,当时调试了半天,总是调不通,最后换了台测试机,上面没装微信,就新安装下,居然跑通了,当时心里一万句mmp,不知道微信怎么会这样,也不知道其中的原理是啥,知道的小伙伴请在评论或者发邮件我,大家交流交流心得。

  1.微信

        在微信开放平台注册一个账号并且创建一个应用,再申请第三方登录与分享的权限

         然后就按照开发文档,微信的开发文档写得还是非常不错的

     在Android Studio的app build.gradle中添加依赖

  

然后就是添加一些用户权限了    

<uses-permission android:name="android.permission.INTERNET"/>

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>


如果已经添加过了,就不用再添加了。

然后就是在自己的Application类中添加微信注册代码

 private void registerToWX() {
        mWxApi = WXAPIFactory.createWXAPI(this,AppConst.WEIXIN.APP_ID,false);
        mWxApi.registerApp(AppConst.WEIXIN.APP_ID);
    }

在Application中的onCreate()方法中调用registerToWX()

在需要登微信登录的地方,也就是点击微信登录按钮处理方法中调用如下方法

 private void wechatLogin() {
        IWXAPI wxapi = ((MyApplication)getActivity().getApplication()).mWxApi;
        if(!wxapi.isWXAppInstalled()){
            Toast.makeText(getContext(),"您还未安装微信客户端",Toast.LENGTH_SHORT).show();
            return;
        }
        final SendAuth.Req req = new SendAuth.Req();
        req.scope = "snsapi_userinfo";
        req.state = "yuanda_wx_login";
        wxapi.sendReq(req);
    }

这个方法很简单,就是先判断用户机是否安装了微信客户端,如果安装了,就向微信客户端发一个获取用户信息的请求,当然,微信其实已经处理了很多种情况了,比如微信没登录,那么调起微信客户端后就会进入到微信登录界面。微信登录验证用了OAuth2.0协议标准,具体过程就是首先发起上面的请求,然后微信客户端登录确认后就会在回调Activity中返回一个code的字符串,然后用这code去请求这个url,就可以获取一个token,这个token就是一个凭证,后面的很多微信请求都需要使用这个token,但其实我们的第三方登录用不到这个token,我们其实需要的是访问这个url后返回的openid字段,因为这个openid表示的是我们创建的这个app应用中每个微信用户的唯一标识。我的设计思路是把code提交给后台,然后后台发起这个url请求,把获取的openid与用户原有的账号绑定,以后再登录时就可以直接通过这个openid获取用户账号,然后就可以返回用户数据了。

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

回调的Activity必须是应用包名+wxapi.WXEntryActivity,并且要实现IWXAPIEventHandler接口,实现onReq、onPause、onResp三个方法,其中code就是在onResp方法中返回的onResp方法有个BaseResp resp形参,resp.errCode是异常类型,如果是BaseResp.ErrCode.ERR_OK的话,就表示确认登录成功,再判断resp.getType()返回请求类型,这里主要有两种,登录和分享,如果是登录,就把resp强转成SendAuth.Resp类型,然后就可以得到code字段和state字段了,其中state字段就是我们在前面调用登录请求时设置的state。拿到code就提交给我们自己的应用服务器后台,调用上面说的那个url,参数说明如下


返回值是一个json字符串

{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid":"o6_bmasdasdsad6_2sgVt7hMZOPfL"

}

其中的openid就是我们想要的,用一张表来保存微信openid和我们自己和用户的id的一个映射。再次登录时就可以通过这个openid获取到用户id,再用用户id查找用户信息了。嗯,过程大概就是这样,最后再啰唆一句,把微信的缓存清一下,或者直接重装微信,否则是调用不成功的,errCode会一直报-6,说你的签名错误。

2.QQ

     也是一样,注册一个腾讯开放平台的账号,然后创建一个应用,得到一个APPID,然后在qq sdk下载中下载sdk,就是一个open_sdk.jar包,添加到项目中去,成为一个library,再添加两个Activity注册

 <activity
            android:name="com.tencent.tauth.AuthActivity"
            android:launchMode="singleTask"
            android:noHistory="true">
            <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="tencentYOUR_APP_ID" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.tencent.connect.common.AssistActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity>
mTencent = Tencent.createInstance(AppConst.QQ.APP_ID,this);

那个scheme="tencentYOUR_APP_ID"中填tencent和你的appid拼接的字符串,这样就完成了qq的集成了,然后在Application中添加如下代码,生成一个Tencent对象

mTencent = Tencent.createInstance(AppConst.QQ.APP_ID,this);

再然后就是在登录按钮处理方法中调用如下方法

 private void qqLogin() {
        Tencent tencent = ((MyApplication)getActivity().getApplication()).mTencent;
        IUiListener loginListener = new IUiListener() {
            @Override
            public void onComplete(Object o) {
                JSONObject obj = (JSONObject) o;
                try {
                    String openId = obj.getString("openid");
                    mLoginPresenter.qqLogin(openId);
                } catch (JSONException e) {
                    e.printStackTrace();
                    Toast.makeText(getActivity(),"QQ登录失败",Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onError(UiError uiError) {
                Toast.makeText(getActivity(),"QQ登录已失败",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onCancel() {
                Toast.makeText(getActivity(),"QQ登录已取消",Toast.LENGTH_SHORT).show();
            }
        };
        ((LoginActivity)getActivity()).setLoginListener(loginListener);
        tencent.login(this.getActivity(),"all",loginListener);

    }

还有一点就是QQ也会回调Activity,回调的原理就是QQ是通过startActivityForResult的,所以要在onActivityResult方法中来接收回调,在调起QQ登录请求的Activity的onActivityResult中

 @Override
    public void onActivityResult(int requsetCode,int resultCode, Intent data) {
        super.onActivityResult(requsetCode,resultCode,data);
        ((MyApplication) getApplication()).mTencent.onActivityResultData(requsetCode, resultCode, data, shareListener);
        if(requsetCode == Constants.REQUEST_API) {
            if (resultCode == Constants.REQUEST_QQ_SHARE || resultCode == Constants.REQUEST_QZONE_SHARE || resultCode == Constants.REQUEST_OLD_SHARE) {
                ((MyApplication) getApplication()).mTencent.handleResultData(data, shareListener);
            }
        }

    }

QQ登录的集成就是这么容易


3.微博

     微博就有点坑了,也不能说是坑,只能说微博的开发文档写得真不咋地,不过还是可以勉强看看的。一样的,在微博开放平台注册一个账号,然后创建一个应用,获得appkey。微博登录是种啥SSO授权,不怎么理解SSO的意思,百度了一波说是通过一次登录就可以获取信任的其他系统的数据。微博登录值得一赞的是不用安装微博客户端,有网页端的登录,这个还是很爽,但貌似分享需要客户端。一样的导入微博的sdk,有点复杂,需要导入openDefault.aar文件,也是放到libs中,而且还要在app build.gradle中加上

compile(name: 'openDefault-4.2.7', ext: 'aar')

这么一句

再在项目包根目录创建一个接口,必须是这个名字

public interface Constants {
    /** 当前 DEMO 应用的 APP_KEY,第三方应用应该使用自己的 APP_KEY 替换该 APP_KEY */
    public static final String APP_KEY      = "YOUR APP KEY";

    String sign = "YOU SIGN";

    /** 
     * 当前 DEMO 应用的回调页,第三方应用可以使用自己的回调页。
     * 建议使用默认回调页:https://api.weibo.com/oauth2/default.html
     */
    public static final String REDIRECT_URL = "https://api.weibo.com/oauth2/default.html";

    /**
     * WeiboSDKDemo 应用对应的权限,第三方开发者一般不需要这么多,可直接设置成空即可。
     * 详情请查看 Demo 中对应的注释。
     */
    public static final String SCOPE = 
            "email,direct_messages_read,direct_messages_write,"
            + "friendships_groups_read,friendships_groups_write,statuses_to_me_read,"
            + "follow_app_official_microblog," + "invitation_write";
}

然后就在按钮点击处理方法中调用如下方法

private void wblogLogin() {
        if(mSsoHandler == null){
            mSsoHandler = new SsoHandler(this.getActivity());
        }
        ((LoginActivity)getActivity()).setSsoHandler(mSsoHandler);
//        new AlertDialog.Builder(getActivity()).setMessage("暂未开通").show();
        mSsoHandler.authorize(new WbAuthListener() {
            @Override
            public void onSuccess(Oauth2AccessToken token) {
                String wUserId = token.getUid();
                mLoginPresenter.wBlogLogin(wUserId);
            }

            @Override
            public void cancel() {
                Toast.makeText(getActivity(),"微博登录授权取消",Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(WbConnectErrorMessage wbConnectErrorMessage) {
                Toast.makeText(getActivity(),"微博登录授权失败",Toast.LENGTH_SHORT).show();
            }
        });
    }

和上面的QQ登录一样,微博也需要在onActivityResult方法中处理回调

 if(mSsoHandler != null){
            mSsoHandler.authorizeCallBack(requestCode,resultCode,data);
        }

这样,微信、QQ、微博的第三方登录就完成了

再来说说三个平台的第三方分享

先贴出代码

private void transmit() {
        final Dialog bottomDialog = new Dialog(this, R.style.BottomDialog);
        View contentView = LayoutInflater.from(this).inflate(R.layout.dialog_bottom_circle, null);
        bottomDialog.setContentView(contentView);
        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) contentView.getLayoutParams();
        params.width = getResources().getDisplayMetrics().widthPixels - DensityUtil.dp2px(this, 16f);
        params.bottomMargin = DensityUtil.dp2px(this, 8f);
        contentView.setLayoutParams(params);
        bottomDialog.getWindow().setGravity(Gravity.BOTTOM);
        bottomDialog.getWindow().setWindowAnimations(R.style.BottomDialog_Animation);
        bottomDialog.show();
        //微信分享
        contentView.findViewById(R.id.share_wx_select).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(((MyApplication)getApplication()).mWxApi.isWXAppInstalled()) {
                    if (wxShareURL(1, AppConst.BASE_URL+"user/share?type="+FIEL_TYPE+"&id=" + mNewsDetailsData.getId())) {
//                    Toast.makeText(KnowledgeDetailsActivity.this,"分享成功",Toast.LENGTH_SHORT).show();
                    }
                }else{
                    Toast.makeText(NewsDetailsActivity.this,"您还未安装微信客户端",Toast.LENGTH_SHORT).show();
                }
                bottomDialog.dismiss();
            }
        });
        //分享取消
        contentView.findViewById(R.id.share_cancel).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bottomDialog.dismiss();
            }
        });
        //qq分享
        contentView.findViewById(R.id.share_qq_select).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(((MyApplication)getApplication()).mTencent.isQQInstalled(NewsDetailsActivity.this)) {
                    final Bundle params = new Bundle();
                    params.putInt(QzoneShare.SHARE_TO_QZONE_KEY_TYPE, QzoneShare.SHARE_TO_QZONE_TYPE_IMAGE_TEXT);
                    params.putString(QzoneShare.SHARE_TO_QQ_TITLE, mNewsDetailsData.getTitle());
                    params.putString(QzoneShare.SHARE_TO_QQ_SUMMARY, "");
                    params.putString(QzoneShare.SHARE_TO_QQ_TARGET_URL, AppConst.BASE_URL+"user/share?type="+FIEL_TYPE+"&id=" + mNewsDetailsData.getId());
                    ArrayList<String> shareImageUrls = new ArrayList();
                    shareImageUrls.add(AppConst.BASE_URL+"img/logo.png");
                    params.putStringArrayList(QzoneShare.SHARE_TO_QQ_IMAGE_URL, shareImageUrls);
                    ((MyApplication) getApplication()).mTencent.shareToQzone(NewsDetailsActivity.this, params, shareListener);
                }else{
                    Toast.makeText(NewsDetailsActivity.this,"您还未安装QQ(TIM)客户端",Toast.LENGTH_SHORT).show();
                }
                bottomDialog.dismiss();
            }
        });

        //微博分享
        contentView.findViewById(R.id.share_wblog_select).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//                new AlertDialog.Builder(NewsDetailsActivity.this).setMessage("暂未开通").show();
                if(mWbShareHandler == null) {
                    mWbShareHandler = new WbShareHandler(NewsDetailsActivity.this);
                    mWbShareHandler.registerApp();
                    mWbShareHandler.setProgressColor(0xff33b5e5);
                }
                if(mWbShareCallback == null){
                    mWbShareCallback = new WbShareCallback() {
                        @Override
                        public void onWbShareSuccess() {
                            Toast.makeText(NewsDetailsActivity.this,"分享到微博成功",Toast.LENGTH_SHORT).show();
                        }

                        @Override
                        public void onWbShareCancel() {
                            Toast.makeText(NewsDetailsActivity.this,"取消微博分享",Toast.LENGTH_SHORT).show();
                        }

                        @Override
                        public void onWbShareFail() {
                            Toast.makeText(NewsDetailsActivity.this,"微博分享失败",Toast.LENGTH_SHORT).show();
                        }
                    };
                }
                WebpageObject mediaObject = new WebpageObject();
                mediaObject.identify = Utility.generateGUID();
                mediaObject.title =mNewsDetailsData.getTitle();
                mediaObject.description = "";
                mediaObject.setThumbImage(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher));
                mediaObject.actionUrl = AppConst.BASE_URL+"user/share?type="+FIEL_TYPE+"&id=" + mNewsDetailsData.getId();
                mediaObject.defaultText = "";
                WeiboMultiMessage message = new WeiboMultiMessage();
                message.mediaObject = mediaObject;

                ImageObject img = new ImageObject();
                img.title = mNewsDetailsData.getTitle();
                img.imagePath = AppConst.BASE_URL+"img/logo.png";
                message.imageObject = img;

                TextObject text = new TextObject();
                text.title = mNewsDetailsData.getTitle();
                Date date = new Date(mNewsDetailsData.getDate());
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
                text.text = mNewsDetailsData.getTitle() + ",发布于"+ sdf.format(date)+","+mNewsDetailsData.getReadCount()+"次阅读";
                message.textObject = text;
                mWbShareHandler.shareMessage(message,false);
                bottomDialog.dismiss();
            }
        });

    }

 public boolean wxShareURL(int flag,String url){
        //初始化一个WXWebpageObject填写url
        WXWebpageObject webpageObject = new WXWebpageObject();
        webpageObject.webpageUrl = url;
        //用WXWebpageObject对象初始化一个WXMediaMessage,天下标题,描述
        WXMediaMessage msg = new WXMediaMessage(webpageObject);
        msg.title = mNewsDetailsData.getTitle();
//        msg.description = mNewsDetailsData;
        //这块需要注意,图片的像素千万不要太大,不然的话会调不起来微信分享,
        //我在做的时候和我们这的UIMM说随便给我一张图,她给了我一张1024*1024的图片
        //当时也不知道什么原因,后来在我的机智之下换了一张像素小一点的图片好了!
        Bitmap thumb = BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher);
        msg.setThumbImage(thumb);
        SendMessageToWX.Req req = new SendMessageToWX.Req();
        req.transaction = String.valueOf(System.currentTimeMillis());
        req.message = msg;
        req.scene = flag==0?SendMessageToWX.Req.WXSceneSession:SendMessageToWX.Req.WXSceneTimeline;
        IWXAPI api = ((MyApplication)getApplication()).mWxApi;
        return api.sendReq(req);
    }

三大平台的分享其实和登录验证差不多,就是调起第三方时发起的Request的类型不同而已,然后处理回调时判断一下回调类型


老板来了说下午等人到齐了做系统测试,测完交付了我要睡个两天先。上午花了两个小时写了这个博客,也回忆了下集成的 辛酸过程,有疑惑的小伙伴发评论(可能不能及时回复)或者邮件([email protected])我,大家一起交流学习。后面有时间再写写ios集成和极光推送集成以及浏览器中唤醒APP分享的解决方案

猜你喜欢

转载自blog.csdn.net/qq_31728311/article/details/80504614
今日推荐