跳转链接使用最佳实践
在调用 授权咨询 接口后,根据授权过程中使用的支付方式,接口响应中会返回不同类型的授权链接。本文为您提供针对不同客户端类型的授权链接使用的最佳实践。有关每种支付方式返回的授权链接的详细信息,请参阅支付方式返回链接。
授权链接参数
对于不同类型的商户客户端(Web,WAP,App),不同的支付方式会在 授权咨询 接口的响应中返回以下三种类型的授权链接的部分或全部,以进行授权过程。
类型 | 描述 |
normalUrl | HTTPS 地址的链接,用于在同个浏览器页面中跳转到支付方式的网站页面。 |
applinkUrl | 在授权过程中用于跳转的 Android App Link 或 iOS Universal Link。 |
schemeUrl | 用于打开支付方式应用的 URL scheme。 示例:boostapp://inAppDeeplink?deeplink_path=deeplink/onetimepayment&source=alipay-connect&codeValue=https%3A%2F%2Fglobal.alipay.com%2F2810020400931LFH2t2mq1jjJ8zSetyv31VU |
注意事项:
- 使用上述链接发起授权时,如果买家未安装支付方式应用,重定向过程中可能会出现异常。如有异常,请妥善处理。
- 某些支付方式返回的链接不能多次使用。如果使用链接未能成功调起授权页面,建议使用新的 authState 值获取链接并重新调起授权页面。
Web
对于电脑网站上的支付,normalUrl 将在 授权咨询 接口响应中返回。
打开 normalUrl
获取到 normalUrl 值后,您需要使用该 normalUrl 指定的授权链接将买家重定向到授权页面。建议在新标签页中打开链接,引导买家完成授权。打开新页面的代码如下:
if (serverResponse.normalUrl != null) {
window.open(serverResponse.normalUrl, '_blank');
}
用户体验
使用 normalUrl 渲染的授权页面可能是二维码扫描页或登录页。以下图表展示了这两种情况下的授权流程:
WAP
对于移动网站上的支付,授权咨询 接口的响应可能包含以下一个或多个链接:
- normalUrl
- applinkUrl
- schemeUrl
选择链接
如果 授权咨询 接口响应只包含三个链接中的一个,直接将接收到的链接用作跳转链接。如果收到多个链接,我们建议您根据以下指示选择链接:
- 对于iOS系统 :优先使用 applinkUrl ,然后是 schemeUrl ,最后是 normalUrl 。
- 对于Android系统 :优先使用 schemeUrl ,然后是 applinkUrl ,最后是 normalUrl 。
打开链接
使用 JavaScript 的重定向方法打开链接,代码如下:
window.location.href = URL;
用户体验
类型 | 支付体验 |
normalUrl | 买家从您的移动网页页面被重定向到支付方式的移动网页页面。支付方式移动网页页面上显示的内容取决于支付方式,可归为以下两类:
|
applinkUrl | 根据买方是否安装了支付方式应用,后续授权流程会自动确定:
|
schemeUrl | 支付体验取决于买家是否安装了支付方式的应用:
|
以下图表展示了移动网站上的授权流程。浏览器需要将买家重定向到跳转链接或在新标签页中打开链接。
APP
对于移动应用支付,授权咨询 接口的响应可能包含以下一个或多个链接:
- normalUrl
- applinkUrl
- schemeUrl
注意:对于移动应用支付,除了上述提到的重定向链接参数外,授权咨询 接口的响应还包含 appIdentifier 参数。此参数是对应支付方式应用的包名,用于判断是否已安装应用以进行应用内支付。它也可用于避免在 Android 上出现消歧对话框。
选择链接
如果 授权咨询 接口的响应只包含三个链接中的一个,直接将接收到的链接用作跳转链接。如果收到多个链接,建议根据以下指导选择链接:
- 对于 iOS 系统:优先使用 applinkUrl ,然后是 schemeUrl ,最后是 normalUrl 。
- 对于 Android 系统:优先使用 schemeUrl ,然后是 applinkUrl ,最后是 normalUrl 。
打开链接
对于 Android 和 iOS,使用以下方法打开授权链接:
iOS | Android |
|
|
每种重定向方法的优缺点
每种重定向方法都有其优点和缺点。我们建议您根据操作系统和集成场景选择最适合的重定向方法。
重定向方法 | 描述 | |
应用外重定向:调用 Android/iOS 方法打开授权链接。 | Antom 推荐此方法。
| |
在应用内重定向 |
| WKWebView/WebView 是内置控件,可以在应用中嵌入一个网络浏览器。您可以使用它来加载网站链接。
|
| 基于 WKWebView/WebView 的升级解决方案。使用 JSBridge/JavascriptInterface 后,可以直接在 WebView 中调用 Android/iOS 方法来打开授权链接。
| |
| 由 iOS/Android 提供,在应用内打开授权链接。相比 WebView,具有更全面的功能。
| |
根据支付方式应用是否安装,选择在应用外或应用内打开授权链接。 | 根据支付方式应用是否安装,提供不同的重定向方法。
|
代码示例(iOS)
方法1:调用 iOS 方法打开授权链接
以下代码示例展示了如何使用 iOS 系统中的 iOS 方法将买家从您的应用重定向到支付方式应用。
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:Url] options:@{} completionHandler:nil];
}else{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:Url]];
}
方法2:在应用内打开授权链接
要在您的应用中打开授权链接,可以使用以下链接类型:
- normalUrl
- applinkUrl
注意:某些支付方式不支持在移动网站上进行授权。打开 normalUrl 会触发通过重定向调用相应的支付方式应用,而 WKWebView 会拦截重定向。您需要使用 WKWebView 的
decidePolicyForNavigationAction
方法,并调用 iOS 方法来打开授权链接,以实现从您的 WKWebView 到支付方式应用的重定向。 以下代码示例展示了如何在 iOS 应用中使用 WKWebView 加载支付方式页面:
// Initialize webview configuration
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]init];
// Initialize webView
WKWebView *webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) configuration:configuration];
webView.navigationDelegate = self;
//Load the payment method URL
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:Url]]];
[self.view addSubview:self.webView];
以下代码示例展示了如何使用 WKWebView 的 decidePolicyForNavigationAction 方法实现从 WKWebView 到支付方式应用的重定向:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
// WKWebView intercepts the redirection by default. Enable the redirection in the following ways.
// Operations such as opening Safari
NSURL *url = navigationAction.request.URL;
NSString *absoluteString = url.absoluteString;
NSString *scheme = url.baseURL.scheme;
DLog(@"navigationAction.request.URL.absoluteString=====> %@", absoluteString);
if ([absoluteString isEqualToString:@"about:blank"]) {
decisionHandler(WKNavigationActionPolicyCancel);
}
if (!([absoluteString containsString:@"https://"] || [absoluteString containsString:@"http://"])) {
if ([absoluteString containsString:@"://"]) {
NSString *urlHeader = [absoluteString componentsSeparatedByString:@"://"][0];
[MBProgressHUD showAutoMessage:[NSString stringWithFormat:@"Scheme\n%@://",urlHeader] toView:self.view];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self openAppWithUrlStr:navigationAction.request.URL];
decisionHandler(WKNavigationActionPolicyAllow);
});
}
} else {
decisionHandler(WKNavigationActionPolicyAllow);
}
}
使用 WKWebView 和 JSBridge
使用 WKWebView 和 JSBridge 可以优化买家的支付体验,但需要强大的开发能力。结合 JSBridge 与通过 WKWebView 打开链接,有利于项目的维护和扩展性,同时提升性能和安全性。JSBridge 使得网页与原生应用之间可以交互,允许 WAP 页面直接调用应用的原生方法。以下代码示例展示了如何在 WKWebView 中使用 JSBridge。
[self.wkWebView evaluateJavaScript:bridge completionHandler:nil];
使用 SFSafariViewController
SFSafariViewController 支持打开和渲染 normalUrl 、applinkUrl 和 schemeUrl 。相比于 WebView,它具有更全面的功能和更简单的集成。关于如何使用 SFSafariViewController 打开授权链接,参阅 SFSafariViewController 用户指南。以下代码示例展示了如何使用 SFSafariViewController。
SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:Url entersReaderIfAvailable:NO];
safariVC.delegate = self;
[self.navigationController presentViewController:safariVC animated:YES completion:nil];
方法3:根据支付方式应用是否已安装处理重定向
首先需要判断买家是否安装了支付方式应用,然后根据情况处理授权链接的打开方式。执行以下步骤:
- 在 LSApplicationQueriesSchemes 中添加配置到 info.plist 。请注意, info.plist 中的方案有数量限制。
- 使用 canOpenURL 方法来判断支付方式应用是否已安装。参考以下代码:
NSString *walletSchemeUrl = @"gcash://";
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:walletSchemeUrl]]){
// The payment method app is installed. Open the app directly.
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:Url] options:@{} completionHandler:nil];
return YES;
} else {
// The payment method app is not installed. We recommend that you load the mobile website in WebView.
SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:Url entersReaderIfAvailable:NO];
safariVC.delegate = self;
[self.navigationController presentViewController:safariVC animated:YES completion:nil];
return NO;
}
代码示例(Android)
方法1:调用Android方法打开授权链接
以下代码示例展示了如何使用 Android 方法打开授权链接,实现从您的应用到支付方式应用的重定向。
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(Url));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// use the startActivity function to redirect to the wallet app
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
使用此方法可能会出现消歧对话框。
什么是消歧对话框
Android App Link 在安装应用时会向谷歌服务器请求验证。如果验证失败,Android App Link 将变得无效,买家尝试通过此类链接打开应用时会出现一个消歧对话框。买家需要手动选择如何打开链接。
此图显示了买家点击 Android App Link 时可能出现的消歧对话框示例。买家需要手动选择如何打开链接:使用谷歌地图还是谷歌浏览器。 |
避免出现消歧对话框
当出现消歧对话框时,买家需要手动选择打开应用的方式,这可能影响支付成功率。因此,您需要采取以下措施来防止消歧对话框的出现:
- 如果买家已安装支付方式应用,指定支付方式的包名并打开支付方式的链接。
- 如果买家未安装支付方式应用,使用以下示例代码打开链接。
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(applinkUrl));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//Specify the package name of the payment method
intent.setPackage(walletPackageName);
PackageManager packageManager = MainActivity.this.getPackageManager();
//Check whether there is an app that supports opening this link.
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
if (activities.size() <= 0) {
//The payment method app is not installed. Initialize the Intent object. This link will be opened by the default Android method.
intent = new Intent(Intent.ACTION_VIEW, Uri.parse(applinkUrl));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else {
//The payment method app is installed. Specify the package name of the payment method and open the payment method URL. The disambiguation dialog box will not appear.
startActivity(intent);
}
注意:某些支付方式的 packageName 值如下所示:
- AlipayHK: hk.alipay.wallet
- GCash: com.globe.gcash.android
- TrueMoney: th.co.truemoney.wallet
- KakaoPay: com.kakao.talk
- Touch 'n Go: my.com.tngdigital.ewallet
- Dana: id.dana
方法2:在应用内打开授权链接链接
在您的应用程序中打开授权链接,可以使用 WebView 加载 normalUrl 或 applinkUrl 作为移动网站:
- normalUrl
- applinkUrl
注意:某些支付方式不支持在移动网站上进行授权。打开 normalUrl 会通过重定向调用相应的支付方式应用,而 WKWebView 会拦截重定向。您需要使用 WKWebView 的
shouldOverrideUrlLoading
方法并调用 Android 方法来打开授权链接,以实现从您的 WKWebView 到支付方式应用的重定向。
使用 WebView
以下代码示例展示了如何在 WebView 中加载支付方式页面。
WebView webView = findViewById(R.id.webview);
//Set webview
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
view.loadUrl(request.getUrl().toString());
return super.shouldOverrideUrlLoading(view, request);
}});
WebSettings webSettings = webView.getSettings();
//Enable javascript
webSettings.setJavaScriptEnabled(true);
//Enable scaling
webSettings.setSupportZoom(true);
//Enable scaling controls (buttons)
webSettings.setBuiltInZoomControls(true);
//Webview has two cache modes. Cache is not used here.
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
//Allow JavaScript to open a new tab (false by default)
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
//Allow JavaScript to load local storage
webSettings.setDomStorageEnabled(true);
//WAP cache size (settings are not needed)
//webSettings.setAppCacheMaxSize(1024 * 1024 * 8);
//WAP cache path
String absolutePath = getApplicationContext().getCacheDir().getAbsolutePath();
//WAP cache size
webSettings.setAppCachePath(absolutePath);
//Set whether to allow WebView to access files (true by default)
webSettings.setAllowFileAccess(true);
//Allow WAP cache to be saved
webSettings.setAppCacheEnabled(true);
//In preview mode, if the page width exceeds the WebView display, scale down the page to fit WebView (false by default)
webSettings.setLoadWithOverviewMode(true);
//Support the viewport HTML meta tag
webSettings.setUseWideViewPort(true);
//Load the payment method URL
webView.loadUrl(Url);
为WebView设置WebViewClient,使用WebViewClient.shouldOverrideUrlLoading
方法拦截链接,并调用相应的Android方法。参考以下代码示例:
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
if (request.getUrl().toString().startsWith("http")) {
view.loadUrl(request.getUrl().toString());
return super.shouldOverrideUrlLoading(view, request);
} else {
view.onPause();
view.stopLoading();
try {
Intent intent = Intent.parseUri(uri, Intent.URI_INTENT_SCHEME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
view.getContext().startActivity(intent);
} catch (URISyntaxException e) {
//Alert that this scheme is not supported
}
return false;
}
}
注意:如果您的应用有可重定向的应用白名单,请正确配置白名单,考虑与旧版本的兼容性问题,以减少应用发布的次数。
使用WebView和JavascriptInterface
这种方法将优化买家的支付体验,但需要较强的研发能力。我们建议在 WevView 中使用 JavascriptInterface。使用JavascriptInterface 可以促进 Android 应用和 WebView 之间的双向通信,允许移动网页直接调用应用的原生方法,使您的应用更加灵活和强大,有利于后续项目的维护和升级。以下代码示例展示了如何在 WebView 中使用JavascriptInterface。
- 在 WebView 中声明 JavascriptInterface
@JavascriptInterface
public void openActivity(String url) {
//Add the code if needed
try {
Intent intent = Intent.parseUri(uri, Intent.URI_INTENT_SCHEME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} catch (Exception e) {
Toast.makeText(context, "App not installed", Toast.LENGTH_SHORT).show();
}
}
- 向 WebView 添加 JavascriptInterface
mWebView.addJavascriptInterface(this, "bridge");
- 使用以下代码打开授权链接
window.bridge.openActivity("Url");
使用自定义标签
自定义标签页支持打开并渲染 normalUrl 、 applinkUrl 和 schemeUrl 。相比于 WebView,它具有更全面的功能和更简单的集成。以下代码示例展示了如何使用自定义标签页。
- 在 build.gradle 文件中添加自定义标签页。
dependencies {
...
implementation "androidx.browser:browser:1.4.0"
}
- 在您的应用中使用自定义标签打开一个 Chrome 标签页。
// Use CustomTabsIntent.Builder to configure CustomTabsIntent.
// Use CustomTabsIntent.Builder.build() to create CustomTabsIntent
// Use CustomTabsIntent.launchUrl() to launch the URL
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(this, Uri.parse(url));
有关如何使用 CustomTabs 打开链接的更多信息,请参阅自定义标签页用户指南。
方法3:根据支付方式应用是否安装处理重定向是否已安装
您必须首先判断买家是否安装了支付方式应用,然后根据情况处理授权链接的打开方式。请按照以下步骤操作:
- 为了遵循 Android 系统的隐私和安全策略,需要在 AndroidManifest.xml 文件中添加 <queries> 标签,以确保授权链接能够调起相应的支付方式应用。需要在 <queries> 标签中配置支付方式应用的包名。您可以通过 Antom 返回的 支付(收银台)接口相应中的 appIdentifier 参数获取相应值,或联系 Antom 技术支持获取。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.llw.scandemo">
...
<queries>
<package android:name="th.co.truemoney.wallet" />
<package android:name="com.eg.android.AlipayGphone" />
<package android:name="my.com.tngdigital.ewallet" />
...
</queries>
...
</manifest>
- 检测支付方式应用是否已安装并调起授权页面:
String Url = "applinkUrl/schemeUrl";
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(Url));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setPackage("my.com.tngdigital.ewallet");
// Determine whether the payment method app is installed
PackageManager packageManager = MainActivity.this.getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
if (activities.size() <= 0) {
// The payment method app is not installed. We recommend that you open the mobile website URL in WebView.
intent = new Intent(MainActivity.this, WebviewActivity.class);
intent.setData(Uri.parse(Url));
startActivity(intent);
} else {
// The payment method app is installed. Open the payment method app directly.
startActivity(intent);
}
} catch (Exception e) {
// Handle exceptions
e.printStackTrace();
}
用户体验
不同授权链接的打开方式对应的授权流程如下:
重定向方法 | 授权过程 |
应用外重定向:调用 Android/iOS 方法打开授权链接。 | 在应用程序外部重定向。授权过程取决于买家是否安装了支付方式应用:
|
在应用程序内重定向 | 存在两种授权体验:从您的应用中重定向和在您的应用内重定向。
|
最佳实践
我们建议根据不同的支付方式来固定配置授权链接的打开方式,或者根据支付方式、设备环境和链接类型。以下是一个基于不同支付方式的固定配置示例:
对于每种支付方式,我们建议您根据以下逻辑确定打开授权链接的方法: