Android 中实现分享和第三方登陆---以新浪微博为例

第三方登陆和分享功能在目前大部分APP中都有,分享功能可以将自己觉得有意义的东西分享给身边的朋友,而第三方登陆可以借助已经有巨大用户基础的平台(如QQ和新浪微博)的账号,让用户在使用自己APP的时候不用注册,直接使用第三方账号登陆,从而避免了注册的过程(其实是服务器端帮你注册),这对于吸引更多的用户非常有意义。下面我们就以新浪微博为例,讲解如何实现分享功能和第三方登陆。首先你需要到新浪微博开放平台创建一个应用:

新浪微博开放平台:http://open.weibo.com/

首先我们来介绍分享功能,分享功能就是将一些信息分享到一些社交app中,如比较热门的就是新浪微博,腾讯微博,人人网,开心网,微信,朋友圈,易信等等,在Android中 实现分享功能通常有四种方式:

方式一:使用Android自带的分享功能,通过Intent找出手机中所有的社交app
这种方式的优点就是实现比较简单,不需要引入第三方sdk,缺点就是需要安装社交app之后才能分享,其实我觉得这个也是合理的,试想如果一个人的手机中没有安装新浪微博,那么意味着他肯定不玩微博,所以不能分享也无所谓
//分享文本
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, 我用手机测试分享内容);
sendIntent.setType(text/plain);
startActivity(Intent.createChooser(sendIntent, 我是弹出框的标题));


弹出界面如下:

/

不同人手机这个节目肯定是不一样的,因为有些人喜欢玩微博,只装了微博,没有微信。如果一个人不玩社交app,那么这个Dialog里面至少有一个是短信和蓝牙之类的,因为这些每个手机都有。

例子:

安卓系统本身可以很简便的实现分享功能,因为我们只需向startActivity传递一个ACTION_SEND的Intent,系统就为我们弹出一个应用程序列表,如果我们再指定intent为chooser的方式,那么这个列表就就会有个指定的标题,如下:

这就是分享界面。

其实凡是以隐式intent调用activity,如果能处理该intent的应用有多个的话,都会出现一个选择应用的对话框,这种对话框除了列出应用列表,还为你提供是永久选择,还是只是这次选择。比如我们发送了这样一个浏览网页的intent:

  1. String url = "http://www.example.com";
  2. Intent i = new Intent(Intent.ACTION_VIEW);
  3. i.setData(Uri.parse(url));
  4. startActivity(i);

那么系统会为我们列出能接收这个intent的应用(一般浏览器都会实现,相当于一种约定),界面如下:

注意上面的对话框只是单纯列出了应用,而且比分享对话框还多了两个选择方式的按钮,所以仅仅这样还不符合分享功能的需求。

分享的需求有两点:

每次都列出所有应用;

不再提示只是一次选择还是永久选择;

为此,我们需要通过Intent来创建chooser:

  1. Intent chooserIntent = Intent.createChooser(intent, "Select app to share");

intent的createChooser方法调用后,上面提到的两个不符合需求的问题就不存在了,其实这就是分享功能的本质,他只不过是利用了Intent的机制而已。

利用系统的api实现分享的代码如下:

  1. Intent intent = new Intent(Intent.ACTION_SEND);
  2. intent.setType("text/plain");
  3. intent.putExtra(Intent.EXTRA_TITLE, title);
  4. intent.putExtra(Intent.EXTRA_SUBJECT, subject);
  5. intent.putExtra(Intent.EXTRA_TEXT, content);
  6. Intent chooserIntent = Intent.createChooser(intent, "Select app to share");
  7. if (chooserIntent == null) {
  8. return;
  9. }
  10. try {
  11. startActivity(chooserIntent);
  12. } catch (android.content.ActivityNotFoundException ex) {
  13. Toast.makeText(this, "Can't find share component to share", Toast.LENGTH_SHORT).show();
  14. }

 

一般,通过上面的代码,提供的分享方式有各种应用:邮件,信息,蓝牙,微博,Twitter,二维码扫描器等。

  1. 但是,第一:我想过滤掉蓝牙,

  2. 其次:我想对邮件分享详细的内容,对信息和微博等分享较简短的内容,对二维码扫描器只分享URL。


解决的办法是得到所有能处理ACTION_SEND的应用程序包名,然后根据名字来过滤或者特殊处理。主要用到getPackageManager().queryIntentActivities方法。

  1. String contentDetails = "";
  2. String contentBrief = "";
  3. String shareUrl = "";
  4. Intent it = new Intent(Intent.ACTION_SEND);
  5. it.setType("text/plain");
  6. List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(it, 0);
  7. if (!resInfo.isEmpty()) {
  8. List<Intent> targetedShareIntents = new ArrayList<Intent>();
  9. for (ResolveInfo info : resInfo) {
  10. Intent targeted = new Intent(Intent.ACTION_SEND);
  11. targeted.setType("text/plain");
  12. ActivityInfo activityInfo = info.activityInfo;
  13. // judgments : activityInfo.packageName, activityInfo.name, etc.
  14. if (activityInfo.packageName.contains("bluetooth") || activityInfo.name.contains("bluetooth")) {
  15. continue;
  16. }
  17. if (activityInfo.packageName.contains("gm") || activityInfo.name.contains("mail")) {
  18. targeted.putExtra(Intent.EXTRA_TEXT, contentDetails);
  19. } else if (activityInfo.packageName.contains("zxing")) {
  20. targeted.putExtra(Intent.EXTRA_TEXT, shareUrl);
  21. } else {
  22. targeted.putExtra(Intent.EXTRA_TEXT, contentBrief);
  23. }
  24. targeted.setPackage(activityInfo.packageName);
  25. targetedShareIntents.add(targeted);
  26. }
  27. Intent chooserIntent = Intent.createChooser(targetedShareIntents.remove(0), "Select app to share");
  28. if (chooserIntent == null) {
  29. return;
  30. }
  31. // A Parcelable[] of Intent or LabeledIntent objects as set with
  32. // putExtra(String, Parcelable[]) of additional activities to place
  33. // a the front of the list of choices, when shown to the user with a
  34. // ACTION_CHOOSER.
  35. chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedShareIntents.toArray(new Parcelable[] {}));
  36. try {
  37. startActivity(chooserIntent);
  38. } catch (android.content.ActivityNotFoundException ex) {
  39. Toast.makeText(this, "Can't find share component to share", Toast.LENGTH_SHORT).show();
  40. }
  41. }

如果我们想指定一个应用来分享,那么可以将上面的代码做些修改:

  1. private void initShareIntent(String type) {
  2. boolean found = false;
  3. Intent share = new Intent(android.content.Intent.ACTION_SEND);
  4. share.setType("image/jpeg");
  5. // gets the list of intents that can be loaded.
  6. List<ResolveInfo> resInfo = getPackageManager().queryIntentActivities(share, 0);
  7. if (!resInfo.isEmpty()){
  8. for (ResolveInfo info : resInfo) {
  9. if (info.activityInfo.packageName.toLowerCase().contains(type) ||
  10. info.activityInfo.name.toLowerCase().contains(type) ) {
  11. share.putExtra(Intent.EXTRA_SUBJECT, "subject");
  12. share.putExtra(Intent.EXTRA_TEXT, "your text");
  13. share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(myPath)) ); // Optional, just if you wanna share an image.
  14. share.setPackage(info.activityInfo.packageName);
  15. found = true;
  16. break;
  17. }
  18. }
  19. if (!found)
  20. return;
  21. startActivity(Intent.createChooser(share, "Select"));
  22. }
  23. }

然后在需要分享的地方加上:

  1. initShareIntent("twi");

其实这种方法的前提是你必须知道某个应用的包名大致是什么样,比如qq的微信和微博的包名其实没有qq

initShareIntent("qq");是没有用的,你可以先将他们打印出来看长什么样子,然后在调用。以下是我总结的一些常用应用包名:

  1. case ID_QQWEIBO:
  2. initShareIntent("com.tencent.wblog");
  3. break;
  4. case ID_WEIXIN:
  5. initShareIntent("com.tencent.mm");
  6. break;
  7. case ID_EVERNOTE:
  8. initShareIntent("evernote");
  9. break;
  10. case ID_SINAWEIBO:
  11. initShareIntent("com.sina.weibo");
  12. break;
  13. case ID_RENREN:
  14. initShareIntent("renren");
  15. break;
  16. case ID_QQ:
  17. initShareIntent("tencent.mobileqq");
  18. break;

方式二:使用ShareSDK实现,ShareSDK是一款功能非常强大的第三方提供的专门用于分享等功能的sdk,使用也很简单,但是需要引入一些sdk,这里我就不举例了,研究一些ShareSDK提供的demo就可以实现,优点是简单,功能强大,并且不需要安装社交app
方式三:使用社交开放平台提供的sdk,有点事简单,但是需要安装社交app
方式四:使用社交平台提供的api接口,通过调用这些api接口实现分享和登陆,使用这种不需要安装社交app


本文着重介绍第四种方式,并以新浪微博为例:
1、创建微博授权所需参数的持久化类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
 * 该类定义了微博授权时所需要的参数。
 *
 * @author SINA
 * @since 2013-10-07
 */
public class AccessTokenKeeper {
    private static final String PREFERENCES_NAME = com_weibo_sdk_android;
 
    private static final String KEY_UID           = uid;
    private static final String KEY_ACCESS_TOKEN  = access_token;
    private static final String KEY_EXPIRES_IN    = expires_in;
     
    /**
     * 保存 Token 对象到 SharedPreferences。
     *
     * @param context 应用程序上下文环境
     * @param token   Token 对象
     */
    public static void writeAccessToken(Context context, Oauth2AccessToken token) {
        if (null == context || null == token) {
            return;
        }
         
        SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND);
        Editor editor = pref.edit();
        editor.putString(KEY_UID, token.getUid());
        editor.putString(KEY_ACCESS_TOKEN, token.getToken());
        editor.putLong(KEY_EXPIRES_IN, token.getExpiresTime());
        editor.commit();
    }
 
    /**
     * 从 SharedPreferences 读取 Token 信息。
     *
     * @param context 应用程序上下文环境
     *
     * @return 返回 Token 对象
     */
    public static Oauth2AccessToken readAccessToken(Context context) {
        if (null == context) {
            return null;
        }
         
        Oauth2AccessToken token = new Oauth2AccessToken();
        SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND);
        token.setUid(pref.getString(KEY_UID, ));
        token.setToken(pref.getString(KEY_ACCESS_TOKEN, ));
        token.setExpiresTime(pref.getLong(KEY_EXPIRES_IN, 0));
        return token;
    }
 
    /**
     * 清空 SharedPreferences 中 Token信息。
     *
     * @param context 应用程序上下文环境
     */
    public static void clear(Context context) {
        if (null == context) {
            return;
        }
         
        SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND);
        Editor editor = pref.edit();
        editor.clear();
        editor.commit();
    }
}


2、创建一个类,用来实分享和登陆功能,当然你需要引入新浪微博的sdk:weibosdkcore.jar,这个jar包在新浪微博开放平台下提供下载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**
 * 新浪微博API,可以根据自己的需要添加API
 *
 * @author cstdingran@gmail.com
 *
 */
public class SinaWeiboAPI {
 
    /**
     * 访问微博服务接口的地址
     */
    public static final String API_SERVER = https://api.weibo.com/2;
 
    private static final String URL_USERS = API_SERVER + /users;
 
    private static final String URL_STATUSES = API_SERVER + /statuses;
 
    private static final String URL_ACCOUNT = API_SERVER + /account;
 
    /**
     * post请求方式
     */
    public static final String HTTPMETHOD_POST = POST;
 
    /**
     * get请求方式
     */
    public static final String HTTPMETHOD_GET = GET;
 
    private Oauth2AccessToken oAuth2accessToken;
 
    private String accessToken;
 
    /**
     * 构造函数,使用各个API接口提供的服务前必须先获取Oauth2AccessToken
     *
     * @param accesssToken
     *            Oauth2AccessToken
     */
    public SinaWeiboAPI(Oauth2AccessToken oauth2AccessToken) {
        this.oAuth2accessToken = oauth2AccessToken;
        if (oAuth2accessToken != null) {
            accessToken = oAuth2accessToken.getToken();
        }
    }
 
    /**
     * 执行请求
     *
     * @param url
     * @param params
     * @param httpMethod
     * @param listener
     */
    private void request(final String url, final WeiboParameters params,
            final String httpMethod, RequestListener listener) {
        params.put(access_token, accessToken);
        AsyncWeiboRunner.requestAsync(url, params, httpMethod, listener);
         
    }
 
    /**
     * 根据用户ID获取用户信息
     *
     * @param uid
     *            需要查询的用户ID。
     * @param listener
     */
    public void show(long uid, RequestListener listener) {
        WeiboParameters params = new WeiboParameters();
        params.put(uid, uid);
        request(URL_USERS + /show.json, params, HTTPMETHOD_GET, listener);
    }
 
    /**
     * 发布一条新微博(连续两次发布的微博不可以重复)
     *
     * @param content
     *            要发布的微博文本内容,内容不超过140个汉字。
     * @param lat
     *            纬度,有效范围:-90.0到+90.0,+表示北纬,默认为0.0。
     * @param lon
     *            经度,有效范围:-180.0到+180.0,+表示东经,默认为0.0。
     * @param listener
     */
    public void update(String content, String lat, String lon,
            RequestListener listener) {
        WeiboParameters params = new WeiboParameters();
        params.put(status, content);
        if (!TextUtils.isEmpty(lon)) {
            params.put(long, lon);
        }
        if (!TextUtils.isEmpty(lat)) {
            params.put(lat, lat);
        }
        request(URL_STATUSES + /update.json, params, HTTPMETHOD_POST,
                listener);
    }
 
    /**
     * 上传图片并发布一条新微博,此方法会处理urlencode
     *
     * @param content
     *            要发布的微博文本内容,内容不超过140个汉字
     * @param file
     *            要上传的图片,仅支持JPEG、GIF、PNG格式,图片大小小于5M。
     * @param lat
     *            纬度,有效范围:-90.0到+90.0,+表示北纬,默认为0.0。
     * @param lon
     *            经度,有效范围:-180.0到+180.0,+表示东经,默认为0.0。
     * @param listener
     */
    public void upload(String content, String file, String lat, String lon,
            RequestListener listener) {
        WeiboParameters params = new WeiboParameters();
        params.put(status, content);
        params.put(pic, file);
        if (!TextUtils.isEmpty(lon)) {
            params.put(long, lon);
        }
        if (!TextUtils.isEmpty(lat)) {
            params.put(lat, lat);
        }
        request(URL_STATUSES + /upload.json, params, HTTPMETHOD_POST,
                listener);
    }
    //分享一张带网络图片的微博
    public void updateImgWithURL(String content, String url,RequestListener listener)
    {
        WeiboParameters params = new WeiboParameters();
        params.put(status, content);
        params.put(url, url);
        request(URL_STATUSES + /upload_url_text.json, params, HTTPMETHOD_POST,
            listener);
    }
 
    /**
     * 退出登录
     *
     * @param listener
     */
    public void endSession(RequestListener listener) {
        WeiboParameters params = new WeiboParameters();
        request(URL_ACCOUNT + /end_session.json, params, HTTPMETHOD_POST,
                listener);
    }
}


3、分享微博

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//从本地读取token,检查是否失效或者是否认证
    mAccessToken=AccessTokenKeeper.readAccessToken(this);
   if(mAccessToken!=null && mAccessToken.isSessionValid())
   {
     mSinaWeiboApi=new SinaWeiboAPI(mAccessToken);
     mSinaWeiboApi.update(视频 康熙来了:http://www.iqiyi.com/v_19rrmo4v0o.html, null, null, listener);
   }else
   {
     //如果失效或者没有认证,那么需要重新认证,
     mWeiboAuth.anthorize(new WeiboAuthListener()
     {
        
       @Override
       public void onWeiboException(WeiboException arg0)
       {
       }
        
       @Override
       public void onComplete(Bundle bundle)
       {
         //认证成功,保存到本地
         mAccessToken = Oauth2AccessToken.parseAccessToken(bundle);
         if(mAccessToken.isSessionValid())
         {
           AccessTokenKeeper.writeAccessToken(ShareActivity.this, mAccessToken);
           mSinaWeiboApi=new SinaWeiboAPI(mAccessToken);
           //然后分享
           mSinaWeiboApi.update(视频 康熙来了:http://www.iqiyi.com/v_19rrmo4v0o.html, null, null, listener);
         }
       }
 
       @Override
       public void onCancel()
       {
       }
    
     });
   }


那么分享到这里就完成了,至于第三方登陆,首先也是要认证,认证成功后AccessToken里面有一个Uid,我们通过这个uid拿到用户信息然后帮助用户在后台注册就实现了第三方登陆了,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
WeiboMessage weiboMessage = new WeiboMessage();
      weiboMessage.mediaObject = getVideoObj();
      SendMessageToWeiboRequest request = new SendMessageToWeiboRequest();
      // 用transaction唯一标识一个请求
      request.transaction = String.valueOf(System.currentTimeMillis());
      request.message = weiboMessage;
       
      // 3. 发送请求消息到微博,唤起微博分享界面
      mWeiboShareAPI.sendRequest(request);
    }else if(view.getId()==R.id.btn_login)
    {
      mAccessToken=AccessTokenKeeper.readAccessToken(this);
      //已经认证
      if(mAccessToken!=null &&mAccessToken.isSessionValid())
      {
        mSinaWeiboApi=new SinaWeiboAPI(mAccessToken);
        mSinaWeiboApi.show(Long.parseLong(mAccessToken.getUid()),listener);
      }else
      {
        //没有认证或者认证过期
        mWeiboAuth.anthorize(new WeiboAuthListener()
        {
           
          @Override
          public void onWeiboException(WeiboException arg0)
          {
          }
           
          @Override
          public void onComplete(Bundle bundle)
          {
            mAccessToken = Oauth2AccessToken.parseAccessToken(bundle);
            AccessTokenKeeper.writeAccessToken(ShareActivity.this, mAccessToken);
            mSinaWeiboApi=new SinaWeiboAPI(mAccessToken);
            mSinaWeiboApi.show(Long.parseLong(mAccessToken.getUid()),listener);
          }
 
          @Override
          public void onCancel()
          {
          }
       
        });
      }


思路其实和分享是一样的,就是调用的接口不一样。

好了,先写到这里,其实如果你学会了分享和登陆,那么其实你完全可以自己去写一个新浪微博,因为这个jar包里面提供了新浪微博所有操作的api,如获取某人发的所有微博,获取粉丝,自己关注的人等等,其实网上很多新浪微博开发的例子都是通过这个方法实现的

原文地址:https://www.cnblogs.com/imqsl/p/6740713.html