手机网站支付转Native支付--Android

学向勤中得,萤窗万卷书。这篇文章主要讲述手机网站支付转Native支付--Android相关的知识,希望能为你提供帮助。
背景 为了节约开发成本, 很多Native-H5混合App采用手机网站支付的方式去实现支付模块。但手机网站支付的网络依赖比较严重, 也通常需要经过更多的验证, 这种种原因导致手机网站支付的成功率比Native支付低, 对商户的利益造成影响。
简介 手机网站支付转Native支付是支付宝标准版SDK内置的一项功能, 能够帮助Native-H5混合App以极低的接入成本极大地提升支付成功率。
手机网站支付PK手机网站转Native支付 主要区别是: 如果用户手机安装了支付宝App, 手机网站转Native支付方式会跳转到支付宝App中进行订单支付, 用户体验和支付成功率均优于手机网站支付方式。除此之外, 还能使用手机网站支付没有提供的功能, 例如: 指纹支付、手环、手表支付、免密支付等。
如果用户手机没有安装支付宝App怎么办? 如果用户手机没有安装支付宝App, 将在SDK提供的WebView中打开H5页面进行支付。即便如此, 由于SDK与服务端的交互携带账号信息, 仍比不携带任何账号信息的普通手机网站支付体验更好。
如何实现手机网站转Native支付 要实现上述功能需接入我们提供的SDK。
下载Demo
接入过程十分简单, 可以以Demo为参考, 该Demo程序只有一个功能: 创建一个WebView, 在WebView中拦截每个URL, 然后调用SDK提供的接口检查该URL是否是有效的支付宝订单支付URL, 如果是则将该URL传给SDK提供的支付接口进行支付。
Android接入说明 配置
步骤1: 导入开发资源

  1. 将alipaySdk-20170309.jar包放入商户应用工程module的libs目录下, 如下图。
    手机网站支付转Native支付--Android

    文章图片

  2. 在module的build.gradle中添加依赖
dependencies { compile fileTree(dir: ' libs' , include: [' *.jar' ]) ...... }

步骤2: 修改Manifest 在商户应用工程的androidManifest.xml文件里面添加Activity声明:
< !-- 支付宝SDK --> < activity android:name= " com.alipay.sdk.app.H5PayActivity" android:configChanges= " orientation|keyboardHidden|navigation" android:exported= " false" android:screenOrientation= " behind" > < /activity> < activity android:name= " com.alipay.sdk.auth.AuthActivity" android:configChanges= " orientation|keyboardHidden|navigation" android:exported= " false" android:screenOrientation= " behind" > < /activity>

和权限声明:
< uses-permission android:name= " android.permission.INTERNET" /> < uses-permission android:name= " android.permission.ACCESS_NETWORK_STATE" /> < uses-permission android:name= " android.permission.ACCESS_WIFI_STATE" /> < uses-permission android:name= " android.permission.READ_PHONE_STATE" /> < uses-permission android:name= " android.permission.WRITE_EXTERNAL_STORAGE" />

步骤3: 添加混淆规则 在商户应用工程的proguard-rules.pro里添加以下相关规则:
# 支付宝SDK -libraryjars ../appcommon/libs/alipaySdk-20170309.jar-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 *; } -dontwarn android.net.SSLCertificateSocketFactory

至此, 开发包开发资源导入完成。
接口调用说明
SDK中提供了若干接口, 手机网站转Native支付只用到其中一部分, 本文未提到的接口无需关注。
如何实现手机网站转Native支付? 步骤一: 在接入方App中拦截H5的URL; 步骤二: 调用SDK提供的“获取订单信息接口(fetchOrderInfoFromH5PayUrl)”对拦截的URL进行处理:
  • 如果返回空字符串则不作任何处理
  • 反之则调用“支付接口(h5Pay)”进行订单支付, 并拦截URL
获取订单信息接口
接口原型
/** * 获取H5native支付的信息 * @ param h5PayUrl * @ return */ public synchronized String fetchOrderInfoFromH5PayUrl(String h5PayUrl)

接口功能 从拦截的URL中获取支付请求相关信息, 封装成新的订单信息字符串作为返回值。如果该URL不是有效的支付宝支付URL, 则返回空字符串。
参数说明
参数名称类型说明
h5PayUrlString手机网站支付的请求URL
返回值说明
返回值类型说明
String1.如果是有效的支付宝支付URL, 则返回非空字符串( 订单信息字符串)
2.如果是无效的支付宝支付URL, 则返回空字符串
接口使用方式 调用本接口对拦截的URL进行处理, 如果返回值为空字符串则不拦截该URL; 如果返回值为非空字符串, 则调用SDK提供的支付接口进行支付, 使用示例如下:
@ Override public boolean shouldOverrideUrlLoading(final WebView view, String url) { final PayTask task = new PayTask(H5PayDemoActivity.this); //处理订单信息 final String ex = task.fetchOrderInfoFromH5PayUrl(url); if (!TextUtils.isEmpty(ex)) { //调用支付接口进行支付 } else { view.loadUrl(url); } return true; } }

支付接口
接口原型
/** * 手机网站支付 * @ param h5PayInfo 订单信息 * @ param isShowPayLoading 是否显示loading图标 * @ return */ public synchronized H5PayResultModel h5Pay(String h5PayInfo, boolean isShowPayLoading)

接口功能 完成订单支付并返回支付结果。
参数说明
参数名称类型说明
h5PayInfoString调用fetchOrderInfoFromH5PayUrl接口返回的订单信息字符串
isShowPayLoadingboolean是否显示loading界面
返回值说明 返回值类型为H5PayResultModel类, 包含下述2个成员变量:
参数名称类型说明
resultCodeString返回码, 标识支付状态, 含义如下:
9000——订单支付成功
8000——正在处理中
4000——订单支付失败
5000——重复请求
6001——用户中途取消
6002——网络连接出错
returnUrlString支付结束后应当跳转的url地址
接口使用方式 【手机网站支付转Native支付--Android】调用本接口进行支付。如果返回的resultCode为9000, 接入方可以提示用户支付成功; 返回结果不是9000的情况, 无需做任何处理。如果returnUrl不为空, 建议接入方跳转到该returnUrl。
  • 自定义实现帮助WebView处理各种通知、请求时间的WebViewClient
setWebViewClient(new XxWebViewClient()); setWebChromeClient(new XxWebChromeClient());

/** * 处理页面加载的相关事件 */ private class XxWebViewClient extends WebViewClient {private AsyncTask< Void, Void, H5PayResultModel> mPayTask = null; @ Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); if (mRequestHandler != null) { String title = view.getTitle(); if (!TextUtils.isEmpty(title) & & !title.contains(" http" )) { mRequestHandler.onRequestChangeTitle(view.getTitle()); } } }@ Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (URLUtil.isNetworkUrl(url)) { // 尝试处理支付宝链接 if (url.contains(" alipay.com" )) { return handleAliPayUrl(url); }return false; }Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); getContext().startActivity(intent); return true; }/** * 处理支付宝支付请求, 转 native 支付 */ private boolean handleAliPayUrl(String url) { Context context = getContext(); if (!(context instanceof Activity)) { return false; }final PayTask task = new PayTask((Activity) context); final String ex = task.fetchOrderInfoFromH5PayUrl(url); if (TextUtils.isEmpty(ex)) { return false; }// 启动 native 支付 if (mPayTask = = null || mPayTask.getStatus() != AsyncTask.Status.RUNNING) { mPayTask = new AsyncTask< Void, Void, H5PayResultModel> () {@ Override protected H5PayResultModel doInBackground(Void... params) { return task.h5Pay(ex, true); }@ Override protected void onPostExecute(H5PayResultModel result) { super.onPostExecute(result); String returnUrl = result.getReturnUrl(); if (TextUtils.isEmpty(returnUrl)) { /* * 返回码, 标识支付状态, 含义如下: * 9000——订单支付成功 * 8000——正在处理中 * 4000——订单支付失败 * 5000——重复请求 * 6001——用户中途取消 * 6002——网络连接出错 */ final String code = result.getResultCode(); if (" 9000" .equals(code)) { if (mRequestHandler != null) { mRequestHandler.onPaySuccess(); } } } else { // 支付结束后应当跳转的url地址// 特殊处理地址中的 notify_id Uri uri = Uri.parse(returnUrl); String notifyId = Uri.encode(uri.getQueryParameter(" notify_id" )); returnUrl = returnUrl.replace(notifyId, Uri.encode(notifyId)); loadUrl(returnUrl); } } }; mPayTask.execute(); }return true; } }

  • 客户端处理支付成功后的页面跳转, 需要注入JS回调
WebSettings settings = getSettings(); settings.setjavascriptEnabled(true); addjavascriptInterface(new JavaScriptInterface(), " android" );

/** * 实现一些JS回调的方法 */ private class JavaScriptInterface {// JS回调的版本,这个值需要根据JavaScriptInterface所支持的方法来调整 private static final String VERSION_JAVASCRIPT_INTERFACE = " 2" ; // 常用的提示文案 private static final String MSG_REQUEST_HANDLER_IS_NULL = " 处理异常,请重新打开页面" ; /** * 支付成功后, 客户端跳转 */ @ JavascriptInterface public void afterPaySuccess(String jsonParam, String callback, String extra) { if (mRequestHandler != null) { mRequestHandler.onPaySuccess(); } } }

  • 处理JS交互请求
/** * 处理WebView内js发起的交互请求 */ public interface OnJsRequestHandler {/** * 请求处理支付成功后页面跳转 */ void onPaySuccess(); }

  • 加载WebView的Activity实现OnJsRequestHandler
@ Override public void onPaySuccess() { //处理业务逻辑及页面重定向 }


    推荐阅读