Android 微信,QQ,新浪三方登录及分享官方SDK集成

来源:互联网 发布:神武3手游狮驼数据 编辑:程序博客网 时间:2024/05/16 12:18

集成过程中踩了不少坑,我会尽量写的详细一点。

微信


关于开发平台申请appID,appSecret,下载SDK等步骤不表。

  • 环境配置
    libammsdk.jar导入lib,androidManifest中添加基本权限
    <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"/>

接收微信的回调消息如分享是否成功,登录授权等信息是否拿到,需要注册一个Activity,这个Activity必须建立在包名下的wxapi文件夹中。
比如项目包名为com.android.test,需要在包名下新建一个wxapi的文件夹,并在其中新建WXEntryActivity类,实现IWXAPIEventHandler接口。
注意类名必须为WXEntryActivity。androidManifest中:

<activity     android:name=".wxapi.WXEntryActivity"     android:exported="true"></activity>

WXEntryActivity 中:

public class WXEntryActivity extends Activity implements IWXAPIEventHandler {    private IWXAPI api;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        //初始化api并向微信注册应用。        api = WXAPIFactory.createWXAPI(this, APP_ID);        api.registerApp(APP_ID);        api.handleIntent(getIntent(), this);    }    // 微信发送请求到第三方应用时,会回调到该方法    @Override    public void onReq(BaseReq baseReq) {    }    // 第三方应用发送到微信的请求处理后的响应结果,会回调到该方法    @Override    public void onResp(BaseResp baseResp) {         switch (baseResp.errCode) {             case BaseResp.ErrCode.ERR_OK:                //如果集成了分享和登录功能,那么可以通过baseResp.getType()来判断是哪个回调信息,1为登录授权,2为分享                //如果是登录授权,那么调用了登录api以后,这里会返回获取accessToken需要的code                 SendAuth.Resp sendResp = (SendAuth.Resp) baseResp;                 String code = sendResp.code;                break;             case BaseResp.ErrCode.ERR_SENT_FAILED:                  break;             case BaseResp.ErrCode.ERR_USER_CANCEL:                 break;         }    }    @Override    protected void onNewIntent(Intent intent) {       super.onNewIntent(intent);       //如果分享的时候,该已经开启,那么微信开始这个activity时,会调用onNewIntent,所以这里要处理微信的返回结果       setIntent(intent);       api.handleIntent(intent, this);    }    public void getAccessToken(String code, String secret) {        //微信登录时,需要通过code请求url获取accesstoken。         String url = "https://api.weixin.qq.com/sns/oauth2/access_token?" +                        "appid=" + APP_ID +                        "&secret=" + secret +                        "&code=" + code +                        "&grant_type=authorization_code";         //以下是网络请求拿到accesstoken以及openid.            ...    }    public void getUserInfo(String accessToken, String openId) {        //如果获取到了AccessToken和openid,请求url获取用户信息         String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" +                        accessToken + "&openid=" + openId;          ...                  }}
  • 微信分享及登录
    我新建了WeChatManager类,在其中做了不同类型的分享及登录。
public class WeChatManager {    private Context mContext;    private IWXAPI wxapi;    private static WeChatManager mInstance;    private static final int THUMB_SIZE = 150;    public static final int WECHAT_SHARE_WAY_TEXT = 1;   //文字    public static final int WECHAT_SHARE_WAY_PICTURE = 2; //图片    public static final int WECHAT_SHARE_WAY_WEBPAGE = 3;  //链接    public static final int WECHAT_SHARE_WAY_VIDEO = 4; //视频    public static final int WECHAT_SHARE_TYPE_TALK = SendMessageToWX.Req.WXSceneSession;  //会话    public static final int WECHAT_SHARE_TYPE_FRIENDS = SendMessageToWX.Req.WXSceneTimeline; //朋友圈    private ShareContent mShareContentText, mShareContentPicture, mShareContentWebpag, mShareContentVideo;     public WeChatManager(Context context) {          this.mContext = context;          initWxApi();    }    private void initWxApi() {         wxapi = WXAPIFactory.createWXAPI(mContext, APP_ID, true);         wxapi.registerApp(APP_ID);    }     /**     * 通过微信分享     *     * @param shareContent 分享的方式(文本、图片、链接)     * @param shareType    分享的类型(朋友圈,会话)     */     public void shareByWebchat(ShareContent shareContent, int shareType) {        switch (shareContent.getShareWay()) {            case WECHAT_SHARE_WAY_TEXT:                shareText(shareContent, shareType);                break;            case WECHAT_SHARE_WAY_PICTURE:                sharePicture(shareContent, shareType);                break;            case WECHAT_SHARE_WAY_WEBPAGE:                shareWebPage(shareContent, shareType);                break;            case WECHAT_SHARE_WAY_VIDEO:                shareVideo(shareContent, shareType);                break;        }     }      private abstract class ShareContent {         protected abstract int getShareWay();         protected abstract String getContent();         protected abstract String getTitle();         protected abstract String getURL();         protected abstract byte[] getPictureResource();     }      /**      * 设置分享链接的内容      *      * @author chengcj1      */     public class ShareContentWebpage extends ShareContent {         private String title;         private String content;         private String url;         private byte[] pictureResource;         public ShareContentWebpage(String title, String content, String url, byte[] pictureResource) {             this.title = title;             this.content = content;             this.url = url;             this.pictureResource = pictureResource;         }         @Override         protected int getShareWay() {             return WECHAT_SHARE_WAY_WEBPAGE;         }         @Override         protected String getContent() {             return content;         }         @Override         protected String getTitle() {             return title;         }         @Override         protected String getURL() {             return url;         }         @Override         protected byte[] getPictureResource() {             return pictureResource;         }     }     /*      * 获取网页分享对象      */     public ShareContent getShareContentWebpag(String title, String content, String url, byte[] pictureResource) {         if (mShareContentWebpag == null) {             mShareContentWebpag = new ShareContentWebpage(title, content, url, pictureResource);         }         return (ShareContentWebpage) mShareContentWebpag;     }      /*      * 分享链接      */     private void shareWebPage(ShareContent shareContent, int shareType) {         WXWebpageObject webpage = new WXWebpageObject();         webpage.webpageUrl = shareContent.getURL();         WXMediaMessage msg = new WXMediaMessage(webpage);         msg.title = shareContent.getTitle();         msg.description = shareContent.getTitle();         if(shareContent.getPictureResource() != null) {             msg.thumbData = shareContent.getPictureResource();         }         else {             Bitmap thumb = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.ic_launcher);             Bitmap thumbBitmap = Bitmap.createScaledBitmap(thumb, THUMB_SIZE, THUMB_SIZE, true);             thumb.recycle();             msg.thumbData = bitmapToByteArray(thumbBitmap);         }         SendMessageToWX.Req req = new SendMessageToWX.Req();         req.transaction = buildTransaction("webpage");         req.message = msg;         req.scene = shareType;         wxapi.sendReq(req);     }}

这里我建议分享的图片类型,如果是工程中的图片,就用int,如果需要是网上下载下来的,或者本地图册获取到的,就用byte[],这里我在下面说明原因。
关于不同类型的分享,应该传递什么必要参数,我建议在文档中找一找。在做链接分享的时候,我要上传的图片是从服务器下载下载的,之前是将图片类型设置为bitmap传入的。
但是常会出现图片大小超过32K的情况(规定链接分享上传的图片大小不能超过32K),如果需要用bitmap传入,这里可以用采样率压缩图片。
压缩图片有质量压缩和采样率压缩,质量压缩即:

 public byte[] compressBmp(Bitmap bitmap){        ByteArrayOutputStream baos = new ByteArrayOutputStream();        int options = 100;        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);        while (baos.toByteArray().length  > 32768 && options!= 10) {            baos.reset();            options -= 10;            bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);        }        return baos.toByteArray();    }

质量压缩能改变File或者stream流的大小,方便上传服务器等操作,但是像素是没有改变的,也就是说转变成bitmap以后的大小还是和以前一样。
如有需要可以去查查更详细的质量压缩的资料。
那么bitmap改变不了大小,传给wxapi的图片还是超过限制,就需要采样率压缩,或者叫做尺寸压缩。我们将流中的图片利用BitmapFactory转成bitmap时,设置
options.inJustDecodeBounds = true,这样将只会读取图片边框,不会将数据读入内存,然后计算长宽比,设置options.inSampleSize = be
采样率压缩会使图片失真

  /**  以上是质量压缩,不会减少图片的像素,但是BitmapFactory.decode到内存中像素和大小仍然没有变  **/    ByteArrayOutputStream bos = new ByteArrayOutputStream();    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());    BitmapFactory.Options options = new BitmapFactory.Options();    options.inJustDecodeBounds = true;    Bitmap newBitmap = BitmapFactory.decodeStream(bis, null, options);    options.inJustDecodeBounds = false ;    int w = options.outWidth;    int h = options.outHeight;    //我们设置为微信的占位图的分辨率    float ww = THUMB_SIZE;    float hh = THUMB_SIZE;    int be = 1; //缩放比,1表示不缩放    if(w > h && w > ww){        be = (int)(options.outWidth*1.0f / ww) + 1;    }    else if(h > w && h > hh){        be = (int)(options.outHeight*1.0f / hh) + 1;    }    if(be <= 0)        be = 1;    options.inSampleSize = be;    bis = new ByteArrayInputStream(bos.toByteArray());    newBitmap = BitmapFactory.decodeStream(bis, null, options);

登录就相对简单了:

    public void loginWX(){        SendAuth.Req req = new SendAuth.Req();        req.scope = "snsapi_userinfo"; //授权域,snsapi_userinfo 表示获取用户个人信息        req.state = "wechat_sdk_demo_test";        wxapi.sendReq(req);    }

剩下的步骤在WXEntryActivity中实现。

QQ


如果客户端没有QQ,那么Android是不能直接进行QQ网页授权登录的!

如果客户端没有QQ,那么Android是不能直接进行QQ网页授权登录的!

如果客户端没有QQ,那么Android是不能直接进行QQ网页授权登录的!

说三遍,因为官方文档上写了可以!(坑),而且你用腾讯提供的测试appid也是能网页授权的,但是换到自己的就不行,因为腾讯就已经不提供网页授权的方式了。
当然,如有需要,可以写前端代码,用js桥获取到前端拿到的用户数据。

我从官方下载的jar包为mta-sdk-1.6.2.jaropen_sdk_r5756.jar
androidmanifest中配置基本权限,声明类:

<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!-- SDK2.1新增获取用户位置信息 --><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" /><uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /><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.GET_TASKS"/>
<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" />        <!-- 这地方的222222需要用你在开放平台申请的appid替换 -->        <data android:scheme="tencent222222" />    </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" />

在分享类里面,我们先初始化Tencent类

    private void initQQApi() {       mTencent = Tencent.createInstance(QQ_APP_ID, getApplicationContext());       mListener = new ShareQQListener();       initDialog();    }

其中mListener实现了IUiListener,主要接受QQ的回调消息,包括分享的和登录的。

/** * @desc QQ分享回调类 */class ShareQQListener implements IUiListener {    @Override    public void onComplete(Object o) {        //TODO  同样都有QQ登录和分享的回调,这个可以分开写。        //QQ登录先初始化openId 和 Token        initOpenidAndToken((JSONObject) o);        //再获取用户信息        getUserInfo();    }    @Override    public void onError(UiError uiError) {        finish();    }    @Override    public void onCancel() {        hideDialog();        finish();    }}

当然要接收到QQ的回调消息,还需要在onActivityResult添加一些代码:

 @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if (mListener == null)            mListener = new ShareQQListener();        if (requestCode == Constants.REQUEST_LOGIN ||                requestCode == Constants.REQUEST_APPBAR) {            Tencent.onActivityResultData(requestCode, resultCode, data, mListener);        }    }

分享分好友和空间,默认好友,params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN)就可以分享空间。

 public void shareToQQFriends() {        final Bundle params = new Bundle();        params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT);        params.putString(QQShare.SHARE_TO_QQ_TITLE, "要分享的标题");        params.putString(QQShare.SHARE_TO_QQ_SUMMARY, "要分享的摘要");        params.putString(QQShare.SHARE_TO_QQ_TARGET_URL, "http://www.qq.com/news/1.html");        params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, "http://imgcache.qq.com/qzone/space_item/pre/0/66768.gif");        mTencent.shareToQQ(QQShareActivity.this, params, mListener);    }

登录授权更简单:

 public void loginQQ() {        String SCOPE = "all"; //授权域        if (!mTencent.isSessionValid()) {            mTencent.login(this, SCOPE, mListener);        }    }

同样的,我们也要在回调消息里面拿到openid和accessToken,才能获取到用户信息

 private void initOpenidAndToken(JSONObject jsonObject) {    try {        String token = jsonObject.getString(Constants.PARAM_ACCESS_TOKEN);        String expires = jsonObject.getString(Constants.PARAM_EXPIRES_IN);        String openid = jsonObject.getString(Constants.PARAM_OPEN_ID);        if (token != null && expires != null && openid != null)            if (!token.isEmpty() && !expires.isEmpty() && !openid.isEmpty()) {                mTencent.setAccessToken(token, expires);                mTencent.setOpenId(openid);                userId = openid;            }    } catch (JSONException e) {        e.printStackTrace();    } }
    public void getUserInfo() {        if (mTencent != null && mTencent.isSessionValid()) {            UserInfo userInfo = new UserInfo(QQShareActivity.this, mTencent.getQQToken());            userInfo.getUserInfo(new IUiListener() {                @Override                public void onComplete(Object o) {                    Log.v(TAG, o.toString());                    //TODO                     hideDialog();                    finish();                }                @Override                public void onError(UiError uiError) {                    hideDialog();                    finish();                }                @Override                public void onCancel() {                    hideDialog();                    finish();                }            });        }    }

微博


我下载的新浪微博的SDK是weiboSDKCore_3.1.4.jar
注意微博的SDK包里面有个lib文件夹,里面所有文件夹和.so库文件都要拷到工程中去

配置androidmanifest

    <activity android:name="com.sina.weibo.sdk.component.WeiboSdkBrowser"            android:configChanges="keyboardHidden|orientation"            android:windowSoftInputMode="adjustResize"            android:exported="false" >    </activity>    <service android:name="com.sina.weibo.sdk.net.DownloadService"        android:exported="false">    </service>

添加DownloadService这个service的时候会报红,提示找不到这个类。是不影响运行的。

做分享的类中要加过滤器:

    <activity        android:name="xxx.xxx.xxx">        <intent-filter>            <action android:name="com.sina.weibo.sdk.action.ACTION_SDK_REQ_ACTIVITY" />            <category android:name="android.intent.category.DEFAULT" />        </intent-filter>    </activity>
  • 初始化微博api:
 public void initSinaApi(Bundle savedInstanceState){    mWeiboShareAPI = WeiboShareSDK.createWeiboAPI(this, WEIBO_APP_KEY);    mWeiboShareAPI.registerApp();    // 当 Activity 被重新初始化时(该 Activity 处于后台时,可能会由于内存不足被杀掉了),    // 需要调用 {@link IWeiboShareAPI#handleWeiboResponse} 来接收微博客户端返回的数据。    // 执行成功,返回 true,并调用 {@link IWeiboHandler.Response#onResponse};    // 失败返回 false,不调用上述回调    if (savedInstanceState != null) {        mWeiboShareAPI.handleWeiboResponse(getIntent(), this);    }}
  • 分享的类实现IWeiboHandler.Response接口,接收回调信息
 @Override    public void onResponse(BaseResponse baseResponse) {        if(baseResponse != null){            switch (baseResponse.errCode){                case WBConstants.ErrorCode.ERR_OK :                    finish();                    break;                case WBConstants.ErrorCode.ERR_CANCEL :                    finish();                    break;                case WBConstants.ErrorCode.ERR_FAIL :                    finish();                    break;            }        }    }
  • 同样需要在onNewIntent中添加一些代码
 @Override    protected void onNewIntent(Intent intent) {        super.onNewIntent(intent);        mWeiboShareAPI.handleWeiboResponse(intent,this);    }
  • 对于微博分享有mWeiShareAPI这种SSO授权的方式,分享的时候调用非常简单:

      WeiboMultiMessage weiboMessage = new WeiboMultiMessage();  //文字  TextObject textObject = new TextObject();  textObject.text = content;  weiboMessage.textObject = textObject;  //图片  ImageObject imageObject = new ImageObject();  imageObject.setImageObject(bm);  weiboMessage.mediaObject = imageObject;  //发送  SendMultiMessageToWeiboRequest request = new SendMultiMessageToWeiboRequest();  request.transaction = String.valueOf(System.currentTimeMillis());  request.multiMessage = weiboMessage;  mWeiboShareAPI.sendRequest(this, request);

但是如果手机上没有微博客户端,是没法进行SSO授权并分享的,所以我用all in one的模式。

    public void sendShareRequest(String content,Bitmap bm){        WeiboMultiMessage weiboMessage = new WeiboMultiMessage();        //文字        TextObject textObject = new TextObject();        textObject.text = content;        weiboMessage.textObject = textObject;        //图片        ImageObject imageObject = new ImageObject();        imageObject.setImageObject(bm);        weiboMessage.mediaObject = imageObject;        // 2. 初始化从第三方到微博的消息请求        SendMultiMessageToWeiboRequest request = new SendMultiMessageToWeiboRequest();        // 用transaction唯一标识一个请求        request.transaction = String.valueOf(System.currentTimeMillis());        request.multiMessage = weiboMessage;        AuthInfo authInfo = new AuthInfo(this, Config.WEIBO_APPKEY, Config.WEIBO_REDIRECT_URL, Config.WEIBO_SCOPE);        Oauth2AccessToken accessToken = AccessTokenKeeper.readAccessToken(getApplicationContext());        String token = "";        if (accessToken != null) {            token = accessToken.getToken();        }        mWeiboShareAPI.sendRequest(this, request, authInfo, token, new WeiboAuthListener() {            @Override            public void onWeiboException( WeiboException arg0 ) {            }            @Override            public void onComplete( Bundle bundle ) {                // TODO Auto-generated method stub                Oauth2AccessToken newToken = Oauth2AccessToken.parseAccessToken(bundle);                AccessTokenKeeper.writeAccessToken(getApplicationContext(), newToken);                Toast.makeText(getApplicationContext(), "onAuthorizeComplete token = " + newToken.getToken(), Toast.LENGTH_SHORT).show();            }            @Override            public void onCancel() {            }        });    }

剩下的可能注意的点


  • 在开发平台申请应用的时候会需要签名,都会提供一些获取应用签名的小应用,下下来用就可以了。
  • 如果项目中原来集成过三方的分享如shareSDK,开发过程中记得把重复的监听和声明都去掉,不然会都收不到回调信息。
0 0
原创粉丝点击