Integrating QQ Connect and WeChat SDK for Social Login and Sharing on Android

QQ Connect Integration

Resolving QQ Zone Sharing Issues

When sharing to QQ Zone, a common pitfall causes the share dialog to fail silent. The mistake involves passing an image URL string directly instead of using a list. The incorrect approach uses:

params.putString(QzoneShare.SHARE_TO_QQ_IMAGE_URL, "image_link_here");

This will not trigger an error but prevents the share page from opaning. The field expects an ArrayList<String>. Fix it by constructing a list and calling the appropriate method:

ArrayList<String> imageUrls = new ArrayList<>();
imageUrls.add("https://example.com/avatar.png");
params.putStringArrayList(QzoneShare.SHARE_TO_QQ_IMAGE_URL, imageUrls);

A correct implementation example:

public static void shareToQzone(Activity context, IUiListener listener) {
    Bundle params = new Bundle();
    params.putInt(QzoneShare.SHARE_TO_QZONE_KEY_TYPE,
            QzoneShare.SHARE_TO_QZONE_TYPE_IMAGE_TEXT);
    params.putString(QzoneShare.SHARE_TO_QQ_TITLE, "Title");
    params.putString(QzoneShare.SHARE_TO_QQ_SUMMARY, "Summary");
    params.putString(QzoneShare.SHARE_TO_QQ_TARGET_URL,
            "https://www.qq.com/news/1.html");
    ArrayList<String> imageUrls = new ArrayList<>();
    imageUrls.add("https://example.com/cover.jpg");
    params.putStringArrayList(QzoneShare.SHARE_TO_QQ_IMAGE_URL, imageUrls);
    mTencent.shareToQzone(context, params, listener);
}

Distinguishing Local and Network Images

Both QQ and QZone shares support local and remote images using different keys:

  • Network image: QQShare.SHARE_TO_QQ_IMAGE_URL or QzoneShare.SHARE_TO_QQ_IMAGE_URL
  • Local image: QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL or QzoneShare.SHARE_TO_QQ_IMAGE_LOCAL_URL
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, shareCoverUrl);

Make sure to use the appropriate putStringArrayList for the space sharing as described above.

WeChat SDK Integration

Initial Setup in Application

Register the WeChat API inside your Application subclass:

public static IWXAPI api;

private void registWX() {
    api = WXAPIFactory.createWXAPI(this, WX_APP_ID, false);
    api.registerApp(WX_APP_ID);
}

Share Manager Implementation

A manager class encapsulates WeChat sharing logic for different content types, avoids reusing stale data by creating new objects each time, and handles network image fetching off the main thread.

public class WechatShareManager {
    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_SESSION =
            SendMessageToWX.Req.WXSceneSession;
    public static final int WECHAT_SHARE_TYPE_TIMELINE =
            SendMessageToWX.Req.WXSceneTimeline;

    private IWXAPI mWXApi;
    private Context mContext;

    public WechatShareManager(Context context) {
        mContext = context;
        mWXApi = MyApplication.api; // reuse the globally registered API
    }

    public void shareByWechat(ShareContent shareContent, int shareType) {
        if (!mWXApi.isWXAppInstalled()) {
            Toast.makeText(mContext, "WeChat not installed", Toast.LENGTH_SHORT).show();
            return;
        }
        switch (shareContent.getShareWay()) {
            case WECHAT_SHARE_WAY_TEXT:
                performTextShare(shareContent, shareType);
                break;
            case WECHAT_SHARE_WAY_PICTURE:
                performPictureShare(shareContent, shareType);
                break;
            case WECHAT_SHARE_WAY_WEBPAGE:
                performWebPageShare(shareContent, shareType);
                break;
            case WECHAT_SHARE_WAY_VIDEO:
                performVideoShare(shareContent, shareType);
                break;
        }
    }

    // Abstract content class
    public abstract static class ShareContent {
        public abstract int getShareWay();
        public abstract String getContent();
        public abstract String getTitle();
        public abstract String getURL();
        public abstract int getPictureResource();
        public abstract String getPictureUrl();
    }

    public static class TextContent extends ShareContent {
        private String text;
        public TextContent(String text) { this.text = text; }
        @Override
        public int getShareWay() { return WECHAT_SHARE_WAY_TEXT; }
        @Override public String getContent() { return text; }
        @Override public String getTitle() { return null; }
        @Override public String getURL() { return null; }
        @Override public int getPictureResource() { return -1; }
        @Override public String getPictureUrl() { return null; }
    }

    // Other content types (PictureContent, WebPageContent, VideoContent) follow the same pattern.

    private void performWebPageShare(ShareContent shareContent, int shareType) {
        new Thread(() -> {
            try {
                WXWebpageObject webpage = new WXWebpageObject();
                webpage.webpageUrl = shareContent.getURL();
                WXMediaMessage msg = new WXMediaMessage(webpage);
                msg.title = shareContent.getTitle();
                msg.description = shareContent.getContent();

                Bitmap bmp = BitmapFactory.decodeStream(
                        new URL(shareContent.getPictureUrl() + "?thumb=1").openStream());
                Bitmap thumb = Bitmap.createScaledBitmap(bmp, THUMB_SIZE, THUMB_SIZE, true);
                bmp.recycle();
                if (thumb != null) {
                    msg.thumbData = Util.bmpToByteArray(thumb, true);
                }

                SendMessageToWX.Req req = new SendMessageToWX.Req();
                req.transaction = buildTransaction("webpage");
                req.message = msg;
                req.scene = shareType;
                mWXApi.sendReq(req);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    private String buildTransaction(String type) {
        return type == null ? String.valueOf(System.currentTimeMillis()) :
                type + System.currentTimeMillis();
    }
}

Usage example:

WechatShareManager shareManager = new WechatShareManager(context);
WechatShareManager.WebPageContent webContent =
        new WechatShareManager.WebPageContent(
                bean.getTitle(), bean.getDesc(), bean.getUrl(), bean.getCoverUrl());
shareManager.shareByWechat(webContent, WechatShareManager.WECHAT_SHARE_TYPE_SESSION);

WeChat Login Integration

Create a dedicated WXEntryActivity that implements IWXAPIEventHandler and disstinguishes between login and share callbacks.

public class WXEntryActivity extends Activity implements IWXAPIEventHandler {
    public static final int LOGIN_TYPE = 1;
    public static final int SHARE_TYPE = 2;

    private IWXAPI api;
    private BaseResp resp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        api = MyApplication.api;
        api.handleIntent(getIntent(), this);
    }

    @Override
    public void onResp(BaseResp resp) {
        switch (resp.errCode) {
            case BaseResp.ErrCode.ERR_OK:
                if (resp.getType() == LOGIN_TYPE) {
                    String code = ((SendAuth.Resp) resp).code;
                    // Forward code to backend or exchange for tokens
                    loginCallback.onCodeReceived(code);
                } else if (resp.getType() == SHARE_TYPE) {
                    Toast.makeText(this, "Shared successfully", Toast.LENGTH_SHORT).show();
                }
                finish();
                break;
            case BaseResp.ErrCode.ERR_USER_CANCEL:
                Toast.makeText(this, "Cancelled", Toast.LENGTH_SHORT).show();
                finish();
                break;
            case BaseResp.ErrCode.ERR_AUTH_DENIED:
                Toast.makeText(this, "Auth denied", Toast.LENGTH_SHORT).show();
                finish();
                break;
            default:
                finish();
                break;
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        api.handleIntent(intent, this);
        finish();
    }

    @Override
    public void onReq(BaseReq req) { finish(); }
}

To initiate login:

if (!api.isWXAppInstalled()) {
    Toast.makeText(this, "Please install WeChat", Toast.LENGTH_SHORT).show();
    return;
}
WXEntryActivity.loginCallback = code -> loginManager.weChatLogin(code);
SendAuth.Req req = new SendAuth.Req();
req.scope = "snsapi_userinfo";
req.state = "app_state";
api.sendReq(req);

Common Issues

  • Network images causing IOExceptions on main thread: Use a background thread as shown in the manager.
  • "hit push hold" error during share: Frequently caused by expired or concurrent WeChat sessions on the device. Log out and log back in.
  • Thumbnail size limit: Always scale bitmaps appropriately (e.g., 150x150) to avoid silent failures when invoking the share dialog.

Tags: Android

Posted on Sat, 29 Aug 2026 16:25:43 +0000 by abnfire