SDK下载
手动集成的话需要添加依赖库
将SDK文件中包含的 libWeChatSDK.a,WXApi.h,WXApiObject.h 三个文件添加到你所建的工程中,在Build Phases下面的Link Binary With Libraries项中添加下面所需的依赖库:
工程配置属性
在你的工程文件中选择Build Setting,在"Other Linker Flags"中加入"-Objc -all_load"
设置URL Scheme
修改 info.plist 文件 URL types 项中后面的URL Schemes内容为"wx+ appid",例如:wx1234567890
(我这里设置了支付宝,qq,微信,微博,只用到微信的话,就添加微信的就ok)
添加URL Schemes白名单
在“Info.plist”中增加一个LSApplicationQueriesSchemes值,设置为array, 添加微信需要的几个item:
wechat
weixin
签名安全问题(这里是客户端来签名的)
这里后台只生成了prepayId提供给我们,签名是在我们iOS客户端来签名的,(为什么呢?因为我们后台不会生成签名╮(╯﹏╰)╭),需要微信给我们的AppID,密钥和商户号,跟支付宝接入一样,签名在客户端来做是有点安全问题的,具体请参考我封装的HHAliPaySDK,签名放在服务端来做,提供给我们,既方便又安全,但是没办法,他做不来,只能我们来做,希望你们后台人员比较给力.
然后就就可以愉快的写代码了
创建了一个继承于NSObject的 HHWeixinSDK工具类(涉及微信登录,微信好友和朋友圈分享,微信支付),而且我在其中封装了一下微信支付时向后台请求prepayId的方法和处理回调结果用到的方法.
ps:这个类中有网络请求,HHttpManager是我自己对AFNetworking3.0的二次封装,感兴趣的可以看一看,不感兴趣的同学可以用AFN或者自己的网络框架.
.h文件
#import <Foundation/Foundation.h>
@interface HHWeixinSDK : NSObject
/**
实例化
*/
+(instancetype) shareInstance;
/**
初始化微信SDK
*/
+(void)initSDK;
/**
打开其他app的回调
*/
+(BOOL)handleOpenURL:(NSURL *)url;
/**
调用微信登录接口
*/
+(void)sendWeixinLoginRequest;
/**
查看微信是否安装
*/
+ (BOOL)isWeiXinInstall;
/**
根据订单信息向后台申请prepayId以调用微信支付接口
@param userId 用户登录app的标识id
@param orderId 订单号,由后台提供
@param account 金额
*/
+ (void)sendWeixinPayRequestWithUserId:(NSString *)userId
orderId:(NSString *)orderId
account:(NSString *)account;
/**
分享到微信好友
@param title 分享的文字标题
@param content 分享的文字内容
@param urlStr 分享的图片URL字符串
*/
+ (void)shareToWeixinFriendWithTitle:(NSString *)title
Content:(NSString *)content
imageURLStr:(NSString *)urlStr;
/**
分享到微信朋友圈
@param title 分享的文字标题
@param content 分享的文字内容
@param urlStr 分享的图片URL字符串
*/
+ (void)shareToWeixinFriendsCircleWithTitle:(NSString *)title
Content:(NSString *)content
imageURLStr:(NSString *)urlStr;
@end
.m文件
#import "HHWeixinSDK.h"
#import "WXApi.h"
//MD5加密需要导入的头文件
#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 - 回调
-(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{
//构造SendAuthReq结构体
SendAuthReq* req =[[SendAuthReq alloc ] init ];
req.scope = @"snsapi_userinfo" ;
req.state = @"123" ;
//第三方向微信终端发送一个SendAuthReq消息结构
[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是微信申请下发的.
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"];
// //用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。
// NSString *unionid = responseObject[@"unionid"];
//获取到用户信息后根据需要保存在本地或上传到服务端,用作的用户信息
} 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后客户端生成签名然后发送支付请求
[self weixinPayWithPrepayId:prepayId];
}else{
}
} failure:^(NSError * error) {
NSLog(@"请求失败--%@",error);
}];
}
#pragma mark - 调起微信客户端,申请支付
+ (void)weixinPayWithPrepayId:(NSString *)prepayID{
//正常情况下,这里所有的参数都是后台提供给我们,但是我们后台人员不给力,只能我放在客户端来做签名了.希望你们后台人员比较给力.
PayReq *request = [[PayReq alloc] init];
//微信支付分配的商户号
request.partnerId = Weixin_PartnerId;
//后台给的订单ID
request.prepayId= prepayID;
//微信给的固定值,就这么写
request.package = @"Sign=WXPay";
//32位随机字符串
request.nonceStr= [self get32RandomString];
//时间戳
request.timeStamp= [self getCurrentTimestamp].intValue;
/**
*签名
*Weixin_AppID:微信开放平台审核通过的应用APPID
*Weixin_AppKey:在微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 里面设置的微信密钥
*/
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];
//将签名进行MD5运算并转换为大写
request.sign= [self stringFromUpperCaseMD5:signStr];
//支付请求
[WXApi sendReq:request];
}
#pragma mark - 微信支付是否成功的回调
-(void)handleWeixinPayCallBackResultWithPayResp:(BaseResp *)resp{
PayResp *response=(PayResp *)resp;
switch(response.errCode){
case WXSuccess:
//服务器端查询支付通知或查询API返回的结果再提示成功
NSLog(@"支付成功");
break;
case WXErrCodeUserCancel:
NSLog(@"用户点击取消并返回");
break;
default:
NSLog(@"支付失败,retcode=%d",resp.errCode);
/**
WXErrCodeCommon = -1, 普通错误类型
WXErrCodeUserCancel = -2, 用户点击取消并返回
WXErrCodeSentFail = -3, 发送失败
WXErrCodeAuthDeny = -4, 授权失败
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位随机字符串 */
+(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;
}
//获取当前时间的时间戳
+(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
设置
在AppDelegate.m文件中初始化
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//微信
[HHWeixinSDK initSDK];
}
openURL方法中设置回调(这里一个是iOS9以下的系统调用的系统方法和一个是iOS9以上的系统调用的系统方法,都要设置)
#pragma mark - OpenURL回调结果
//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];
}
}
调用
调用之前需要判断是否安装了微信
/**
查看微信是否安装
*/
+ (BOOL)isWeiXinInstall;
如果上述方法返回YES,直接调用接口就好,个人喜欢类方法,调用方便,可根据喜好自行修改.当然,前提是你已经取得了微信支付和登录分享的授权
/**
调用微信登录接口
*/
+(void)sendWeixinLoginRequest;
/**
根据订单信息向后台申请prepayId以调用微信支付接口
@param userId 用户id
@param orderId 订单信息
@param account 金额
*/
+ (void)sendWeixinPayRequestWithUserId:(NSString *)userId
orderId:(NSString *)orderId
account:(NSString *)account;
/**
分享到微信好友
@param title 分享的文字标题
@param content 分享的文字内容
@param urlStr 分享的图片URL字符串
*/
+ (void)shareToWeixinFriendWithTitle:(NSString *)title
Content:(NSString *)content
imageURLStr:(NSString *)urlStr;
/**
分享到微信朋友圈
@param title 分享的文字标题
@param content 分享的文字内容
@param urlStr 分享的图片URL字符串
*/
+ (void)shareToWeixinFriendsCircleWithTitle:(NSString *)title
Content:(NSString *)content
imageURLStr:(NSString *)urlStr;