iOS 微信支付分享授权登录封装

// Pods for WXPay

// 1. pod 'WechatOpenSDK'

// 2.用到一个 XMLDictionary 工具类

//  info.plist 打开方式 Source Code

 // 设置 CFBundleURLTypes 如下注意 APPid写自己的

  <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
            <key>CFBundleURLName</key>
            <string>weixin</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>微信APPid</string>
            </array>
        </dict>
    </array>

#import <Foundation/Foundation.h>
#import "WXApi.h"

/**  微信appid  */
#define WXAPPID @""
/**  微信支付商户号  */
#define  MCH_ID     @"" // 微信支付商户号 partnerId
/**  交易结果通知网站此处用于测试,随意填写,正式使用时填写正确网站  */
#define  NOTIFY_URL @"http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php"
/**  商户密钥 partner  */
#define  kEY        @""

NS_ASSUME_NONNULL_BEGIN

//0 = 好友列表 1 = 朋友圈 2 = 收藏
typedef NS_ENUM(NSUInteger, WechtShareType) {
    WechtShareTypeFriends = 0,
    WechtShareTypePengYouQuan,
    WechtShareTypeFavorites
};

@interface WeChatManager : NSObject
<
WXApiDelegate
>
+(instancetype)shareManager;
/**
 * 支付
 * https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
 */
-(void)weiXinPayName:(NSString *)name money:(CGFloat)money ;
/**  分享  */
-(void)weChatShare:(NSString *)tittle
           content:(NSString *)content
               url:(NSString *)url
             image:(UIImage *)image
         scenetype:(WechtShareType)scenetype;
/**
 *登录
 * https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317851&token=&lang=zh_CN
 */
-(void)weChatLogin;

@end

NS_ASSUME_NONNULL_END
#import "WeChatManager.h"
#import <CommonCrypto/CommonDigest.h>
#import "XMLDictionary.h"
/**  统一下单地址  */
#define HTTP @"https://api.mch.weixin.qq.com/pay/unifiedorder"

@interface WeChatManager ()
/**
 *  预支付订单号
 */
@property (nonatomic,strong)NSString *out_trade_no;
/**
 *  随机数 时间戳
 */
@property (nonatomic,strong)NSString *nonceStr;
/**
 *  预支付订单返回值
 */
@property (nonatomic,strong)NSDictionary *backDic;
@end

@implementation WeChatManager

+ (instancetype)shareManager
{
    static WeChatManager * manager =nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (manager == nil)
        {
            manager = [[self alloc]init];
        }
    });
    return manager;
}

#pragma mark ————————— 充值 —————————————
- (void)weiXinPayName:(NSString *)name money:(CGFloat)money
{
    [WXApi registerApp:WXAPPID];//注册appid
    _nonceStr     = [self md5:[self generateTradeNO]] ; // 随机数MD5
    _out_trade_no = [self genTimeStamp]; // 商户订单号(时间戳)
    NSString *appid, *mch_id, *nonce_str, *sign, *body, *out_trade_no, *total_fee, *spbill_create_ip, *notify_url, *trade_type, *partner;
    //应用APPID
    appid = WXAPPID;
    //微信支付商户号
    mch_id = MCH_ID;
    ///产生随机字符串
    nonce_str = _nonceStr;
    // 商品名称
    body = name;
    //商户订单号
    out_trade_no = _out_trade_no;
    // 交易价格1表示0.01元,10表示0.1元
    NSInteger JG = [[NSString stringWithFormat:@"%f", money * 100] integerValue];
    //  NSLog(@"money = %zd",JG);
    total_fee = [NSString stringWithFormat:@"%zd", JG];
    //获取本机IP地址,请再wifi环境下测试,否则获取的ip地址为error,正确格式应该是8.8.8.8
    spbill_create_ip = @"192.168.23.138" ;
    //交易结果通知网站此处用于测试,随意填写,正式使用时填写正确网站
    notify_url = NOTIFY_URL;
    // 移动端类型
    trade_type = @"APP";
    //商户密钥
    partner = kEY;
    
    sign = [self getSignForMD5ppid:appid
                            mch_id:mch_id
                         nonce_str:nonce_str
                        partner_id:partner
                              body:body
                      out_trade_no:out_trade_no
                         total_fee:total_fee
                  spbill_create_ip:spbill_create_ip
                        notify_url:notify_url
                        trade_type:trade_type];
    
    NSLog(@"sign = %@",sign);
    NSString *xmlData = [self getXmlFromAppid:appid
                                       mch_id:mch_id
                                    nonce_str:nonce_str
                                         sign:sign
                                         body:body
                                 out_trade_no:out_trade_no
                                    total_fee:total_fee
                             spbill_create_ip:spbill_create_ip
                                   notify_url:notify_url
                                   trade_type:trade_type];
    NSLog(@"xmlData \n  %@",xmlData);
    [self http:HTTP data:xmlData];
    
}

#pragma mark ————————— 设置参数并转化成xml格式 —————————————
-(NSString *)getXmlFromAppid:(NSString *)appid
                      mch_id:(NSString *)mch_id
                   nonce_str:(NSString *)nonce_str
                        sign:(NSString *)sign
                        body:(NSString *)body
                out_trade_no:(NSString *)out_trade_no
                   total_fee:(NSString *)total_fee
            spbill_create_ip:(NSString *)spbill_create_ip
                  notify_url:(NSString *)notify_url
                  trade_type:(NSString *)trade_type
{
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    [dic setValue:appid forKey:@"appid"];//公众账号ID
    [dic setValue:mch_id forKey:@"mch_id"];//商户号
    [dic setValue:nonce_str forKey:@"nonce_str"];//随机字符串
    [dic setValue:sign forKey:@"sign"];//签名
    [dic setValue:body forKey:@"body"];//商品描述
    [dic setValue:out_trade_no forKey:@"out_trade_no"];//订单号
    [dic setValue:total_fee forKey:@"total_fee"];//金额
    [dic setValue:spbill_create_ip forKey:@"spbill_create_ip"];//终端IP
    [dic setValue:notify_url forKey:@"notify_url"];//通知地址
    [dic setValue:trade_type forKey:@"trade_type"];//交易类型
    
    return [dic XMLString];
}

#pragma mark ————————— 组合sign签名必要参数 —————————————
-(NSString *)getSignForMD5ppid:(NSString *)appid_key
                        mch_id:(NSString *)mch_id_key
                     nonce_str:(NSString *)noce_str_key
                    partner_id:(NSString *)partner_id
                          body:(NSString *)body_key
                  out_trade_no:(NSString *)out_trade_no_key
                     total_fee:(NSString *)total_fee_key
              spbill_create_ip:(NSString *)spbill_create_ip_key
                    notify_url:(NSString *)notify_url_key
                    trade_type:(NSString *)trade_type_key
{
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    [dic setValue:appid_key forKey:@"appid"];
    [dic setValue:mch_id_key forKey:@"mch_id"];
    [dic setValue:noce_str_key forKey:@"nonce_str"];
    [dic setValue:body_key forKey:@"body"];
    [dic setValue:out_trade_no_key forKey:@"out_trade_no"];
    [dic setValue:total_fee_key forKey:@"total_fee"];
    [dic setValue:spbill_create_ip_key forKey:@"spbill_create_ip"];
    [dic setValue:notify_url_key forKey:@"notify_url"];
    [dic setValue:trade_type_key forKey:@"trade_type"];
    return [self createMd5Sign:dic];
}

#pragma mark ————————— 创建Md5格式的 sign 签名 —————————————
- (NSString*) createMd5Sign:(NSMutableDictionary*)dict
{
    NSMutableString *contentString  =[NSMutableString string];
    NSArray *keys = [dict allKeys];
    //按字母顺序排序
    NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        return [obj1 compare:obj2 options:NSNumericSearch];
    }];
    //拼接字符串
    for (NSString *categoryId in sortedArray)
    {
        if (![[dict objectForKey:categoryId] isEqualToString:@""]&&
            ![[dict objectForKey:categoryId] isEqualToString:@"sign"]&&
            ![[dict objectForKey:categoryId] isEqualToString:@"key"] )
        {
            [contentString appendFormat:@"%@=%@&", categoryId, [dict objectForKey:categoryId]];
        }
    }
    //添加商户密钥key字段
    [contentString appendFormat:@"key=%@", kEY];
    //得到MD5 sign签名
    NSString *md5Sign =[self md5:contentString];
    return md5Sign;
}

#pragma mark ————————— 预支付订单号请求 —————————————
- (void)http:(NSString *)url data:(NSString *)send
{
    __weak __typeof(self) weakself= self;
    // 1 创建URL
    NSURL *urls = [NSURL URLWithString:url];
    // 2  创建请求对象
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:urls];
    [request setHTTPMethod:@"POST"];
    // 3 设置body
    NSData *bodyData = [send dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:bodyData];
    // 4 创建会话
    NSURLSession *session = [NSURLSession sharedSession];
    // 5 创建数据请求任务
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSString * newStr = [[NSString alloc] initWithData:data  encoding:NSUTF8StringEncoding];
        NSLog(@"预支付订单号请求结果XML=%@",newStr);
        NSDictionary *xmlDoc = [NSDictionary dictionaryWithXMLString:newStr];
        NSLog(@"预支付订单号请求结果%@",xmlDoc);
        [weakself WeiXinPay:xmlDoc];
        
    }];
    // 4.3、 启动任务
    [task resume];
}

#pragma mark ————————— 调用微信支付 —————————————
- (void)WeiXinPay:(NSDictionary *)xmlDoc {
    //判断返回的许可
    if ([[xmlDoc objectForKey:@"result_code"] isEqualToString:@"SUCCESS"] &&
        [[xmlDoc objectForKey:@"return_code"] isEqualToString:@"SUCCESS"])
    {
        //发起微信支付,设置参数
        PayReq *request   = [[PayReq alloc] init];
        request.partnerId = [xmlDoc objectForKey:@"mch_id"];
        request.prepayId  = [xmlDoc objectForKey:@"prepay_id"];
        request.package   = @"Sign=WXPay";
        request.nonceStr  = [xmlDoc objectForKey:@"nonce_str"];
        UInt32 timestamp = (UInt32)time(0);
        request.timeStamp = timestamp;
        request.sign = [self createMD5SingForPay:WXAPPID
                                       partnerid:request.partnerId
                                        prepayid:request.prepayId
                                         package:request.package
                                        noncestr:request.nonceStr
                                       timestamp:request.timeStamp];
        
        [self saveOrder:xmlDoc];
        
        // 调用微信
        [WXApi sendReq:request];
        
        NSLog(@"\n appid=%@ \n partid=%@ \n prepayid=%@ \n noncestr=%@ \n timestamp=%ld \n package=%@ \n sign=%@",[xmlDoc objectForKey:@"appid"],request.partnerId,request.prepayId,request.nonceStr,(long)request.timeStamp,request.package,request.sign );
    }
    else
    {
        NSLog(@"参数不正确,请检查参数");
    }
}

#pragma mark ————————— 微信分享 —————————————
-(void)weChatShare:(NSString *)tittle
           content:(NSString *)content
               url:(NSString *)url
             image:(UIImage *)image
         scenetype:(WechtShareType)scenetype
{
    [WXApi registerApp:WXAPPID];//注册appid
    // 无图分享
    //创建发送对象实例
    SendMessageToWXReq *sendReq = [[SendMessageToWXReq alloc] init];
    sendReq.bText = NO;//不使用文本信息
    sendReq.scene = scenetype;//0 = 好友列表 1 = 朋友圈 2 = 收藏
    
    //创建分享内容对象
    WXMediaMessage *urlMessage = [WXMediaMessage message];
    
    if (tittle.length > 0)
    {
        urlMessage.title = tittle;//分享标题
    }
    if (content.length > 0)
    {
        urlMessage.description = content;//分享描述
    }
    
    if (url)
    {
        //   [urlMessage setThumbImage:   [UIImage imageNamed:@"ic_launcher"]];
        [urlMessage setThumbImage:[self imageByScalingAndCroppingForSize:CGSizeMake(30, 30) withSourceImage:image]];
        //创建多媒体对象
        WXWebpageObject *webObj = [WXWebpageObject object];
        webObj.webpageUrl = url;//分享链接
        //完成发送对象实例
        urlMessage.mediaObject = webObj;
    }
    else
    {
        if (image)
        {
            //创建分享内容对象
            [urlMessage setThumbImage:image]; //分享图片,使用SDK的setThumbImage方法可压缩图片大小
            //完成发送对象实例
            urlMessage.mediaObject = urlMessage;
        }
    }

    sendReq.message = urlMessage;
    //发送分享信息
    [WXApi sendReq:sendReq];
}
#pragma mark ————————— 微信登录 —————————————
-(void)weChatLogin
{
    [WXApi registerApp:WXAPPID];//注册appid
    SendAuthReq* req =[[SendAuthReq alloc ] init];
    req.scope = @"snsapi_userinfo";// snsapi_userinfo // snsapi_userinfo,snsapi_base
    req.state = @"0744" ;
    if ([WXApi sendReq:req])
    {
        NSLog(@"YES");
    }
    else
    {
        NSLog(@"NO");
    }
    
}

#pragma mark -
#pragma mark WXApiDelegate
#pragma mark ————————— 收到微信的回应 分享 支付 第三方登录后 —————————————

/*
 * @brief 发送一个sendReq后,收到微信的回应
 * 收到一个来自微信的处理结果。调用一次sendReq后会收到onResp。
 * 可能收到的处理结果有SendMessageToWXResp、SendAuthResp等。
 */

- (void)onResp:(BaseResp*)resp
{
    NSLog(@"收到微信的回应\n %d",resp.errCode);
    PayResp *response = (PayResp*)resp;
    // 支付结果回调
    if ([resp isKindOfClass:[PayResp class]])
    {
        switch(response.errCode){
            case WXSuccess:
            {
                NSLog(@"支付成功");
            }
                break;
            default:
            {
                 NSLog(@"支付失败,retcode=%d",resp.errCode);
            }
            break;
        }
    }
    // 第三方登陆
    if ([resp isKindOfClass:[SendAuthResp class]])
    {
        SendAuthResp *aresp = (SendAuthResp *)resp;
        
        switch (aresp.errCode) {
            case WXSuccess:
            {
                // 微信授权登陆 获取令牌 令牌获取成功后直接获取用户信息
                NSString *code = aresp.code ;
                NSString *state = aresp.state;
                NSLog(@"授权登陆获取到用户信息 %@ %@",code,state);
            }
                break;
            case WXErrCodeUserCancel:
            {
                NSLog(@"用户取消微信授权登陆");
            }
                break;
            case WXErrCodeAuthDeny:
            {
                NSLog(@"用户拒绝微信授权登陆");
            }
                break;
                
            default:
            {
                NSLog(@"消微信授权登陆失败");
            }
                break;
        }
        
    }
    
    // 微信分享 SendMessageToWXResp
    if ([resp isKindOfClass:[SendMessageToWXResp class]]) {
        SendMessageToWXResp *saresp = (SendMessageToWXResp *)resp;
        NSLog(@"分享完回调 = %d",saresp.errCode);
        switch (saresp.errCode) {
            case WXSuccess:
            {
                NSLog(@"分享成功");
            }
                break;
            case WXErrCodeUserCancel:
            {
                NSLog(@"取消分享");
            }
                break;
            default:
            {
                NSLog(@"取消失败");
            }
                break;
        }
    }
}

#pragma mark ————————— 收到一个来自微信的请求 —————————————
/*
 *! @brief 收到一个来自微信的请求,第三方应用程序处理完后调用sendResp向微信发送结果
 * 收到一个来自微信的请求,异步处理完成后必须调用sendResp发送处理结果给微信。
 * 可能收到的请求有GetMessageFromWXReq、ShowMessageFromWXReq等。
 * req 具体请求内容,是自动释放的
 */
- (void)onReq:(BaseReq*)req
{
    NSLog(@"收到一个来自微信的请求 = %@",req.openID);
}

#pragma mark -
#pragma mark ————————— 保存订单信息 —————————————
-(void)saveOrder:(NSDictionary *)xmlDoc
{
    NSUserDefaults * us = [NSUserDefaults standardUserDefaults];
    [us setObject:xmlDoc forKey:[NSString stringWithFormat:@"用户名+%@",[NSDate date]]];
    [us synchronize];
}

#pragma mark ————————— 创建发起支付时的sige签名 —————————————
- (NSString *)createMD5SingForPay:(NSString *)appid_key
                        partnerid:(NSString *)partnerid_key
                         prepayid:(NSString *)prepayid_key
                          package:(NSString *)package_key
                         noncestr:(NSString *)noncestr_key
                        timestamp:(UInt32)timestamp_key
{
    
    NSMutableDictionary *signParams = [NSMutableDictionary dictionary];
    [signParams setObject:appid_key forKey:@"appid"];
    [signParams setObject:noncestr_key forKey:@"noncestr"];
    [signParams setObject:package_key forKey:@"package"];
    [signParams setObject:partnerid_key forKey:@"partnerid"];
    [signParams setObject:prepayid_key forKey:@"prepayid"];
    [signParams setObject:[NSString stringWithFormat:@"%u",timestamp_key] forKey:@"timestamp"];
    
    NSMutableString *contentString  =[NSMutableString string];
    NSArray *keys = [signParams allKeys];
    //按字母顺序排序
    NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        return [obj1 compare:obj2 options:NSNumericSearch];
    }];
    //拼接字符串
    for (NSString *categoryId in sortedArray)
    {
        if (![[signParams objectForKey:categoryId] isEqualToString:@""]&&
            ![[signParams objectForKey:categoryId] isEqualToString:@"sign"]&&
            ![[signParams objectForKey:categoryId] isEqualToString:@"key"])
        {
            [contentString appendFormat:@"%@=%@&", categoryId, [signParams objectForKey:categoryId]];
        }
    }
    //添加商户密钥key字段
    [contentString appendFormat:@"key=%@", kEY];
    NSString *result = [self md5:contentString];
    return result;
}

#pragma mark ————————— 获取时间戳 —————————————
- (NSString *)genTimeStamp
{
    NSString* timeString = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
    NSLog(@"timeString = %@",timeString);
    return timeString;
}

#pragma mark ————————— 将订单号使用md5加密 —————————————
-(NSString *) md5:(NSString *)str
{
    const char *cStr = [str UTF8String];
    unsigned char result[16]= "0123456789abcdef";
    CC_MD5(cStr, (CC_LONG)strlen(cStr), result); // This is the md5 call
    return [NSString stringWithFormat:
            @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
            result[0], result[1], result[2], result[3],
            result[4], result[5], result[6], result[7],
            result[8], result[9], result[10], result[11],
            result[12], result[13], result[14], result[15]
            ];
}

#pragma mark ————————— 产生随机订单号 —————————————
- (NSString *)generateTradeNO {
    static int kNumber = 5;
    NSString *sourceStr = @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    NSMutableString *resultStr = [[NSMutableString alloc] init];
    srand(time(0)); // 此行代码有警告:
    for (int i = 0; i < kNumber; i++)
    {
        unsigned index = rand() % [sourceStr length];
        NSString *oneStr = [sourceStr substringWithRange:NSMakeRange(index, 1)];
        [resultStr appendString:oneStr];
    }
    NSString *str = [NSString stringWithFormat:@"%@%@",[self genTimeStamp],resultStr];
    return str;
}


/**
 * 图片压缩到指定大小
 * @param targetSize 目标图片的大小
 * @param sourceImage 源图片
 * @return 目标图片
 */
- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize withSourceImage:(UIImage *)sourceImage
{
    UIImage *newImage = nil;
    CGSize imageSize = sourceImage.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;
    CGFloat targetWidth = targetSize.width;
    CGFloat targetHeight = targetSize.height;
    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetWidth;
    CGFloat scaledHeight = targetHeight;
    CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
    if (CGSizeEqualToSize(imageSize, targetSize) == NO)
    {
        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;
        if (widthFactor > heightFactor)
            scaleFactor = widthFactor; // scale to fit height
        else
            scaleFactor = heightFactor; // scale to fit width
        scaledWidth= width * scaleFactor;
        scaledHeight = height * scaleFactor;
        // center the image
        if (widthFactor > heightFactor)
        {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
        }
        else if (widthFactor < heightFactor)
        {
            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
    }
    UIGraphicsBeginImageContext(targetSize); // this will crop
    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width= scaledWidth;
    thumbnailRect.size.height = scaledHeight;
    
    [sourceImage drawInRect:thumbnailRect];
    newImage = UIGraphicsGetImageFromCurrentImageContext();
    if(newImage == nil)
        NSLog(@"could not scale image");
    
    //pop the context to get back to the default
    UIGraphicsEndImageContext();
    
    return newImage;
}

/*
 #warning 微信官方参数测试
 - (NSString *)jumpToBizPay {
 
 //============================================================
 // V3&V4支付流程实现
 // 注意:参数配置请查看服务器端Demo
 // 更新时间:2015年11月20日
 //============================================================
 NSString *urlString   = @"http://wxpay.weixin.qq.com/pub_v2/app/app_pay.php?plat=ios";
 //解析服务端返回json数据
 NSError *error;
 //加载一个NSURL对象
 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
 //将请求的url数据放到NSData对象中
 NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
 if ( response != nil) {
 NSMutableDictionary *dict = NULL;
 //IOS5自带解析类NSJSONSerialization从response中解析出数据放到字典中
 dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableLeaves error:&error];
 
 NSLog(@"url:%@",urlString);
 if(dict != nil){
 NSMutableString *retcode = [dict objectForKey:@"retcode"];
 if (retcode.intValue == 0){
 NSMutableString *stamp  = [dict objectForKey:@"timestamp"];
 
 //调起微信支付
 PayReq* req             = [[PayReq alloc] init];
 req.partnerId           = [dict objectForKey:@"partnerid"];
 req.prepayId            = [dict objectForKey:@"prepayid"];
 req.nonceStr            = [dict objectForKey:@"noncestr"];
 req.timeStamp           = stamp.intValue;
 req.package             = [dict objectForKey:@"package"];
 req.sign                = [dict objectForKey:@"sign"];
 [WXApi sendReq:req];
 
 //日志输出
 NSLog(@"\nappid=%@\npartid=%@\nprepayid=%@\nnoncestr=%@\ntimestamp=%ld\npackage=%@\nsign=%@",[dict objectForKey:@"appid"],req.partnerId,req.prepayId,req.nonceStr,(long)req.timeStamp,req.package,req.sign );
 return @"";
 }else{
 return [dict objectForKey:@"retmsg"];
 }
 }else{
 return @"服务器返回错误,未获取到json对象";
 }
 }else{
 return @"服务器返回错误";
 }
 }
 */

@end
#import <Foundation/Foundation.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wobjc-missing-property-synthesis"


NS_ASSUME_NONNULL_BEGIN


typedef NS_ENUM(NSInteger, XMLDictionaryAttributesMode)
{
    XMLDictionaryAttributesModePrefixed = 0, //default
    XMLDictionaryAttributesModeDictionary,
    XMLDictionaryAttributesModeUnprefixed,
    XMLDictionaryAttributesModeDiscard
};


typedef NS_ENUM(NSInteger, XMLDictionaryNodeNameMode)
{
    XMLDictionaryNodeNameModeRootOnly = 0, //default
    XMLDictionaryNodeNameModeAlways,
    XMLDictionaryNodeNameModeNever
};


static NSString *const XMLDictionaryAttributesKey   = @"__attributes";
static NSString *const XMLDictionaryCommentsKey     = @"__comments";
static NSString *const XMLDictionaryTextKey         = @"__text";
static NSString *const XMLDictionaryNodeNameKey     = @"__name";
static NSString *const XMLDictionaryAttributePrefix = @"_";


@interface XMLDictionaryParser : NSObject <NSCopying>

+ (XMLDictionaryParser *)sharedInstance;

@property (nonatomic, assign) BOOL collapseTextNodes; // defaults to YES
@property (nonatomic, assign) BOOL stripEmptyNodes;   // defaults to YES
@property (nonatomic, assign) BOOL trimWhiteSpace;    // defaults to YES
@property (nonatomic, assign) BOOL alwaysUseArrays;   // defaults to NO
@property (nonatomic, assign) BOOL preserveComments;  // defaults to NO
@property (nonatomic, assign) BOOL wrapRootNode;      // defaults to NO

@property (nonatomic, assign) XMLDictionaryAttributesMode attributesMode;
@property (nonatomic, assign) XMLDictionaryNodeNameMode nodeNameMode;

- (nullable NSDictionary<NSString *, id> *)dictionaryWithParser:(NSXMLParser *)parser;
- (nullable NSDictionary<NSString *, id> *)dictionaryWithData:(NSData *)data;
- (nullable NSDictionary<NSString *, id> *)dictionaryWithString:(NSString *)string;
- (nullable NSDictionary<NSString *, id> *)dictionaryWithFile:(NSString *)path;

@end


@interface NSDictionary (XMLDictionary)

+ (nullable NSDictionary<NSString *, id> *)dictionaryWithXMLParser:(NSXMLParser *)parser;
+ (nullable NSDictionary<NSString *, id> *)dictionaryWithXMLData:(NSData *)data;
+ (nullable NSDictionary<NSString *, id> *)dictionaryWithXMLString:(NSString *)string;
+ (nullable NSDictionary<NSString *, id> *)dictionaryWithXMLFile:(NSString *)path;

@property (nonatomic, readonly, copy, nullable) NSDictionary<NSString *, NSString *> *attributes;
@property (nonatomic, readonly, copy, nullable) NSDictionary<NSString *, id> *childNodes;
@property (nonatomic, readonly, copy, nullable) NSArray<NSString *> *comments;
@property (nonatomic, readonly, copy, nullable) NSString *nodeName;
@property (nonatomic, readonly, copy, nullable) NSString *innerText;
@property (nonatomic, readonly, copy) NSString *innerXML;
@property (nonatomic, readonly, copy) NSString *XMLString;

- (nullable NSArray *)arrayValueForKeyPath:(NSString *)keyPath;
- (nullable NSString *)stringValueForKeyPath:(NSString *)keyPath;
- (nullable NSDictionary<NSString *, id> *)dictionaryValueForKeyPath:(NSString *)keyPath;

@end


@interface NSString (XMLDictionary)

@property (nonatomic, readonly, copy) NSString *XMLEncodedString;

@end


NS_ASSUME_NONNULL_END


#pragma GCC diagnostic pop
#import "XMLDictionary.h"


#pragma GCC diagnostic ignored "-Wobjc-missing-property-synthesis"
#pragma GCC diagnostic ignored "-Wpartial-availability"
#pragma GCC diagnostic ignored "-Wdirect-ivar-access"
#pragma GCC diagnostic ignored "-Wformat-non-iso"
#pragma GCC diagnostic ignored "-Wgnu"


#import <Availability.h>
#if !__has_feature(objc_arc)
#error This class requires automatic reference counting
#endif


@interface XMLDictionaryParser () <NSXMLParserDelegate>

@property (nonatomic, strong) NSMutableDictionary<NSString *, id> *root;
@property (nonatomic, strong) NSMutableArray *stack;
@property (nonatomic, strong) NSMutableString *text;

@end


@implementation XMLDictionaryParser

+ (XMLDictionaryParser *)sharedInstance
{
    static dispatch_once_t once;
    static XMLDictionaryParser *sharedInstance;
    dispatch_once(&once, ^{
        
        sharedInstance = [[XMLDictionaryParser alloc] init];
    });
    return sharedInstance;
}

- (instancetype)init
{
    if ((self = [super init]))
    {
        _collapseTextNodes = YES;
        _stripEmptyNodes = YES;
        _trimWhiteSpace = YES;
        _alwaysUseArrays = NO;
        _preserveComments = NO;
        _wrapRootNode = NO;
    }
    return self;
}

- (id)copyWithZone:(NSZone *)zone
{
    XMLDictionaryParser *copy = [[[self class] allocWithZone:zone] init];
    copy.collapseTextNodes = _collapseTextNodes;
    copy.stripEmptyNodes = _stripEmptyNodes;
    copy.trimWhiteSpace = _trimWhiteSpace;
    copy.alwaysUseArrays = _alwaysUseArrays;
    copy.preserveComments = _preserveComments;
    copy.attributesMode = _attributesMode;
    copy.nodeNameMode = _nodeNameMode;
    copy.wrapRootNode = _wrapRootNode;
    return copy;
}

- (NSDictionary<NSString *, id> *)dictionaryWithParser:(NSXMLParser *)parser
{
    parser.delegate = self;
    [parser parse];
    id result = _root;
    _root = nil;
    _stack = nil;
    _text = nil;
    return result;
}

- (NSDictionary<NSString *, id> *)dictionaryWithData:(NSData *)data
{
	NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    return [self dictionaryWithParser:parser];
}

- (NSDictionary<NSString *, id> *)dictionaryWithString:(NSString *)string
{
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    return [self dictionaryWithData:data];
}

- (NSDictionary<NSString *, id> *)dictionaryWithFile:(NSString *)path
{	
	NSData *data = [NSData dataWithContentsOfFile:path];
	return [self dictionaryWithData:data];
}

+ (NSString *)XMLStringForNode:(id)node withNodeName:(NSString *)nodeName
{	
    if ([node isKindOfClass:[NSArray class]])
    {
        NSMutableArray<NSString *> *nodes = [NSMutableArray arrayWithCapacity:[node count]];
        for (id individualNode in node)
        {
            [nodes addObject:[self XMLStringForNode:individualNode withNodeName:nodeName]];
        }
        return [nodes componentsJoinedByString:@"\n"];
    }
    else if ([node isKindOfClass:[NSDictionary class]])
    {
        NSDictionary<NSString *, NSString *> *attributes = [(NSDictionary *)node attributes];
        NSMutableString *attributeString = [NSMutableString string];
        [attributes enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, __unused BOOL *stop) {
            [attributeString appendFormat:@" %@=\"%@\"", key.description.XMLEncodedString, value.description.XMLEncodedString];
        }];
        
        NSString *innerXML = [node innerXML];
        if (innerXML.length)
        {
            return [NSString stringWithFormat:@"<%1$@%2$@>%3$@</%1$@>", nodeName, attributeString, innerXML];
        }
        else
        {
            return [NSString stringWithFormat:@"<%@%@/>", nodeName, attributeString];
        }
    }
    else
    {
        return [NSString stringWithFormat:@"<%1$@>%2$@</%1$@>", nodeName, [node description].XMLEncodedString];
    }
}

- (void)endText
{
	if (_trimWhiteSpace)
	{
		_text = [[_text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] mutableCopy];
	}
	if (_text.length)
	{
        NSMutableDictionary *top = _stack.lastObject;
		id existing = top[XMLDictionaryTextKey];
        if ([existing isKindOfClass:[NSArray class]])
        {
            [existing addObject:_text];
        }
        else if (existing)
        {
            top[XMLDictionaryTextKey] = [@[existing, _text] mutableCopy];
        }
		else
		{
			top[XMLDictionaryTextKey] = _text;
		}
	}
	_text = nil;
}

- (void)addText:(NSString *)text
{	
	if (!_text)
	{
		_text = [NSMutableString stringWithString:text];
	}
	else
	{
		[_text appendString:text];
	}
}

- (void)parser:(__unused NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(__unused NSString *)namespaceURI qualifiedName:(__unused NSString *)qName attributes:(NSDictionary *)attributeDict
{	
	[self endText];
	
	NSMutableDictionary<NSString *, id> *node = [NSMutableDictionary dictionary];
	switch (_nodeNameMode)
	{
        case XMLDictionaryNodeNameModeRootOnly:
        {
            if (!_root)
            {
                node[XMLDictionaryNodeNameKey] = elementName;
            }
            break;
        }
        case XMLDictionaryNodeNameModeAlways:
        {
            node[XMLDictionaryNodeNameKey] = elementName;
            break;
        }
        case XMLDictionaryNodeNameModeNever:
        {
            break;
        }
	}
    
	if (attributeDict.count)
	{
        switch (_attributesMode)
        {
            case XMLDictionaryAttributesModePrefixed:
            {
                for (NSString *key in attributeDict)
                {
                    node[[XMLDictionaryAttributePrefix stringByAppendingString:key]] = attributeDict[key];
                }
                break;
            }
            case XMLDictionaryAttributesModeDictionary:
            {
                node[XMLDictionaryAttributesKey] = attributeDict;
                break;
            }
            case XMLDictionaryAttributesModeUnprefixed:
            {
                [node addEntriesFromDictionary:attributeDict];
                break;
            }
            case XMLDictionaryAttributesModeDiscard:
            {
                break;
            }
        }
	}
	
	if (!_root)
	{
        _root = node;
        _stack = [NSMutableArray arrayWithObject:node];
        if (_wrapRootNode)
        {
            _root = [NSMutableDictionary dictionaryWithObject:_root forKey:elementName];
            [_stack insertObject:_root atIndex:0];
        }
	}
	else
	{
        NSMutableDictionary<NSString *, id> *top = _stack.lastObject;
		id existing = top[elementName];
        if ([existing isKindOfClass:[NSArray class]])
        {
            [(NSMutableArray *)existing addObject:node];
        }
        else if (existing)
        {
            top[elementName] = [@[existing, node] mutableCopy];
        }
        else if (_alwaysUseArrays)
        {
            top[elementName] = [NSMutableArray arrayWithObject:node];
        }
		else
		{
			top[elementName] = node;
		}
		[_stack addObject:node];
	}
}

- (NSString *)nameForNode:(NSDictionary<NSString *, id> *)node inDictionary:(NSDictionary<NSString *, id> *)dict
{
	if (node.nodeName)
	{
		return node.nodeName;
	}
	else
	{
		for (NSString *name in dict)
		{
			id object = dict[name];
			if (object == node)
			{
				return name;
			}
			else if ([object isKindOfClass:[NSArray class]] && [(NSArray *)object containsObject:node])
			{
				return name;
			}
		}
	}
	return nil;
}

- (void)parser:(__unused NSXMLParser *)parser didEndElement:(__unused NSString *)elementName namespaceURI:(__unused NSString *)namespaceURI qualifiedName:(__unused NSString *)qName
{	
	[self endText];
    
    NSMutableDictionary<NSString *, id> *top = _stack.lastObject;
    [_stack removeLastObject];
    
	if (!top.attributes && !top.childNodes && !top.comments)
    {
        NSMutableDictionary<NSString *, id> *newTop = _stack.lastObject;
        NSString *nodeName = [self nameForNode:top inDictionary:newTop];
        if (nodeName)
        {
            id parentNode = newTop[nodeName];
            NSString *innerText = top.innerText;
            if (innerText && _collapseTextNodes)
            {
                if ([parentNode isKindOfClass:[NSArray class]])
                {
                    parentNode[[parentNode count] - 1] = innerText;
                }
                else
                {
                    newTop[nodeName] = innerText;
                }
            }
            else if (!innerText)
            {
                if (_stripEmptyNodes)
                {
                    if ([parentNode isKindOfClass:[NSArray class]])
                    {
                        [(NSMutableArray *)parentNode removeLastObject];
                    }
                    else
                    {
                        [newTop removeObjectForKey:nodeName];
                    }
                }
                else if (!_collapseTextNodes)
                {
                    top[XMLDictionaryTextKey] = @"";
                }
            }
        }
	}
}

- (void)parser:(__unused NSXMLParser *)parser foundCharacters:(NSString *)string
{
	[self addText:string];
}

- (void)parser:(__unused NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
	[self addText:[[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding]];
}

- (void)parser:(__unused NSXMLParser *)parser foundComment:(NSString *)comment
{
	if (_preserveComments)
	{
        NSMutableDictionary<NSString *, id> *top = _stack.lastObject;
		NSMutableArray<NSString *> *comments = top[XMLDictionaryCommentsKey];
		if (!comments)
		{
			comments = [@[comment] mutableCopy];
			top[XMLDictionaryCommentsKey] = comments;
		}
		else
		{
			[comments addObject:comment];
		}
	}
}

@end


@implementation NSDictionary(XMLDictionary)

+ (NSDictionary<NSString *, id> *)dictionaryWithXMLParser:(NSXMLParser *)parser
{
	return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithParser:parser];
}

+ (NSDictionary<NSString *, id> *)dictionaryWithXMLData:(NSData *)data
{
	return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithData:data];
}

+ (NSDictionary<NSString *, id> *)dictionaryWithXMLString:(NSString *)string
{
	return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithString:string];
}

+ (NSDictionary<NSString *, id> *)dictionaryWithXMLFile:(NSString *)path
{
	return [[[XMLDictionaryParser sharedInstance] copy] dictionaryWithFile:path];
}

- (nullable NSDictionary<NSString *, NSString *> *)attributes
{
	NSDictionary<NSString *, NSString *> *attributes = self[XMLDictionaryAttributesKey];
	if (attributes)
	{
		return attributes.count? attributes: nil;
	}
	else
	{
		NSMutableDictionary<NSString *, id> *filteredDict = [NSMutableDictionary dictionaryWithDictionary:self];
        [filteredDict removeObjectsForKeys:@[XMLDictionaryCommentsKey, XMLDictionaryTextKey, XMLDictionaryNodeNameKey]];
        for (NSString *key in filteredDict.allKeys)
        {
            [filteredDict removeObjectForKey:key];
            if ([key hasPrefix:XMLDictionaryAttributePrefix])
            {
                filteredDict[[key substringFromIndex:XMLDictionaryAttributePrefix.length]] = self[key];
            }
        }
        return filteredDict.count? filteredDict: nil;
	}
	return nil;
}

- (nullable NSDictionary *)childNodes
{	
	NSMutableDictionary *filteredDict = [self mutableCopy];
	[filteredDict removeObjectsForKeys:@[XMLDictionaryAttributesKey, XMLDictionaryCommentsKey, XMLDictionaryTextKey, XMLDictionaryNodeNameKey]];
	for (NSString *key in filteredDict.allKeys)
    {
        if ([key hasPrefix:XMLDictionaryAttributePrefix])
        {
            [filteredDict removeObjectForKey:key];
        }
    }
    return filteredDict.count? filteredDict: nil;
}

- (nullable NSArray *)comments
{
	return self[XMLDictionaryCommentsKey];
}

- (nullable NSString *)nodeName
{
	return self[XMLDictionaryNodeNameKey];
}

- (id)innerText
{	
	id text = self[XMLDictionaryTextKey];
	if ([text isKindOfClass:[NSArray class]])
	{
		return [text componentsJoinedByString:@"\n"];
	}
	else
	{
		return text;
	}
}

- (NSString *)innerXML
{	
	NSMutableArray *nodes = [NSMutableArray array];
	
	for (NSString *comment in [self comments])
	{
        [nodes addObject:[NSString stringWithFormat:@"<!--%@-->", [comment XMLEncodedString]]];
	}
    
    NSDictionary *childNodes = [self childNodes];
	for (NSString *key in childNodes)
	{
		[nodes addObject:[XMLDictionaryParser XMLStringForNode:childNodes[key] withNodeName:key]];
	}
	
    NSString *text = [self innerText];
    if (text)
    {
        [nodes addObject:[text XMLEncodedString]];
    }
	
	return [nodes componentsJoinedByString:@"\n"];
}

- (NSString *)XMLString
{
    if (self.count == 1 && ![self nodeName])
    {
        //ignore outermost dictionary
        return [self innerXML];
    }
    else
    {
        return [XMLDictionaryParser XMLStringForNode:self withNodeName:[self nodeName] ?: @"root"];
    }
}

- (nullable NSArray *)arrayValueForKeyPath:(NSString *)keyPath
{
    id value = [self valueForKeyPath:keyPath];
    if (value && ![value isKindOfClass:[NSArray class]])
    {
        return @[value];
    }
    return value;
}

- (nullable NSString *)stringValueForKeyPath:(NSString *)keyPath
{
    id value = [self valueForKeyPath:keyPath];
    if ([value isKindOfClass:[NSArray class]])
    {
        value = ((NSArray *)value).firstObject;
    }
    if ([value isKindOfClass:[NSDictionary class]])
    {
        return [(NSDictionary *)value innerText];
    }
    return value;
}

- (nullable NSDictionary<NSString *, id> *)dictionaryValueForKeyPath:(NSString *)keyPath
{
    id value = [self valueForKeyPath:keyPath];
    if ([value isKindOfClass:[NSArray class]])
    {
        value = [value count]? value[0]: nil;
    }
    if ([value isKindOfClass:[NSString class]])
    {
        return @{XMLDictionaryTextKey: value};
    }
    return value;
}

@end


@implementation NSString (XMLDictionary)

- (NSString *)XMLEncodedString
{	
	return [[[[[self stringByReplacingOccurrencesOfString:@"&" withString:@"&amp;"]
               stringByReplacingOccurrencesOfString:@"<" withString:@"&lt;"]
              stringByReplacingOccurrencesOfString:@">" withString:@"&gt;"]
             stringByReplacingOccurrencesOfString:@"\"" withString:@"&quot;"]
            stringByReplacingOccurrencesOfString:@"\'" withString:@"&apos;"];
}

@end

//调用

#import "AppDelegate.h"
#import "WeChatManager.h"
@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    return YES;
}

#pragma mark ————————— 9.0以后使用 —————————————
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
    return [WXApi handleOpenURL:url delegate:[WeChatManager shareManager]];
}
@end
#import "ViewController.h"
#import "WeChatManager.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // Pods for WXPay
    // 1. pod 'WechatOpenSDK'
    // 2.用到一个 XMLDictionary 工具类拖入项目
    WeChatManager *wx = [WeChatManager shareManager];
//    [wx weiXinPayName:@"商品名字" money:0.01f];
//    [wx weChatShare:@"标题" content:@"详细内容" url:@"http://wwww.baidu.com" image:nil scenetype:(WechtShareTypeFriends)];
    [wx weChatLogin];
}

@end

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值