当开发者已完成 **手机网站支付服务端接入** 后可以通过 Native 支付方式唤起支付宝 App。
为了节约开发成本,商家在自有App内嵌H5页接入手机网站支付,由于手机网站支付的网络依赖比较严重,通常需要经过更多的验证, 这样会降低支付的成功率。为了能够帮助商家使用 Native-H5 混合 App 以极低的接入成本 极大的 提升支付成功率,平台推出了手机网站支付转 Native 支付方式,商家下载使用 [支付宝标准版 SDK](https://ideservice.alipay.com/cms/site/02km9l) 内置的功能完成手机网站支付。
**注意**:若未安装支付宝App参考下图,点击下载支付宝App付款下载之后再进行支付。
下面以淘宝为例对比手机网站支付和手机网站转 Native 支付的流程。
## 手机网站支付流程
在手机端浏览器中访问淘宝主页 www.taobao.com,在页面挑选商品并进行付款,点击 **立即支付** 进入付款详情页面(H5 页面)。
### iOS

### Android

## 手机网站转 Native 支付流程
[下载](https://gw.alipayobjects.com/os/bmw-prod/35af7422-15e4-4605-be0a-e5caf653d50f.zip) 并运行 Demo,将 Demo App 安装到手机上即可体验该流程,并在 Demo 中打开淘宝主页 www.taobao.com,挑选商品并进行付款。
**注意**:请确保手机上安装了支付宝客户端。
### iOS
点击 **URLPay** >** openUrl**,输入 www.taobao.com 并点击 **Go**,然后在淘宝主页选中商品并付款。

### Android
点击 **网页支付转native** 然后在淘宝主页选中商品并付款。

## 对比总结
手机网站支付与手机网站转 Native 支付的主要区别为:
- 如果用户手机安装了支付宝客户端,手机网站转 Native 支付方式将跳转到支付宝客户端中进行订单支付,用户体验和支付成功率均优于手机网站支付方式。除此之外,还能使用手机网站支付没有提供的指纹支付、手环支付、手表支付、免密支付等功能。
- 如果用户手机没有安装支付宝客户端,将在 SDK 提供的 Web-view 中打开 H5 页面进行支付。即便如此,由于 SDK 与服务端的交互携带账号信息,仍比不携带任何账号信息的普通手机网站支付体验更好。
## 如何实现手机网站转Native支付
要实现上述功能需接入支付宝提供的 SDK。接入过程十分简单,可以以上述 Demo 为参考,该 Demo 程序只有一个功能:创建一个 Web-view,在 Web-view 中拦截每个 URL,然后调用 SDK 提供的接口检查该 URL 是否是有效的支付宝订单支付 URL,如果是则将该 URL 传给 SDK 提供的支付接口进行支付。
# iOS 接入说明
## 配置
**步骤1:**启动 IDE(如 Xcode),把 iOS 包中的压缩文件中以下文件拷贝到项目文件夹下,并导入到项目工程中。
```csharp
AlipaySDK.bundle
AlipaySDK.framework
```
在 Build Phases 选项卡的 Link Binary With Libraries 中,增加以下依赖:
其中,需要注意的是:
- 如果是 Xcode 7.0 之后的版本,需要添加 libc++.tbd、libz.tbd。
- 如果是 Xcode 7.0 之前的版本,需要添加 libc++.dylib、libz.dylib(如下图)。
**步骤2:**在需要调用 AlipaySDK 的文件中,增加头文件引用。
```csharp
#import
```
**步骤3:**配置支付宝客户端返回 URL 处理方法。外部存在支付宝客户端,支付宝客户端将处理结果通过 url 返回。如示例 AliSDKDemo\APAppDelegate.m 文件中,增加引用代码:
```csharp
#import
```
在 _@_implementation AppDelegate 中增加如下代码:
```csharp
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
//如果极简开发包不可用,会跳转支付宝客户端进行支付,需要将支付宝客户端的支付结果回传给开发包
if ([url.host isEqualToString:@"safepay"]) {
[[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
//【由于在跳转支付宝客户端支付的过程中,商户App在后台很可能被系统kill了,所以pay接口的callback就会失效,请商户对standbyCallback返回的回调结果进行处理,就是在这个方法里面处理跟callback一样的逻辑】
NSLog(@"result = %@",resultDic);
}];
}
if ([url.host isEqualToString:@"platformapi"]){//支付宝客户端快登授权返回authCode
[[AlipaySDK defaultService] processAuthResult:App在后台很可能被系统kill了,所以pay接口的callback就会失效,请商户对standbyCallback返回的回调结果进行处理,就是在这个方法里面处理跟callback一样的逻辑】
NSLog(@"result = %@",resultDic);
}];
}
return YES;
}
```
## 接口调用说明
本 SDK 提供的所有接口均定义在 AlipaySDK.h 中。SDK 中提供了若干接口,手机网站转 Native 支付只用到其中一部分,本文未提到的接口无需关注。
### 调用提供的接口
App 支付最新版本 15.4.0 新增拦截+支付二合一接口(payInterceptorWithUrl... ),该接口将原来的获取 H5 支付订单信息接口和支付接口进行了合并。接口的调用方式是先调用 defaultService 获取 SDK 的实例,然后再调用单独提供的功能接口,以 payInterceptorWithUrl 为例:
```csharp
[[AlipaySDK defaultService] payInterceptorWithUrl:url fromScheme:scheme callback:^(NSDictionary *result) {
// 处理支付结果
NSLog(@"%@", result);
}];
```
### 实现手机网站转APP支付
1. 实现 UIWebViewDelegate 协议,拦截 H5 的 URL。
2. 调用新增拦截+支付二合一接口(payInterceptorWithUrl...)进行 URL 拦截及支付转化;具体查看下文 **拦截+支付二合一接口**。
## 拦截+支付二合一接口
本接口首先是个拦截器,拦截支付宝 H5 支付 URL。其次是个支付方式转化器,将手机网站支付方式转化为 APP 支付方式。
### 示例代码
```csharp
/**
* 支付宝H5支付URL拦截器,完成拦截及支付方式转化
*
* @param urlStr 待过滤拦截的 url string
* @param schemeStr 调用支付的App注册在info.plist中的scheme
* @param compltionBlock 支付结果回调Block
*
* @return YES:表示URL为支付宝支付URL,URL已经被拦截转化;NO:表示URL非支付宝支付URL;
*/
- (BOOL)payInterceptorWithUrl:(NSString *)urlStr
fromScheme:(NSString *)schemeStr
callback:(CompletionBlock)completionBlock;
```
### 参数说明
| **参数名称** | **类型** | **说明** |
| --- | --- | --- |
| urlStr | NSString * | 手机网站支付的请求 URL。 |
| schemeStr | NSString * | 接入方 App 注册的 URL scheme,供支付完成后跳回接入方 App。 |
| completionBlock | objc(^CompletionBlock)(NSDictionary *resultDic) | 支付结束之后的回调,其中 CompletionBlock 定义如下:`objctypedef void(^CompletionBlock)(NSDictionary \\*resultDic);` |
### 同步拦截结果返回值说明
| **返回值类型** | **描述** |
| --- | --- |
| BOOL |
- 如果 urlStr 是有效的支付宝 H5 支付 URL,则说明拦截转化成功,返回 YES,商户容器无需再加载该 URL。
- 如果是无效的,则返回 NO,商户容器需要继续加载该 URL。
|
### 异步支付结果返回值说明
支付结束后 SDK 将回调 completionBlock,并将支付结果 resultDic(NSDictionary *类型)作为参数传入该 Block。resultDic 中主要包含两个字段,如下所示:
| **参数名称** | **类型** | **说明** |
| --- | --- | --- |
| resultCode | NSString * | 返回码,标识支付状态,含义如下:
9000——订单支付成功
8000——正在处理中
4000——订单支付失败
5000——重复请求
6001——用户中途取消
6002——网络连接出错 |
| returnUrl | NSString * | 支付结束后应当跳转的 URL 地址。 |
### 接口使用方式
调用本接口对支付宝支付 URL 进行拦截和支付转化。当接口调用完成后,该接口会返回一个 BOOL 类型的同步拦截结果:
- 如果同步结果返回值为 YES,说明传入的 URL 为支付宝支付 URL,支付宝 SDK 已经成功拦截该 URL,并转化为 App 支付方式,商户容器无需再加载该 URL。
- 如果返回值为 NO,说明传入的 URL 并非支付宝支付 URL,商户容器需要继续加载该URL。
当支付结束后,会通过回调的方式返回异步支付结果:
- 如果返回的支付结果中的 resultCode 为 9000,则表示支付成功,接入方可以提示用户支付成功。
- 如果返回结果不是 9000,则无需做任何处理。当返回的 returnUrl 不为空,建议接入方跳转到该 returnUrl。
```csharp
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
__weak APWebViewController* wself = self;
BOOL isIntercepted = [[AlipaySDK defaultService] payInterceptorWithUrl:[request.URL absoluteString] fromScheme:@"alisdkdemo" callback:^(NSDictionary *result) {
// 处理支付结果
NSLog(@"%@", result);
// isProcessUrlPay 代表 支付宝已经处理该URL
if ([result[@"isProcessUrlPay"] boolValue]) {
// returnUrl 代表 第三方App需要跳转的成功页URL
NSString* urlStr = result[@"returnUrl"];
[wself loadWithUrlStr:urlStr];
}
}];
if (isIntercepted) {
return NO;
}
return YES;
}
```
# Android接入说明
## 配置
### 导入开发资源
1. 将 alipaySdk-xxxxxxxx.jar 包放入商户应用工程的 libs 目录下,如下图。

2. 进入商家应用工程的 Project Structure,在 app module 下选择 File dependency,将 libs 目录下的 alipaySDK-xxxxxxxx.jar 导入,如下图。
或者在 app module 下的 build.gradle 下手动添加依赖,如下代码所示:
```json
dependencies {
......
compile files('libs/alipaySdk-20170725.jar')
......
}
```
### 修改 Manifest
在商家应用工程的 AndroidManifest.xml 文件里面添加声明:
```html
```
和权限声明:
```html
```
### 添加混淆规则
在商家应用工程的 proguard-project.txt 里添加以下相关规则:
```csharp
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IAlixPay$Stub{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{ public *;}
-keep class com.alipay.sdk.app.AuthTask{ public *;}
-keep class com.alipay.sdk.app.H5PayCallback {
;
;
}
-keep class com.alipay.android.phone.mrpc.core.** { *; }
-keep class com.alipay.apmobilesecuritysdk.** { *; }
-keep class com.alipay.mobile.framework.service.annotation.** { *; }
-keep class com.alipay.mobilesecuritysdk.face.** { *; }
-keep class com.alipay.tscenter.biz.rpc.** { *; }
-keep class org.json.alipay.** { *; }
-keep class com.alipay.tscenter.** { *; }
-keep class com.ta.utdid2.** { *;}
-keep class com.ut.device.** { *;}
```
至此,开发包开发资源导入完成。
## 接口调用说明
SDK中提供了若干接口,手机网站转 Native 支付只用到其中一部分,本文未提到的接口无需关注。
### 调用提供的接口
APP 支付最新版本 15.4.0 新增拦截+支付二合一接口(payInterceptorWithUrl...),该接口将原来的获取 H5 支付订单信息接口和支付接口进行了合并。
### 实现手机网站转Native支付
1. 在接入方 App 中拦截 H5 的 URL。
2. 调用新增拦截+支付二合一接口(payInterceptorWithUrl...)进行 URL 拦截及支付转化;具体可查看下方** 拦截+支付二合一接口**。
## 拦截+支付二合一接口
本接口首先是个拦截器,拦截支付宝 H5 支付 URL;其次是个支付方式转化器,将手机网站支付方式转化为APP支付方式。
### 示例代码
```csharp
/**
* 支付宝H5支付URL拦截器,完成拦截及支付方式转化
*
* @param h5PayUrl 待过滤拦截的 URL
* @param isShowPayLoading 是否出现loading
* @param callback 异步回调接口
*
* @return true:表示URL为支付宝支付URL,URL已经被拦截并支付转化;false:表示URL非支付宝支付URL;
*
*/
public synchronized boolean payInterceptorWithUrl(final String h5PayUrl, final boolean isShowPayLoading, final H5PayCallback callback)
```
### 参数说明
| **参数名称** | **类型** | **说明** |
| --- | --- | --- |
| h5PayUrl | String | 手机网站支付的请求 URL。 |
| isShowPayLoading | boolean | 是否出现 loading。 |
| callback | H5PayCallback | 异步回调接口。 |
### 同步拦截结果返回值说明
| **返回值类型** | **描述** |
| --- | --- |
| boolean |
- 如果 h5PayUrl 是有效的支付宝 H5 支付 URL,则说明拦截转化成功,返回 true,商户容器无需再加载该 URL。
- 如果是无效的,则返回 false,商户容器需要继续加载该 URL。
|
### 异步支付结果返回值说明
支付结束后 SDK 将回调 H5PayCallback,并将支付结果 H5PayResultModel 作为参数传入该 Callback。H5PayResultModel 中主要包含两个字段,如下所示:
| **参数名称** | **类型** | **说明** |
| --- | --- | --- |
| resultCode | String | 返回码,标识支付状态,含义如下:
9000——订单支付成功
8000——正在处理中
4000——订单支付失败
5000——重复请求
6001——用户中途取消
6002——网络连接出错 |
| returnUrl | String | 支付结束后应当跳转的 URL 地址。 |
### 接口使用方式
调用本接口对支付宝支付 URL 进行拦截和支付转化。当接口调用完成后,该接口会返回一个 boolean 类型的同步拦截结果。
- 如果同步结果返回值为 true,说明传入的 URL 为支付宝支付 URL,支付宝 SDK 已经成功拦截该 URL,并转化为 APP 支付方式,商户容器无需再加载该 URL。
- 如果返回值为 false,说明传入的 URL 并非支付宝支付 URL,商户容器需要继续加载该 URL。
当支付结束后,会通过回调的方式返回异步支付结果。
- 如果返回的支付结果中的 resultCode 为 9000,则表示支付成功,接入方可以提示用户支付成功。
- 如果返回结果不是 9000,无需做任何处理。当返回的 returnUrl 不为空,建议接入方跳转到该 returnUrl。
```csharp
@Override
public boolean shouldOverrideUrlLoading(final WebView view, String url) {
if (!(url.startsWith("http") || url.startsWith("https"))) {
return true;
}
/**
* 推荐采用的新的二合一接口(payInterceptorWithUrl),只需调用一次
*/
final PayTask task = new PayTask(H5PayDemoActivity.this);
boolean isIntercepted = task.payInterceptorWithUrl(url, true, new H5PayCallback() {
@Override
public void onPayResult(final H5PayResultModel result) {
// 支付结果返回
final String url = result.getReturnUrl();
if (!TextUtils.isEmpty(url)) {
H5PayDemoActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
view.loadUrl(url);
}
});
}
}
});
/**
* 判断是否成功拦截
* 若成功拦截,则无需继续加载该URL;否则继续加载
*/
if (!isIntercepted) {
view.loadUrl(url);
}
return true;
}
```
# 沙箱联调指南
沙箱环境是开放平台提供给开发者调试接口的环境,详情可查看[沙箱环境](https://ideservice.alipay.com/cms/site/02kkv7)。请开发者在使用 SDK 时,在支付接口前调用如下方法用于切换沙箱环境与生产环境,如果不使用此方法,默认使用生产环境。
```csharp
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
```
方法调用位置如下图所示:
使用支付宝沙箱版客户端测试:在 **开放平台控制台** > **沙箱** > [沙箱工具](https://openhome.alipay.com/develop/sandbox/tool)。
**注意**:在生产环境,必须将此代码注释。在沙箱调通接口后,必须在生产环境进行测试与验收,所有返回码及业务逻辑以生产环境为准。