iOS 接入微信SDK封裝的工具類HHWeixinSDK(微信登錄,微信好友和朋友圈分享,微信支付(客戶端簽名))

SDK下載

這里是微信官方的SDK下載接入流程文檔

手動(dòng)集成的話需要添加依賴庫(kù)

將SDK文件中包含的 libWeChatSDK.a,WXApi.h,WXApiObject.h 三個(gè)文件添加到你所建的工程中,在Build Phases下面的Link Binary With Libraries項(xiàng)中添加下面所需的依賴庫(kù):

661823-7bc9bc5416528645.png

工程配置屬性

在你的工程文件中選擇Build Setting,在"Other Linker Flags"中加入"-Objc -all_load"

設(shè)置URL Scheme

修改 info.plist 文件 URL types 項(xiàng)中后面的URL Schemes內(nèi)容為"wx+ appid",例如:wx1234567890
(我這里設(shè)置了支付寶,qq,微信,微博,只用到微信的話,就添加微信的就ok)


2EA80578-7343-433E-8803-73E4E826BE11.png

添加URL Schemes白名單

在“Info.plist”中增加一個(gè)LSApplicationQueriesSchemes值,設(shè)置為array, 添加微信需要的幾個(gè)item:
wechat
weixin

簽名安全問(wèn)題(這里是客戶端來(lái)簽名的)

這里后臺(tái)只生成了prepayId提供給我們,簽名是在我們iOS客戶端來(lái)簽名的,(為什么呢?因?yàn)槲覀兒笈_(tái)不會(huì)生成簽名╮(╯﹏╰)╭),需要微信給我們的AppID,密鑰和商戶號(hào),跟支付寶接入一樣,簽名在客戶端來(lái)做是有點(diǎn)安全問(wèn)題的,具體請(qǐng)參考我封裝的HHAliPaySDK,簽名放在服務(wù)端來(lái)做,提供給我們,既方便又安全,但是沒辦法,他做不來(lái),只能我們來(lái)做,希望你們后臺(tái)人員比較給力.

然后就就可以愉快的寫代碼了

創(chuàng)建了一個(gè)繼承于NSObject的 HHWeixinSDK工具類(涉及微信登錄,微信好友和朋友圈分享,微信支付),而且我在其中封裝了一下微信支付時(shí)向后臺(tái)請(qǐng)求prepayId的方法和處理回調(diào)結(jié)果用到的方法.
ps:這個(gè)類中有網(wǎng)絡(luò)請(qǐng)求,HHttpManager是我自己對(duì)AFNetworking3.0的二次封裝,感興趣的可以看一看,不感興趣的同學(xué)可以用AFN或者自己的網(wǎng)絡(luò)框架.

.h文件

#import <Foundation/Foundation.h>

@interface HHWeixinSDK : NSObject
/**
 實(shí)例化
 */
+(instancetype) shareInstance;

/**
 初始化微信SDK
 */
+(void)initSDK;

/**
 打開其他app的回調(diào)
 */
+(BOOL)handleOpenURL:(NSURL *)url;

/** 
 調(diào)用微信登錄接口 
 */
+(void)sendWeixinLoginRequest;


/** 
 查看微信是否安裝 
 */
+ (BOOL)isWeiXinInstall;

/**
 根據(jù)訂單信息向后臺(tái)申請(qǐng)prepayId以調(diào)用微信支付接口
 
 @param userId   用戶登錄app的標(biāo)識(shí)id
 @param orderId  訂單號(hào),由后臺(tái)提供
 @param account  金額
 */
+ (void)sendWeixinPayRequestWithUserId:(NSString *)userId
                               orderId:(NSString *)orderId
                               account:(NSString *)account;

/**
 分享到微信好友
 
 @param title    分享的文字標(biāo)題
 @param content  分享的文字內(nèi)容
 @param urlStr   分享的圖片URL字符串
 */
+ (void)shareToWeixinFriendWithTitle:(NSString *)title
                             Content:(NSString *)content
                         imageURLStr:(NSString *)urlStr;

/**
 分享到微信朋友圈
 
 @param title    分享的文字標(biāo)題
 @param content  分享的文字內(nèi)容
 @param urlStr   分享的圖片URL字符串
 */
+ (void)shareToWeixinFriendsCircleWithTitle:(NSString *)title
                                    Content:(NSString *)content
                                imageURLStr:(NSString *)urlStr;

@end

.m文件

#import "HHWeixinSDK.h"
#import "WXApi.h"
//MD5加密需要導(dǎo)入的頭文件
#import <CommonCrypto/CommonCrypto.h>

//微信接口
#define Weixin_GetAccessTokenURL    @"https://api.weixin.qq.com/sns/oauth2/access_token?appid=%@&secret=%@&code=%@&grant_type=authorization_code"
#define Weixin_isAccessTokenCanUse     @"https://api.weixin.qq.com/sns/auth?access_token=%@&openid=%@"
#define Weixin_UseRefreshToken      @"https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=wx8daa93036f9c7721&grant_type=refresh_token&refresh_token=%@"
#define Weixin_GetUserInformation  @"https://api.weixin.qq.com/sns/userinfo?access_token=%@&openid=%@"


@interface HHWeixinSDK ()<WXApiDelegate>

@end

@implementation HHWeixinSDK

static NSString * safeURL(NSString * origin) {
    return [origin stringByAddingPercentEscapesUsingEncoding:
             NSUTF8StringEncoding];
}

static HHWeixinSDK* _instance = nil;

//單例
+(instancetype) shareInstance{
    static dispatch_once_t onceToken ;
    dispatch_once(&onceToken, ^{
        _instance = [[super allocWithZone:NULL] init] ;
    }) ;
    
    return _instance ;
}

+(id) allocWithZone:(struct _NSZone *)zone{
    return [HHWeixinSDK shareInstance] ;
}

-(id) copyWithZone:(NSZone *)zone{
    return [HHWeixinSDK shareInstance] ;//return _instance;
}

-(id) mutablecopyWithZone:(NSZone *)zone{
    return [HHWeixinSDK shareInstance] ;
}

#pragma mark - 回調(diào)
-(void)onReq:(BaseReq *)req{
    
}

-(void)onResp:(BaseResp *)resp{
    /** 微信登錄 */
    if([resp isKindOfClass:[SendAuthResp class]]){
        if (resp.errCode == 0) {
            [self loginWeixinSuccessWithBaseResp:resp];
        }else{
            //登錄失敗
        }
    }
    
    /** 微信支付 */
    if ([resp isKindOfClass:[PayResp class]]){
        [self handleWeixinPayCallBackResultWithPayResp:resp];
    }
}

+(void)initSDK {
    // 打開微信的登錄
     [WXApi registerApp:Weixin_AppID];
}

+(BOOL)handleOpenURL:(NSURL *)url {
    return [WXApi handleOpenURL:url delegate:[self shareInstance]];
}

+(void)sendWeixinLoginRequest{
    //構(gòu)造SendAuthReq結(jié)構(gòu)體
    SendAuthReq* req =[[SendAuthReq alloc ] init ];
    req.scope = @"snsapi_userinfo" ;
    req.state = @"123" ;
    //第三方向微信終端發(fā)送一個(gè)SendAuthReq消息結(jié)構(gòu)
    [WXApi sendReq:req];
}

+ (BOOL)isWeiXinInstall{
    return  [WXApi isWXAppInstalled];
}

#pragma mark - 微信登錄成功獲取token
-(void)loginWeixinSuccessWithBaseResp:(BaseResp *)resp{
    SendAuthResp  *auth = (SendAuthResp*)resp;
    NSString *code = auth.code;
    NSLog(@"code:%@", code);
    //Weixin_AppID和Weixin_AppSecret是微信申請(qǐng)下發(fā)的.
    NSString *str = [NSString stringWithFormat:Weixin_GetAccessTokenURL,Weixin_AppID,Weixin_AppSecret,code];
    [HHttpManager GET:str success:^(id responseObject) {
        NSString *access_token = responseObject[@"access_token"];
        NSString *refresh_token = responseObject[@"refresh_token"];
        NSString *openid = responseObject[@"openid"];
        [self isAccess_tokenCanUseWithAccess_token:access_token openID:openid completionHandler:^(BOOL isCanUse) {
            if (isCanUse) {
                [self getUserInformationWithAccess_token:access_token openID:openid];
            }else{
                [self useRefresh_token:refresh_token];
            }
        }];
        
    } failure:^(NSError * error) {
        NSLog(@"請(qǐng)求失敗--%@",error);
    }];
    
}

#pragma mark - 判斷access_token是否過(guò)期
- (void)isAccess_tokenCanUseWithAccess_token:(NSString *)access_token openID:(NSString *)openID completionHandler:(void(^)(BOOL isCanUse))completeHandler{
    NSString *strOfSeeAccess_tokenCanUse = [NSString stringWithFormat:Weixin_isAccessTokenCanUse, access_token,openID];
    
    [HHttpManager GET:strOfSeeAccess_tokenCanUse success:^(id responseObject) {
        if ([responseObject[@"errmsg"] isEqualToString:@"ok"]) {
            completeHandler(YES);
        }else{
            completeHandler(NO);
        }
    } failure:^(NSError * error) {
        NSLog(@"請(qǐng)求失敗--%@",error);
        completeHandler(NO);
    }];
}

#pragma mark - 若過(guò)期,使用refresh_token獲取新的access_token
- (void)useRefresh_token:(NSString *)refresh_token{
    NSString *strOfUseRefresh_token = [NSString stringWithFormat:Weixin_UseRefreshToken, refresh_token];
    NSLog(@"%@", strOfUseRefresh_token);

    [HHttpManager GET:strOfUseRefresh_token success:^(id responseObject) {
        NSString *openid = responseObject[@"openid"];
        NSString *access_token = responseObject[@"access_token"];
        NSString *refresh_tokenNew = responseObject[@"refresh_token"];
        [self isAccess_tokenCanUseWithAccess_token:access_token openID:openid completionHandler:^(BOOL isCanUse) {
            if (isCanUse) {
                [self getUserInformationWithAccess_token:access_token openID:openid];
            }else{
                [self useRefresh_token:refresh_tokenNew];
            }
        }];
    } failure:^(NSError * error) {
        NSLog(@"請(qǐng)求失敗--%@",error);
    }];
}

#pragma mark - 若未過(guò)期,獲取用戶信息
- (void)getUserInformationWithAccess_token:(NSString *)access_token openID:(NSString *)openID{
    NSString *strOfGetUserInformation = [NSString stringWithFormat:Weixin_GetUserInformation, access_token,openID];
    [HHttpManager GET:strOfGetUserInformation success:^(id responseObject) {
        NSString *nickname = responseObject[@"nickname"];
        NSLog(@"nickname:%@", nickname);
        NSString *headimgurl = responseObject[@"headimgurl"];
        NSLog(@"headimgurl:%@", headimgurl);
                NSNumber *sexnumber = responseObject[@"sex"];
                NSString *sexstr = [NSString stringWithFormat:@"%@",sexnumber];
                NSString *sex;
                if ([sexstr isEqualToString:@"1"]) {
                    sex = @"男";
                }else if ([sexstr isEqualToString:@"2"]){
                    sex = @"女";
                }else{
                    sex = @"未知";
                }
//                NSString *province = responseObject[@"province"];
//                NSString *city = responseObject[@"city"];
//        //用戶統(tǒng)一標(biāo)識(shí)。針對(duì)一個(gè)微信開放平臺(tái)帳號(hào)下的應(yīng)用,同一用戶的unionid是唯一的。
//                    NSString *unionid = responseObject[@"unionid"];


//獲取到用戶信息后根據(jù)需要保存在本地或上傳到服務(wù)端,用作的用戶信息



    } failure:^(NSError * error) {
        NSLog(@"請(qǐng)求失敗--%@",error);
    }];
}

#pragma mark - 向后臺(tái)申請(qǐng)支付請(qǐng)求,獲取prepayId
+ (void)sendWeixinPayRequestWithUserId:(NSString *)userId
                               orderId:(NSString *)orderId
                               account:(NSString *)account{
    NSDictionary *paramDict = @{
                                @"userId":@(userId.integerValue),
                                @"orderId":orderId,
                                @"account":@(account.integerValue)
                                };
    //getWeixinPrepayID:后臺(tái)提供,用來(lái)向后臺(tái)請(qǐng)求prepayId的接口
     [HHttpManager POST:getWeixinPrepayID parameters:paramDict success:^(id responseObject) {
        NSNumber *state = responseObject[@"state"];
        if (state.integerValue == 0) {
            NSString *prepayId = responseObject[@"data"][0][@"prepayId"];
            //獲取prepayId后客戶端生成簽名然后發(fā)送支付請(qǐng)求
            [self weixinPayWithPrepayId:prepayId];
        }else{
            
        }
    } failure:^(NSError * error) {
        NSLog(@"請(qǐng)求失敗--%@",error);
        
    }];
}

#pragma mark - 調(diào)起微信客戶端,申請(qǐng)支付
+ (void)weixinPayWithPrepayId:(NSString *)prepayID{
//正常情況下,這里所有的參數(shù)都是后臺(tái)提供給我們,但是我們后臺(tái)人員不給力,只能我放在客戶端來(lái)做簽名了.希望你們后臺(tái)人員比較給力.
    PayReq *request = [[PayReq alloc] init];
    //微信支付分配的商戶號(hào)
    request.partnerId = Weixin_PartnerId;
    //后臺(tái)給的訂單ID
    request.prepayId= prepayID;
    //微信給的固定值,就這么寫
    request.package = @"Sign=WXPay";
    //32位隨機(jī)字符串
    request.nonceStr= [self get32RandomString];
    //時(shí)間戳
    request.timeStamp= [self getCurrentTimestamp].intValue;
    /** 
     *簽名
     
     *Weixin_AppID:微信開放平臺(tái)審核通過(guò)的應(yīng)用APPID
     *Weixin_AppKey:在微信商戶平臺(tái)(pay.weixin.qq.com)-->賬戶設(shè)置-->API安全-->密鑰設(shè)置 里面設(shè)置的微信密鑰
     */
    NSString * signStr = [NSString stringWithFormat:@"appid=%@&noncestr=%@&package=%@&partnerid=%@&prepayid=%@&timestamp=%u&key=%@",Weixin_AppID,request.nonceStr,request.package,request.partnerId,request.prepayId,(unsigned int)request.timeStamp,Weixin_AppKey];
    //將簽名進(jìn)行MD5運(yùn)算并轉(zhuǎn)換為大寫
    request.sign= [self stringFromUpperCaseMD5:signStr];
    //支付請(qǐng)求
    [WXApi sendReq:request];
}

#pragma mark - 微信支付是否成功的回調(diào)
-(void)handleWeixinPayCallBackResultWithPayResp:(BaseResp *)resp{
    PayResp *response=(PayResp *)resp;
    switch(response.errCode){
        case WXSuccess:
            //服務(wù)器端查詢支付通知或查詢API返回的結(jié)果再提示成功
            NSLog(@"支付成功");
            break;
        case WXErrCodeUserCancel:
            NSLog(@"用戶點(diǎn)擊取消并返回");
            break;
            
        default:
            NSLog(@"支付失敗,retcode=%d",resp.errCode);
            /**
             WXErrCodeCommon     = -1,   普通錯(cuò)誤類型
             WXErrCodeUserCancel = -2,   用戶點(diǎn)擊取消并返回
             WXErrCodeSentFail   = -3,   發(fā)送失敗
             WXErrCodeAuthDeny   = -4,   授權(quán)失敗
             WXErrCodeUnsupport  = -5,   微信不支持
             */
            
            
            break;
    }
    
}


#pragma mark - 微信分享
//分享到微信好友
+ (void)shareToWeixinFriendWithTitle:(NSString *)title
                             Content:(NSString *)content
                            imageURLStr:(NSString *)urlStr{
    WXMediaMessage *message = [WXMediaMessage message];
    message.title = title;
    message.description = content;
    
    //縮略圖
    NSData *thumbData = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlStr]];
    UIImage *thumbImage = [UIImage imageWithData:thumbData];
    [message setThumbImage:thumbImage];
    //大圖
    WXWebpageObject *webpageObject = [WXWebpageObject object];
    webpageObject.webpageUrl = urlStr;
    message.mediaObject = webpageObject;
    
    SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
    req.bText = NO;
    req.message = message;
    req.scene = WXSceneSession;
    [WXApi sendReq:req];

}


//分享到朋友圈
+ (void)shareToWeixinFriendsCircleWithTitle:(NSString *)title
                             Content:(NSString *)content
                         imageURLStr:(NSString *)urlStr{
    WXMediaMessage *message = [WXMediaMessage message];
    message.title = title;
    message.description = content;
    
    //縮略圖
    NSData *thumbData = [NSData dataWithContentsOfURL:[NSURL URLWithString:safeURL(urlStr)]];
    UIImage *thumbImage = [UIImage imageWithData:thumbData];
    [message setThumbImage:thumbImage];
    //大圖
    WXWebpageObject *webpageObject = [WXWebpageObject object];
    webpageObject.webpageUrl = safeURL(urlStr);
    message.mediaObject = webpageObject;
    
    SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
    req.bText = NO;
    req.message = message;
    req.scene = WXSceneTimeline;
    [WXApi sendReq:req];
    
}


/** 生成32位隨機(jī)字符串 */
+(NSString *)get32RandomString{
    
    NSString *string = [[NSString alloc]init];
    for (int i = 0; i < 32; i++) {
        int number = arc4random() % 36;
        if (number < 10) {
            int figure = arc4random() % 10;
            NSString *tempString = [NSString stringWithFormat:@"%d", figure];
            string = [string stringByAppendingString:tempString];
        }else {
            int figure = (arc4random() % 26) + 97;
            char character = figure;
            NSString *tempString = [NSString stringWithFormat:@"%c", character];
            string = [string stringByAppendingString:tempString];
        }
    }
    return string;
    
}

//獲取當(dāng)前時(shí)間的時(shí)間戳
+(NSString*)getCurrentTimestamp{
    NSDate* date = [NSDate dateWithTimeIntervalSinceNow:0];
    NSTimeInterval timestamp=[date timeIntervalSince1970];
    NSString*timeString = [NSString stringWithFormat:@"%0.f", timestamp];
    //    NSLog(@"%@", timeString);
    return timeString;
}

//MD5加密大寫
+ (NSString *)stringFromUpperCaseMD5:(NSString *)sourceString{
    const char *string = sourceString.UTF8String;
    unsigned char bytes[CC_MD5_DIGEST_LENGTH];
    extern unsigned char * CC_MD5(const void *data, CC_LONG len, unsigned char *md);
    CC_MD5(string, (CC_LONG)strlen(string), bytes);
    NSMutableString *md5Str = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH];
    for (NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++) {
        [md5Str appendFormat:@"%02x", bytes[count]];
    }
    return [md5Str uppercaseString];
}


@end

設(shè)置

在AppDelegate.m文件中初始化

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 //微信
    [HHWeixinSDK initSDK];
}

openURL方法中設(shè)置回調(diào)(這里一個(gè)是iOS9以下的系統(tǒng)調(diào)用的系統(tǒng)方法和一個(gè)是iOS9以上的系統(tǒng)調(diào)用的系統(tǒng)方法,都要設(shè)置)

#pragma mark - OpenURL回調(diào)結(jié)果
//iOS9-
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
    [self handleOpenURLWithURLHost:url];
    return YES;
}
//iOS9和9+
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options{
    [self handleOpenURLWithURLHost:url];
    return YES;
}

- (void)handleOpenURLWithURLHost:(NSURL *)url{
 NSLog(@"url.host:%@", url.host);
   //微信(登錄,支付,分享)
   if ([url.host isEqualToString:@"oauth"]||[url.host isEqualToString:@"pay"]||[url.host isEqualToString:@"platformId=wechat"]) {
        [HHWeixinSDK handleOpenURL:url];
    }


}

調(diào)用

調(diào)用之前需要判斷是否安裝了微信

/** 
 查看微信是否安裝 
 */
+ (BOOL)isWeiXinInstall;

如果上述方法返回YES,直接調(diào)用接口就好,個(gè)人喜歡類方法,調(diào)用方便,可根據(jù)喜好自行修改.當(dāng)然,前提是你已經(jīng)取得了微信支付和登錄分享的授權(quán)

/** 
 調(diào)用微信登錄接口 
 */
+(void)sendWeixinLoginRequest;

/**
 根據(jù)訂單信息向后臺(tái)申請(qǐng)prepayId以調(diào)用微信支付接口
 
 @param userId   用戶id
 @param orderId  訂單信息
 @param account  金額
 */
+ (void)sendWeixinPayRequestWithUserId:(NSString *)userId
                               orderId:(NSString *)orderId
                               account:(NSString *)account;

/**
 分享到微信好友
 
 @param title    分享的文字標(biāo)題
 @param content  分享的文字內(nèi)容
 @param urlStr   分享的圖片URL字符串
 */
+ (void)shareToWeixinFriendWithTitle:(NSString *)title
                             Content:(NSString *)content
                         imageURLStr:(NSString *)urlStr;

/**
 分享到微信朋友圈
 
 @param title    分享的文字標(biāo)題
 @param content  分享的文字內(nèi)容
 @param urlStr   分享的圖片URL字符串
 */
+ (void)shareToWeixinFriendsCircleWithTitle:(NSString *)title
                                    Content:(NSString *)content
                                imageURLStr:(NSString *)urlStr;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,553評(píng)論 19 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,023評(píng)論 25 709
  • 今日推薦 經(jīng)常閱讀博客是個(gè)好習(xí)慣推薦鴻洋CSDN的博客 微信支付相關(guān)文章 詳細(xì)介紹Android開發(fā)集成微信支付(...
    MrQ_Android閱讀 6,281評(píng)論 9 52
  • 實(shí)現(xiàn)支付寶支付的準(zhǔn)備工作: 1.向支付寶簽約,成為支付寶的商戶 簽約完成后,支付寶會(huì)提供一些必要的數(shù)據(jù)給我們 商戶...
    Anson楊春安閱讀 8,627評(píng)論 0 6
  • 自己總結(jié)的微信支付寶支付流程和注意點(diǎn): 準(zhǔn)備工作: 需要公司的營(yíng)業(yè)執(zhí)照,稅務(wù)信息,等老板的身份證信息等,我記得,用...
    Www劉閱讀 18,681評(píng)論 2 50

友情鏈接更多精彩內(nèi)容