「Android」SocialSdk-快速接入社會化登陸分享

使用 微博QQ微信釘釘 原生 SDK 接入,提供這些平臺的登陸、分享功能支持。針對業務邏輯對各個平臺的接口進行封裝,對外提供一致的表現,在減輕接入壓力的同時,又能得到原生 SDK 最大的靈活性。php

考慮到每一個平臺的 SDK 也在不斷的更新,且每一個項目的需求差別比較大,如可能只須要支持部分平臺,所以沒有對類庫進行發佈,請下載 GitHub 上的 module 自行依賴,在類庫設計的過程當中,每一個平臺都是獨立的,若是隻須要支持部分平臺,只須要刪除 platform 包下面對應的實現便可,不會對其餘平臺形成影響。java

項目地址 : GitHub - SocialSdkLibrarygit

本文地址 :快速接入微信微博QQ釘釘原生登陸分享github

🎉 2018.5.12 修復內存問題、功能擴展 穩定版本 1.1.0web

🎉 2018.2.12 支持釘釘分享json

🎉 2017.12.12 對代碼進行簡單重構並測試 穩定版本 1.0.0bash

優勢

還在優化中...微信

🔥 簡單:只須要關注幾個管理類和相關數據的構造便可實現所需功能,不須要考慮複雜的受權和分享邏輯。網絡

🔥 輕量:除了必須的第三方 sdk 以外,本項目只依賴了一個簡單的異步任務的框架 bolts (38k),後續會考慮也剔除掉,不引入無用依賴,保證與宿主項目高度統一。app

🔥 全面:內部存儲受權 token,避免屢次受權;對 qq、微信、微博 作了完善的支持;

🔥 擴展性:

  • 平臺獨立,項目以平臺進行劃分,各個平臺之間徹底獨立,若是想僅支持部分平臺,只須要刪除 platform 包下該平臺的具體實現便可。
  • 請求、JSON 解析等功能可從外部注入代理,對一些功能進行自定義的擴展。
  • 能夠繼承 AbsPlatform 接入其餘平臺分享,自定義擴展。

🔥 功能性:針對實際項目需求進行擴展,例如在分享前統一對分享數據提供一次從新構造的機會。

🔥 兼容性:

  • 爲多個平臺提供外觀一致的分享接口,若不支持,使用 web 分享兼容。
  • 支持直接使用網絡圖片分享,內置自動下載功能。
  • 使用 Intent 兼容不支持的數據模式,如支持本地視頻分享,qq 的純文字分享等等。

主要類文件

使用 SocialSdk 只須要關注如下幾個文件:

👉️ SocialSdk.java 結合 SocialConfig.java 用來進行受權信息的配置。

👉️ Target.java 類是單獨分離出來的常量類,指向了登陸和分享的具體目標。

👉️ LoginManager.java 用來實現 qq、微信、微博第三方受權登陸,內部存儲 accessToken,無需屢次受權,只要調用 LoginManager.login() 方法。

👉️️ ShareManager.java 用來實現 8 種數據類型、4 個平臺、8 個渠道的分享,只要調用 ShareManager.share() 方法。

gradle 配置

針對多方 SDK 的要求,對權限、和必要的界面、服務都已經在類庫中進行了配置,當依賴該類庫時,會自動合併,不過仍然還須要在項目的 app/build.gradle 中配置對應的 qqIdmanifestPlaceholders,代碼以下:

defaultConfig {
	manifestPlaceholders = [qq_id: "11049xxxxx"]
}
複製代碼

關於 manifestPlaceholders 的使用

當使用 manifestPlaceholders = [qq_id: "11049xxxxx"] 的方式時,以前聲明的全部 manifestPlaceholders 都會被替換掉,只保留最後的。

當使用 manifestPlaceholders.qq_id = "11049xxxxx" 的方式時,會在原來的 manifestPlaceholders 中追加新的,同時也保留之前的。

建議的方式是,在 defaultConfig 中使用直接賦值的方式,而在 buildTypes 和 Favors 中使用追加的方式,避免將以前的覆蓋掉。
複製代碼

初始化

你須要在使用 SDK 以前進行初始化操做,建議放在 Applicaton 中進行。

String qqAppId = getString(R.string.QQ_APP_ID);
String wxAppId = getString(R.string.WX_APP_ID);
String wxSecretKey = getString(R.string.WX_SECRET_KEY);
String sinaAppId = getString(R.string.SINA_APP_ID);
String ddAppId = getString(R.string.DD_APP_ID);
SocialSdkConfig config = new SocialSdkConfig(this)
        // 開啓調試
        .setDebug(true)
        // 配置釘釘
        .dd(ddAppId)
        // 配置qq
        .qq(qqAppId)
        // 配置微信
        .wechat(wxAppId, wxSecretKey)
        // 配置微博
        .sina(sinaAppId)
        // 配置Sina的RedirectUrl,有默認值,若是是官網默認的不須要設置
        .sinaRedirectUrl("http://open.manfenmm.com/bbpp/app/weibo/common.php")
        // 配置Sina受權scope,有默認值,默認值 all
        .sinaScope(SocialConstants.SCOPE)
        // 不加載釘釘和微博平臺
        .disablePlatform(Target.PLATFORM_DD)
        .disablePlatform(Target.PLATFORM_WB)
        // 當縮略圖由於各類緣由沒法獲取時,將會使用默認圖,避免分享中斷
        .defImageResId(R.mipmap.ic_launcher_new);
// 👮 添加 config 數據,必須
SocialSdk.init(config);
// 👮 添加自定義的 json 解析,必須,參考 temp 文件夾下的實現
SocialSdk.setJsonAdapter(new GsonJsonAdapter());
// 👮 請求處理類,若是使用了微博的 openApi 分享,這個是必須的,參考 temp 文件夾下的實現
SocialSdk.setRequestAdapter(new OkHttpRequestAdapter());
複製代碼

adapter

使用 adapter 這種模式主要參照了一些成熟的類庫,目的是爲了對外提供更好的擴展性,這部份內容能夠關注 SocialSdk.java.

  • IJsonAdapter,負責 Json 解析,爲了保持和宿主項目 json 解析框架的統一,是必須自定義添加的(沒有內置一個實現是由於使用自帶的 JsonObject 解析實在麻煩,又不想內置一個三方庫進來,採起的這種折衷方案),提供一個 Gson 下的實現僅供參考 - GsonJsonAdapter.java

  • IRequestAdapter,負責請求數據,目前微信的 OAuth2 受權和圖片下載的相關請求都是使用 IRequestAdapter 代理,已經使用 URLConnection 內置了一個實現,若是你有本身的需求能夠重寫這部分,能夠參考 - OkHttpRequestAdapter.java

登陸功能

登錄功能支持三個平臺,qq,微信,微博;

// 3個平臺
Target.LOGIN_QQ;
Target.LOGIN_WX;
Target.LOGIN_WB;
複製代碼

使用 OnLoginListener 監聽登陸返回結果,返回的 LoginResult 中主要包括登陸類型,基本用戶信息,令牌信息 3 部分。

public class LoginResult {
    // 登錄的類型,對應 Target.LOGIN_QQ 等。。。
    private int             type;
    // 返回的基本用戶信息
    // 針對登陸類型可強轉爲 WbUser,WxUser,QQUser 來獲取更加豐富的信息
    private BaseUser        mBaseUser;
    // 本次登錄的 token 信息,openid,unionid,token,expires_in
    private BaseAccessToken mBaseToken;
}

// 登錄結果監聽
mOnLoginListener = new OnLoginListener() {
    @Override
    public void onSuccess(LoginResult loginResult) {
        Log.e(TAG, loginResult.toString());
    }
    @Override
    public void onCancel() {
        toast("登陸取消");
    }
    @Override
    public void onException(PlatformException e) {
        toast("登陸失敗 " + e.toString());
    }
};

// 3個平臺
Target.LOGIN_QQ;
Target.LOGIN_WX;
Target.LOGIN_WB;

// 喚醒登錄
LoginManager.login(mActivity, Target.LOGIN_QQ, mOnLoginListener);
複製代碼

清除受權 token,爲了不每次登陸都要求用戶打開受權界面從新點擊受權的很差體驗,類庫裏面對 token 進行了持久化的存儲,當本地 token 沒有過時時,直接使用這個 token 去請求用戶信息,同時提供了清除本地 token 的方法。

LoginManager.java

// 清除所有平臺的 token
public static void clearAllToken(Context context) // 清除指定平臺的 token public static void clearToken(Context context, @Target.LoginTarget int loginTarget) 複製代碼

分享功能

請仔細查看平臺和數據類型中間的支持能力

  • 當 微博 使用 openApi 形式去分享時,可能有較長的延時,建議在生命週期中增長進度條顯示,避免用戶等待好久沒有響應。

擴展支持

// 發短信
ShareManager.sendSms(mActivity,"13612391817","msg body");
// 發郵件
ShareManager.sendEmail(mActivity,"1101873740@qq.com","subject","msg body");
// 打開渠道對應應用
ShareManager.openApp(mActivity,Target.PLATFORM_QQ);
複製代碼

8 種數據支持

分享支持 8 種類型的數據;若是某個平臺不兼容某種類型的分享,將會使用 web 分享的方式代替;好比微信不支持 app 分享,分享出去以後時 web 分享的模式。支持的 8 種類型分別是:

  1. 開啓渠道對用的 app。
  2. 分享文字。
  3. 分享圖片( jpg , png , gif )。
  4. 分享 app。
  5. 分享 web。
  6. 分享 music。
  7. 分享 video。
  8. 分享本地 video,使用 Intent 方式喚醒。

8 個分享渠道

// 支持的分享渠道
Target.SHARE_DD; // 釘釘好友
Target.SHARE_QQ_FRIENDS; // qq好友
Target.SHARE_QQ_ZONE; // qq空間
Target.SHARE_WX_FRIENDS; // 微信好友
Target.SHARE_WX_ZONE; // 微信朋友圈
Target.SHARE_WX_FAVORITE; // 微信收藏
Target.SHARE_WB; // 新浪微博
複製代碼

建立分享數據

分享時,咱們首先要構造分享用的數據,ShareObj 對象提供了多種靜態方法用來快速建立對應分享的類型的對象。

// 測試用的路徑
localImagePath = new File(Environment.getExternalStorageDirectory(), "1.jpg").getAbsolutePath();
localVideoPath = new File(Environment.getExternalStorageDirectory(), "video.mp4").getAbsolutePath();
localGifPath = new File(Environment.getExternalStorageDirectory(), "3.gif").getAbsolutePath();
netVideoPath = "http://7xtjec.com1.z0.glb.clouddn.com/export.mp4";
netImagePath = "http://7xtjec.com1.z0.glb.clouddn.com/token.png";
netMusicPath = "http://7xtjec.com1.z0.glb.clouddn.com/test_music.mp3";
netMusicPath = "http://mp3.haoduoge.com/sSocialSdkConfig/2017-05-19/1495207225.mp3";
targetUrl = "http://bbs.csdn.net/topics/391545021";


// 打開渠道對應app
ShareObj shareMediaObj = ShareObj.buildOpenAppObj();
// 分享文字
ShareObj textObj = ShareObj.buildTextObj("分享文字", "summary");
// 分享圖片
ShareObj imageObj = ShareObj.buildImageObj("分享圖片", "summary", localImagePath);
// 分享gif
ShareObj imageGifObj = ShareObj.buildImageObj("分享圖片", "summary", localGifPath);
// 分享app
ShareObj appObj = ShareObj.buildAppObj("分享app", "summary", localImagePath, targetUrl);
// 分享web
ShareObj webObj = ShareObj.buildWebObj("分享web", "summary", localImagePath, targetUrl);
// 分享視頻
ShareObj videoObj = ShareObj.buildVideoObj("分享視頻", "summary", localImagePath, targetUrl, localVideoPath, 10);
// 本地視頻分享、部分平臺支持
ShareObj videoLocalObj = ShareObj.buildVideoObj("分享本地視頻", "summary", localVideoPath);
// 分享音樂
ShareObj musicObj = ShareObj.buildMusicObj("分享音樂", "summary", localImagePath, targetUrl, netMusicPath, 10);
複製代碼

分享監聽

分享結果,使用 OnShareListener 進行檢測。OnShareListener 提供了豐富的方法來支持分享的各個階段,關於分享對象重構的操做,在下一部分說明。

public class SimpleShareListener implements OnShareListener{
    @Override
    public void onStart(int shareTarget, ShareObj obj) {
        // 分享開始
    }
    @Override
    public ShareObj onPrepareInBackground(int shareTarget, ShareObj obj) {
        // 重構分享對象,不須要時返回 null 便可
        return null;
    }
    @Override
    public void onSuccess() {
        // 分享成功
    }
    @Override
    public void onFailure(SocialError e) {
        // 分享失敗
    }
    @Override
    public void onCancel() {
        // 分享取消
    }
}
複製代碼

發起分享

// 喚醒分享
ShareManager.share(mActivity, Target.SHARE_QQ_FRIENDS, imageObj, mOnShareListener);
複製代碼

重寫分享對象

關於重寫分享對象,其實提供一種能在分享以前對須要分享的 ShareObj 進行統一處理的機會,相似中間插一道自定義工序,好比能夠用來解決網絡圖片沒法分享,咱們須要將它下載到本地,在進行分享,又好比圖片分享出去以前加上 app 水印等操做。

主要是重寫 OnShareListeneronPrepareInBackground 方法,這個方法會在分享以前首先執行,若是返回不是 null,將會使用新建立的 ShareObj 進行分享,另外因爲考慮到可能進行耗時操做,這個方法是在子線程執行的。

@Override
public ShareObj onPrepareInBackground(int shareTarget,ShareObj obj) {
    // 重構分享對象,不須要時返回 null 便可
    return null;
}
複製代碼

看一個實現,主要功能是在分享以前用來將網絡圖下載到本地而後更新 ShareObj 指向的圖片地址,這樣就能夠支持網絡圖片的直接分享,固然,SocialSdk 目前已經支持網絡圖片的分享,這只是一個例子。

public class MyShareListener extends SimpleShareListener {

    public static final String TAG = MyShareListener.class.getSimpleName();

    private Context       mContext;
    private LoadingDialog mLoadingDialog;

    public MyShareListener(Context context) {
        mContext = context;
        mLoadingDialog = new LoadingDialog(mContext);
    }

    @Override
    public void onStart(int shareTarget, ShareObj obj) {
        if (mLoadingDialog != null)
            mLoadingDialog.show();
    }

    @Override
    public ShareObj onPrepareInBackground(int shareTarget, ShareObj obj) throws Exception{
        // 網絡路徑,先進行文件下載進行文件下載
        ShareObjHelper.prepareThumbImagePath(obj);
        // 分享照片且不是gif時加水印
        if (obj.getShareObjType() == ShareObj.SHARE_TYPE_IMAGE
                && !FileHelper.isGifFile(obj.getThumbImagePath())) {
            File thumbImageFile = new File(obj.getThumbImagePath());
            File saveFile = new File(Constants.THUMB_IMAGE_PATH, thumbImageFile.getName());
            if (!FileUtil.fileIsExist(saveFile.getAbsolutePath())) {
                ImageUtils.drawWaterMarkSync(mContext, obj.getThumbImagePath(), saveFile.getAbsolutePath(), false, false);
            }
            obj.setThumbImagePath(saveFile.getAbsolutePath());
        }
        return obj;
    }

    @Override
    public void onSuccess() {
        ToastUtil.show("分享成功");
    }

    @Override
    public void onFailure(SocialError e) {
        switch (e.getErrorCode()) {
            case SocialError.CODE_NOT_INSTALL:
                ToastUtil.show("應用未安裝");
                break;
        }
        L.e(TAG, "分享失敗" + e.toString());
    }

    @Override
    public void onCancel() {
        ToastUtil.show("分享取消");
    }
}
複製代碼

錯誤碼

爲了更好的統一分享失敗時返回的異常,返回的全部異常都會有一個 code,能夠根據不一樣的 code 定位問題和給出更友好的提示。

CODE_COMMON_ERROR         = 101; // 通用錯誤,未歸類
CODE_NOT_INSTALL          = 102; // 沒有安裝應用
CODE_VERSION_LOW          = 103; // 版本太低,不支持
CODE_SHARE_OBJ_VALID      = 104; // 分享的對象參數有問題
CODE_SHARE_BY_INTENT_FAIL = 105; // 使用 Intent 分享失敗
CODE_STORAGE_READ_ERROR   = 106; // 沒有讀存儲的權限,獲取分享縮略圖將會失敗
CODE_STORAGE_WRITE_ERROR  = 107; // 沒有寫存儲的權限,微博分享視頻copy操做將會失敗
CODE_FILE_NOT_FOUND       = 108; // 文件不存在
CODE_SDK_ERROR            = 109; // sdk 返回錯誤
CODE_REQUEST_ERROR        = 110; // 網絡請求發生錯誤
CODE_CANNOT_OPEN_ERROR    = 111; // 沒法啓動 app
CODE_PARSE_ERROR          = 112; // 數據解析錯誤
CODE_IMAGE_COMPRESS_ERROR = 113; // 圖片壓縮失敗
複製代碼

例如你能夠這麼作:

mOnShareListener = new SimpleShareListener() {
    @Override
    public void onFailure(SocialError e) {
        showMsg("分享失敗 " + e.toString());
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (e.getErrorCode() == SocialError.CODE_STORAGE_READ_ERROR) {
                requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 100);
            } else if (e.getErrorCode() == SocialError.CODE_STORAGE_WRITE_ERROR) {
                requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
            }
        }
    }
};
複製代碼
相關文章
相關標籤/搜索