Android第三方登陆之新浪微博Weibo篇(原生登陆授权)

时间:2024-03-01 15:27:30

前言 
Android第三方登录可以说是非常的常见,今天主要先说一下新浪微博第三方登陆授权。

  • SDK版本支持

SDK v3.0已经发布了支持iPhone和Android的版本。 
须将你的应用的包名签名信息在平台进行填写注册。 
SDK3.0不区分Phone和Pad。Windows Phone请下载SDK v2.0。 
SDK下载地址:http://open.weibo.com/wiki/SDK 
SDK接入流程 
新应用

sdk72205.png

1、注册成为开发者,创建移动应用

sdk72203.png

如果你还不是一名开发者,请先注册成为开发者,具体参考新手指南 : http://open.weibo.com/wiki/%E6%96%B0%E6%89%8B%E6%8C%87%E5%8D%97

创建应用时,开发者需要谨慎选择应用对应平台,不同的平台建议使用不同APPKEY开发。 
sdk72201.png

2、创建应用完成后,可以在“我的应用 - 应用信息”中查看您所创建应用的APPKEY及APPSECRET,请妥善保管您的这些信息,这将 成为您调用微博开放平台各API的身份标志,如下图所示: 
khd411.png

3、请在“我的应用 - 应用信息 - 高级信息”中填写您的应用回调页,这样才能使OAuth2.0授权正常进行。如果您的APPSECRET发生泄露,您也可以通过该页面中的重置按钮对其重置,如下图所示:

khd5.jpg

注:通常Mobile Native App没有服务器回调地址,您可以在应用控制台授权回调页处填写平台提供的默认回调页,该页面用户不可见,仅用于获取access token。 OAuth2.0客户端默认回调页:https://api.weibo.com/oauth2/default.html

4、在“我的应用 - 应用信息”填写应用的平台信息 
sdk72204.png 
这里iPhone应用填写Apple ID和Buddle ID,Android应用填写包名,签名及下载地址。 
关于各字段含义在控制台中均有说明。

5、下载并集成对应平台SDK到你的应用中,当您开发完您的应用后,您就可以通过“我的应用”页面提交审核了。只有当您的应用通过审核后,才能在微博中正确显示您的来源地址等。

khd611.png

6、您可以通过“我的应用 – 数据统计”页面查看您的应用的相关统计数据,包括应用统计、接口统计、用户特征统计等信息。

khd6.jpg 
已上线应用

sdk72206.png

请直接编辑“我的应用 – 应用信息”补充应用平台信息,改字段修改后立即生效,无需二次审核。


  • Android 代码实现

git下来weibo_sdk_demo,感受了下他的代码,又是库文件,又是依赖包,真的是非常的麻烦,但是,我们可以从依赖module中取出我们所需要的java文件即可,我们先看一下他的demo架构图,如下所示:

这里写图片描述 
,我们把jar包导入到libs中,还有so库文件,官方说的也很明确,一定要导入进去。 
我们先看一下官方demo,是如何授权的,有好多种授权方式,这里我们看看sso,以及web授权

// 创建微博实例
        //mWeiboAuth = new WeiboAuth(this, Constants.APP_KEY, Constants.REDIRECT_URL, Constants.SCOPE);
        // 快速授权时,请不要传入 SCOPE,否则可能会授权不成功
        mAuthInfo = new AuthInfo(this, Constants.APP_KEY, Constants.REDIRECT_URL, Constants.SCOPE);
        mSsoHandler = new SsoHandler(WBAuthActivity.this, mAuthInfo);

        // **SSO 授权, 仅客户端**
        findViewById(R.id.obtain_token_via_sso).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
              //看清楚是mSsoHandler.authorizeClientSso
              mSsoHandler.authorizeClientSso(new AuthListener());
            }
        });

        // 手机短信授权 
        //  title 短信注册页面title,可选,不传时默认为""验证码登录""。此处WeiboAuthListener 对象 listener 
        //可以是和sso 同一个 listener   回调对象 也可以是不同的。开发者根据需要选择
        findViewById(R.id.obtain_token_via_mobile).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mSsoHandler.registerOrLoginByMobile("验证码登录",new AuthListener());
            }
        });

        // SSO 授权, 仅Web
        findViewById(R.id.obtain_token_via_web).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
            //看清楚是mSsoHandler.authorizeWeb
                mSsoHandler.authorizeWeb(new AuthListener());
            }
        });

        // SSO 授权, ALL IN ONE   如果手机安装了微博客户端则使用客户端授权,没有则进行网页授权
        findViewById(R.id.obtain_token_via_signature).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
            //看清楚是mSsoHandler.authorize
                mSsoHandler.authorize(new AuthListener());
            }
        });



 /**
     * 当 SSO 授权 Activity 退出时,该函数被调用。
     * 
     * @see {@link Activity#onActivityResult}
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // SSO 授权回调
        // 重要:发起 SSO 登陆的 Activity 必须重写 onActivityResults
        if (mSsoHandler != null) {
            mSsoHandler.authorizeCallBack(requestCode, resultCode, data);
        }

    }


/**
     * 微博认证授权回调类。
     * 1. SSO 授权时,需要在 {@link #onActivityResult} 中调用 {@link SsoHandler#authorizeCallBack} 后,
     *    该回调才会被执行。
     * 2. 非 SSO 授权时,当授权结束后,该回调就会被执行。
     * 当授权成功后,请保存该 access_token、expires_in、uid 等信息到 SharedPreferences 中。
     */
    class AuthListener implements WeiboAuthListener {

        @Override
        public void onComplete(Bundle values) {
            // 从 Bundle 中解析 Token
            mAccessToken = Oauth2AccessToken.parseAccessToken(values);
            //从这里获取用户输入的 电话号码信息 
            String  phoneNum =  mAccessToken.getPhoneNum();
            if (mAccessToken.isSessionValid()) {
                // 显示 Token
                updateTokenView(false);

                // 保存 Token 到 SharedPreferences
                AccessTokenKeeper.writeAccessToken(WBAuthActivity.this, mAccessToken);
                Toast.makeText(WBAuthActivity.this, 
                        R.string.weibosdk_demo_toast_auth_success, Toast.LENGTH_SHORT).show();
            } else {
                // 以下几种情况,您会收到 Code:
                // 1. 当您未在平台上注册的应用程序的包名与签名时;
                // 2. 当您注册的应用程序包名与签名不正确时;
                // 3. 当您在平台上注册的包名和签名与您当前测试的应用的包名和签名不匹配时。
                String code = values.getString("code");
                String message = getString(R.string.weibosdk_demo_toast_auth_failed);
                if (!TextUtils.isEmpty(code)) {
                    message = message + "\nObtained the code: " + code;
                }
                Toast.makeText(WBAuthActivity.this, message, Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onCancel() {
            Toast.makeText(WBAuthActivity.this, 
                   R.string.weibosdk_demo_toast_auth_canceled, Toast.LENGTH_LONG).show();
        }

        @Override
        public void onWeiboException(WeiboException e) {
            Toast.makeText(WBAuthActivity.this, 
                    "Auth exception : " + e.getMessage(), Toast.LENGTH_LONG).show();
        }
    }

其实官方建议我们用sso跟web一起,更加的安全有效,就是加上判断而已,授权前检测是否有没有安装客户端

放出检测是否有没有客户端code

 public static boolean isWeiboInstalled(@NonNull Context context) {
        PackageManager pm;
        if ((pm = context.getApplicationContext().getPackageManager()) == null) {
            return false;
        }
        List<PackageInfo> packages = pm.getInstalledPackages(0);
        for (PackageInfo info : packages) {
            String name = info.packageName.toLowerCase(Locale.ENGLISH);
            if ("com.sina.weibo".equals(name)) {
                return true;
            }
        }
        return false;
}

-接下来我们自己的实现代码

完整代码如下,有授权和注销代码,需要注意几个地方,我们所需要的api(官方demo里面(WeiboSDK里面有,跟WeiboSDKDemo同级)): 
这里写图片描述

自己封装的工具类:

public class WeiboLogin {

    private AuthInfo mAuthInfo;
    public SsoHandler mSsoHandler;
    private Activity mActivity;
    private Oauth2AccessToken mAccessToken;

    private static WeiboLogin instance = new WeiboLogin();
    private static String TAG = "weibo";
    /**
     * 注销回调
     */

    private AuthListener mAuthListener;

    private WeiboLogin() {
    }

    public static WeiboLogin getInstance() {

        return WeiboLogin.instance;
    }

    public void Weibologin(Activity activity) {
        this.mActivity = activity;

        if (mAuthInfo == null) {
            mAuthInfo = new AuthInfo(Application.getContext(), Constants.WBAPP_KEY, Constants.REDIRECT_URL, "");
        }
        if (mSsoHandler == null) {
            mSsoHandler = new SsoHandler(mActivity, mAuthInfo);
        }
        mAuthListener = new AuthListener(mActivity);

 //        if (isWeiboInstalled(mActivity)) {
//
//            mSsoHandler.authorizeClientSso(mAuthListener);
//        } else {
//
//            mSsoHandler.authorizeWeb(mAuthListener);
//        }
        mSsoHandler.authorize(mAuthListener);
    }

    /**
     * 微博认证授权回调类。
     * 1. SSO 授权时,需要在 {@link "onActivityResult"} 中调用 {@link SsoHandler#authorizeCallBack} 后,
     * 该回调才会被执行。
     * 2. 非 SSO 授权时,当授权结束后,该回调就会被执行。
     * 当授权成功后,请保存该 access_token、expires_in、uid 等信息到 SharedPreferences 中。
     */
    class AuthListener implements WeiboAuthListener {

        private Activity activity;

        public AuthListener(Activity activity) {
            this.activity = activity;
        }

        @Override
        public void onComplete(Bundle values) {
            // 从 Bundle 中解析 Token
            mAccessToken = Oauth2AccessToken.parseAccessToken(values);
            //从这里获取用户输入的 电话号码信息
            String phoneNum = mAccessToken.getPhoneNum();
            String uid = mAccessToken.getUid();

            if (mAccessToken.isSessionValid()) {

                 //这个地方的UsersAPI ,是官方的demo的依赖库module里面的,
                UsersAPI usersAPI = new UsersAPI(Application.getContext(), Constants.WBAPP_KEY, mAccessToken);
                usersAPI.show(Long.parseLong(uid), new SinaRequestListener(activity));
                // 保存 Token 到 SharedPreferences
                AccessTokenKeeper.writeAccessToken(Application.getContext(), mAccessToken);
                Toast.makeText(Application.getContext(),
                        R.string.weibosdk_demo_toast_auth_success, Toast.LENGTH_SHORT).show();
            } else {
                // 以下几种情况,您会收到 Code:
                // 1. 当您未在平台上注册的应用程序的包名与签名时;
                // 2. 当您注册的应用程序包名与签名不正确时;
                // 3. 当您在平台上注册的包名和签名与您当前测试的应用的包名和签名不匹配时。
                String code = values.getString("code");
                String message = Application.getContext().getString(R.string.weibosdk_demo_toast_auth_failed);
                if (!TextUtils.isEmpty(code)) {
                    message = message + "\nObtained the code: " + code;
                }
                Toast.makeText(Application.getContext(), message, Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onCancel() {
            Toast.makeText(Application.getContext(),
                    R.string.weibosdk_demo_toast_auth_canceled, Toast.LENGTH_LONG).show();
        }

        @Override
        public void onWeiboException(WeiboException e) {
            Toast.makeText(Application.getContext(),
                    "Auth exception : " + e.getMessage(), Toast.LENGTH_LONG).show();
        }
    }


    class SinaRequestListener implements RequestListener {

        private Activity mActivity;

        public SinaRequestListener(Activity activity) {
            this.mActivity = activity;
        }

        @Override
        public void onComplete(String response) {
            Log.e("xxxx", "微博==" + response);
            com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(response);
            try {
                String idstr = jsonObject.getString("idstr");// 唯一标识符(uid)
                String name = jsonObject.getString("name");// 姓名
                String avatar_hd = jsonObject.getString("avatar_hd");

              //通过获取到的用户数据,你可以进行自己的业务逻辑操作
              //do something
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onWeiboException(WeiboException e) {

            Log.e("xxxx", e.toString());

        }
    }



    /**
     * 调用 {@link LogoutAPI#logout(RequestListener)} 来注销。
     */
    public void logout(Activity activity) {
        this.mActivity = activity;
        new LogoutAPI(mActivity, Constants.WBAPP_KEY, AccessTokenKeeper.readAccessToken(mActivity)).logout(new RequestListener() {
            @Override
            public void onComplete(String response) {
                if (!TextUtils.isEmpty(response)) {
                    try {
                        JSONObject obj = new JSONObject(response);
                        if (obj.isNull("error")) {
                            String value = obj.getString("result");

                            // 注销成功
                            if ("true".equalsIgnoreCase(value)) {
                                // XXX: 考虑是否需要将 AccessTokenKeeper 放到 SDK 中??
                                //AccessTokenKeeper.clear(getContext());
                                // 清空当前 Token
                                Log.e("xxxx", "注销成功");
                                mAccessToken = null;

                            }
                        } else {
                            String error_code = obj.getString("error_code");
                            if (error_code.equals("21317")) {
                                mAccessToken = null;
                            }
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }

            }

            @Override
            public void onWeiboException(WeiboException e) {
                LogUtil.e(TAG, "WeiboException: " + e.getMessage());
                // 注销失败
            }
        });
    }

    public static boolean isWeiboInstalled(@NonNull Context context) {
        PackageManager pm;
        if ((pm = context.getApplicationContext().getPackageManager()) == null) {
            return false;
        }
        List<PackageInfo> packages = pm.getInstalledPackages(0);
        for (PackageInfo info : packages) {
            String name = info.packageName.toLowerCase(Locale.ENGLISH);
            if ("com.sina.weibo".equals(name)) {
                return true;
            }
        }
        return false;
    }


}

授权的时候出现的一些问题:

有时候是因为debug版本的时候,授权不成功,出现错误码,网络异常(其实我们网络很好),主要是因为微博客户端不是最新的,更新即可

有时候库文件原因,新建jnilibs文件夹即可

有时候可以添加如下 
sourceSets { 
main.jniLibs.srcDirs = [‘libs’] 
test.jniLibs.srcDirs = [‘libs’] 

还有就是在mainfest文件中进行相关的配置,

<!-- 必须注册在微博授权,分享微博时候用到 -->
        <activity android:name="com.sina.weibo.sdk.component.WeiboSdkBrowser"
            android:configChanges="keyboardHidden|orientation"
            android:windowSoftInputMode="adjustResize"
            android:exported="false" >
        </activity>