微信支付最详解教程

最近要用微信支付功能,在此总结一下!

需要下面第三方支持

备注:JSONKit框架是基于MRC的,如果工程开发环境是ARC的话,请在编译时设定 编译参数 -fno-objc-arc

1、首先到微信开放平台上,申请app及与T进行签约、认证

https://open.weixin.qq.com/

获取到:

/**

*  微信开放平台申请得到的 appid, 需要同时添加在info.plist文件中URL schema,用于完成时,回调到app

*/

#define WXAppId @"wxd930ea5d5a258f4f"

#define WXAppSecret @"db426a9829e4b49a0dcac7b4162da6b6"

以上两个参数用于获取access_token

access_token是APP的全局唯一票据,APP调用各接口时都需使用access_token。正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效。

APP可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在开放平台后台获得。注意调用接口时需使用https协议。

接口调用请求说明

https://api.weixin.qq.com/cgi-

bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

返回说明

正常情况下,微信会返回下述JSON数据包给开发者:

{"access_token":"ACCESS_TOKEN","expires_in":7200}

参数说明:

appkey 、partnerId、partnerKey、paySignKey

appkey:appkey就是Paysignkey,申请支付通过之后由财付通下发。

partnerId:财付通商户身份的标识。审核通过后,在财付通发送的邮件中查看。

partnerKey:财付通商户权限密钥Key。审核通过后,在财付通发送的邮件中查看。

paySignKey:除了支付请求需要用到paySignKey,公众平台接口API的权限获取所需密钥Key,在使用所有公众平台API时,都需要先用它去换取access_token,然后再进行调用。审核通过后,在微信发送的邮件中查看。

2、代码实现

@interface SkyAppDelegate : UIResponder <UIApplicationDelegate, WXApiDelegate> //在appDelegate方法中实现WXApiDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

// 向微信终端注册appID

[WXApi registerApp:WXAppId withDescription:@"weixin demo"];

/*! @brief WXApi的成员函数,在微信终端程序中注册第三方应用。

*

* 需要在每次启动第三方应用程序时调用。第一次调用后,会在微信的可用应用列表中出现。

* @param appid 微信开发者ID

* @param appdesc 应用附加信息,长度不超过1024字节

* @return 成功返回YES,失败返回NO。

*/

return YES;

}

//用于完成支付后的程序回调,

- (BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation

{

NSLog(@"%@",url);//跳转到URL schema中配置的地址

return [WXApi handleOpenURL:url delegate:self];

}

//收到一个来自微信的处理结果。调用一次sendReq后会收到onResp。

- (void)onResp:(BaseResp *)resp

{

if ([resp isKindOfClass:[PayResp class]])

{

PayResp *response = (PayResp *)resp;

NSString *strTitle = [NSString stringWithFormat:@"支付结果"];

NSString *strMsg = [NSString stringWithFormat:@"errcode:%d", response.errCode];

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:strTitle

message:strMsg

delegate:self

cancelButtonTitle:@"OK"

otherButtonTitles:nil, nil];

[alert show];

switch (response.errCode) {

case WXSuccess: {

NSNotification *notification = [NSNotification notificationWithName:ORDER_PAY_NOTIFICATION object:@"success"];

[[NSNotificationCenter defaultCenter] postNotification:notification];

break;

}

default: {

NSNotification *notification = [NSNotification notificationWithName:ORDER_PAY_NOTIFICATION object:@"fail"];

[[NSNotificationCenter defaultCenter] postNotification:notification];

break;

}

}

}

}

为了保证发送请求的方便,自己封装了两个工具类

1、http

typedef void (^BKHttpCallback)(BOOL isSuccessed, NSDictionary *result);

/**

*  GET方法请求数据

*

*  @param url     请求的URL

*  @param params  请求参数

*  @param (BOOL isSuccessed, Result *result))callback  回调方法

*/

+ (void)doGetWithUrl:(NSString *)url path:(NSString *)path params:(NSDictionary *)params callback:(BKHttpCallback) callback;

/**

*  请求WebService数据

*

*  @param baseUrl  请求的基础URL

*  @param params   请求参数

*  @param (BOOL isSuccessed, Result *result))callback  回调方法

*/

+ (void)doPostWithUrl:(NSString *)url path:(NSString *)path params:(NSDictionary *)params callback:(BKHttpCallback)callback;

/**

*  Get方法请求图片

*

*  @param url      图片URL

*  @param (BOOL isSuccessed, Result *result))callback  回调方法

*/

+ (void)getImageWithUrl:(NSString *)url callback:(BKHttpCallback)callback;

.m文件

+ (void)doGetWithUrl:(NSString *)url path:(NSString *)path params:(NSDictionary *)params callback:(BKHttpCallback) callback

{

AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:url]];

[httpClient getPath:path

parameters:params

success:^(AFHTTPRequestOperation *operation, id responseObject){

NSString *responseJson = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];

if (responseJson)

{

NSDictionary *result = [responseJson objectFromJSONString];

callback(YES, result);

}

else

{

callback(NO, nil);

}

}

failure:^(AFHTTPRequestOperation *operation, NSError *error){

callback(NO, nil);

}];

}

+ (void)doPostWithUrl:(NSString *)url path:(NSString *)path params:(NSDictionary *)params callback:(BKHttpCallback)callback

{

AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:url]];

httpClient.parameterEncoding = AFJSONParameterEncoding;

[httpClient postPath:path

parameters:params

success:^(AFHTTPRequestOperation *operation, id responseObject){

NSString *responseJson = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];

if (responseJson)

{

NSDictionary *result = [responseJson objectFromJSONString];

callback(YES, result);

}

else

{

callback(NO, nil);

}

}

failure:^(AFHTTPRequestOperation *operation, NSError *error){

callback(NO, nil);

}];

}

+ (void)getImageWithUrl:(NSString *)url callback:(BKHttpCallback)callback

{

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];

AFImageRequestOperation *requestOperation = [[AFImageRequestOperation alloc] initWithRequest:request];

[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

UIImage *image = responseObject;

NSDictionary *result = @{@"image":image};

callback(YES, result);

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

callback(NO, nil);

}];

[requestOperation start];

}

2、MD5加密

+ (NSString *)md5:(NSString *)input;

+ (NSString *)sha1:(NSString *)input;

+ (NSString *)getIPAddress:(BOOL)preferIPv4;

+ (NSDictionary *)getIPAddresses;

.m文件

#define IOS_CELLULAR    @"pdp_ip0"

#define IOS_WIFI        @"en0"

#define IP_ADDR_IPv4    @"ipv4"

#define IP_ADDR_IPv6    @"ipv6"

@implementation CommonUtil

+ (NSString *)md5:(NSString *)input

{

const char *cStr = [input UTF8String];

unsigned char digest[16];

CC_MD5( cStr, strlen(cStr), digest ); // This is the md5 call

NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];

for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)

[output appendFormat:@"%02x", digest[i]];

return  output;

}

+ (NSString *)sha1:(NSString *)input

{

const char *ptr = [input UTF8String];

int i =0;

int len = strlen(ptr);

Byte byteArray[len];

while (i!=len)

{

unsigned eachChar = *(ptr + i);

unsigned low8Bits = eachChar & 0xFF;

byteArray[i] = low8Bits;

i++;

}

unsigned char digest[CC_SHA1_DIGEST_LENGTH];

CC_SHA1(byteArray, len, digest);

NSMutableString *hex = [NSMutableString string];

for (int i=0; i<20; i++)

[hex appendFormat:@"%02x", digest[i]];

NSString *immutableHex = [NSString stringWithString:hex];

return immutableHex;

}

+ (NSString *)getIPAddress:(BOOL)preferIPv4

{

NSArray *searchArray = preferIPv4 ?

@[ IOS_WIFI @"/" IP_ADDR_IPv4, IOS_WIFI @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6 ] :

@[ IOS_WIFI @"/" IP_ADDR_IPv6, IOS_WIFI @"/" IP_ADDR_IPv4, IOS_CELLULAR @"/" IP_ADDR_IPv6, IOS_CELLULAR @"/" IP_ADDR_IPv4 ] ;

NSDictionary *addresses = [self getIPAddresses];

//NSLog(@"addresses: %@", addresses);

__block NSString *address;

[searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)

{

address = addresses[key];

if(address) *stop = YES;

} ];

return address ? address : @"0.0.0.0";

}

+ (NSDictionary *)getIPAddresses

{

NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8];

// retrieve the current interfaces - returns 0 on success

struct ifaddrs *interfaces;

if(!getifaddrs(&interfaces)) {

// Loop through linked list of interfaces

struct ifaddrs *interface;

for(interface=interfaces; interface; interface=interface->ifa_next) {

if(!(interface->ifa_flags & IFF_UP) || (interface->ifa_flags & IFF_LOOPBACK)) {

continue; // deeply nested code harder to read

}

const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;

if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {

NSString *name = [NSString stringWithUTF8String:interface->ifa_name];

char addrBuf[INET6_ADDRSTRLEN];

if(inet_ntop(addr->sin_family, &addr->sin_addr, addrBuf, sizeof(addrBuf))) {

NSString *key = [NSString stringWithFormat:@"%@/%@", name, addr->sin_family == AF_INET ? IP_ADDR_IPv4 : IP_ADDR_IPv6];

addresses[key] = [NSString stringWithUTF8String:addrBuf];

}

}

}

// Free memory

freeifaddrs(interfaces);

}

// The dictionary keys have the form "interface" "/" "ipv4 or ipv6"

return [addresses count] ? addresses : nil;

}

主体代码:

#define BASE_URL @"https://api.weixin.qq.com"

@interfaceSkyViewController ()

@property (nonatomic, copy) NSString *timeStamp;

@property (nonatomic, copy) NSString *nonceStr;

@property (nonatomic, copy) NSString *traceId;

@end

@implementation SkyViewController

- (void)viewDidLoad

{

[super viewDidLoad];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getOrderPayResult:) name:ORDER_PAY_NOTIFICATION object:nil];//监听一个通知

}

- (void)dealloc

{

[[NSNotificationCenter defaultCenter]removeObserver:self];//移除通知

}

- (void)didReceiveMemoryWarning

{

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

- (IBAction)pay:(id)sender

{

[self getAccessToken];//获取access_token

}

#pragma mark - 主体流程

// 获取token

- (void)getAccessToken

{

NSString *tokenUrl = @"cgi-bin/token";

NSDictionary *param = @{@"grant_type":@"client_credential", @"appid":WXAppId, @"secret":WXAppSecret};

[HttpUtil doGetWithUrl:BASE_URL

path:tokenUrl

params:param

callback:^(BOOL isSuccessed, NSDictionary *result){

NSString *accessToken = result[AccessTokenKey];

[self getPrepayId:accessToken];

}];

}

// 生成预支付订单

- (void)getPrepayId:(NSString *)accessToken

{

NSString *prepayIdUrl = [NSString stringWithFormat:@"pay/genprepay?access_token=%@", accessToken];

// 拼接详细的订单数据

NSDictionary *postDict = [self getProductArgs];

[HttpUtil doPostWithUrl:BASE_URL

path:prepayIdUrl

params:postDict

callback:^(BOOL isSuccessed, NSDictionary *result){

NSString *prePayId = result[PrePayIdKey];

// 获取预支付订单id,调用微信支付sdk

if (prePayId)

{

NSLog(@"--- PrePayId: %@", prePayId);

// 调起微信支付

PayReq *request   = [[PayReq alloc] init];

request.partnerId = WXPartnerId;

request.prepayId  = prePayId;

request.package   = @"Sign=WXPay";

request.nonceStr  = self.nonceStr;

request.timeStamp = [self.timeStamp intValue];

// 构造参数列表

NSMutableDictionary *params = [NSMutableDictionary dictionary];

[params setObject:WXAppId forKey:@"appid"];

[params setObject:WXAppKey forKey:@"appkey"];

[params setObject:request.nonceStr forKey:@"noncestr"];

[params setObject:request.package forKey:@"package"];

[params setObject:request.partnerId forKey:@"partnerid"];

[params setObject:request.prepayId forKey:@"prepayid"];

[params setObject:self.timeStamp forKey:@"timestamp"];

request.sign = [self genSign:params];

// 在支付之前,如果应用没有注册到微信,应该先调用 [WXApi registerApp:appId] 将应用注册到微信

[WXApi safeSendReq:request];//发送一个安全请求

}

}];

}

#pragma mark - 生成各种参数

// 获取时间戳

- (NSString *)genTimeStamp

{

return [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];

}

/**

*  获取32位内的随机串, 防重发

*

*  注意:商户系统内部的订单号,32个字符内、可包含字母,确保在商户系统唯一

*/

- (NSString *)genNonceStr

{

return [CommonUtil md5:[NSString stringWithFormat:@"%d", arc4random() % 10000]];

}

/**

*  获取商家对用户的唯一标识

*

*  traceId 由开发者自定义,可用于订单的查询与跟踪,建议根据支付用户信息生成此id

*  建议 traceid 字段包含用户信息及订单信息,方便后续对订单状态的查询和跟踪

*/

- (NSString *)genTraceId

{

return [NSString stringWithFormat:@"crestxu_%@", [self genTimeStamp]];

}

- (NSString *)genOutTradNo

{

return [CommonUtil md5:[NSString stringWithFormat:@"%d", arc4random() % 10000]];

}

// 订单详情

- (NSString *)genPackage

{

// 构造订单参数列表

NSMutableDictionary *params = [NSMutableDictionary dictionary];

[params setObject:@"WX" forKey:@"bank_type"];

[params setObject:@"千足金箍棒" forKey:@"body"];

[params setObject:@"1" forKey:@"fee_type"];

[params setObject:@"UTF-8" forKey:@"input_charset"];

[params setObject:@"http://weixin.qq.com" forKey:@"notify_url"];

[params setObject:[self genOutTradNo] forKey:@"out_trade_no"];

[params setObject:WXPartnerId forKey:@"partner"];

[params setObject:[CommonUtil getIPAddress:YES] forKey:@"spbill_create_ip"];

[params setObject:@"1" forKey:@"total_fee"];    // 1 == ¥0.01

NSArray *keys = [params allKeys];

NSArray *sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {

return [obj1 compare:obj2 options:NSNumericSearch];

}];

// 生成 packageSign

NSMutableString *package = [NSMutableString string];

for (NSString *key in sortedKeys) {

[package appendString:key];

[package appendString:@"="];

[package appendString:[params objectForKey:key]];

[package appendString:@"&"];

}

[package appendString:@"key="];

[package appendString:WXPartnerKey]; // 注意:不能hardcode在客户端,建议genPackage这个过程都由服务器端完成

// 进行md5摘要前,params内容为原始内容,未经过url encode处理

NSString *packageSign = [[CommonUtil md5:[package copy]] uppercaseString];

package = nil;

// 生成 packageParamsString

NSString *value = nil;

package = [NSMutableString string];

for (NSString *key in sortedKeys)

{

[package appendString:key];

[package appendString:@"="];

value = [params objectForKey:key];

// 对所有键值对中的 value 进行 urlencode 转码

value = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)value, nil, (CFStringRef)@"!*‘&=();:@+$,/?%#[]", kCFStringEncodingUTF8));

[package appendString:value];

[package appendString:@"&"];

}

NSString *packageParamsString = [package substringWithRange:NSMakeRange(0, package.length - 1)];

NSString *result = [NSString stringWithFormat:@"%@&sign=%@", packageParamsString, packageSign];

NSLog(@"--- Package: %@", result);

return result;

}

// 签名

- (NSString *)genSign:(NSDictionary *)signParams

{

// 排序

NSArray *keys = [signParams allKeys];

NSArray *sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {

return [obj1 compare:obj2 options:NSNumericSearch];

}];

// 生成

NSMutableString *sign = [NSMutableString string];

for (NSString *key in sortedKeys) {

[sign appendString:key];

[sign appendString:@"="];

[sign appendString:[signParams objectForKey:key]];

[sign appendString:@"&"];

}

NSString *signString = [[sign copy] substringWithRange:NSMakeRange(0, sign.length - 1)];

NSString *result = [CommonUtil sha1:signString];

NSLog(@"--- Gen sign: %@", result);

return result;

}

// 构造订单参数列表

- (NSDictionary *)getProductArgs

{

self.timeStamp = [self genTimeStamp];   // 获取时间戳

self.nonceStr = [self genNonceStr];     // 获取32位内的随机串, 防重发

self.traceId = [self genTraceId];       // 获取商家对用户的唯一标识

NSMutableDictionary *params = [NSMutableDictionary dictionary];

[params setObject:WXAppId forKey:@"appid"];

[params setObject:WXAppKey forKey:@"appkey"];

[params setObject:self.timeStamp forKey:@"noncestr"];

[params setObject:self.timeStamp forKey:@"timestamp"];

[params setObject:self.traceId forKey:@"traceid"];

[params setObject:[self genPackage] forKey:@"package"];

[params setObject:[self genSign:params] forKey:@"app_signature"];

[params setObject:@"sha1" forKey:@"sign_method"];

return params;

}

#pragma mark - 支付结果

- (void)getOrderPayResult:(NSNotification *)notification

{

if ([notification.object isEqualToString:@"success"])

{

NSLog(@"success: 支付成功");

}

else

{

NSLog(@"fail: 支付失败");

}

}

这只是一个简单的使用,里面没有用到数据模型,在使用过程中,里面的有些参数要转成数据模型。

时间: 2024-10-02 04:47:32

微信支付最详解教程的相关文章

基于H5的微信支付开发详解

这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可供参考,有的朋友直接看文档就可以自己实现此支付接口的开发了. 一.前言 为何我还写一篇微信支付接口的博文呢?第一,我们必须知道,所谓的工作经验很多都是靠总结出来的,你只有总结了更多知识,积累了更多经验,你才能在该行业中脱颖而出,我个人觉得如今的招聘,很多都需要工作经验(1年.3年.5年....),其

****基于H5的微信支付开发详解[转]

这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可供参考,有的朋友直接看文档就可以自己实现此支付接口的开发了. 一.前言 为何我还写一篇微信支付接口的博文呢?第一,我们必须知道,所谓的工作经验很多都是靠总结出来的,你只有总结了更多知识,积累了更多经验,你才能在该行业中脱颖而出,我个人觉得如今的招聘,很多都需要工作经验(1年.3年.5年....),其

iOS 微信支付流程详解

背景 自微信支付.支付宝支付入世以来,移动端的支付日渐火热.虚拟货币有取代实体货币的趋向(这句纯属扯淡,不用管),支付在app开发中是一项基本的功能,有必要去掌握.从难易程度上讲,不管是微信支付还是支付宝支付都是非常简单的,因为第三方的支付文档非常详细,而且他们内部的安全性也非常高.作为使用这些支付策略的我们,只需要掌握流程,能够实现正常支付的功能即可.为什么要写下这篇博文,原因有二.其一,微信支付流程中有坑,其二,以后忘记了可以拿出来看看. 配置 1.微信支付需要两个账号,财付通和微信开发者,

Linux计划任务Crontab实例详解教程

说明:Crontab是Linux系统中在固定时间执行某一个程序的工具,类似于Windows系统中的任务计划程序 下面通过详细实例来说明在Linux系统中如何使用Crontab 操作系统:CentOS 一.安装crontab yum install vixie-cron  #安装 chkconfig crond on  #设为开机启动,先要安装chkconfig(yum install chkconfig) service crond start  #启动 service crond stop  

杠铃俯身划船:杠铃俯身划船动作详解教程

杠铃俯身划船:杠铃俯身划船动作详解教程  杠铃俯身划船(Barbell Bent-over Row)主要锻炼中部背阔肌,是增加背阔肌厚度的最佳方法,因此是一项最普遍最受青睐的背阔肌增肌训练.许多运动员和健身爱好者用上百公斤的杠铃做俯身划船练习. 目标肌群:背阔肌中部(即内侧).大圆肌 动作要领: 1.宽距站姿,双手正握,握距比肩稍宽,双臂完全伸直:微微屈膝,从臀部屈背,保持身体成45度角不变:持铃在身前,稍稍低于膝盖. 2.收紧肩胛骨,绷紧整个上身,将杠铃提至上腹部. 3.稍停顿,然后缓缓下铃回

微信支付PHP SDK —— 公众号支付代码详解

在微信支付 开发者文档页面 下载最新的 php SDK http://mch.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1 这里假设你已经申请完微信支付 1. 微信后台配置  如图 我们先进行测试,所以先把测试授权目录和 测试白名单添加上.测试授权目录是你要发起微信请求的哪个文件所在的目录. 例如jsapi 发起请求一般是jsapi.php所在目录 为测试目录,测试白名单即开发人员的微信号. 正式的支付授权目录不能和测试的一样否则会报错.不填

2017-9月微信公众号支付-Java详解

微信支付源代码 在此之前,先C麻瓜藤N遍,MD官方文档一半正确一半错误.言归正传, 微信支付整体流程:微信授权登录商户的公众号--微信支付的公众号配置--统一下单--微信js调起支付页面--输入密码支付--支付成功,异步回调URL处理商户的相应业务 一.业务场景: 先看一下支付的业务场景:用户使用微信登录商户页面,点击支付按钮,调起微信支付,选择付款卡号,输入密码,完成支付,如图: 场景十分简单,不过步骤比较多,稍不注意就掉坑里了. 二.微信公众号支付的配置准备: 1)调用公众号支付,首先你得有

【微信小程序】支付过程详解

一.介绍 今天跟大家分享微信小程序集成支付. 二.分析 1.小程序支付API 地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-pay.html#wxrequestpaymentobject 注释: 通过接口的查看,我们知道,小程序端要想使用支付的接口,必须要拿到相应的值 timeStamp:Linux时间戳,可获取本地时间. nonceStr:随机字符串,从服务器统一下单接口返回. package:统一下单接口返回的prepay_id参数

微信支付之扫码、APP、小程序支付接入详解

做电商平台的小伙伴都知道,支付服务是必不可少的一部分,今天我们开始就说说支付服务的接入及实现.目前在国内,几乎90%中小公司的支付系统都离不开微信支付和支付宝支付.那么大家要思考了,为什么微信支付和支付宝支付能作为大多数公司接入的首选呢?其实这个问题大多小伙伴应该是很清楚的,说白了就是人家有庞大的用户流量,目前微信在国内的用户已突破10亿,支付宝也接近8亿左右,如此庞大的用户群体,你还会选择其他的第三方支付(微博钱包.财付通.快钱等)吗,作为普通客户,大家都希望能方便快捷,谁会为了在一个平台买点