SDK下載
手動集成的話需要添加依賴庫
將SDK文件中包含的 libWeChatSDK.a骗绕,WXApi.h,WXApiObject.h 三個文件添加到你所建的工程中,在Build Phases下面的Link Binary With Libraries項中添加下面所需的依賴庫:
工程配置屬性
在你的工程文件中選擇Build Setting,在"Other Linker Flags"中加入"-Objc -all_load"
設(shè)置URL Scheme
修改 info.plist 文件 URL types 項中后面的URL Schemes內(nèi)容為"wx+ appid",例如:wx1234567890
(我這里設(shè)置了支付寶,qq,微信,微博,只用到微信的話,就添加微信的就ok)
添加URL Schemes白名單
在“Info.plist”中增加一個LSApplicationQueriesSchemes值,設(shè)置為array, 添加微信需要的幾個item:
wechat
weixin
簽名安全問題(這里是客戶端來簽名的)
這里后臺只生成了prepayId提供給我們,簽名是在我們iOS客戶端來簽名的,(為什么呢?因為我們后臺不會生成簽名╮(╯﹏╰)╭),需要微信給我們的AppID,密鑰和商戶號,跟支付寶接入一樣,簽名在客戶端來做是有點(diǎn)安全問題的,具體請參考我封裝的HHAliPaySDK,簽名放在服務(wù)端來做,提供給我們,既方便又安全,但是沒辦法,他做不來,只能我們來做,希望你們后臺人員比較給力.
然后就就可以愉快的寫代碼了
創(chuàng)建了一個繼承于NSObject的 HHWeixinSDK工具類(涉及微信登錄,微信好友和朋友圈分享,微信支付),而且我在其中封裝了一下微信支付時向后臺請求prepayId的方法和處理回調(diào)結(jié)果用到的方法.
ps:這個類中有網(wǎng)絡(luò)請求,HHttpManager是我自己對AFNetworking3.0的二次封裝,感興趣的可以看一看,不感興趣的同學(xué)可以用AFN或者自己的網(wǎng)絡(luò)框架.
.h文件
#import <Foundation/Foundation.h>
@interface HHWeixinSDK : NSObject
/**
實例化
*/
+(instancetype) shareInstance;
/**
初始化微信SDK
*/
+(void)initSDK;
/**
打開其他app的回調(diào)
*/
+(BOOL)handleOpenURL:(NSURL *)url;
/**
調(diào)用微信登錄接口
*/
+(void)sendWeixinLoginRequest;
/**
查看微信是否安裝
*/
+ (BOOL)isWeiXinInstall;
/**
根據(jù)訂單信息向后臺申請prepayId以調(diào)用微信支付接口
@param userId 用戶登錄app的標(biāo)識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;
@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ā)送一個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是微信申請下發(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(@"請求失敗--%@",error);
}];
}
#pragma mark - 判斷access_token是否過期
- (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(@"請求失敗--%@",error);
completeHandler(NO);
}];
}
#pragma mark - 若過期,使用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(@"請求失敗--%@",error);
}];
}
#pragma mark - 若未過期,獲取用戶信息
- (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)識。針對一個微信開放平臺帳號下的應(yīng)用,同一用戶的unionid是唯一的。
// NSString *unionid = responseObject[@"unionid"];
//獲取到用戶信息后根據(jù)需要保存在本地或上傳到服務(wù)端,用作的用戶信息
} failure:^(NSError * error) {
NSLog(@"請求失敗--%@",error);
}];
}
#pragma mark - 向后臺申請支付請求,獲取prepayId
+ (void)sendWeixinPayRequestWithUserId:(NSString *)userId
orderId:(NSString *)orderId
account:(NSString *)account{
NSDictionary *paramDict = @{
@"userId":@(userId.integerValue),
@"orderId":orderId,
@"account":@(account.integerValue)
};
//getWeixinPrepayID:后臺提供,用來向后臺請求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ā)送支付請求
[self weixinPayWithPrepayId:prepayId];
}else{
}
} failure:^(NSError * error) {
NSLog(@"請求失敗--%@",error);
}];
}
#pragma mark - 調(diào)起微信客戶端,申請支付
+ (void)weixinPayWithPrepayId:(NSString *)prepayID{
//正常情況下,這里所有的參數(shù)都是后臺提供給我們,但是我們后臺人員不給力,只能我放在客戶端來做簽名了.希望你們后臺人員比較給力.
PayReq *request = [[PayReq alloc] init];
//微信支付分配的商戶號
request.partnerId = Weixin_PartnerId;
//后臺給的訂單ID
request.prepayId= prepayID;
//微信給的固定值,就這么寫
request.package = @"Sign=WXPay";
//32位隨機(jī)字符串
request.nonceStr= [self get32RandomString];
//時間戳
request.timeStamp= [self getCurrentTimestamp].intValue;
/**
*簽名
*Weixin_AppID:微信開放平臺審核通過的應(yīng)用APPID
*Weixin_AppKey:在微信商戶平臺(pay.weixin.qq.com)-->賬戶設(shè)置-->API安全-->密鑰設(shè)置 里面設(shè)置的微信密鑰
*/
NSString * signStr = [NSString stringWithFormat:@"appid=%@&noncestr=%@&package=%@&partnerid=%@&prepayid=%@×tamp=%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];
//支付請求
[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, 普通錯誤類型
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)前時間的時間戳
+(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)(這里一個是iOS9以下的系統(tǒng)調(diào)用的系統(tǒng)方法和一個是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)用接口就好,個人喜歡類方法,調(diào)用方便,可根據(jù)喜好自行修改.當(dāng)然,前提是你已經(jīng)取得了微信支付和登錄分享的授權(quán)
/**
調(diào)用微信登錄接口
*/
+(void)sendWeixinLoginRequest;
/**
根據(jù)訂單信息向后臺申請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;