美文网首页Android 开发技术分享
Android 微信,QQ,新浪三方登录及分享官方SDK集成

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

作者: cherishyan | 来源:发表于2016-11-24 15:33 被阅读947次

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

    微信


    关于开发平台申请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,开发过程中记得把重复的监听和声明都去掉,不然会都收不到回调信息。

    相关文章

      网友评论

        本文标题:Android 微信,QQ,新浪三方登录及分享官方SDK集成

        本文链接:https://www.haomeiwen.com/subject/atwbpttx.html