现在有很多第三分享平台,号称一键分享到所有平台,其实对于一般的分享需求,使用隐式Intent请求也可以分享出去,但是对于需要定制分享内容和样式的(比如分享框的title ,文字样式,图标头像等等),这种需求,像umeng,sharesdk这些平台我只能呵呵了。。。。这就是为什么很多公司还是选择官方的SDK,于是去腾讯开放平台查看文档,发现太难找了,不想吐槽了。。。下面写篇博文整理一下。
首先,去QQ开放平台下载SDK : http://wiki.open.qq.com/wiki/mobile/SDK下载
首先下载sdk,我下载的版本是Android_SDK_V3.1.0,解压后目录如图所示
以下以Android studio 为开发的IDE进行范例说明:
将上面解压的jar文件夹里的两个jar文件黏贴到项目的libs文件夹下
黏贴完毕之后依次右键刚刚黏贴的jar文件--Add As Library
在应用的AndroidManifest.xml增加配置的
application 节点内添加以下代码:
注意:
你的AppId" />
将“你的AppId” 整个字段换成你的APP ID,但要保留tecent字符串(很诡异的需求,不知道QQ技术团队为什么这么设计)。
SDK_V2.0以上引入了AssistActivity,开发者需在androidManifest.xml中注册。application节点内添加 如下 代码:
通过以上步骤,工程就已经配置完成了。接下来就可以在代码里使用QQ互联的SDK进行开发了。
创建实例
创建SDK主要实现类Tencent类的示例代码如下:
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Tencent类是SDK的主要实现类,开发者可通过Tencent类访问腾讯开放的OpenAPI。
// 其中APP_ID是分配给第三方应用的appid,类型为String。
mTencent = Tencent.createInstance(APP_ID, this.getApplicationContext());
// 1.4版本:此处需新增参数,传入应用程序的全局context,可通过activity的getApplicationContext方法获取
// 初始化视图
initViews();
}
所有的SDK接口调用,都会传入一个回调,用以接收SDK返回的调用结果。回调的主要接口有两种:
(1) IUiListener:调用SDK已经封装好的接口时,例如:登录、快速支付登录、应用分享、应用邀请等接口。
IUiListener的实现示例代码如下:
private class BaseUiListener implements IUiListener {
@Override
public void onComplete(Object response) {
//V2.0版本,参数类型由JSONObject 改成了Object,具体类型参考api文档
mBaseMessageText.setText("onComplete:");
doComplete(response);
}
protected void doComplete(JSONObject values) {
}
@Override
public void onError(UiError e) {
showResult("onError:", "code:" + e.errorCode + ", msg:"
+ e.errorMessage + ", detail:" + e.errorDetail);
}
@Override
public void onCancel() {
showResult("onCancel", "");
}
}
(2) IRequestListener:使用requestAsync、request等通用方法调用sdk未封装的接口时,例如上传图片、查看相册等。
IRequestListener的实现示例代码如下:
private class BaseApiListener implements IRequestListener {
@Override
public void onComplete(final JSONObject response, Object state) {
showResult("IRequestListener.onComplete:", response.toString());
doComplete(response, state);
}
protected void doComplete(JSONObject response, Object state) {
}
@Override
public void onIOException(final IOException e, Object state) {
showResult("IRequestListener.onIOException:", e.getMessage());
}
@Override
public void onMalformedURLException(final MalformedURLException e,
Object state) {
showResult("IRequestListener.onMalformedURLException", e.toString());
}
@Override
public void onJSONException(final JSONException e, Object state) {
showResult("IRequestListener.onJSONException:", e.getMessage());
}
@Override
public void onConnectTimeoutException(ConnectTimeoutException arg0,
Object arg1) {
// TODO Auto-generated method stub
}
@Override
public void onSocketTimeoutException(SocketTimeoutException arg0,
Object arg1) {
// TODO Auto-generated method stub
}
//1.4版本中IRequestListener 新增两个异常
@Override
public void onNetworkUnavailableException(NetworkUnavailableException e, Object state){
// 当前网络不可用时触发此异常
}
@Override
public void onHttpStatusException(HttpStatusException e, Object state) {
// http请求返回码非200时触发此异常
}
public void onUnknowException(Exception e, Object state) {
// 出现未知错误时会触发此异常
}
}
应用在调用SDK提供的接口时,将实现了对应回调接口的实例传入。当SDK的接口调用完成后,具体如登录、应用邀请和应用分享调用完成后,会回调传入的接口实例。
特别注意:
在某些低端机上调用登录后,由于内存紧张导致APP被系统回收,登录成功后无法成功回传数据。解决办法如下
在调用login的Activity或者Fragment重写onActivityResult方法,示例代码如下:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == Constants.REQUEST_API) { if(resultCode == Constants.RESULT_LOGIN) { mTencent.handleLoginData(data, loginListener); } } super.onActivityResult(requestCode, resultCode, data); }
SDK_V2.0引入了AssistActivity,开发者只需在androidManifest.xml中注册即可。代码如下:
}
应用通过调用SDK的登录接口获取access_token和openid。登录接口的调用说明详见SDK包里的《Andriod_SDK_V2.0接口调用说明》中的"1.1登录"
调用SDK的登录接口,用户登录成功后,会通过回调的方式返回一个json格式的字符串,在这个json字符串中会包含三个参数,分别是openid、access_token、expires_in。
返回参数说明如下表所示:
返回参数 | 参数说明 |
---|---|
openid | 用于唯一标识用户身份(每一个openid与QQ号码对应)。 |
access_token | 用户进行应用邀请、分享、支付等基本业务请求的凭据。 |
expires_in | access_token的有效时间,在有效期内可以发起业务请求,过期失效。 |
access_token的有效期为3个月,在有效期内,使用此token进行应用分享、邀请等操作都是可以正常完成的。超过这个时间,服务器会认为token已失效,需要重新登录。
应用在每次登录之后,都会获取到openid、access_token和expires_in,在调用SDK提供的接口时,后台会根据这三个参数来验证请求的合法性。
(1)如果应用已经走过登录流程,调用应用分享、邀请等接口,是不需要再将这三个参数传入到请求参数中去的,这是因为在登录成功后,SDK会自动将这几个参数保存在SDK的上下文中,在发送请求时,会自动为请求加上这些参数。
(2)如果应用不希望每次都走登录流程来使用SDK的功能,可以通过以下步骤来实现:
Step1:在首次登录成功后,将返回的openid、access_token、expires_in三个参数保存在本地(比如保存在sharedPreferrence)。其中expires_in参数在存储前需进行如下计算:
System.currentTimeMillis() + Long.parseLong(expires_in) * 1000;
这样得出的就是token的失效日期。
Step2:在用户下次进入应用,发起应用分享等SDK调用之前,首先创建Tencent实例,然后取出之前保存的openid、access_token、expires_in(前面计算出来的值)的值。
Step3:调用Tencent类的setOpenId和setAccessToken方法。其中setOpenId的参数传入上一步取出的openid,setAccessToken的第一个参数传入上一步取出的access_token,第二个参数传入(上一步保存的token失效日期-当前系统时间)/1000。这里计算出的结果是当前保存的token的有效时间,如果结果小于或等于0,表示token已经过期,应该提示用户重新走登录流程。
免登录流程调用SDK接口的示例代码如下(省去了获取存储的变量的过程):
String openid = "1234567896ASDFGHJKLLIUYT";
String access_token = "2C0884DC4B930010D852D8D504FC9F4D";
String expires_in = "7776000"; // 实际值需要通过上面介绍的方法来计算
mTencent = Tencent.createInstance(APP_ID);
mTencent.setOpenId(openid);
mTencent.setAccessToken(access_token, expires_in);
4.5 调用OpenAPISDK中
Tencent类是对外提供功能接口的主要实现类,所有接口都通过Tencent类的实例来调用。
接口的详细调用说明,请参见SDK包中的《Andriod_SDK_V2.0接口调用说明》。
接口调用的详细示例,请参见SDK包中的sample\src\com\tencent\sample目录下的MainActivity.java文件。
4.6 混淆说明
如果应用需要混淆代码,为了保证SDK的正常使用,建议不要混淆SDK的jar包,如果仍要混淆,需要在混淆规则中加上下面几行配置:
-keep class com.tencent.open.TDialog$*
-keep class com.tencent.open.TDialog$* {*;}
-keep class com.tencent.open.PKDialog
-keep class com.tencent.open.PKDialog {*;}
-keep class com.tencent.open.PKDialog$*
-keep class com.tencent.open.PKDialog$* {*;}
4.7 签名验证说明
为了防止开发商所申请的appid被非法利用,也为了防止应用安装包被恶意修改,我们在SDK1.7中,增加了应用签名验证的功能,具体使用步骤如下:
(1)分别使用debug版keystore和release版keystore签名打包自己的应用,生成两个apk包。
(2)通过签名工具分别获取这两个apk包的签名值,(签名工具在tools目录下)。
(3)在腾讯开放平台的注册流程中,分别填入debug版的签名值和release版的签名值。
(4)一旦使用该功能,则不能再随意更换keystore文件,否则会被认为是apk包被修改了,导致登录授权验证不通过。
特别注意:
该功能不强制使用,但为了安全起见,我们建议使用。只有拥有合法签名的应用程序才能够进入登录授权界面,所以应用要确保自己在接入平台上填入的签名值与实际应用程序的签名值一致。
之前的API使用get_simple_userinfo, 修改为get_user_info。
调用获取用户信息API的示例代码如下:
UserInfo info = new UserInfo(this, MainActivity.mQQAuth.getQQToken()); info.getUserInfo(new BaseUIListener(this,"get_simple_userinfo"));
本接口用于发送一条带有图片的微博。
调用发布带图微博API参数说明如下:
参数 | 是否必传 | 类型 | 参数说明 |
---|---|---|---|
format | 可选 | String | 定义API返回的数据格式。 取值说明:为xml时表示返回的格式是xml;为json时表示返回的格式是json。 注意:json、xml为小写,否则将不识别。format不传或非xml,则返回json格式数据。 |
content | 必传 | String | 表示要发表的微博内容。必须为UTF-8编码,最长为140个汉字,也就是420字节。 如果微博内容中有URL,后台会自动将该URL转换为短URL,每个URL折算成11个字节。 若在此处@好友,需正确填写好友的微博账号,而非昵称。 |
pic | 必传 | String | 要上传的图片的文件名以及图片的内容(在发送请求时,图片内容以二进制数据流的形式发送,见下面的请求示例)。 图片仅支持gif、jpeg、jpg、png、bmp及ico格式(所有图片都会重新压缩,gif被重新压缩后不会再有动画效果),图片size小于4M。 |
调用发布带图微博API的示例代码如下:
private void onClickUserInfo() { Bundle bundle = new Bundle(); bundle.putString("format", "json"); bundle.putString("content", "test add pic with url"); // 把 bitmap 转换为 byteArray , 用于发送请求 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 40, baos); byte[] buff = baos.toByteArray(); // Log.v(TAG, "length: " + buff.length); bundle.putByteArray("pic", buff); mTencent.requestAsync(Constants.GRAPH_ADD_PIC_T, bundle, Constants.HTTP_POST, new BaseApiListener("add_pic_t", false), null); bitmap.recycle(); mProgressDialog.show(); }
分享消息到QQ的接口,可将新闻、图片、文字、应用等分享给QQ好友、群和讨论组。Tencent类的shareToQQ函数可直接调用,不用用户授权(使用手机QQ当前的登录态)。调用将打开分享的界面,用户选择好友、群或讨论组之后,点击确定即可完成分享,并进入与该好友进行对话的窗口。
本接口支持3种模式,每种模式的参数设置不同,下面分别进行介绍:
(1) 分享图文消息
调用分享接口的params参数说明如下:
参数 | 是否必传 | 类型 | 参数说明 |
---|---|---|---|
QQShare.SHARE_TO_QQ_KEY_TYPE | 必填 | Int | 分享的类型。图文分享(普通分享)填Tencent.SHARE_TO_QQ_TYPE_DEFAULT |
QQShare.PARAM_TARGET_URL | 必填 | String | 这条分享消息被好友点击后的跳转URL。 |
QQShare.PARAM_TITLE | 必填 | String | 分享的标题, 最长30个字符。 |
QQShare.PARAM_SUMMARY | 可选 | String | 分享的消息摘要,最长40个字。 |
QQShare.SHARE_TO_QQ_IMAGE_URL | 可选 | String | 分享图片的URL或者本地路径 |
QQShare.SHARE_TO_QQ_APP_NAME | 可选 | String | 手Q客户端顶部,替换“返回”按钮文字,如果为空,用返回代替 |
QQShare.SHARE_TO_QQ_EXT_INT | 可选 | Int | 分享额外选项,两种类型可选(默认是不隐藏分享到QZone按钮且不自动打开分享到QZone的对话框): QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN,分享时自动打开分享到QZone的对话框。 |
private void onClickShare() { 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"); params.putString(QQShare.SHARE_TO_QQ_APP_NAME, "测试应用222222"); params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, "其他附加功能"); mTencent.shareToQQ(MainActivity.this, params, new BaseUiListener()); }
(2) 分享纯图片
调用分享纯图片接口的params参数说明如下:
参数 | 是否必传 | 类型 | 参数说明 |
---|---|---|---|
QQShare.SHARE_TO_QQ_KEY_TYPE | 必选 | Int | 分享类型,分享纯图片时填写QQShare.SHARE_TO_QQ_TYPE_IMAGE。 |
QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL | 必选 | String | 需要分享的本地图片路径。 |
QQShare.SHARE_TO_QQ_APP_NAME | 可选 | String | 手Q客户端顶部,替换“返回”按钮文字,如果为空,用返回代替。 |
QQShare.SHARE_TO_QQ_EXT_INT | 可选 | Int | 分享额外选项,两种类型可选(默认是不隐藏分享到QZone按钮且不自动打开分享到QZone的对话框): QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN,分享时自动打开分享到QZone的对话框。 |
调用分享纯图片接口的示例代码如下:
private void onClickShare() { Bundle params = new Bundle(); params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL,imageUrl.getText().toString()); params.putString(QQShare.SHARE_TO_QQ_APP_NAME, appName.getText().toString()); params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_IMAGE); params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN); mTencent.shareToQQ(MainActivity.this, params, new BaseUiListener()); }
(3) 分享音乐
音乐分享后,发送方和接收方在聊天窗口中点击消息气泡即可开始播放音乐。
调用分享接口的params参数说明如下:
参数 | 是否必传 | 类型 | 参数说明 |
---|---|---|---|
QQShare.SHARE_TO_QQ_KEY_TYPE | 必填 | Int | 分享的类型。分享音乐填Tencent.SHARE_TO_QQ_TYPE_AUDIO。 |
QQShare.PARAM_TARGET_URL | 必选 | String | 这条分享消息被好友点击后的跳转URL。 |
QQShare.SHARE_TO_QQ_AUDIO_URL | 必填 | String | 音乐文件的远程链接, 以URL的形式传入, 不支持本地音乐。 |
QQShare.PARAM_TITLE | 必选 | String | 分享的标题, 最长30个字符。 |
QQShare.PARAM_SUMMARY | 可选 | String | 分享的消息摘要,最长40个字符。 |
QQShare.SHARE_TO_QQ_IMAGE_URL | 可选 | String | 分享图片的URL或者本地路径。 |
QQShare.SHARE_TO_QQ_APP_NAME | 可选 | String | 手Q客户端顶部,替换“返回”按钮文字,如果为空,用返回代替。 |
QQShare.SHARE_TO_QQ_EXT_INT | 可选 | Int | 分享额外选项,两种类型可选(默认是不隐藏分享到QZone按钮且不自动打开分享到QZone的对话框): QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN,分享时自动打开分享到QZone的对话框。 |
private void onClickAudioShare() { final Bundle params = new Bundle(); params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_AUDIO); 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"); params.putString(QQShare.SHARE_TO_QQ_AUDIO_URL, "音乐链接"); params.putString(QQShare.SHARE_TO_QQ_APP_NAME, "测试应用222222"); params.putInt(QQShare.SHARE_TO_QQ_EXT_INT,QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN); mTencent.shareToQQ(MainActivity.this, params, new BaseUiListener()); }
(4) 分享应用
应用分享后,发送方和接收方在聊天窗口中点击消息气泡即可进入应用的详情页。
调用分享接口的params参数说明如下:
参数 | 是否必传 | 类型 | 参数说明 |
---|---|---|---|
QQShare.SHARE_TO_QQ_KEY_TYPE | 必填 | Int | 分享的类型。分享音乐填Tencent.SHARE_TO_QQ_TYPE_PP。 |
QQShare.PARAM_TITLE | 必选 | String | 分享的标题, 最长30个字符。 |
QQShare.PARAM_SUMMARY | 可选 | String | 分享的消息摘要,最长40个字符。 |
QQShare.SHARE_TO_QQ_IMAGE_URL | 可选 | String | 分享图片的URL或者本地路径。 |
QQShare.SHARE_TO_QQ_APP_NAME | 可选 | String | 手Q客户端顶部,替换“返回”按钮文字,如果为空,用返回代替。 |
QQShare.SHARE_TO_QQ_EXT_INT | 可选 | Int | 分享额外选项,两种类型可选(默认是不隐藏分享到QZone按钮且不自动打开分享到QZone的对话框): QQShare.SHARE_TO_QQ_FLAG_QZONE_AUTO_OPEN,分享时自动打开分享到QZone的对话框。 |
调用分享接口的示例代码如下:
private void onClickAppShare() { final Bundle params = new Bundle(); params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_APP); params.putString(QQShare.SHARE_TO_QQ_TITLE, "要分享的标题"); params.putString(QQShare.SHARE_TO_QQ_SUMMARY, "要分享的摘要"); params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, "http://imgcache.qq.com/qzone/space_item/pre/0/66768.gif"); params.putString(QQShare.SHARE_TO_QQ_APP_NAME, "测试应用222222"); mTencent.shareToQQ(MainActivity.this, params, new BaseUiListener()); }
完善了分享到QZone功能,分享类型参数Tencent.SHARE_TO_QQ_KEY_TYPE,目前只支持图文分享。Tencent. shareToQzone()函数可直接调用,不用用户授权(使用手机QQ当前的登录态)。调用后将打开手机QQ内QQ空间的界面,或者用浏览器打开QQ空间页面进行分享操作。
params参数说明如下:
参数 | 是否必传 | 类型 | 参数说明 |
---|---|---|---|
QzoneShare.SHARE_TO_QQ_KEY_TYPE | 选填 | Int | SHARE_TO_QZONE_TYPE_IMAGE_TEXT(图文) |
QzoneShare.SHARE_TO_QQ_TITLE | 必填 | Int | 分享的标题,最多200个字符。 |
QzoneShare.SHARE_TO_QQ_SUMMARY | 选填 | String | 分享的摘要,最多600字符。 |
QzoneShare.SHARE_TO_QQ_TARGET_URL | 必填 | String | 需要跳转的链接,URL字符串。 |
QzoneShare.SHARE_TO_QQ_IMAGE_URL | 选填 | String | 分享的图片, 以ArrayList |
注意:QZone接口暂不支持发送多张图片的能力,若传入多张图片,则会自动选入第一张图片作为预览图。多图的能力将会在以后支持。:
private void shareToQzone () { //分享类型 params.putString(QzoneShare.SHARE_TO_QQ_KEY_TYPE,SHARE_TO_QZONE_TYPE_IMAGE_TEXT ); params.putString(QzoneShare.SHARE_TO_QQ_TITLE, "标题");//必填 params.putString(QzoneShare.SHARE_TO_QQ_SUMMARY, "摘要");//选填 params.putString(QzoneShare.SHARE_TO_QQ_TARGET_URL, "跳转URL");//必填 params.putStringArrayList(QzoneShare.SHARE_TO_QQ_IMAGE_URL, "图片链接ArrayList"); mTencent.shareToQzone(activity, params, new BaseUiListener()); }