前言
提到分享喻旷,幾乎所有應(yīng)用都會有的功能蝙茶,雖然說不是難點(diǎn)何缓,但是還是要有稻薇。最近公司也在做分享功能乾戏,以前也做過很多次分享懦铺,基本都是集成第三方分享SDK白粉,然后按照開發(fā)文檔步驟完成割卖。隔一段時間就會忘記來龍去脈壁畸,再次做分享贼急,還要去查看官方文檔茅茂。因此,本次準(zhǔn)備花點(diǎn)時間封裝第三方分享SDK太抓,這樣做的好處是方便以后使用空闲,另一方面也可以自己學(xué)習(xí)到一些新的東西。分享有兩種方式走敌,一種是第三方分享SDK碴倾,第二種是隱士跳轉(zhuǎn)方式,用于隱士跳轉(zhuǎn)方式有某些局限掉丽,一方面是QQ空間分享不對外開放跌榔,另一方面是第三方分享SDK額分享監(jiān)聽做的比較全面,不需要再次自己去封裝捶障。因此本文主要介紹關(guān)于第三方分享SDK的封裝僧须,,后面也會把原生的封裝帶上项炼。本文同樣采用建造者模式創(chuàng)建担平,結(jié)構(gòu)簡單清晰,本文省略申請賬號過程锭部≡萋郏基本使用如下:
ShareKeeper.getInstance()
.builder(this)
.setPlatform(ShareKeeper.PLATFORM_QZONE)
.setShareType(ShareKeeper.TYPE_DEFAULT)
.setTitle(title)
.setDesc(desc)
.setImageUrl(imageUrl)
.setImagePath(localPicPath)
.setWebUrl(webUrl)
.setAVdioUrl(videoUrl)
.setAVdioPath(localVideoPath)
.setOnShareListener(this)
.share();
屬性介紹
可能看到上面的使用可能會覺得那么多屬性,肯定很復(fù)雜拌禾,其實(shí)不然取胎。上面舉例是把所有的屬性都列舉出來了,但是實(shí)際用不到那么多屬性湃窍。下面就來介紹所有的屬性闻蛀。
builder(this) :構(gòu)建建造者模式
setPlatform(): 設(shè)置分享平臺,例如:QQ坝咐、微信循榆、QQ空間等 (可以不填,默認(rèn)QQ分享)
setShareType():設(shè)置分享的類型墨坚,根據(jù)形式分為,圖文映挂、純圖片泽篮、音視頻、純文本(此分類不已第三方分享SDK分類)柑船,可以不設(shè)置帽撑,默認(rèn)為圖文類型
setTitle(title):設(shè)置標(biāo)題,可以不設(shè)置(內(nèi)部已經(jīng)做了防止空指針鞍时,但是建議設(shè)置亏拉,或者設(shè)置appname亦可)
setDesc(desc):設(shè)置簡介扣蜻,設(shè)置同上
setImageUrl(imageUrl):設(shè)置網(wǎng)絡(luò)圖片路徑
.setImagePath(localPicPath):設(shè)置本地圖片路徑
setAVdioUrl(videoUrl):設(shè)置網(wǎng)絡(luò)音視頻鏈接
setAVdioPath(localVideoPath):設(shè)置本地音視頻地址
setWebUrl(webUrl):設(shè)置分享的鏈接(除了分享圖片之外,都是必備的屬性)
setOnShareListener(this):設(shè)置分享監(jiān)聽回調(diào)(建議回調(diào))
微信分享
檢測客戶端
/**
* 手機(jī)是否安裝微信客戶端
*
* @param context
* @return
*/
public static boolean isWeixinAvilible(Context context) {
final PackageManager packageManager = context.getPackageManager();// 獲取packagemanager
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);// 獲取所有已安裝程序的包信息
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
if (pn.equals("com.tencent.mm")) {
return true;
}
}
}
return false;
}
微信屬性介紹
WXMediaMessage.IMediaObject :微信分享SDK內(nèi)部做了分享的封裝類,包括文本及塘、圖片莽使、視頻等
WXMediaMessage :攜帶IMediaObject 以及標(biāo)題、描述笙僚、縮略圖信息
msg.title :標(biāo)題
msg.description :描述
msg.thumbData :縮略數(shù)據(jù)(圖片內(nèi)容)
SendMessageToWX.Req:攜帶WXMediaMessage 和分享數(shù)據(jù)
transaction :分享攜帶數(shù)據(jù)芳肌,相當(dāng)于類型,回調(diào)到WXEntryActivity為BaseResp resp中的參數(shù)肋层,可以做過濾作用
message :攜帶WXMediaMessage
scene :場景亿笤,即分享平臺
創(chuàng)建不同的類型
由于微信分享和朋友圈分享沒有區(qū)別,所以在一起統(tǒng)一封裝如下:
/**
* 創(chuàng)建分享的IMediaObject
*
* @param builder
* @param bitmap
* @return
*/
private static WXMediaMessage.IMediaObject createIMediaObject(ShareKeeper.Builder builder, Bitmap bitmap) {
int mPlatform = builder.mPlatform;
int mShareType = builder.mShareType;
WXMediaMessage.IMediaObject mediaObject = null;
OnShareListener mOnShareListener = builder.mOnShareListener;
if (mShareType == ShareKeeper.TYPE_DEFAULT) {
WXWebpageObject webpageObject = new WXWebpageObject();
String mWebUrl = builder.mWebUrl;
if (!TextUtils.isEmpty(mWebUrl)) {
webpageObject.webpageUrl = mWebUrl;
mediaObject = webpageObject;
} else {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(mPlatform, "分享的鏈接不能為空!");
}
}
} else if (mShareType == ShareKeeper.TYPE_PICTURE) {
if (bitmap != null) {
WXImageObject imgObj = new WXImageObject(bitmap);
mediaObject = imgObj;
} else {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(mPlatform, "分享的圖片不能為空!");
}
}
} else if (mShareType == ShareKeeper.TYPE_AVDIO) {
String videoUrl = builder.mAVdioUrl;
if (!TextUtils.isEmpty(videoUrl)) {
WXVideoObject videoObject = new WXVideoObject();
videoObject.videoUrl = videoUrl;
mediaObject = videoObject;
} else {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(mPlatform, "分享的視頻鏈接不能為空!");
}
}
} else if (mShareType == ShareKeeper.TYPE_TXT) {
String desc = builder.mDesc;
if (!TextUtils.isEmpty(desc)) {
WXTextObject textObj = new WXTextObject();
textObj.text = desc;
mediaObject = textObj;
} else {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(mPlatform, "分享的文本不能為空!");
}
}
}
return mediaObject;
}
說明:WXMediaMessage.IMediaObject封裝了微信分享不同栋猖,所以在此根據(jù)分享類型創(chuàng)建不同的IMediaObject净薛,有些必不可缺的屬性都做了分享回調(diào)失敗,當(dāng)然也可以做拋異常的形式(不建議蒲拉,程序會崩潰)罕拂。
微信分享
/**
* 執(zhí)行
*
* @param bitmap
* @param iwxapi
* @param builder
*/
private static void performShare(Bitmap bitmap, IWXAPI iwxapi, ShareKeeper.Builder builder) {
OnShareListener mOnShareListener = builder.mOnShareListener;
WXMediaMessage.IMediaObject iMediaObject = createIMediaObject(builder, bitmap);
if (iMediaObject != null) {
//檢測參數(shù)可以分享
boolean checkArgs = iMediaObject.checkArgs();
if (checkArgs) {
//共同的部分
WXMediaMessage msg = new WXMediaMessage(iMediaObject);
msg.title = builder.mTitle;//標(biāo)題
msg.description = builder.mDesc;//描述
//縮略圖
if (bitmap != null) {
byte[] thumbData = BitmpUtils.compressBitmapSpecifySize(bitmap, IMAGE_MAX_SIZE);
if (thumbData.length > IMAGE_MAX_SIZE) {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, "分享的縮略圖過大");
}
return;
}
msg.thumbData = thumbData;//縮略數(shù)據(jù)(圖片內(nèi)容)
}
//共同的部分
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildDiffTransaction(builder.mShareType);
req.message = msg;
int mScene = builder.mPlatform == ShareKeeper.PLATFORM_WECHAT ? WXSceneSession : WXSceneTimeline;
req.scene = mScene;
//攜帶監(jiān)聽
Bundle bundle = new Bundle();
bundle.putSerializable("builder", builder);
req.toBundle(bundle);
iwxapi.sendReq(req);
} else {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, "分享參數(shù)異常");
}
}
}
}
說明:1、boolean checkArgs = iMediaObject.checkArgs()全陨,微信分享SDK內(nèi)部檢測參數(shù)爆班,判斷參數(shù)是否正確
2、byte[] thumbData = BitmpUtils.compressToBitmapLast(bitmap, IMAGE_MAX_SIZE)為縮略圖辱姨,除了分享圖片 必備之外柿菩,其他情況都可以沒有。
壓縮圖片
關(guān)于微信分享最容易出錯的就是分享的圖片過大雨涛,微信規(guī)定分享的縮略圖大小不能超過32768K枢舶,所以分享之前必須做壓縮處理,本文主要采用先質(zhì)量壓縮至10%替久,如果還超過規(guī)定分享縮略圖大小再采取尺寸壓縮凉泄,如果尺寸壓縮之后依舊不行,可以采用第三方壓縮工具或者替換圖片蚯根。
/**
* 圖片壓縮到指定大小
*
* @param bmp
* @param maxByteSize
* @return
*/
public static byte[] compressBitmapSpecifySize(final Bitmap bmp, final long maxByteSize) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] bytes = null;
int options = 100;
int outSize = baos.size();
if (outSize <= maxByteSize) {
bytes = baos.toByteArray();
} else {
while (outSize > maxByteSize && options > 0) {
baos.reset(); //清空baos
bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);//這里壓縮options%后众,把壓縮后的數(shù)據(jù)存放到baos中
outSize = baos.size();
options -= 10;
}
if (outSize > maxByteSize) {
bytes = compressBitmapSize(bmp, options, maxByteSize);
} else {
bytes = baos.toByteArray();
}
}
if (!bmp.isRecycled()) bmp.recycle();
return bytes;
}
/**
* 需要壓縮
*
* @param bmp
*/
private static byte[] compressBitmapSize(Bitmap bmp, int options, final long maxByteSize) {
//繼續(xù)在當(dāng)前的質(zhì)量下壓縮
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
int outSize = baos.size();
int orginOpi = options;
while (outSize > maxByteSize && options > 0) {
baos.reset(); //清空baos
Bitmap bitmap = BitmpUtils.scaleBitmap(bmp, options * 0.1f);
bitmap.compress(Bitmap.CompressFormat.JPEG, orginOpi, baos);//這里壓縮options%,把壓縮后的數(shù)據(jù)存放到baos中
options--;
}
byte[] bytes = baos.toByteArray();
return bytes;
}
微信分享結(jié)果處理
微信分享的結(jié)果處理是在WXEntryActivity的onResp(BaseResp resp)方法中處理各種分享返回結(jié)果
if (shareBuilder != null) {
OnShareListener onShareListener = shareBuilder.mOnShareListener;
if (onShareListener != null) {
int errCode = resp.errCode;
if (errCode == BaseResp.ErrCode.ERR_OK) {
onShareListener.onShareSuccess(shareBuilder.mPlatform);
} else if (errCode == BaseResp.ErrCode.ERR_SENT_FAILED) {
onShareListener.onShareFailed(shareBuilder.mPlatform, "發(fā)送失敗");
} else if (errCode == BaseResp.ErrCode.ERR_AUTH_DENIED) {
onShareListener.onShareFailed(shareBuilder.mPlatform, "認(rèn)證被否決");
} else if (errCode == BaseResp.ErrCode.ERR_UNSUPPORT) {
onShareListener.onShareFailed(shareBuilder.mPlatform, "版本不支持");
} else if (errCode == BaseResp.ErrCode.ERR_COMM) {
onShareListener.onShareFailed(shareBuilder.mPlatform, "一般錯誤");
} else if (errCode == BaseResp.ErrCode.ERR_USER_CANCEL) {
onShareListener.onCancleShare(shareBuilder.mPlatform, "取消分享");
} else {
onShareListener.onShareFailed(shareBuilder.mPlatform, "未知錯誤");
}
}
}
說明:關(guān)于微信分享結(jié)果需要注意一點(diǎn)颅拦,由于微信分享SDK升級蒂誉,分享取消和分享成功都會返回分享成功。
新版微信分享取消與成功合并
QQ分享
檢測QQ客戶端
/**
* 手機(jī)是否安裝QQ客戶端
*
* @param context
* @return
*/
public static boolean isQQClientAvailable(Context context) {
final PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
if (pn.equals("com.tencent.mobileqq")) {
return true;
}
}
}
return false;
}
QQ分享屬性介紹
qq分享屬性全部封裝在一個Bundle里面
QQShare.SHARE_TO_QQ_KEY_TYPE:分享類型
QQShare.SHARE_TO_QQ_TITLE:分享標(biāo)題(默認(rèn)不可以為空距帅,內(nèi)部做了防止空指針)
QQShare.SHARE_TO_QQ_SUMMARY:分享簡介(設(shè)置同上)
QQShare.SHARE_TO_QQ_TARGET_URL:weburl(除了分享圖片以外必須參數(shù))
QQShare.SHARE_TO_QQ_IMAGE_URL:網(wǎng)絡(luò)圖片(縮略圖右锨,但不是單純分享圖片的地址,沒有也不影響)
QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL:本地圖片路徑(單純的本地圖片碌秸,必要參數(shù)绍移,一定要本地路徑)
QQShare.SHARE_TO_QQ_EXT_INT, QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN):分享qq空間特有(權(quán)限)
注意:1悄窃、qq空間的屬性需要把QQ替換成QZONE
2、網(wǎng)絡(luò)圖片鏈接在qq分享和qq空間分享的數(shù)據(jù)裝載形式不一樣蹂窖,qq分享直接存在Bundle中轧抗,qq空間在先存放在集合中,然后添加集合方式恼策,具體看下面代碼鸦致。
QQ分享
由于QQ不能單獨(dú)分享文本,因此需要單獨(dú)處理涣楷,另外QQ空間不對外開放且QQ空間不能單獨(dú)分享圖片和視頻分唾,因此QQ空間分享只做默認(rèn)的圖文分享。因此下面僅介紹QQ分享狮斗。
文本分享
//純文本分享
Intent intent = new Intent("android.intent.action.SEND");
intent.setType(NetiveShareTask.TYPE_TXT);
intent.putExtra(Intent.EXTRA_SUBJECT,"分享");
intent.putExtra(Intent.EXTRA_TEXT,builder.mDesc+"");//不能為空
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(new ComponentName(QQ_PACKAGE_NAME,QQ_SHARE_COMPONENT_NAME));
activity.startActivityForResult(intent,TEXT_REQUEST_CODE);
圖片分享
QQ分享SDK默認(rèn)只支持本地圖片路徑分享绽乔,因此如果是網(wǎng)絡(luò)圖片,需要先下載到本地然后再去分享碳褒,本地圖片分享跟其他分享區(qū)別不大折砸,只有一點(diǎn)就是純圖片分享,圖片不能為空沙峻,但是鏈接是唯一可以為空的類型睦授,因此這里主要講解網(wǎng)絡(luò)圖片的分享。
/**
* 分享網(wǎng)絡(luò)圖片
* 需要先下載到本地
* 然后設(shè)置到本地路徑去分享
*
* @param activity
* @param builder
*/
private static void performShareNetPic(final Activity activity, final Tencent mTencent, final ShareKeeper.Builder builder) {
new Thread() {
public void run() {
OnShareListener mOnShareListener = builder.mOnShareListener;
try {
String mImageUrl = builder.mImageUrl;
//先獲取圖片然后保存到本地分享
Bitmap urlBitmap = BitmpUtils.getUrlBitmap(mImageUrl);
//檢測生成的圖片是否存在
if (urlBitmap == null && mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享圖片為空!");
return;
}
//SDK分享網(wǎng)絡(luò)圖片
final String saveBitmapToLocal = BitmpUtils.saveBitmapToLocal(activity, urlBitmap);
builder.setImagePath(saveBitmapToLocal);
//最后轉(zhuǎn)為本地分享
performShareLocalPic(activity, mTencent, builder);
} catch (IOException e) {
e.printStackTrace();
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享異常:" + e.getMessage());
}
}
}
}.start();
}
音視頻分享
QQ分享SDK是支持音視頻分享的摔寨,不過是分享的鏈接去枷,因此如果要分享本地音視頻,要特殊處理是复。因此此處單獨(dú)做QQ本地音視頻的分享講解删顶。此處采用系統(tǒng)的分享方式,通過隱士跳轉(zhuǎn)分享淑廊。
/**
* QQ分享本地視頻
*
* @param activity
* @param builder
*/
private static void performQQShareAVideoNative(Activity activity, ShareKeeper.Builder builder) {
String mAVdioPath = builder.mAVdioPath;
OnShareListener mOnShareListener = builder.mOnShareListener;
Uri uri = UriUtils.getUri(activity, mAVdioPath);
if (uri == null) {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享本地視頻地址異常!");
}
return;
}
Intent intent = new Intent("android.intent.action.SEND");
intent.setType(NetiveShareTask.TYPE_VIDEO);
intent.putExtra(Intent.EXTRA_TEXT, builder.mTitle + "");//不能為空
intent.putExtra(Intent.EXTRA_SUBJECT, builder.mDesc + "");
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(new ComponentName(QQ_PACKAGE_NAME, QQ_SHARE_COMPONENT_NAME));
activity.startActivityForResult(intent, VIDEO_REQUEST_CODE);
}
其他類型分享
/**
* 分享網(wǎng)頁 默認(rèn)類型
*
* @param activity
* @param mTencent
* @param builder
*/
private static void performQQShareWeb(Activity activity, Tencent mTencent, ShareKeeper.Builder builder) {
Bundle params = new Bundle();
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT);//默認(rèn)分享類型
params.putString(QQShare.SHARE_TO_QQ_TITLE, builder.mTitle + "");//分享標(biāo)題(默認(rèn)不可以為空逗余,防止空指針)
params.putString(QQShare.SHARE_TO_QQ_SUMMARY, builder.mDesc + "");//分享簡介(默認(rèn)可以為空防止空指針)
params.putString(QQShare.SHARE_TO_QQ_TARGET_URL, builder.mWebUrl);//weburl(除了圖片以外都需要)
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, builder.mImageUrl);//網(wǎng)絡(luò)圖片(縮略圖,沒有也不影響)
params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, builder.mImagePath);//本地圖片路徑(單純的本地圖片分享使用)
//創(chuàng)建監(jiān)聽器
mQQShareListener = new QQShareListener(builder);
mTencent.shareToQQ(activity, params, mQQShareListener);
}
說明:
1季惩、由于文本分享沒用SDK录粱,所以監(jiān)聽只以跳轉(zhuǎn)成功為分享成功,無取消分享監(jiān)聽
2蜀备、QQ空間無法進(jìn)行圖片分享(建議QQ空間只做圖文分享)
3关摇、QQ分享如果單獨(dú)分享圖片,只能分享本地圖片
4碾阁、由于SDK做了判斷,因此performShare()不再做一些基本的參數(shù)判斷
QQ分享結(jié)果處理
QQ分享一定要處理當(dāng)前activity的onActivityResult()些楣,否則無法監(jiān)聽到QQ內(nèi)部的分享回調(diào)脂凶。
/**
* 處理QQ分享
*
* @param requestCode
* @param resultCode
* @param data
*/
public void performQQShareResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
return;
}
if (mShareBuilder != null) {
OnShareListener mOnShareListener = mShareBuilder.mOnShareListener;
//需要判斷是否是QQ分享
if (requestCode == Constants.REQUEST_QQ_SHARE
|| requestCode == Constants.REQUEST_QZONE_SHARE
|| requestCode == Constants.REQUEST_OLD_SHARE) {
IUiListener mIUiListener = QQShareTask.getIUiListener();
if (mOnShareListener != null && mIUiListener != null) {
Tencent.onActivityResultData(requestCode, resultCode, data, mIUiListener);
}
} else if (requestCode == QQShareTask.TEXT_REQUEST_CODE
|| requestCode == QQShareTask.PIC_REQUEST_CODE
|| requestCode == QQShareTask.VIDEO_REQUEST_CODE) {
//說明是QQ原生方式分享
if (mOnShareListener != null) {
mOnShareListener.onShareSuccess(mShareBuilder.mPlatform, mShareBuilder.mShareType);
}
}
}
}
原生分享
利用原生的分享也是可以的宪睹,但是無法監(jiān)聽分享的結(jié)果,暫且以跳轉(zhuǎn)到目標(biāo)頁面為分享成功蚕钦,異常情況為分享失敗亭病。
原生分享文本
/**
* 分享文本
*
* @param activity
* @param builder
*/
private static void performNativeShareTxt(Activity activity, ShareKeeper.Builder builder) {
OnShareListener mOnShareListener = builder.mOnShareListener;
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType(NetiveShareTask.TYPE_TXT);
intent.putExtra(Intent.EXTRA_TEXT, builder.mDesc + "");//不能為空
Intent chooser = Intent.createChooser(intent, builder.mTitle);
if (intent.resolveActivity(activity.getPackageManager()) != null) {
activity.startActivityForResult(chooser, SHARE_REQUEST_CODE);
} else {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享所在Activity異常!");
}
}
}
原生分享圖片
原生分享還是分享本地圖片,網(wǎng)絡(luò)圖片要下載到本地再做分享嘶居。
/**
* 原生本地圖片分享
*
* @param activity
* @param builder
*/
private static void performNativeShareLocalPic(Activity activity, ShareKeeper.Builder builder) {
String mImagePath = builder.mImagePath;
OnShareListener mOnShareListener = builder.mOnShareListener;
Uri uri = UriUtils.getUri(activity, mImagePath);
if (uri == null) {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享本地視頻地址異常!");
}
return;
}
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType(NetiveShareTask.TYPE_IMAGE);
intent.putExtra(Intent.EXTRA_TEXT, builder.mTitle + "");//不能為空
intent.putExtra(Intent.EXTRA_SUBJECT, builder.mDesc + "");
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent chooser = Intent.createChooser(intent, builder.mTitle);
if (intent.resolveActivity(activity.getPackageManager()) != null) {
activity.startActivityForResult(chooser, SHARE_REQUEST_CODE);
} else {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享所在Activity異常!");
}
}
}
原生分享視頻
/**
* 原生分享本地視頻
*
* @param activity
* @param builder
*/
private static void performNativeShareVideo(Activity activity, ShareKeeper.Builder builder) {
String mAVdioPath = builder.mAVdioPath;
OnShareListener mOnShareListener = builder.mOnShareListener;
Uri uri = UriUtils.getUri(activity, mAVdioPath);
if (uri == null) {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享本地視頻地址異常!");
}
return;
}
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType(NetiveShareTask.TYPE_VIDEO);
intent.putExtra(Intent.EXTRA_TEXT, builder.mTitle + "");//不能為空
intent.putExtra(Intent.EXTRA_SUBJECT, builder.mDesc + "");
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent chooser = Intent.createChooser(intent, builder.mTitle);
if (intent.resolveActivity(activity.getPackageManager()) != null) {
activity.startActivityForResult(chooser, SHARE_REQUEST_CODE);
} else {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享所在Activity異常!");
}
}
}
微博分享
微博分享跟微信分享是非常相似的罪帖,所以很多細(xì)節(jié),具體細(xì)節(jié)可以參考代碼邮屁。
檢測微博客戶端
/**
* 判斷 用戶是否安裝微博客戶端
*/
public static boolean isWeiboClientAvailable(Context context) {
final PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
if (pn.equalsIgnoreCase("com.sina.weibo")) {
return true;
}
}
}
return false;
}
檢測參數(shù)是否異常
微博分享每個類型的都有特有的檢測參數(shù)是否正常的方法整袁,所以還是要單獨(dú)檢測的。具體如下:
/**
* 檢測參數(shù)是否可以分享
*
* @param mShareType
* @param baseMediaObject
* @return
*/
private static boolean checkShareArgs(int mShareType, BaseMediaObject baseMediaObject) {
if (mShareType == ShareKeeper.TYPE_TXT) {
TextObject textObject = (TextObject) baseMediaObject;
return textObject.checkArgs();
} else if (mShareType == ShareKeeper.TYPE_PICTURE) {
ImageObject imageObject = (ImageObject) baseMediaObject;
return imageObject.checkArgs();
} else if (mShareType == ShareKeeper.TYPE_AVDIO || mShareType == ShareKeeper.TYPE_DEFAULT) {
WebpageObject webpageObject = (WebpageObject) baseMediaObject;
return webpageObject.checkArgs();
}
return false;
}
微博分享特殊處
1佑吝、既有web分享也有客戶端分享坐昙,暫時項目中只支持客戶端分享,如想支持web分享芋忿,需要在manifest添加
<!--sina-->
<activity android:name="com.sina.weibo.sdk.component.WeiboSdkBrowser"
android:configChanges="keyboardHidden|orientation"
android:windowSoftInputMode="adjustResize"
android:exported="false" >
</activity>
2炸客、結(jié)果回調(diào)需要用到當(dāng)前分享activity的onNewIntent(Intent intent)方法
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
ShareKeeper.getInstance().performWBShareResult(intent);
}
wbShareHandler.doResultIntent即是微博分享的回調(diào),處理如下:
/**
* 處理微博的分享監(jiān)聽
*
* @param intent
*/
public void performWBShareResult(Intent intent) {
WbShareHandler wbShareHandler = WBShareTask.getWbShareHandler();
if (wbShareHandler != null) {
if (mShareBuilder != null) {
final int mPlatform = mShareBuilder.mPlatform;
final int mShareType = mShareBuilder.mShareType;
final OnShareListener mOnShareListener = mShareBuilder.mOnShareListener;
if (mOnShareListener != null) {
wbShareHandler.doResultIntent(intent, new WbShareCallback() {
@Override
public void onWbShareSuccess() {
mOnShareListener.onShareSuccess(mPlatform, mShareType);
}
@Override
public void onWbShareCancel() {
mOnShareListener.onCancleShare(mPlatform, mShareType, "取消分享!");
}
@Override
public void onWbShareFail() {
mOnShareListener.onShareFailed(mPlatform, mShareType, "分享失敗!");
}
});
}
}
}
}
3戈钢、微博SDK內(nèi)部需要加載libweibosdkcore.so的文件痹仙,原因可以參考 Android7.x找不到libsqlite.so 問題,項目中已經(jīng)添加殉了,具體請參考代碼
微博分享完整
public class WBShareTask {
private static WbShareHandler mShareHandler;
public static final int IMAGE_MAX_SIZE = 32768;//分享圖片大小限制
/**
* 子線程中執(zhí)行操作
*
* @param activity
* @param builder
*/
public static void executeShare(Activity activity, final ShareKeeper.Builder builder) {
boolean weiboClientAvailable = isWeiboClientAvailable(activity);
OnShareListener mOnShareListener = builder.mOnShareListener;
//監(jiān)測是否有客戶端
if (!weiboClientAvailable) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "監(jiān)測不到客戶端");
} else {
WbSdk.install(activity, new AuthInfo(activity, Config.WEIBO_APP_ID, Config.WEIBO_WEB_SITE, Config.SCOPE));
if (mShareHandler == null) mShareHandler = new WbShareHandler(activity);
mShareHandler.registerApp();
final Bitmap mLocalImage = BitmapFactory.decodeFile(builder.mImagePath);
final String mImageUrl = builder.mImageUrl;
//根據(jù)有沒有圖片分為三種情況
new Thread() {
public void run() {
if (mLocalImage != null) {
performShare(mLocalImage, mShareHandler, builder);
} else if (!TextUtils.isEmpty(mImageUrl)) {
Bitmap urlBitmap = BitmpUtils.getUrlBitmap(builder.mImageUrl);
performShare(urlBitmap, mShareHandler, builder);
} else {
performShare(null, mShareHandler, builder);
}
}
}.start();
}
}
/**
* 開始分享
*
* @param bitmap
* @param mShareHandler
* @param builder
*/
private static void performShare(Bitmap bitmap, WbShareHandler mShareHandler, ShareKeeper.Builder builder) {
OnShareListener mOnShareListener = builder.mOnShareListener;
BaseMediaObject iMediaObject = createIMediaObject(builder, bitmap);
if (iMediaObject != null) {
//檢測參數(shù)可以分享
boolean checkArgs = checkShareArgs(builder.mShareType, iMediaObject);
if (checkArgs) {
WeiboMultiMessage message = new WeiboMultiMessage();
message.mediaObject = iMediaObject;
mShareHandler.shareMessage(message, true);
} else {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享參數(shù)異常");
}
}
}
}
/**
* 創(chuàng)建不同的 BaseMediaObject
*
* @param builder
* @param bitmap
* @return
*/
private static BaseMediaObject createIMediaObject(ShareKeeper.Builder builder, Bitmap bitmap) {
int mShareType = builder.mShareType;
OnShareListener mOnShareListener = builder.mOnShareListener;
BaseMediaObject baseMediaObject = null;
if (mShareType == ShareKeeper.TYPE_TXT) {
TextObject textObject = new TextObject();
textObject.text = builder.mDesc;
textObject.title = builder.mTitle;
baseMediaObject = textObject;
} else if (mShareType == ShareKeeper.TYPE_PICTURE) {
ImageObject imageObject = new ImageObject();
//縮略圖
if (bitmap != null) {
byte[] thumbData = BitmpUtils.compressBitmapSpecifySize(bitmap, IMAGE_MAX_SIZE);
if (thumbData.length > IMAGE_MAX_SIZE) {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享的縮略圖過大");
}
} else {
Bitmap byteToBitmap = BitmpUtils.byteToBitmap(thumbData);
if (byteToBitmap != null) {
imageObject.setImageObject(bitmap);
} else {
if (mOnShareListener != null) {
mOnShareListener.onShareFailed(builder.mPlatform, builder.mShareType, "分享的縮略圖異常");
}
}
}
}
baseMediaObject = imageObject;
} else if (mShareType == ShareKeeper.TYPE_AVDIO || mShareType == ShareKeeper.TYPE_DEFAULT) {
WebpageObject webpageObject = new WebpageObject();
webpageObject.actionUrl = builder.mWebUrl;
webpageObject.title = builder.mTitle;
webpageObject.description = builder.mDesc;
baseMediaObject = webpageObject;
}
return baseMediaObject;
}
/**
* 檢測參數(shù)是否可以分享
*
* @param mShareType
* @param baseMediaObject
* @return
*/
private static boolean checkShareArgs(int mShareType, BaseMediaObject baseMediaObject) {
if (mShareType == ShareKeeper.TYPE_TXT) {
TextObject textObject = (TextObject) baseMediaObject;
return textObject.checkArgs();
} else if (mShareType == ShareKeeper.TYPE_PICTURE) {
ImageObject imageObject = (ImageObject) baseMediaObject;
return imageObject.checkArgs();
} else if (mShareType == ShareKeeper.TYPE_AVDIO || mShareType == ShareKeeper.TYPE_DEFAULT) {
WebpageObject webpageObject = (WebpageObject) baseMediaObject;
return webpageObject.checkArgs();
}
return false;
}
/**
* 判斷 用戶是否安裝微博客戶端
*/
public static boolean isWeiboClientAvailable(Context context) {
final PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
if (pn.equalsIgnoreCase("com.sina.weibo")) {
return true;
}
}
}
return false;
}
/**
* 獲取分享的handler
*
* @return
*/
public static WbShareHandler getWbShareHandler() {
return mShareHandler;
}
/**
* 銷毀
*/
public static void onDestory() {
if (mShareHandler != null) {
mShareHandler = null;
}
}
}
分享總結(jié)
本文既有原生分享又有第三方分享SDK分享开仰,后續(xù)會把微博分享補(bǔ)上。由于時間匆忙宣渗,也未做過多的測試抖所,如果使用過程中遇到什么問題,請在評論區(qū)留言痕囱。代碼已經(jīng)上傳至GitHub田轧,需要主要替換自己的APPID。
分享的輕量級封裝傳送門