美文网首页selector程序员
我的APP不可能这么胖之QQ空间分享

我的APP不可能这么胖之QQ空间分享

作者: 萌恬丶 | 来源:发表于2017-07-18 13:51 被阅读239次

简介

这一系列讲述的是免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不可能这么胖之支付宝支付

相关文章

网友评论

    本文标题:我的APP不可能这么胖之QQ空间分享

    本文链接:https://www.haomeiwen.com/subject/emfhkxtx.html