天天看點

Android開發筆記(一百零五)社會化分享SDK社會化分享系統自帶的分享友盟社會化分享騰訊平台分享(QQ、微信)

社會化分享

社會化分享,指的是使用者通過網際網路這個媒介,把文本/圖檔/多媒體資訊分享到該使用者的交際圈,進而加快資訊傳播的行為。對于app來說,網絡社群雖多,但使用者量足夠大的就那幾個,是以app的社會化分享功能抓住幾個大的圈子就夠了,比如說QQ、微信、QQ空間、微信朋友圈、新浪微網誌、騰訊微網誌等等。下面是截止到2016年6月6日,根據應用寶官網的統計,主要社交app的下載下傳次數:

QQ : 42億次下載下傳

微信 : 24億次下載下傳

QQ空間 : 12億次下載下傳

新浪微網誌 : 5.8億次下載下傳

騰訊微網誌 : 1.4億次下載下傳

除了社交app的分享,還有傳統的資訊傳播途徑,例如發短信、發郵件等等。另外,出于安全考慮或流量消耗,有的使用者不希望直接分享多媒體資訊,是以應當允許使用者複制文本或連結,由使用者自行決定分享形式。

系統自帶的分享

APP分享

社會化分享的sdk也不少,隻是都比較臃腫,其實我們可以使用android自帶的發送功能"android.intent.action.SEND",隻要使用者手機上安裝了對應的app,即可簡單并快速地完成分享動作。下面是幾個常用分享對象的調用資訊:

微信 : 包名為com.tencent.mm,分享頁面為com.tencent.mm.ui.tools.ShareImgUI

微信朋友圈 : 包名為com.tencent.mm,分享頁面為com.tencent.mm.ui.tools.ShareToTimeLineUI

QQ : 包名為com.tencent.mobileqq,分享頁面為com.tencent.mobileqq.activity.JumpActivity

QQ空間 : 包名為com.qzone,分享頁面為com.qzone.ui.operation.QZonePublishMoodActivity

新浪微網誌 : 包名為com.sina.weibo,分享頁面為com.sina.weibo.EditActivity

騰訊微網誌 : 包名為com.tencent.WBlog,分享頁面為com.tencent.WBlog.intentproxy.TencentWeiboIntent

傳統途徑分享

1、短信分享:把分享内容通過短信發送給好友,有關發送短信的說明參見《Android開發筆記(五十五)手機裝置基本操作》,下面是短信分享的例子代碼:

private void sendSMS(String message) {
		Uri smsToUri = Uri.parse("smsto:");
		Intent intent = new Intent(Intent.ACTION_SENDTO, smsToUri);
		intent.putExtra("sms_body", message);
		mContext.startActivity(intent);
		mHandler.sendEmptyMessage(0);
	}           

複制

2、郵件分享,把分享内容通過郵件發送給好友,有關發送郵件的說明參見《Android開發筆記(五十五)手機裝置基本操作》,下面是郵件分享的例子代碼:

private void sendEmail(String title, String content) {
		Intent intent = new Intent(Intent.ACTION_SEND);
		intent.putExtra(Intent.EXTRA_SUBJECT, title);
		intent.putExtra(Intent.EXTRA_TEXT, content);
		intent.setType("message/rfc822");
		mContext.startActivity(Intent.createChooser(intent, "請選擇郵件用戶端"));
		mHandler.sendEmptyMessage(0);
	}           

複制

複制到剪貼闆

剪貼闆複制使用的是剪貼闆管理類ClipboardManager,該類用到了系統服務Context.CLIPBOARD_SERVICE,把文本複制到剪貼闆有兩種方法:

方法一,隻能複制文本,編譯時提示過時@deprecated,代碼如下:

ClipboardManager cm = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
			cm.setText(mUrl);           

複制

方法二,可複制文本、圖檔、URI等等,代碼如下:

ClipboardManager cm = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
			ClipData data = ClipData.newPlainText("mUrl", mUrl);
			cm.setPrimaryClip(data);           

複制

下面是啟用系統自帶分享的效果截圖

Android開發筆記(一百零五)社會化分享SDK社會化分享系統自帶的分享友盟社會化分享騰訊平台分享(QQ、微信)

下面是啟用系統自帶分享的示例代碼

import java.io.File;
import java.util.ArrayList;

import net.sourceforge.simcpux.R;
import com.example.exmshare.util.Utils;

import android.annotation.TargetApi;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class ItemSystemAdapter extends BaseAdapter implements OnItemClickListener {

	private LayoutInflater mInflater;
	private Context mContext;
	private Handler mHandler;
	private String mUrl;
	private String mTitle;
	private String mContent;
	private String mImageUrl;
	private ArrayList<ShareChanels> mChannelList;

	private int[] mShareIcons = {R.drawable.share_weixin, R.drawable.share_pengyou, 
			R.drawable.share_qq, R.drawable.share_qzone, 
			R.drawable.share_weibo, R.drawable.share_tweibo, 
			R.drawable.share_sms, R.drawable.share_mail, R.drawable.share_copy};

	public ItemSystemAdapter(final Context context, Handler handler,
			String url, String title, String content, final String imageUrl,
			ArrayList<ShareChanels> channelList) {
		mInflater = LayoutInflater.from(context);
		mContext = context;
		mHandler = handler;
		mUrl = url;
		mTitle = title;
		mContent = content;
		if (imageUrl!=null && Patterns.WEB_URL.matcher(imageUrl).matches()) {
			new Thread(new Runnable() {
				public void run() {
					try {
						mImageUrl = Utils.getImagePath(imageUrl, Utils.getFileCache(context));
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}).start();
		} else {
			mImageUrl = imageUrl;
		}
		if(channelList == null){
			mChannelList = new ArrayList<ShareChanels>();
			mChannelList.add(new ShareChanels("微信好友", 0,
					"com.tencent.mm.ui.tools.ShareImgUI", "com.tencent.mm"));
			mChannelList.add(new ShareChanels("微信朋友圈", 1,
					"com.tencent.mm.ui.tools.ShareToTimeLineUI", "com.tencent.mm"));
			mChannelList.add(new ShareChanels("QQ好友", 2,
					"com.tencent.mobileqq.activity.JumpActivity","com.tencent.mobileqq"));
			mChannelList.add(new ShareChanels("QQ空間", 3,
					"com.qzone.ui.operation.QZonePublishMoodActivity","com.qzone"));
			mChannelList.add(new ShareChanels("新浪微網誌", 4,
					"com.sina.weibo.EditActivity", "com.sina.weibo"));
			mChannelList.add(new ShareChanels("騰訊微網誌", 5,
					"com.tencent.WBlog.intentproxy.TencentWeiboIntent","com.tencent.WBlog"));
			mChannelList.add(new ShareChanels("發送短信", 6, "", ""));
			mChannelList.add(new ShareChanels("發送郵件", 7, "", ""));
			mChannelList.add(new ShareChanels("複制連結", 8, "", ""));
		}else{
			mChannelList = channelList;
		}
	}

	@Override
	public int getCount() {
		return mChannelList.size();
	}

	@Override
	public Object getItem(int position) {
		return mChannelList.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder = null;
		if (convertView == null) {
			holder = new ViewHolder();
			convertView = mInflater.inflate(R.layout.item_share_system, null);
			holder.tv_share_name = (TextView) convertView.findViewById(R.id.tv_share_name);
			holder.iv_share_icon = (ImageView) convertView.findViewById(R.id.iv_share_icon);
			convertView.setTag(holder);
		} else {
			holder = (ViewHolder) convertView.getTag();
		}

		ShareChanels item = mChannelList.get(position);
		holder.tv_share_name.setText(item.channelName);
		holder.iv_share_icon.setImageResource(mShareIcons[item.channelType]);
		return convertView;
	}
	
	public final class ViewHolder {
		public TextView tv_share_name;
		public ImageView iv_share_icon;
	}
	
	public static class ShareChanels {
		public String channelName;
		public int channelType;
		public String activityName;
		public String packageName;

		public ShareChanels(String name, int type, String activityName, String packageName) {
			this.channelName = name;
			this.channelType = type;
			this.activityName = activityName;
			this.packageName = packageName;
		}
	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		ShareChanels item = mChannelList.get(position);
		mHandler.sendEmptyMessageDelayed(0, 1500);
		if (item.channelType <= 5) {  //朋友圈僅支援分享圖檔
			shareMsg(mContext, mTitle, mContent + mUrl, mImageUrl, item);
		} else if (item.channelType == 6) {
			sendSMS(mContent + mUrl);
		} else if (item.channelType == 7) {
			sendEmail(mTitle, mContent + mUrl);
		} else if (item.channelType == 8) {
			Toast.makeText(mContext, "成功複制連結", Toast.LENGTH_LONG).show();
			ClipboardManager cm = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
			cm.setText(mUrl);
//			ClipData data = ClipData.newPlainText("mUrl", mUrl);
//			cm.setPrimaryClip(data);
		}
	}

	private void sendSMS(String message) {
		Uri smsToUri = Uri.parse("smsto:");
		Intent intent = new Intent(Intent.ACTION_SENDTO, smsToUri);
		intent.putExtra("sms_body", message);
		mContext.startActivity(intent);
		mHandler.sendEmptyMessage(0);
	}

	private void sendEmail(String title, String content) {
		Intent intent = new Intent(Intent.ACTION_SEND);
		intent.putExtra(Intent.EXTRA_SUBJECT, title);
		intent.putExtra(Intent.EXTRA_TEXT, content);
		intent.setType("message/rfc822");
		mContext.startActivity(Intent.createChooser(intent, "請選擇郵件用戶端"));
		mHandler.sendEmptyMessage(0);
	}

	@TargetApi(Build.VERSION_CODES.GINGERBREAD)
	private void shareMsg(Context context, String msgTitle, String msgText,
			String imgPath, ShareChanels share) {
		if (!share.packageName.isEmpty() && !Utils.isAvailable(mContext, share.packageName)) {
			Toast.makeText(mContext, "請先安裝" + share.channelName.replace("好友", ""), Toast.LENGTH_SHORT).show();
			return;
		}

		Intent intent = new Intent("android.intent.action.SEND");
		if ((imgPath == null) || (imgPath.equals(""))) {
			intent.setType("text/plain");
		} else {
			File f = new File(imgPath);
			if ((f != null) && (f.exists()) && (f.isFile())) {
				intent.setType("image/png");
				intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
			}
		}

		intent.putExtra(Intent.EXTRA_SUBJECT, msgTitle);
		intent.putExtra(Intent.EXTRA_TEXT, msgText);
		intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		if(!share.packageName.isEmpty()) {
			intent.setComponent(new ComponentName(share.packageName, share.activityName));
			context.startActivity(intent);
		} else {
			context.startActivity(Intent.createChooser(intent, msgTitle));
		}
	}

}           

複制

友盟社會化分享

由于系統自帶的分享功能要求使用者手機上安裝了對應的app,是以限制了該方式的使用範圍,因為總不能讓使用者分享之前先下載下傳幾十M的app吧。基于此,社會化分享的sdk雖然臃腫,但也還是有它存在的理由。這其中,友盟sdk是比較常用的社會化分享sdk,它內建了知名的幾十種分享管道,除了之前提到的,還包括易信、人人網、來往、豆瓣。不過,因為不同app對應的開放平台有不同的接入賬号,是以多一個分享管道就多一個麻煩,是以我們平常還是主要分享到QQ、微信、微網誌等。

友盟的分享動作主要是由ShareAction這個類來完成,下面是該類的常用方法說明:

setPlatform : 設定分享管道。SHARE_MEDIA.WEIXIN表示微信好友,SHARE_MEDIA.WEIXIN_CIRCLE表示微信朋友圈,SHARE_MEDIA.QQ表示QQ好友,SHARE_MEDIA.QZONE表示QQ空間内,SHARE_MEDIA.SINA表示新浪微網誌,SHARE_MEDIA.TENCENT表示騰訊微網誌,SHARE_MEDIA.SMS表示短信,SHARE_MEDIA.EMAIL表示郵件。

setCallback : 設定分享回調監聽器。監聽器是一個UMShareListener對象,該對象提供了三個回調方法,其中onResult表示分享完成,onError表示分享失敗,onCancel表示分享取消。

withTitle : 設定分享标題。

withText : 設定分享内容。

withTargetUrl : 設定目标URL。

withMedia : 設定分享的多媒體内容。多媒體内容主要有四類:UMImage表示圖像,UMusic表示音頻,UMVideo表示視訊,UMEmoji表示表情。

share : 開始分享。

下面是啟用友盟社會化分享的效果截圖

Android開發筆記(一百零五)社會化分享SDK社會化分享系統自帶的分享友盟社會化分享騰訊平台分享(QQ、微信)

下面是啟用友盟社會化分享的示例代碼

import java.io.File;
import java.util.ArrayList;

import net.sourceforge.simcpux.R;
import com.example.exmshare.util.Utils;

import android.annotation.TargetApi;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class ItemSystemAdapter extends BaseAdapter implements OnItemClickListener {

	private LayoutInflater mInflater;
	private Context mContext;
	private Handler mHandler;
	private String mUrl;
	private String mTitle;
	private String mContent;
	private String mImageUrl;
	private ArrayList<ShareChanels> mChannelList;

	private int[] mShareIcons = {R.drawable.share_weixin, R.drawable.share_pengyou, 
			R.drawable.share_qq, R.drawable.share_qzone, 
			R.drawable.share_weibo, R.drawable.share_tweibo, 
			R.drawable.share_sms, R.drawable.share_mail, R.drawable.share_copy};

	public ItemSystemAdapter(final Context context, Handler handler,
			String url, String title, String content, final String imageUrl,
			ArrayList<ShareChanels> channelList) {
		mInflater = LayoutInflater.from(context);
		mContext = context;
		mHandler = handler;
		mUrl = url;
		mTitle = title;
		mContent = content;
		if (imageUrl!=null && Patterns.WEB_URL.matcher(imageUrl).matches()) {
			new Thread(new Runnable() {
				public void run() {
					try {
						mImageUrl = Utils.getImagePath(imageUrl, Utils.getFileCache(context));
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}).start();
		} else {
			mImageUrl = imageUrl;
		}
		if(channelList == null){
			mChannelList = new ArrayList<ShareChanels>();
			mChannelList.add(new ShareChanels("微信好友", 0,
					"com.tencent.mm.ui.tools.ShareImgUI", "com.tencent.mm"));
			mChannelList.add(new ShareChanels("微信朋友圈", 1,
					"com.tencent.mm.ui.tools.ShareToTimeLineUI", "com.tencent.mm"));
			mChannelList.add(new ShareChanels("QQ好友", 2,
					"com.tencent.mobileqq.activity.JumpActivity","com.tencent.mobileqq"));
			mChannelList.add(new ShareChanels("QQ空間", 3,
					"com.qzone.ui.operation.QZonePublishMoodActivity","com.qzone"));
			mChannelList.add(new ShareChanels("新浪微網誌", 4,
					"com.sina.weibo.EditActivity", "com.sina.weibo"));
			mChannelList.add(new ShareChanels("騰訊微網誌", 5,
					"com.tencent.WBlog.intentproxy.TencentWeiboIntent","com.tencent.WBlog"));
			mChannelList.add(new ShareChanels("發送短信", 6, "", ""));
			mChannelList.add(new ShareChanels("發送郵件", 7, "", ""));
			mChannelList.add(new ShareChanels("複制連結", 8, "", ""));
		}else{
			mChannelList = channelList;
		}
	}

	@Override
	public int getCount() {
		return mChannelList.size();
	}

	@Override
	public Object getItem(int position) {
		return mChannelList.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder = null;
		if (convertView == null) {
			holder = new ViewHolder();
			convertView = mInflater.inflate(R.layout.item_share_system, null);
			holder.tv_share_name = (TextView) convertView.findViewById(R.id.tv_share_name);
			holder.iv_share_icon = (ImageView) convertView.findViewById(R.id.iv_share_icon);
			convertView.setTag(holder);
		} else {
			holder = (ViewHolder) convertView.getTag();
		}

		ShareChanels item = mChannelList.get(position);
		holder.tv_share_name.setText(item.channelName);
		holder.iv_share_icon.setImageResource(mShareIcons[item.channelType]);
		return convertView;
	}
	
	public final class ViewHolder {
		public TextView tv_share_name;
		public ImageView iv_share_icon;
	}
	
	public static class ShareChanels {
		public String channelName;
		public int channelType;
		public String activityName;
		public String packageName;

		public ShareChanels(String name, int type, String activityName, String packageName) {
			this.channelName = name;
			this.channelType = type;
			this.activityName = activityName;
			this.packageName = packageName;
		}
	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		ShareChanels item = mChannelList.get(position);
		mHandler.sendEmptyMessageDelayed(0, 1500);
		if (item.channelType <= 5) {  //朋友圈僅支援分享圖檔
			shareMsg(mContext, mTitle, mContent + mUrl, mImageUrl, item);
		} else if (item.channelType == 6) {
			sendSMS(mContent + mUrl);
		} else if (item.channelType == 7) {
			sendEmail(mTitle, mContent + mUrl);
		} else if (item.channelType == 8) {
			Toast.makeText(mContext, "成功複制連結", Toast.LENGTH_LONG).show();
			ClipboardManager cm = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
			cm.setText(mUrl);
//			ClipData data = ClipData.newPlainText("mUrl", mUrl);
//			cm.setPrimaryClip(data);
		}
	}

	private void sendSMS(String message) {
		Uri smsToUri = Uri.parse("smsto:");
		Intent intent = new Intent(Intent.ACTION_SENDTO, smsToUri);
		intent.putExtra("sms_body", message);
		mContext.startActivity(intent);
		mHandler.sendEmptyMessage(0);
	}

	private void sendEmail(String title, String content) {
		Intent intent = new Intent(Intent.ACTION_SEND);
		intent.putExtra(Intent.EXTRA_SUBJECT, title);
		intent.putExtra(Intent.EXTRA_TEXT, content);
		intent.setType("message/rfc822");
		mContext.startActivity(Intent.createChooser(intent, "請選擇郵件用戶端"));
		mHandler.sendEmptyMessage(0);
	}

	@TargetApi(Build.VERSION_CODES.GINGERBREAD)
	private void shareMsg(Context context, String msgTitle, String msgText,
			String imgPath, ShareChanels share) {
		if (!share.packageName.isEmpty() && !Utils.isAvailable(mContext, share.packageName)) {
			Toast.makeText(mContext, "請先安裝" + share.channelName.replace("好友", ""), Toast.LENGTH_SHORT).show();
			return;
		}

		Intent intent = new Intent("android.intent.action.SEND");
		if ((imgPath == null) || (imgPath.equals(""))) {
			intent.setType("text/plain");
		} else {
			File f = new File(imgPath);
			if ((f != null) && (f.exists()) && (f.isFile())) {
				intent.setType("image/png");
				intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
			}
		}

		intent.putExtra(Intent.EXTRA_SUBJECT, msgTitle);
		intent.putExtra(Intent.EXTRA_TEXT, msgText);
		intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		if(!share.packageName.isEmpty()) {
			intent.setComponent(new ComponentName(share.packageName, share.activityName));
			context.startActivity(intent);
		} else {
			context.startActivity(Intent.createChooser(intent, msgTitle));
		}
	}

}           

複制

騰訊平台分享(QQ、微信)

QQ互聯平台

在調試社會化分享sdk的時候,因為sdk把各平台的接口調用都封裝好了,反而難以跟蹤各平台的接口結果,是以有條件的話最好直接調各開放平台。比如,部落客在使用友盟sdk分享到騰訊微網誌時,發現死活分享不了,Toast提示“QQ is not auth”,檢視日志提示“umengsocial(29555): QQ沒有授權”。這裡的帳号設定用的是PlatformConfig的setQQZone方法,如果用setTencentWeibo方法,則日志報錯“Caused by: java.lang.ClassCastException: com.umeng.socialize.PlatformConfig$QQZone cannot be cast to com.umeng.socialize.PlatformConfig$TencentWeibo”。

根據友盟提供的sdk指南,登入到管理頁面,在友盟背景應用管理->社會化分享->設定,填寫應用位址(QQ開放平台上的應用頁面URL),送出後會自動生成封裝連結。按照頁面的說明,還得把該連結填寫騰訊微網誌開放平台對應APP資訊頁的“應用位址”字段。可是在QQ互聯平台上(從騰訊微網誌開放平台改版而來),應用資訊壓根就沒有“應用位址”字段,根本無法進行設定。

折騰了許久,還是沒轍,估計友盟覺得騰訊微網誌使用者少,也就不管它的分享了。得了,還是老老實實使用QQ提供的api來開發好了,一開始用騰訊的sdk來分享給QQ好友與QQ空間都挺順利,沒想到分享到騰訊微網誌時又卡殼了,總是提示“openid is invalid”。查了老久,才發現QQ平台的文檔管理混亂,按照舊的文檔說明,是無法在新的sdk上使用微網誌分享的。QQ平台舊的文檔連結是下面這個,裡面的說明并不适用于騰訊新的sdk

http://wiki.open.qq.com/wiki/mobile/API%E8%B0%83%E7%94%A8%E8%AF%B4%E6%98%8E#1._SDK_API.E8.B0.83.E7.94.A8.E8.AF.B4.E6.98.8E

QQ平台新的文檔說明入口是http://wiki.connect.qq.com/,對應的API調試工具入口是http://connect.qq.com/sdk/webtools/index.html。開發者可在新文檔入口處下載下傳demo工程,裡面有手機QQ各種分享功能的代碼例子。

下面是QQ分享用到的Tencent類的主要方法說明:

createInstance : 根據appid建立一個Tencent執行個體。

shareToQQ : 分享給QQ好友。該方法需指定分享的參數,以及分享回調監聽器IUiListener。

shareToQzone : 分享到QQ空間。該方法需指定分享的參數。

login : QQ賬号登入。分享到騰訊微網誌時需要登入授權,該方法需指定登入回調監聽器IUiListener。

setAccessToken : 設定入密碼牌。登入成功後設定,即完成授權動作。

setOpenId : 設定開放辨別。登入成功後設定,即完成授權動作。

getQQToken : 擷取QQ登入授權的令牌。該方法用于生成Weibo執行個體時的傳參,Weibo執行個體有了這個令牌,才能調用sendText方法去分享文本消息,才能調用sendPicText方法去分享圖文消息。

下面是調用QQ分享接口的參數說明:

QQShare.SHARE_TO_QQ_KEY_TYPE : 分享的類型。圖文分享(普通分享)填Tencent.SHARE_TO_QQ_TYPE_DEFAULT

QQShare.PARAM_TARGET_URL : 分享消息被點選後的跳轉URL。

QQShare.PARAM_TITLE : 分享的标題。

QQShare.PARAM_SUMMARY : 分享的消息摘要。

QQShare.SHARE_TO_QQ_IMAGE_URL : 分享圖檔的URL或者本地路徑。 

QQShare.SHARE_TO_QQ_APP_NAME : 手機QQ頂部,“傳回”按鈕文字後加上應用名;如果為空,則“傳回”按鈕保持原樣。

QQShare.SHARE_TO_QQ_EXT_INT : 分享的額外選項,兩種類型可選(預設是不隐藏分享到QZone按鈕且不自動打開分享到QZone的對話框):

--QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN,分享時自動打開分享到QZone的對話框。

--QQShare.SHARE_TO_QQ_FLAG_QZONE_ITEM_HIDE,分享時隐藏分享到QZone按鈕

下面是分享到騰訊微網誌時的QQ登入授權截圖,有這個登入授權,才能進行後續的微網誌分享。

Android開發筆記(一百零五)社會化分享SDK社會化分享系統自帶的分享友盟社會化分享騰訊平台分享(QQ、微信)

QQ分享完畢,可能收不到回調,這是因為有的手機會自動回收資源,要避免該問題,得重寫Activity頁面的onActivityResult方法,加入Tencent類的onActivityResultData方法調用,示例代碼如下:

@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	    Log.d(TAG, "-->onActivityResult " + requestCode  + " resultCode=" + resultCode);
	    if (requestCode==Constants.REQUEST_LOGIN || requestCode==Constants.REQUEST_APPBAR) {
	    	Tencent.onActivityResultData(requestCode,resultCode,data,ItemTencentAdapter.mLoginListener);
	    } else if (requestCode==Constants.REQUEST_QQ_SHARE || requestCode==Constants.REQUEST_QZONE_SHARE) {
	    	Tencent.onActivityResultData(requestCode,resultCode,data,ItemTencentAdapter.mShareListener);
	    }
	    super.onActivityResult(requestCode, resultCode, data);
	}           

複制

微信開放平台

弄完了QQ開放平台,隻是搞定了QQ好友、QQ空間、騰訊微網誌這三個管道的分享,微信好友與微信朋友圈的分享,還得到微信開放平台從頭開始。微信開放平台也有提供demo工程,按照上面的例子一步步來,也還好辦。下面是我在開發過程中遇到的幾個問題:

1、微信開放平台上申請的應用,包名和應用簽名要正确設定,不然會導緻後面沒法正常分享;

2、如果appid用的是已用應用的appid,比如說使用demo工程的appid,那麼你的工程的包名要設定為該appid對應的包名;同時,你的工程的簽名也得使用該appid對應的簽名檔案,設定簽名檔案的方法是:依次選擇window->preference->Android->build,設定custom debugger keystore作為你的工程的簽名檔案(例如demo工程的debugger.keystore)

3、WXEntryActivity.java檔案必須放在“包名.wxapi”這個package下面,不然無法正确收到微信分享的傳回結果。AndroidManifest.xml裡面的WXEntryActivity要設定android:exported="true",否則分享完畢無法回調至該Activity。

微信平台分享主要用到IWXAPI、SendMessageToWX.Req和WXMediaMessage三個類,下面是IWXAPI的常用方法說明:

createWXAPI : 建立一個微信api的執行個體。當傳入的appid為空時,還需調用registerApp方法進行注冊;注冊完畢,再傳入appid,此時獲得的執行個體才可進行後續的分享。

registerApp : 注冊指定的appid。

sendReq : 發送分享請求。該方法的參數為SendMessageToWX.Req對象。

下面是SendMessageToWX.Req的常用屬性說明:

transaction : 本次請求的流水。用于辨別每次請求的唯一性。

scene : 本次請求的場景。SendMessageToWX.Req.WXSceneSession表示分享給微信好友,SendMessageToWX.Req.WXSceneTimeline表示分享到朋友圈。

message : 本次請求的資訊。該方法的參數為WXMediaMessage對象。

下面是WXMediaMessage的常用屬性說明:

title : 分享的标題。

description : 分享的内容。

mediaObject : 分享的媒體資訊。如果是純文字則使用WXTextObject對象,如果是純圖檔則使用WXImageObject對象,如果是圖文消息則使用WXWebpageObject對象。

thumbData : 分享的縮略圖。

下面是啟用騰訊平台分享的效果截圖

Android開發筆記(一百零五)社會化分享SDK社會化分享系統自帶的分享友盟社會化分享騰訊平台分享(QQ、微信)

下面是啟用騰訊平台分享的示例代碼

import java.util.ArrayList;

import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Patterns;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Toast;

import net.sourceforge.simcpux.R;

import com.example.exmshare.util.Utils;
import com.tencent.connect.common.Constants;
import com.tencent.connect.share.QQShare;
import com.tencent.connect.share.QzoneShare;
import com.tencent.mm.sdk.modelmsg.SendMessageToWX;
import com.tencent.mm.sdk.modelmsg.WXImageObject;
import com.tencent.mm.sdk.modelmsg.WXMediaMessage;
import com.tencent.mm.sdk.modelmsg.WXTextObject;
import com.tencent.mm.sdk.modelmsg.WXWebpageObject;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.WXAPIFactory;
import com.tencent.open.t.Weibo;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
import com.umeng.socialize.utils.Log;

public class ItemTencentAdapter extends BaseAdapter implements OnItemClickListener {
	private final static String TAG = "ItemTentcentAdapter";

	private LayoutInflater mInflater;
	private static Context mContext;
	private Handler mHandler;
	private String mUrl;
	private String mTitle;
	private static String mContent;
	private static String mImageUrl;
	private ArrayList<ShareChanels> mChannelList;

	private final String QQ_APPID = "100330589";  //這裡替換為開發者在QQ互聯平台申請的應用id
	private static Tencent mTencent;
	private static Weibo mWeibo = null;
	private final String WX_APPID = "wxd930ea5d5a258f4f";  //這裡替換為開發者在微信開放平台申請的應用id
	private IWXAPI mWeixinApi;

	private int[] mShareIcons = {R.drawable.logo_wechat, R.drawable.logo_wechatcircle, 
			R.drawable.logo_qq, R.drawable.logo_qzone, R.drawable.logo_tencentweibo};

	public ItemTencentAdapter(final Context context, Handler handler,
			String url, String title, String content, 
			final String imageUrl, ArrayList<ShareChanels> channelList) {
		mInflater = LayoutInflater.from(context);
		mContext = context;
		mHandler = handler;
		mUrl = url;
		mTitle = title;
		mContent = content;
		if (imageUrl!=null && Patterns.WEB_URL.matcher(imageUrl).matches()) {
			new Thread(new Runnable() {
				public void run() {
					try {
						mImageUrl = Utils.getImagePath(imageUrl, Utils.getFileCache(context));
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}).start();
		} else {
			mImageUrl = imageUrl;
		}
		
		if (channelList == null) {
			mChannelList = new ArrayList<ShareChanels>();
			mChannelList.add(new ShareChanels("微信好友", 0));
			mChannelList.add(new ShareChanels("微信朋友圈", 1));
			mChannelList.add(new ShareChanels("QQ好友", 2));
			mChannelList.add(new ShareChanels("QQ空間", 3));
			mChannelList.add(new ShareChanels("騰訊微網誌", 4));
		} else {
			mChannelList = channelList;
		}

		// 建立一個QQ執行個體,用于QQ分享、QQ空間分享、騰訊微網誌分享
		mTencent = Tencent.createInstance(QQ_APPID, mContext);

		// 将該app注冊到微信,用于微信分享、微信朋友圈分享
		mWeixinApi = WXAPIFactory.createWXAPI(mContext, null);
		mWeixinApi.registerApp(WX_APPID);
		mWeixinApi = WXAPIFactory.createWXAPI(mContext, WX_APPID);
	}

	@Override
	public int getCount() {
		return mChannelList.size();
	}

	@Override
	public Object getItem(int position) {
		return mChannelList.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder = null;
		if (convertView == null) {
			holder = new ViewHolder();
			convertView = mInflater.inflate(R.layout.item_share_system, null);
			holder.tv_share_name = (TextView) convertView.findViewById(R.id.tv_share_name);
			holder.iv_share_icon = (ImageView) convertView.findViewById(R.id.iv_share_icon);
			convertView.setTag(holder);
		} else {
			holder = (ViewHolder) convertView.getTag();
		}

		ShareChanels item = mChannelList.get(position);
		holder.tv_share_name.setText(item.channelName);
		holder.tv_share_name.setPadding(0, 0, 0, 0);
		holder.iv_share_icon.setImageResource(mShareIcons[item.channelType]);
		return convertView;
	}
	
	public final class ViewHolder {
		public TextView tv_share_name;
		public ImageView iv_share_icon;
	}

	public static class ShareChanels {
		public String channelName;
		public int channelType;

		public ShareChanels(String name, int type) {
			this.channelName = name;
			this.channelType = type;
		}
	}

	public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
		ShareChanels item = mChannelList.get(arg2);
		mHandler.sendEmptyMessageDelayed(0, 1500);
		if (item.channelType == 0) {
			SendMessageToWX.Req req = new SendMessageToWX.Req();
			// transaction字段用于唯一辨別一個請求
			req.transaction = "wx_share" + System.currentTimeMillis();
			req.message = getWXMessage();
			req.scene = SendMessageToWX.Req.WXSceneSession;
			mWeixinApi.sendReq(req);
		} else if (item.channelType == 1) {
			SendMessageToWX.Req req = new SendMessageToWX.Req();
			req.transaction = "wx_share" + System.currentTimeMillis();
			req.message = getWXMessage();
			req.scene = SendMessageToWX.Req.WXSceneTimeline;
			mWeixinApi.sendReq(req);
		} else if (item.channelType == 2) {
			mShareListener = new ShareQQListener(mContext, item.channelName);
		    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, mTitle);
		    params.putString(QQShare.SHARE_TO_QQ_SUMMARY,  mContent);
		    params.putString(QQShare.SHARE_TO_QQ_TARGET_URL,  mUrl);
		    params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, mImageUrl);
		    params.putString(QQShare.SHARE_TO_QQ_APP_NAME,  mContext.getPackageName());
		    mTencent.shareToQQ((Activity) mContext, params, mShareListener);
		} else if (item.channelType == 3) {
			mShareListener = new ShareQQListener(mContext, item.channelName);
			ArrayList<String> urlList = new ArrayList<String>();
			urlList.add(mImageUrl);
		    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, mTitle);
			params.putString(QzoneShare.SHARE_TO_QQ_SUMMARY, mContent);
			params.putString(QzoneShare.SHARE_TO_QQ_TARGET_URL, mUrl);
			params.putStringArrayList(QzoneShare.SHARE_TO_QQ_IMAGE_URL, urlList);
			mTencent.shareToQzone((Activity) mContext, params, mShareListener);
		} else if (item.channelType == 4) {
			// 騰訊微網誌分享需要QQ登入授權
			mTencent.login((Activity) mContext, "all", mLoginListener);
		}
	}

	private int THUMB_SIZE = 150;
	private WXMediaMessage getWXMessage() {
		WXMediaMessage msg = new WXMediaMessage();
		if (!TextUtils.isEmpty(mTitle) && TextUtils.isEmpty(mImageUrl)) {
			// 分享文本消息
			WXTextObject textObj = new WXTextObject();
			textObj.text = mContent;
			msg.mediaObject = textObj;
			msg.title = mTitle;
			msg.description = mContent;
		} else if (TextUtils.isEmpty(mTitle) && !TextUtils.isEmpty(mImageUrl)) {
			// 分享圖檔消息
//			WXImageObject imgObj = new WXImageObject();
//			imgObj.setImagePath(mImageUrl);
			Bitmap bmp = BitmapFactory.decodeFile(mImageUrl);
			WXImageObject imgObj = new WXImageObject(bmp);
			msg.mediaObject = imgObj;
			Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, THUMB_SIZE, THUMB_SIZE, true);
			msg.thumbData = Utils.bmpToByteArray(thumbBmp, true);  // 設定縮略圖
		} else if (!TextUtils.isEmpty(mTitle) && !TextUtils.isEmpty(mImageUrl)) {
			// 分享圖文消息
			WXWebpageObject webpage = new WXWebpageObject();
			webpage.webpageUrl = mUrl;
			msg.title = mTitle;
			msg.description = mContent;
			msg.mediaObject = webpage;
			Bitmap bmp = BitmapFactory.decodeFile(mImageUrl);
			Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, THUMB_SIZE, THUMB_SIZE, true);
			msg.thumbData = Utils.bmpToByteArray(thumbBmp, true);  // 設定縮略圖
		}
		return msg;
	}

    public static final int REQUEST_ADD_PIC_T = 1001;
	public static IUiListener mLoginListener = new IUiListener() {

		@Override
		public void onComplete(Object object) {
			Log.d(TAG, "登入完成:"+object.toString());
			try {
				JSONObject jsonObject = (JSONObject)object;
	            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 (!TextUtils.isEmpty(token) && !TextUtils.isEmpty(expires)
	                    && !TextUtils.isEmpty(openId)) {
	                mTencent.setAccessToken(token, expires);
	                mTencent.setOpenId(openId);
	        		mWeibo = new Weibo(mContext, mTencent.getQQToken());
	        		if (mImageUrl==null || mImageUrl.length()<=0) {
	        			mWeibo.sendText(mContent, new ShareQQListener(mContext, "微網誌文字"));
	        		} else {
	        			mWeibo.sendPicText(mContent, mImageUrl, new ShareQQListener(mContext, "微網誌圖文"));
	        		}
	            }
			} catch (Exception e) {
				Log.d(TAG, "登入異常:"+e.getMessage());
			}
		}

		@Override
		public void onError(UiError error) {
			Log.d(TAG, "登入失敗:"+error.errorMessage);
		}

		@Override
		public void onCancel() {
			Log.d(TAG, "登入取消");
		}
	};

	public static ShareQQListener mShareListener;
	private static class ShareQQListener implements IUiListener {
		private Context context;
		private String channelName;
		
		public ShareQQListener(final Context context, final String channelName) {
			this.context = context;
			this.channelName = channelName;
		}

		@Override
		public void onComplete(Object object) {
			Toast.makeText(context, channelName+"分享完成:"+object.toString(), Toast.LENGTH_LONG).show();
		}

		@Override
		public void onError(UiError error) {
			Toast.makeText(context, channelName+"分享失敗:"+error.errorMessage, Toast.LENGTH_LONG).show();
		}

		@Override
		public void onCancel() {
			Toast.makeText(context, channelName+"分享取消", Toast.LENGTH_LONG).show();
		}
	}

}           

複制

點此檢視Android開發筆記的完整目錄