因?yàn)榻陧?xiàng)目中需要接入支付寶支付功能妖碉,自己也爬了很多的坑忽肛,所以做了一下這邊文章供大家學(xué)習(xí)參考,遠(yuǎn)離爬坑损敷,文章主要講到以下五部分:
一葫笼、支付寶開(kāi)放平臺(tái)創(chuàng)建應(yīng)用
二、簽約移動(dòng)支付功能
三拗馒、接入支付前的準(zhǔn)備工作附準(zhǔn)備工作中遇到難題的解決方法
四路星、配置官方Demo附BUG解決方法
五、集成項(xiàng)目诱桂,具體代碼編寫洋丐、
本文為本人學(xué)習(xí)記錄筆記,如需轉(zhuǎn)載挥等,請(qǐng)注明出處@iOSlyon
支付寶開(kāi)放平臺(tái)創(chuàng)建應(yīng)用 登錄支付寶開(kāi)放平臺(tái)
1. 應(yīng)用創(chuàng)建完成后點(diǎn)擊查看我的應(yīng)用詳情進(jìn)行移動(dòng)支付功能的簽約
或者
2.進(jìn)入支付寶商家服務(wù)頁(yè)面"https://b.alipay.com/newIndex.htm"選擇移動(dòng)支付功能進(jìn)行簽約
簽約過(guò)程以下以簽約移動(dòng)支付功能為例子
商戶簽約審核簽約審核具體步驟請(qǐng)參見(jiàn)支付寶官方文檔簽約與審核
或者
??????? 下列圖示
-
填寫簽約信息
上圖的附件文檔
因?yàn)橛写挝臋n錯(cuò)誤導(dǎo)致審核不通過(guò)友绝,所以以下貼出審核成功的文檔供大家參考
上述簽約步驟審核通過(guò)之后就可以開(kāi)始集成工作了
接入前準(zhǔn)備工作
第一步、商戶密鑰管理密鑰作用
這個(gè)步驟完全可以看官方文檔中的操作肝劲,官方文檔寫得很詳細(xì)迁客,但是其中有幾點(diǎn)需要說(shuō)明:
一郭宝、說(shuō)明問(wèn)題
上傳密鑰步驟不知道怎么上傳?因?yàn)槊荑€是pem文件哲泊,但是上傳的是字符串文本剩蟀。
一、解決方法
將生成的pem文件復(fù)制一份到桌面切威,改成Txt文件打開(kāi)即可獲取我們需要的字符串育特,記住當(dāng)我們引用這兩個(gè)長(zhǎng)的字符串時(shí),字符串不能包括先朦,換行缰冤,空格,以及其他誤加的字符喳魏,所以復(fù)制的時(shí)候一定要小心棉浸。
二、說(shuō)明問(wèn)題
Mac 自帶openssl環(huán)境刺彩,不用安裝迷郑,直接終端輸入openssl
就可以。
配置官方Demo代碼部分下載Demo
支付寶官方Demo中需要配置商戶的資料(如下)
//開(kāi)放平臺(tái)登錄https://openhome.alipay.com/platform/appManage.htm
//管理中心獲取APPID
#define MXAlipayAPPID @"請(qǐng)配置你的AppID"
//支付寶私鑰(用戶自主生成创倔,使用pkcs8格式的私鑰)
#define MXAlipayPrivateKey @"請(qǐng)配置你的支付寶pkcs8私鑰"
配置以上數(shù)據(jù)后嗡害,真機(jī)編譯,遇到以下問(wèn)題
- 輸出錯(cuò)誤信息
如配置信息中的私鑰(即上述PartnerPrivKey)使用的不適pkcs8的私鑰的話畦攘,則會(huì)報(bào)以下錯(cuò)誤
rsa_private read error : private key is NULL
- 解決方法:
-
方法一
將私鑰轉(zhuǎn)成PKCS8替換一下原私鑰即可轉(zhuǎn)換方法如下
( PHP服務(wù)端語(yǔ)言讀取私鑰不需要PKCS8轉(zhuǎn)換)
OpenSSL> genrsa -out rsa_private_key.pem 1024 #生成私鑰
OpenSSL> pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out rsa_private_key_pkcs8.pem #Java開(kāi)發(fā)者需要將私鑰轉(zhuǎn)換成PKCS8格式
OpenSSL> rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem #生成公鑰
OpenSSL> exit #退出OpenSSL程序
-
方法二
檢查PID是否寫正確
接下來(lái)重新運(yùn)行霸妹,上述錯(cuò)誤已經(jīng)解決,但遇到新問(wèn)題如下圖
-
彈框顯示
-
解決方法: 可參考百度中查到的結(jié)果上述問(wèn)題解決方法
- 問(wèn)題源頭是因?yàn)樗借€跟商戶上傳的公鑰不匹配
處理完上述問(wèn)題之后,就可以進(jìn)行支付操作了
測(cè)試Demo具體操作
1.創(chuàng)建一個(gè)AlipayDemoTest項(xiàng)目
2.新建一個(gè)AliSDK文件夾知押,提取SDK包中以下文件到此文件夾里叹螟,
3.編譯項(xiàng)目,會(huì)出現(xiàn)以下問(wèn)題:
1)"Unknown type name ‘NSString‘ "或"Unknown type name ‘NSData‘ "
這是因?yàn)槿鄙貴oundation類庫(kù)和UIKit類庫(kù)台盯,支付寶Demo中之所以沒(méi)有出現(xiàn)此錯(cuò)誤罢绽,是因?yàn)樵?pch文件中導(dǎo)入過(guò)這些類庫(kù)
解決辦法:只需要在出現(xiàn)錯(cuò)誤的文件中導(dǎo)入這些類庫(kù)即可
2)‘openssl/asn1.h‘ file not found
這是openssl文件夾頭文件鏈接問(wèn)題,如果openssl文件夾隨意拉進(jìn)項(xiàng)目中静盅,即使添加頭文件鏈接有缆,也可能解決不了此問(wèn)題,
這也是一開(kāi)始就將所需要的文件放到一個(gè)新建文件夾中再添加到項(xiàng)目中的原因温亲。
解決辦法:
Targets->Build Settings->Header Search Path中添加AliPaySDK文件夾的路徑
4.編譯項(xiàng)目棚壁,會(huì)出現(xiàn)以下問(wèn)題:
解決方法:在xcode中,點(diǎn)擊項(xiàng)目名栈虚,選擇"target"->"Link Binary With Libraries"添加依賴庫(kù)袖外。
編輯程序,已經(jīng)可以成功編譯了魂务,接下來(lái)就是集成代碼了
#import "AppDelegate.h"
#import <AlipaySDK/AlipaySDK.h>
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
if ([url.host isEqualToString:@"safepay"]) {
//跳轉(zhuǎn)支付寶錢包進(jìn)行支付曼验,處理支付結(jié)果
[[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
NSLog(@"result = %@",resultDic);
}];
}
return YES;
}
// NOTE: 9.0以后使用新API接口
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
if ([url.host isEqualToString:@"safepay"]) {
//跳轉(zhuǎn)支付寶錢包進(jìn)行支付泌射,處理支付結(jié)果
[[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
NSLog(@"result = %@",resultDic);
}];
}
return YES;
}
@end
#import "ViewController.h"
#import "Order.h"
#import "DataSigner.h"
#import <AlipaySDK/AlipaySDK.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
/*=========================================================*/
/*====客戶端調(diào)用支付寶支付(實(shí)際操作請(qǐng)放到服務(wù)端)=================*/
/*=========================================================*/
//AppId和PrivateKey沒(méi)有配置下的提示
if ( [MXAlipayAPPID length] == 0
||[MXAlipayPrivateKey length] == 0
||[MXAlipayAPPID isEqualToString:@"請(qǐng)配置你的AppID"]
||[MXAlipayPrivateKey isEqualToString:@"請(qǐng)配置你的支付寶pkcs8私鑰"])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示"
message:@"缺少appId或者私鑰。"
delegate:self
cancelButtonTitle:@"確定"
otherButtonTitles:nil];
[alert show];
return;
}
//商品價(jià)格
NSString *price = [NSString stringWithFormat:@"%.2f", 0.01];
//將商品信息賦予AlixPayOrder的成員變量
Order* order = [Order new];
order.app_id = MXAlipayAPPID;// NOTE: app_id設(shè)置
order.method = MXUrlAlipay; // NOTE: 支付接口名稱
order.charset = @"utf-8"; // NOTE: 參數(shù)編碼格式
NSDateFormatter* formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
order.timestamp = [formatter stringFromDate:[NSDate date]]; // NOTE: 當(dāng)前時(shí)間點(diǎn)
order.version = @"1.0"; // NOTE: 支付版本
order.sign_type = @"RSA"; // NOTE: sign_type設(shè)置
// NOTE: 商品數(shù)據(jù)
order.biz_content = [BizContent new];
order.biz_content.body = @"我是測(cè)試數(shù)據(jù)";
order.biz_content.subject = @"1";
order.biz_content.out_trade_no = [self generateTradeNO]; //訂單ID(由商家自行制定)
order.biz_content.timeout_express = @"30m"; //超時(shí)時(shí)間設(shè)置
order.biz_content.total_amount = price; //商品價(jià)格
//將商品信息拼接成字符串
NSString *orderInfo = [order orderInfoEncoded:NO];
NSString *orderInfoEncoded = [order orderInfoEncoded:YES];
NSLog(@"orderSpec = %@",orderInfo);
// NOTE: 獲取私鑰并將商戶信息簽名鬓照,外部商戶的加簽過(guò)程請(qǐng)務(wù)必放在服務(wù)端熔酷,防止公私鑰數(shù)據(jù)泄露;
// 需要遵循RSA簽名規(guī)范豺裆,并將簽名字符串base64編碼和UrlEncode
id<DataSigner> signer = CreateRSADataSigner(MXAlipayPrivateKey);
NSString *signedString = [signer signString:orderInfo];
// NOTE: 如果加簽成功拒秘,則繼續(xù)執(zhí)行支付
if (signedString != nil) {
//應(yīng)用注冊(cè)scheme,在AliSDKDemo-Info.plist定義URL types
NSString *appScheme = MXURLScheme;
// NOTE: 將簽名成功字符串格式化為訂單字符串,請(qǐng)嚴(yán)格按照該格式
NSString *orderString = [NSString stringWithFormat:@"%@&sign=%@",
orderInfoEncoded, signedString];
// NOTE: 調(diào)用支付結(jié)果開(kāi)始支付
[[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
NSLog(@"reslut = %@",resultDic);
}];
}
}
#pragma mark - Private Method
//==============產(chǎn)生隨機(jī)訂單號(hào)==============
+ (NSString *)generateTradeNO
{
static int kNumber = 15;
NSString *sourceStr = @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
NSMutableString *resultStr = [[NSMutableString alloc] init];
srand((unsigned)time(0));
for (int i = 0; i < kNumber; i++)
{
unsigned index = rand() % [sourceStr length];
NSString *oneStr = [sourceStr substringWithRange:NSMakeRange(index, 1)];
[resultStr appendString:oneStr];
}
return resultStr;
}
@end
這里也可以下載我自己搭建的DEMO
已解決所有錯(cuò)誤
下載后替換掉MXAlipayConfig.h中的配置參數(shù)即可運(yùn)行,前提是你的參數(shù)不能錯(cuò)
使用方法可以參考Demo中的ReadMe文件
正式接入階段
服務(wù)端
負(fù)責(zé)生成訂單及簽名,及接受支付異步通知臭猜。
客戶端
負(fù)責(zé)使用服務(wù)端傳來(lái)的訂單信息調(diào)用支付寶支付接口躺酒,及根據(jù)SDK同步返回的支付結(jié)果展示結(jié)果頁(yè)。
服務(wù)端接入
私鑰必須放在服務(wù)端蔑歌,簽名過(guò)程必須放在服務(wù)端羹应。
集成支付寶后打包ipa,報(bào)如下一系列警告:
解決方法:
- Go to Build Settings -> Build Options -> Debug Information Format
- Change the Debug setting from "DWARF with dSYM File" to "DWARF"
- Leave the Release setting at "DWARF with dSYM File"
AlipaySDK.framework 是先 build 的靜態(tài) lib 次屠,然后轉(zhuǎn)成的 framework 园匹,但是在 build 靜態(tài) lib 時(shí) CLANG_ENABLE_MODULES 沒(méi)有被設(shè)置成 disabled 。