前言
市面上的app大部分都可以使用qq,微信这些第三方平台的账号来登录,这样可以提高用户体验,避免手工输入账号和密码的麻烦。那么第三方登录的原理到底是什么,以及使用友盟这个平台怎样实现qq和微信的联合登录?下面就来开始本片文章的正文。
原理
使用第三方登录,通过访问第三方平台,拿到QQ、微信的用户id,拿着第三方平台平台(QQ、微信)返回uid或者openid这些用户的唯一标识,然后拿着这些唯一标识访问自己APP的后台服务,如果已经在后台注册则直接登录返回用户信息。若没有登录会直接后台创建新的用户,并返回用户信息。下载再使用这个账号登录就可以直接登录了。这是一般APP第三方登录的流程。
流程图:
但是对于一些商城类的APP就不可以这么搞了,需要去绑定已经存在的用户。
流程图:
前期准备
友盟后台申请AppKey
微信开发者平台申请AppID,AppSecret
链接:https://open.weixin.qq.com/
申请微信的appId是比较麻烦的,首先需要在微信开发者平台上申请一个开发者账号,并进行开发者资质认证(花钱的)
认证完成后,点击移动应用,并按照要求一步一步填写信息,创建应用
注意填写平台信息的时候需要填写一个应用签名,这个签名是和签名文件相对应的,一个签名文件对应一个签名。腾讯开发平台注册账号,申请appid和appkey
链接: http://open.qq.com/
申请QQ的appid没有像微信那么麻烦了,直接注册了账号就可以创建应用了
接入步骤
官方文档:http://dev.umeng.com/social/android/quick-integration
下载sdk
根据需求下载对应平台的sdk,对于QQ,微信,新浪微博都有完整版和精简版的区别,这里自行选择。精简版的就可以实现第三方登录了。根据要实现的功能下载具体的版本。
拷贝资源(jar,res)到工程中
拷贝jar和res有如下两种形式
a .将main文件夹以及platform(选择你想使用的平台即可)文件下,对应的资源文件和jar放入你的工程
b.如果不想像a方式一样一个个拷贝,可以使用集成工具umeng_integrate_tool.jar双击点开这个工具,如下图所示:
选择你想使用的平台,以及你所使用的开发工具,点击ok 会在当前目录下生成一个新的文件夹umeng_integratetool_result
只需将该文件夹下生成的对应文件对应放入你的工程中即可 这里注意如果使用了新浪微博精简版,或者豆瓣人人腾讯微博,需要加入umeng_social_shareview.jar及其对应的资源文件,如果没有使用这些平台可以不加 如果您的程序不想使用我们的分享面板,想自定义UI分享UI界面,umeng_social_shareboard.jar以及对应的资源文件也可以不用加 如果您使用了我们的分享面板,您的工程已经依赖的v4,可以不使用我们的umeng_shareboard_widget.jar添加对应的回调Activity
使用微信分享或者登陆功能
在包名目录下创建wxapi文件夹,新建一个名为WXEntryActivity的activity继承WXCallbackActivity。这里注意一定是包名路径下,例如我的包名是com.umeng.soexample,则配置如下:(需要注意,如果使用精简版WXCallbackActivity的路径为com.umeng.weixin.callback.WXCallbackActivity,如果使用完整版路径是com.umeng.socialize.weixin.view.WXCallbackActivity)
同理需要建立回调的平台还有支付宝与易信,支付宝是需要建立一个apshare的文件夹,然后建立一个ShareEntryActivity的类,继承ShareCallbackActivity。易信是需要建立一个yxapi的文件夹,建立一个YXEntryActivity的类继承YXCallbackActivity。如果不使用这两个平台可以不用建立。 同理新浪微博也需要一个回调的Activity,与微信不同的是它只需要在包名目录下建立一个名为WBShareActivity类即可,不用建立文件夹,该类继承WBShareCallBackActivity,如下图所示(注意看目录结构)
修改AndroidManiFest
首先需要添加权限:
<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"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
然后加入sdk中需要的Activity:
新浪:
<activity android:name=".WBShareActivity"android:configChanges="keyboardHidden|orientation"android:screenOrientation="portrait" ><intent-filter><action android:name="com.sina.weibo.sdk.action.ACTION_SDK_REQ_ACTIVITY" /><category android:name="android.intent.category.DEFAULT" /></intent-filter></activity>
微信:
<activity android:name=".wxapi.WXEntryActivity"android:configChanges="keyboardHidden|orientation|screenSize"android:exported="true"android:screenOrientation="portrait"android:theme="@android:style/Theme.Translucent.NoTitleBar" />
支付宝:
<activity android:name=".apshare.ShareEntryActivity"android:configChanges="keyboardHidden|orientation|screenSize"android:exported="true"android:screenOrientation="portrait"android:theme="@android:style/Theme.Translucent.NoTitleBar" />
qq精简版:
<activity android:name="com.umeng.qq.tencent.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="tencent100424468" /></intent-filter></activity><activity android:name="com.umeng.qq.tencent.AssistActivity"android:screenOrientation="portrait"android:theme="@android:style/Theme.Translucent.NoTitleBar"android:configChanges="orientation|keyboardHidden|screenSize"/>
qq完整版:
<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="tencent100424468" /></intent-filter></activity><activity android:name="com.tencent.connect.common.AssistActivity"android:screenOrientation="portrait"android:theme="@android:style/Theme.Translucent.NoTitleBar"android:configChanges="orientation|keyboardHidden|screenSize"/>
添加友盟key:
<meta-dataandroid:name="UMENG_APPKEY"android:value="561cae6ae0f55abd990035bf" ></meta-data>
修改build.gradle文件
将文件夹中的签名文件放入到工程中,例如我的签名文件是appKey.jks
然后增加签名文件的密码:
signingConfigs {debug {storeFile file('../appKey.jks')storePassword "******"keyAlias "******"keyPassword "******"}}
然后在buildTypes中将这个signingConfigs配置进去,如下图所示:
buildTypes {release {minifyEnabled falsesigningConfig signingConfigs.debugproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}debug {minifyEnabled falsesigningConfig signingConfigs.debugproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}
配置各个平台的appkey
在application文件中配置对应平台的key:
{PlatformConfig.setWeixin("wxbec65736501d0564", "82bc1e49bbb56cdded05cc8875d02ea79");PlatformConfig.setQQZone("1105979137", "jODSgRir417714vY");}
在application中初始化sdk,这个初始化最好放在application的程序入口中,防止意外发生:
UMShareAPI.get(this);
以上以精简版的为例,如果是完整版的就需要把完整版的jar和res拷贝到工程中,在清单文件中配置完整版的activity。
混淆文件
-dontusemixedcaseclassnames -dontshrink -dontoptimize -dontwarn com.google.android.maps.** -dontwarn android.webkit.WebView -dontwarn com.umeng.** -dontwarn com.tencent.weibo.sdk.** -dontwarn com.facebook.** -keep public class javax.** -keep public class android.webkit.** -dontwarn android.support.v4.** -keep enum com.facebook.** -keepattributes Exceptions,InnerClasses,Signature -keepattributes *Annotation* -keepattributes SourceFile,LineNumberTable -keep public interface com.facebook.** -keep public interface com.tencent.** -keep public interface com.umeng.socialize.** -keep public interface com.umeng.socialize.sensor.** -keep public interface com.umeng.scrshot.** -keep class com.android.dingtalk.share.ddsharemodule.** { *; } -keep public class com.umeng.socialize.* {*;} -keep class com.facebook.** -keep class com.facebook.** { *; } -keep class com.umeng.scrshot.** -keep public class com.tencent.** {*;} -keep class com.umeng.socialize.sensor.** -keep class com.umeng.socialize.handler.** -keep class com.umeng.socialize.handler.* -keep class com.umeng.weixin.handler.** -keep class com.umeng.weixin.handler.* -keep class com.umeng.qq.handler.** -keep class com.umeng.qq.handler.* -keep class UMMoreHandler{*;} -keep class com.tencent.mm.sdk.modelmsg.WXMediaMessage {*;} -keep class com.tencent.mm.sdk.modelmsg.** implements com.tencent.mm.sdk.modelmsg.WXMediaMessage$IMediaObject {*;} -keep class im.yixin.sdk.api.YXMessage {*;} -keep class im.yixin.sdk.api.** implements im.yixin.sdk.api.YXMessage$YXMessageData{*;} -keep class com.tencent.mm.sdk.** { *;}-keep class com.tencent.mm.opensdk.** { *;}-dontwarn twitter4j.** -keep class twitter4j.** { *; } -keep class com.tencent.** {*;} -dontwarn com.tencent.** -keep public class com.umeng.com.umeng.soexample.R$*{ public static final int *;}-keep public class com.linkedin.android.mobilesdk.R$*{ public static final int *;}-keepclassmembers enum * { public static **[] values();public static ** valueOf(java.lang.String);}-keep class com.tencent.open.TDialog$* -keep class com.tencent.open.TDialog$* {*;} -keep class com.tencent.open.PKDialog -keep class com.tencent.open.PKDialog {*;} -keep class com.tencent.open.PKDialog$* -keep class com.tencent.open.PKDialog$* {*;} -keep class com.sina.** {*;} -dontwarn com.sina.** -keep class com.alipay.share.sdk.** { *;}-keepnames class * implements android.os.Parcelable { public static final ** CREATOR;}-keep class com.linkedin.** { *; } -keepattributes Signature
调用代码:友盟官方有两种方式,一种直接获取用户资料,另外一种是先去授权,获取accesstoken后再去回去用户资料,对于安全性要求高的话可以使用第二种方式。这里以第一种为例:
UMShareAPI.get(this).getPlatformInfo(this, SHARE_MEDIA.WEIXIN, authListener);
其中umAuthListener为授权回调,构建如下,其中授权成功会回调onComplete,取消授权回调onCancel,授权错误回调onError,对应的错误信息可以用过onError的Throwable参数来打印
private UMAuthListener umAuthListener = new UMAuthListener() {@Overridepublic void onStart(SHARE_MEDIA platform) {//授权开始的回调}@Overridepublic void onComplete(SHARE_MEDIA platform, int action, Map<String, String> data) {Toast.makeText(getApplicationContext(), "Authorize succeed", Toast.LENGTH_SHORT).show();}@Overridepublic void onError(SHARE_MEDIA platform, int action, Throwable t) {Toast.makeText( getApplicationContext(), "Authorize fail", Toast.LENGTH_SHORT).show();}@Overridepublic void onCancel(SHARE_MEDIA platform, int action) {Toast.makeText( getApplicationContext(), "Authorize cancel", Toast.LENGTH_SHORT).show();} };
最后在登录所在的Activity里复写onActivityResult方法,注意不可在fragment中实现,如果在fragment中调用登录,在fragment依赖的Activity中实现,如果不实现onActivityResult方法,会导致登录或回调无法正常进行
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);UMShareAPI.get(this).onActivityResult(requestCode, resultCode, data);}
登录成功后,第三方平台会将用户资料传回, 全部会在Map data中返回 ,由于各个平台对于用户资料的标识不同,因此为了便于开发者使用,我们将一些常用的字段做了统一封装,开发者可以直接获取,不再需要对不同平台的不同字段名做转换,这里列出封装的字段及含义
用户资料与各平台的对应关系:
QQ
name:name(6.2以前用screen_name)
用户id:uid
accesstoken: accessToken (6.2以前用access_token)
过期时间:expiration (6.2以前用expires_in)
性别:gender
头像:iconurl(6.2以前用profile_image_url)
是否黄钻:is_yellow_year_vip
黄钻等级:yellow_vip_level
城市:city
省份:province
微信
微信返回的openID和unionID都可以实现用户标识的需求,二者的区别在于,unionID可以实现同一个开发者账号下的应用之间账号打通的需求
openid:openid
unionid:(6.2以前用unionid)用户id
accesstoken: accessToken (6.2以前用access_token)
refreshtoken: refreshtoken: (6.2以前用refresh_token)
过期时间:expiration (6.2以前用expires_in)
name:name(6.2以前用screen_name)
城市:city
省份:prvinice
国家:country
性别:gender
头像:iconurl(6.2以前用profile_image_url)
效果:
QQ
返回的信息
微信
返回的信息
拿到对应平台的信息后,用uid或openid请求服务器,进行后续的操作。每个app的产品定义可能会有一定的差别。这里就不在说,大体流程在上面已经说过。