程序员

我的APP不可能这么胖之QQ好友分享

2017-07-18  本文已影响327人  萌恬丶

简介

这一系列讲述的是免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 * qqInfoData = [pasteboard valueForPasteboardType:@"com.tencent.mqq.api.apiLargeData"];
        //QQ是使用NSKeyedArchiver序列化数据的
        //图片分享是会有file_data previewimagedata,链接分享只有previewimagedata
        //qqInfoDic:
        //{
        //    "file_data" = NSData数据
        //    "previewimagedata" = NSData数据
        //}
        NSDictionary * qqInfoDic = [NSKeyedUnarchiver unarchiveObjectWithData:qqInfoData];
        //图片
        NSData * file_data = qqInfoDic[@"file_data"];
        UIImage * image = [UIImage imageWithData:file_data];
        
        //缩略图 小于32k
        NSData * previewimagedata = qqInfoDic[@"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=0&file_type=text&callback_name=QQ05FB8B52&src_type=app&file_data=U2hhcmUgU0RL&version=1&cflag=0&callback_type=scheme&generalpastboard=1&sdkv=3.2.1

图片分享 图片存在剪切板里

----------open url: 1----------
mqqapi://share/to_fri?thirdAppDisplayName=U2hhcmVTREtEZW1v&shareType=0&objectlocation=pasteboard&file_type=img&callback_name=QQ05FB8B52&src_type=app&version=1&description=U2hhcmUgU0RL&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=0&title=U2hhcmUgU0RL&thirdAppDisplayName=U2hhcmVTREtEZW1v&callback_name=QQ05FB8B52&objectlocation=pasteboard&cflag=0&sdkv=3.2.1

3、参数解释

//QQ的URL Scheme
mqqapi   

//固定开头 
share/to_fri  

//我们app的名字(这里要对名字做Base64编码) 
thirdAppDisplayName  

// 0 QQ好友
shareType   

// 分享类型 
// text(纯文本)、img(图片,可为图文)、news(链接)  
file_type   

// 例如QQ05FB8B52 QQ是固定写法,05FB8B52是appId  
//需要做8位16进制转换(%08llx)
callback_name   

// 客户端分享固定写法 src_type=app   
src_type   

// 版本号 version=1 
version  

//cflag = 0
cflag

//callback_type=scheme 固定写法 
callback_type   

// 固定写法 generalpastboard=1  
generalpastboard   

//SDK版本
sdkv 

//带图片的分享,包括链接、图片分享需要用到
//需要把图片放到剪切板里
//objectlocation=pasteboard 固定写法
objectlocation   

// 当file_type为text时,file_data为分享内容(内容需要Base64编码)。file_data直接作为URl参数。
// 当file_type为img时,file_data为UIImage的NSData(即需要将UIImage转成NSData)。QQ好友分享只能一张图片。
//file_data需要放到剪切板里。  
file_data   

//缩略图(QQ好友分享专属字段,小于32k) 
//当file_type为img、news时用到。
previewimagedata 

//QQ好友图片分享、链接分享。该参数为分享内容(Base64编码)
description 

//当file_type为news时用到,该参数为链接标题
title   

//当file_type为news时用到,该参数为网页url(Base64编码)
url

二、构造分享参数

代码仅供参考,部分代码做了封装,需要到demo里的TQQPlatform类查看。

//分享到QQ好友
+ (NSString *)shareToQQParameters:(NSMutableDictionary *)parameters appId:(NSString *)appId onStateChanged:(TStateChangedHandler)stateChangedHandler {
    
    if (stateChangedHandler) {
        [TQQPlatform shareInstance].stateChangedHandler = stateChangedHandler;
    }
    
    if ([TQQPlatform isQQInstalled]) {
        NSString * file_type = @"";
        TContentType TPlatformType = [[parameters typeForParams] integerValue];
        if (TPlatformType == TContentTypeText) {
            //文本类型
            file_type = @"text";
        }
        else if (TPlatformType == TContentTypeImage) {
            //图片类型
            file_type = @"img";
        }
        else if (TPlatformType == TContentTypeWebPage) {
            //链接
            file_type = @"news";
        }
        
        //公共参数
        NSMutableString *qqInfo = [[NSMutableString alloc] initWithString:@"mqqapi://share/to_fri?thirdAppDisplayName="];
        [qqInfo appendString:[NSString base64Encode:kCFBundleDisplayName]];
        [qqInfo appendString:@"&shareType=0"];
        [qqInfo appendString:@"&file_type="];
        [qqInfo appendString:file_type];
        [qqInfo appendString:@"&callback_name="];
        [qqInfo appendString:[NSString stringWithFormat:@"QQ%08llx",[appId longLongValue]]];
        [qqInfo appendString:@"&src_type=app"];
        [qqInfo appendString:@"&version=1"];
        [qqInfo appendString:@"&cflag=0"];
        [qqInfo appendString:@"&callback_type=scheme"];
        [qqInfo appendString:@"&sdkv=3.2.1"];
        [qqInfo appendString:@"&generalpastboard=1"];
        
        //纯文本时才会有file_data字段
        if ([file_type isEqualToString:@"text"]) {
            [qqInfo appendString:@"&file_data="];
            [qqInfo appendString:[NSString base64Encode:[parameters textForParams]]];
        }
        
        //图片分享、链接分享
        if ([file_type isEqualToString:@"text"] == NO) {
            [qqInfo appendString:@"&objectlocation=pasteboard"];
            [qqInfo appendString:@"&description="];
            [qqInfo appendString:[NSString base64Encode:[parameters textForParams]]];
            [qqInfo appendString:@"&title="];
            [qqInfo appendString:[NSString base64Encode:[parameters titleForParams]]];
            
            //图片集合,传入参数可以为UIImage、数组(UIImage、NSString(图片路径)、NSURL(图片路径))
            NSMutableArray * img = [NSMutableArray arrayWithImages:[parameters imagesForParams] isCompress:NO];
            //如果缩略图为空 就使用大图压缩
            NSMutableArray * thumbImg = [parameters thumbImageForParams] == nil ? [NSMutableArray arrayWithImages:[parameters imagesForParams] isCompress:YES] : [NSMutableArray arrayWithImages:[parameters thumbImageForParams] isCompress:YES];
            NSDictionary *data = nil;
            
            if ([file_type isEqualToString:@"img"]) {
                //图片分享 QQ好友只支持一张,默认选取数组第0位置图片
                data=@{@"file_data":img[0],
                       @"previewimagedata":thumbImg[0]};
                
            }
            else if ([file_type isEqualToString:@"news"]) {
                //链接分享 QQ好友只支持一张,默认选取数组第0位置图片
                data=@{@"previewimagedata":thumbImg[0]};
            }
            [UIPasteboard setPasteboard:@"com.tencent.mqq.api.apiLargeData" value:data encoding:TPboardEncodingKeyedArchiver];
        }
        
        //链接分享
        if ([file_type isEqualToString:@"news"]) {
            
            [qqInfo appendString:@"&url="];
            [qqInfo appendString:[NSString base64Encode:[parameters[@"URL"] absoluteString]]];
            
        }
        
        return qqInfo;
    }
    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 TPlatformSubTypeQQFriend: {
            
            shareUrl = [TQQPlatform shareToQQParameters: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) {
            
            if ([TQQPlatform shareInstance].stateChangedHandler) {
                [TQQPlatform shareInstance].stateChangedHandler(TResponseStateCancel, nil, nil);
            }
            
        }
        else if ([dic[@"error"] intValue] == 0) {
            //分享成功
            if ([TQQPlatform shareInstance].stateChangedHandler) {
                [TQQPlatform shareInstance].stateChangedHandler(TResponseStateSuccess, nil, nil);
            }
        }
        else{
            //分享失败 失败是什么状态 我也不知道 等测试到再说
            NSError *err=[NSError errorWithDomain:@"QQErrorDomain" 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不可能这么胖之支付宝支付

上一篇下一篇

猜你喜欢

热点阅读