简介
这一系列讲述的是免SDK实现分享、登录、支付等业务。
将会使用ShareSDK Demo进行部分试验。
一、拦截分享参数
1、打开ShareSDK Demo,找到AppDelegate.m 添加如下代码
//头文件不要忘
#import <objc/runtime.h>
//对UIApplication的openURL:方法进行hook
-(void)swizzleOpenUrl{
SEL openUrlSEL=@selector(openURL:);
BOOL (*openUrlIMP)(id,SEL,id) =(BOOL(*)(id,SEL,id))[UIApplication instanceMethodForSelector:openUrlSEL];
static int count=0;
BOOL (^myOpenURL)(id SELF,NSURL * url)=^(id SELF,NSURL *url){
//打印出分享的URL
NSLog(@"\n----------open url: %d----------\n%@\n%@\n",count++,url,@"\n"/*[NSThread callStackSymbols]*/);
//获取系统剪切板
UIPasteboard * pasteboard = [UIPasteboard generalPasteboard];
//打印获取QQ在剪切板的key 得知key为 com.tencent.mqq.api.apiLargeData
NSLog(@"%@",pasteboard.pasteboardTypes);
//获取QQ在剪切板参数 图片与链接分享时才有值
NSData * qzoneInfoData = [pasteboard valueForPasteboardType:@"com.tencent.mqq.api.apiLargeData"];
//QQ是使用NSKeyedArchiver序列化数据的
//图片分享是会有image_data_list
//qzoneInfoDic:
//{
// "image_data_list" = NSData数据
//}
//链接分享只有previewimagedata
//qzoneInfoDic:
//{
// "previewimagedata" = NSData数据
//}
NSDictionary * qzoneInfoDic = [NSKeyedUnarchiver unarchiveObjectWithData:qzoneInfoData];
//图片
NSData * image_data_list_data = qzoneInfoDic[@"image_data_list"];
NSArray * image_data_list = [NSKeyedUnarchiver unarchiveObjectWithData:image_data_list_data];
NSMutableArray * images = [NSMutableArray array];
for (NSData * imgData in image_data_list) {
UIImage * image = [UIImage imageWithData:imgData];
[images addObject:image];
}
//缩略图 小于32k
NSData * previewimagedata = qzoneInfoDic[@"previewimagedata"];
UIImage * previewimage = [UIImage imageWithData:previewimagedata];
return (BOOL)openUrlIMP(SELF,openUrlSEL,url);
};
class_replaceMethod([UIApplication class], openUrlSEL, imp_implementationWithBlock(myOpenURL), NULL);
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//只要添加这句
[self swizzleOpenUrl];
}
2、查看控制台打印的URL
文字分享
----------open url: 0----------
mqqapi://share/to_fri?thirdAppDisplayName=U2hhcmVTREtEZW1v&shareType=1&objectlocation=pasteboard&file_type=qzone&title=U2hhcmUgU0RL&callback_name=QQ05FB8B52&src_type=app&version=1&cflag=0&callback_type=scheme&generalpastboard=1&sdkv=3.2.1
图片分享 图片存在剪切板里
----------open url: 1----------
mqqapi://share/to_fri?thirdAppDisplayName=U2hhcmVTREtEZW1v&shareType=1&objectlocation=pasteboard&file_type=qzone&callback_name=QQ05FB8B52&src_type=app&version=1&cflag=0&callback_type=scheme&generalpastboard=1&sdkv=3.2.1
链接分享 图片存在剪切板里
----------open url: 2----------
mqqapi://share/to_fri?file_type=news&generalpastboard=1&src_type=app&version=1&description=U2hhcmUgU0RLIExpbmsgRGVzYw==&callback_type=scheme&url=aHR0cHM6Ly93d3cubW9iLmNvbQ==&shareType=1&title=U2hhcmUgU0RL&thirdAppDisplayName=U2hhcmVTREtEZW1v&callback_name=QQ05FB8B52&objectlocation=pasteboard&cflag=1&sdkv=3.2.1
相册视频分享
----------open url: 3----------
mqqapi://share/to_fri?thirdAppDisplayName=U2hhcmVTREtEZW1v&shareType=1&file_type=qzone&video_assetURL=YXNzZXRzLWxpYnJhcnk6Ly9hc3NldC9hc3NldC5tcDQ/aWQ9RUYwODc2N0YtNjk5MC00MjI2LTgxOUEtQzVCMEI2QzdERDcwJmV4dD1tcDQ=&callback_name=QQ05FB8B52&src_type=app&version=1&cflag=0&callback_type=scheme&generalpastboard=1&sdkv=3.2.1
3、参数解释
//QQ的URL Scheme
mqqapi
//固定开头
share/to_fri
// 我们app的名字(这里要对名字做Base64编码)
thirdAppDisplayName
//1 QQ空间
shareType
//分享类型
//文本、图片、视频均为Qzone 链接为news
file_type
//例如QQ05FB8B52 QQ是固定写法,05FB8B52是appId
//需要做8位16进制转换(%08llx)
callback_name
//客户端分享固定写法 src_type=app
src_type
//版本号 version=1
version
//链接类型为1 其余均为0
cflag
//callback_type=scheme 固定写法
callback_type
//固定写法 generalpastboard=1
generalpastboard
//SDK版本
sdkv
//带图片的分享,包括链接、图片分享需要用到
//需要把图片放到剪切板里
//objectlocation=pasteboard 固定写法
objectlocation
//链接分享用到,该参数为分享内容(Base64编码)
description
//当file_type为news时title为链接标题,其余状态均为分享内容。
title
//当file_type为news时用到,该参数为网页url(Base64编码)
url
//当file_type为news时用到 缩略图 小于32k
previewimagedata
//QZone专属字段 图片分享用到为NSArray或其子类数组,数组内存放UIImage的NSDate(即需要将UIImage转成NSData)。需要放到剪切板里。
image_data_list
//QZone专属字段 相册视频本地路径(Base64编码)
video_assetURL
二、构造分享参数
代码仅供参考,部分代码做了封装,需要到demo里的TQQPlatform类查看。
//分享到QZone
+ (NSString *)shareToQZoneParameters:(NSMutableDictionary *)parameters appId:(NSString *)appId onStateChanged:(TStateChangedHandler)stateChangedHandler {
if (stateChangedHandler) {
[TQQPlatform shareInstance].stateChangedHandler = stateChangedHandler;
}
if ([TQQPlatform isQQInstalled]) {
NSString * file_type = @"";
NSString * cflag = @"";
//公共参数
NSMutableString *qzoneInfo = [[NSMutableString alloc] initWithString:@"mqqapi://share/to_fri?thirdAppDisplayName="];
[qzoneInfo appendString:[NSString base64Encode:kCFBundleDisplayName]];
[qzoneInfo appendString:@"&shareType=1"];
[qzoneInfo appendString:@"&callback_name="];
[qzoneInfo appendString:[NSString stringWithFormat:@"QQ%08llx",[appId longLongValue]]];
[qzoneInfo appendString:@"&src_type=app"];
[qzoneInfo appendString:@"&version=1"];
[qzoneInfo appendString:@"&callback_type=scheme"];
[qzoneInfo appendString:@"&sdkv=3.2.1"];
[qzoneInfo appendString:@"&generalpastboard=1"];
[qzoneInfo appendString:@"&objectlocation=pasteboard"];
TContentType TPlatformType = [[parameters typeForParams] integerValue];
if (TPlatformType == TContentTypeText) {
//文本类型
file_type = @"qzone";
cflag = @"0";
[qzoneInfo appendString:@"&title="];
[qzoneInfo appendString:[NSString base64Encode:[parameters textForParams]]];
}
else if (TPlatformType == TContentTypeImage) {
//图片类型
file_type = @"qzone";
cflag = @"0";
//图片集合,传入参数可以为UIImage、NSString(图片路径)、NSURL(图片路径)
NSDictionary *data=@{@"image_data_list":[NSMutableArray arrayWithImages:[parameters imagesForParams] isCompress:NO]
};
[UIPasteboard setPasteboard:@"com.tencent.mqq.api.apiLargeData" value:data encoding:TPboardEncodingKeyedArchiver];
}
else if (TPlatformType == TContentTypeWebPage) {
//链接
file_type = @"news";
cflag = @"1";
[qzoneInfo appendString:@"&title="];
[qzoneInfo appendString:[NSString base64Encode:[parameters titleForParams]]];
[qzoneInfo appendString:@"&description="];
[qzoneInfo appendString:[NSString base64Encode:[parameters textForParams]]];
[qzoneInfo appendString:@"&url="];
[qzoneInfo appendString:[NSString base64Encode:[parameters urlForParams].absoluteString]];
NSMutableArray * thumbImg = [NSMutableArray arrayWithImages:[parameters thumbImageForParams] isCompress:YES];
NSDictionary * data=@{@"previewimagedata":thumbImg[0]};
[UIPasteboard setPasteboard:@"com.tencent.mqq.api.apiLargeData" value:data encoding:TPboardEncodingKeyedArchiver];
}
else if (TPlatformType == TContentTypeVideo) {
//视频
file_type = @"qzone";
[qzoneInfo appendString:@"&video_assetURL="];
[qzoneInfo appendString:[NSString base64Encode:[parameters urlForParams].absoluteString]];
cflag = @"0";
}
[qzoneInfo appendString:@"&cflag="];
[qzoneInfo appendString:cflag];
[qzoneInfo appendString:@"&file_type="];
[qzoneInfo appendString:file_type];
return qzoneInfo;
}
else {
if (stateChangedHandler) {
NSError * err = [NSError errorWithDomain:@"TrochilusErrorDomain" code:-1001 userInfo:@{@"error_message":@"分享平台[QQ]尚未安装QQ或者QQ空间客户端!无法进行分享!"}];
stateChangedHandler(TResponseStateFail,nil,err);
}
}
return nil;
}
三、发起请求
代码仅供参考,部分代码做了封装,需要到demo里的Trochilus类查看。
+ (void)share:(TPlatformType)platformType parameters:(NSMutableDictionary *)parameters onStateChanged:(TStateChangedHandler)stateChangedHandler {
NSString * shareUrl = @"";
switch (platformType) {
case TPlatformSubTypeQZone: {
shareUrl = [TQQPlatform shareToQZoneParameters:parameters
appId:[self platformForKey:qq][@"appId"]
onStateChanged:^(TResponseState state, NSDictionary *userData, NSError *error) {
if (stateChangedHandler) {
stateChangedHandler(state,userData,error);
}
}];
}
break;
default:
break;
}
[Trochilus sendToURL:shareUrl];
}
+ (void)sendToURL:(NSString *)url {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.001 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
});
}
四、QQ客户端回调
代码仅供参考,部分代码做了封装,需要到demo里的TQQPlatform类查看。
//回调
+ (BOOL)handleUrlWithQQ:(NSURL *)url {
if ([url.scheme hasPrefix:@"QQ"]) {
//分享
NSDictionary *dic=[NSMutableDictionary dictionaryWithUrl:url];
if (dic[@"error_description"]) {
[dic setValue:[NSString base64Decode:dic[@"error_description"]] forKey:@"error_description"];
}
if ([dic[@"error"] intValue] == -4) {
//用户取消分享
NSError *err=[NSError errorWithDomain:@"response_from_qq" code:[dic[@"error"] intValue] userInfo:dic];
if ([TQQPlatform shareInstance].stateChangedHandler) {
[TQQPlatform shareInstance].stateChangedHandler(TResponseStateCancel, nil, err);
}
}
else if ([dic[@"error"] intValue] == 0) {
//分享成功
if ([TQQPlatform shareInstance].stateChangedHandler) {
[TQQPlatform shareInstance].stateChangedHandler(TResponseStateSuccess, nil, nil);
}
}
else{
//分享失败 失败是什么状态 我也不知道 等测试到再说
NSError *err=[NSError errorWithDomain:@"response_from_qq" code:[dic[@"error"] intValue] userInfo:dic];
if ([TQQPlatform shareInstance].stateChangedHandler) {
[TQQPlatform shareInstance].stateChangedHandler(TResponseStateFail, nil, err);
}
}
return YES;
}
return NO;
}
五、参考资料
https://github.com/100apps/openshare
六、Demo
https://github.com/quanweiwang/Trochilus
目录
分享篇
1、我的APP不可能这么胖之QQ好友分享
2、我的APP不可能这么胖之QQ空间分享
3、我的APP不可能这么胖之微信好友分享
4、我的APP不可能这么胖之微信朋友圈分享
5、我的APP不可能这么胖之新浪微博分享
登录篇
6、我的APP不可能这么胖之QQ登录
7、我的APP不可能这么胖之微信登录
8、我的APP不可能这么胖之新浪微博登录
支付篇
9、我的APP不可能这么胖之微信支付
10、我的APP不可能这么胖之支付宝支付
网友评论