赞
踩
接入APP支付能力前,开发者需要完成以下前置步骤。
本文档展示了如何从零开始,使用支付宝开放平台服务端 SDK 快速接入App支付产品,完成与支付宝对接的部分。
接入准备——支付宝开发能力
- // 支付宝 SDK AAR 包所需的配置
- compile (name: 'alipaysdk-15.8.03.210428205839', ext: 'aar')
- //这里alipaysdk-15.8.03.210428205839必须和导入的sdk名字一样
二.配置清单文件AndroidManifest.xml:
①添加Activity声明:
- <activity
- android:name="com.alipay.sdk.pay.demo.PayDemoActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity
- android:name="com.alipay.sdk.pay.demo.H5PayDemoActivity"
- 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" />
- <!-- 如果您的 App 的 targetSdkVersion 大于或等于 30,则需要在 AndroidManifest.xml 中提供下面的应用可见性声明,
- 让支付宝 SDK 感知设备上是否已经安装了支付宝 App。同时,您可能还需要升级 Gradle Plugin 到最新版本。
- 关于 Android 11 的 "应用可见性" 机制,参见 https://developer.android.com/about/versions/11/privacy/package-visibility?hl=zh-cn -->
- <queries>
- <package android:name="com.eg.android.AlipayGphone" /> <!-- 支付宝 -->
- <package android:name="hk.alipay.wallet" /> <!-- AlipayHK -->
- </queries>
如果想混淆代码,在工程proguard-rules.pro添加如下代码:
- -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 {
- <fields>;
- <methods>;
- }
- -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.** { *;}
-
- public class PayDemoActivity extends AppCompatActivity {
-
-
-
- public static int price=100;
-
- /**
- * 用于支付宝支付业务的入参 app_id。
- */
- public static final String APPID = "************";
-
- /**
- * 用于支付宝账户登录授权业务的入参 pid。
- */
- public static final String PID = "************";
-
- /**
- * 用于支付宝账户登录授权业务的入参 target_id。商家的收款账号
- */
- public static final String TARGET_ID = "************";
-
- /**
- * pkcs8 格式的商户私钥。
- *
- * 如下私钥,RSA2_PRIVATE 或者 RSA_PRIVATE 只需要填入一个,如果两个都设置了,本 Demo 将优先
- * 使用 RSA2_PRIVATE。RSA2_PRIVATE 可以保证商户交易在更加安全的环境下进行,建议商户使用
- * RSA2_PRIVATE。
- *
- * 建议使用支付宝提供的公私钥生成工具生成和获取 RSA2_PRIVATE。
- * 工具地址:https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=106097&docType=1
- */
- public static final String RSA2_PRIVATE = "************";//密钥
- public static final String RSA_PRIVATE = "";
-
- private static final int SDK_PAY_FLAG = 1;
- private static final int SDK_AUTH_FLAG = 2;
-
- @SuppressLint("HandlerLeak")
- private Handler mHandler = new Handler() {
- @SuppressWarnings("unused")
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case SDK_PAY_FLAG: {
- @SuppressWarnings("unchecked")
- PayResult payResult = new PayResult((Map<String, String>) msg.obj);
- /**
- * 对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
- */
- String resultInfo = payResult.getResult();// 同步返回需要验证的信息
- String resultStatus = payResult.getResultStatus();
- // 判断resultStatus 为9000则代表支付成功
- if (TextUtils.equals(resultStatus, "9000")) {
- // 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
- showAlert(PayDemoActivity.this, getString(R.string.pay_success) + payResult);
- } else {
- // 该笔订单真实的支付结果,需要依赖服务端的异步通知。
- showAlert(PayDemoActivity.this, getString(R.string.pay_failed) + payResult);
- }
- break;
- }
- }
- };
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);//沙箱环境需要的代码
- super.onCreate(savedInstanceState);
- setContentView(R.layout.pay_main);
- Button button = findViewById(R.id.payV2);
- button.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- payV2(v);
- }
- });
- }
- /**
- * 支付宝支付业务示例
- */
- public void payV2(View v) {
- if (TextUtils.isEmpty(APPID) || (TextUtils.isEmpty(RSA2_PRIVATE) && TextUtils.isEmpty(RSA_PRIVATE))) {
- showAlert(this, getString(R.string.error_missing_appid_rsa_private));
- return;
- }
-
- /*
- * 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
- * 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
- * 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
- *
- * orderInfo 的获取必须来自服务端;
- */
- boolean rsa2 = (RSA2_PRIVATE.length() > 0);
- Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(APPID, rsa2,price);
-
-
- String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
-
- String privateKey = rsa2 ? RSA2_PRIVATE : RSA_PRIVATE;
-
- String sign = OrderInfoUtil2_0.getSign(params, privateKey, rsa2);
- final String orderInfo = orderParam + "&" + sign;
-
- final Runnable payRunnable = new Runnable() {
-
- @Override
- public void run() {
- PayTask alipay = new PayTask(PayDemoActivity.this);
- Map<String, String> result = alipay.payV2(orderInfo, true);
- Log.i("msp", result.toString());
-
- Message msg = new Message();
- msg.what = SDK_PAY_FLAG;
- msg.obj = result;
- mHandler.sendMessage(msg);
- }
- };
-
- // 必须异步调用
- Thread payThread = new Thread(payRunnable);
- payThread.start();
- }
-
-
-
-
- private static void showAlert(Context ctx, String info) {
- showAlert(ctx, info, null);
- }
-
- private static void showAlert(Context ctx, String info, DialogInterface.OnDismissListener onDismiss) {
- new AlertDialog.Builder(ctx)
- .setMessage(info)
- .setPositiveButton(R.string.confirm, null)
- .setOnDismissListener(onDismiss)
- .show();
- }
-
- private static void showToast(Context ctx, String msg) {
- Toast.makeText(ctx, msg, Toast.LENGTH_LONG).show();
- }
-
- private static String bundleToString(Bundle bundle) {
- if (bundle == null) {
- return "null";
- }
- final StringBuilder sb = new StringBuilder();
- for (String key: bundle.keySet()) {
- sb.append(key).append("=>").append(bundle.get(key)).append("\n");
- }
- return sb.toString();
- }
- }
-
-
- public class OrderInfoUtil2_0 {
-
- /**
- * 构造授权参数列表
- *
- * @param pid
- * @param app_id
- * @param target_id
- * @return
- */
- public static Map<String, String> buildAuthInfoMap(String pid, String app_id, String target_id, boolean rsa2) {
- Map<String, String> keyValues = new HashMap<String, String>();
-
- // 商户签约拿到的app_id,如:2013081700024223
- keyValues.put("app_id", app_id);
-
- // 商户签约拿到的pid,如:2088102123816631
- keyValues.put("pid", pid);
-
- // 服务接口名称, 固定值
- keyValues.put("apiname", "com.alipay.account.auth");
-
- // 服务接口名称, 固定值
- keyValues.put("methodname", "alipay.open.auth.sdk.code.get");
-
- // 商户类型标识, 固定值
- keyValues.put("app_name", "mc");
-
- // 业务类型, 固定值
- keyValues.put("biz_type", "openservice");
-
- // 产品码, 固定值
- keyValues.put("product_id", "APP_FAST_LOGIN");
-
- // 授权范围, 固定值
- keyValues.put("scope", "kuaijie");
-
- // 商户唯一标识,如:kkkkk091125
- keyValues.put("target_id", target_id);
-
- // 授权类型, 固定值
- keyValues.put("auth_type", "AUTHACCOUNT");
-
- // 签名类型
- keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA");
-
- return keyValues;
- }
-
- /**
- * 构造支付订单参数列表
- */
- public static Map<String, String> buildOrderParamMap(String app_id, boolean rsa2,int price) {
- Map<String, String> keyValues = new HashMap<String, String>();
-
- keyValues.put("app_id", app_id);
-
- keyValues.put("biz_content", "{\"timeout_express\":\"30m\",\"product_code\":\"QUICK_MSECURITY_PAY\",\"total_amount\":\""+price+"\",\"subject\":\"1\",\"body\":\"我是测试数据\",\"out_trade_no\":\"" + getOutTradeNo() + "\"}");
-
- keyValues.put("charset", "utf-8");
-
- keyValues.put("method", "alipay.trade.app.pay");
-
- keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA");
-
- keyValues.put("timestamp", "2016-07-29 16:55:53");
-
- keyValues.put("version", "1.0");
-
- return keyValues;
- }
-
- /**
- * 构造支付订单参数信息
- *
- * @param map
- * 支付订单参数
- * @return
- */
- public static String buildOrderParam(Map<String, String> map) {
- List<String> keys = new ArrayList<String>(map.keySet());
-
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < keys.size() - 1; i++) {
- String key = keys.get(i);
- String value = map.get(key);
- sb.append(buildKeyValue(key, value, true));
- sb.append("&");
- }
-
- String tailKey = keys.get(keys.size() - 1);
- String tailValue = map.get(tailKey);
- sb.append(buildKeyValue(tailKey, tailValue, true));
-
- return sb.toString();
- }
-
- /**
- * 拼接键值对
- *
- * @param key
- * @param value
- * @param isEncode
- * @return
- */
- private static String buildKeyValue(String key, String value, boolean isEncode) {
- StringBuilder sb = new StringBuilder();
- sb.append(key);
- sb.append("=");
- if (isEncode) {
- try {
- sb.append(URLEncoder.encode(value, "UTF-8"));
- } catch (UnsupportedEncodingException e) {
- sb.append(value);
- }
- } else {
- sb.append(value);
- }
- return sb.toString();
- }
-
- /**
- * 对支付参数信息进行签名
- *
- * @param map
- * 待签名授权信息
- *
- * @return
- */
- public static String getSign(Map<String, String> map, String rsaKey, boolean rsa2) {
- List<String> keys = new ArrayList<String>(map.keySet());
- // key排序
- Collections.sort(keys);
-
- StringBuilder authInfo = new StringBuilder();
- for (int i = 0; i < keys.size() - 1; i++) {
- String key = keys.get(i);
- String value = map.get(key);
- authInfo.append(buildKeyValue(key, value, false));
- authInfo.append("&");
- }
-
- String tailKey = keys.get(keys.size() - 1);
- String tailValue = map.get(tailKey);
- authInfo.append(buildKeyValue(tailKey, tailValue, false));
-
- String oriSign = SignUtils.sign(authInfo.toString(), rsaKey, rsa2);
- String encodedSign = "";
-
- try {
- encodedSign = URLEncoder.encode(oriSign, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- return "sign=" + encodedSign;
- }
-
- /**
- * 要求外部订单号必须唯一。
- * @return
- */
- private static String getOutTradeNo() {
- SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
- Date date = new Date();
- String key = format.format(date);
-
- Random r = new Random();
- key = key + r.nextInt();
- key = key.substring(0, 15);
- return key;
- }
-
- }
-
- public class SignUtils {
-
- private static final String ALGORITHM = "RSA";
-
- private static final String SIGN_ALGORITHMS = "SHA1WithRSA";
-
- private static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA";
-
- private static final String DEFAULT_CHARSET = "UTF-8";
-
- private static String getAlgorithms(boolean rsa2) {
- return rsa2 ? SIGN_SHA256RSA_ALGORITHMS : SIGN_ALGORITHMS;
- }
-
- public static String sign(String content, String privateKey, boolean rsa2) {
- try {
- PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
- Base64.decode(privateKey));
- KeyFactory keyf = KeyFactory.getInstance(ALGORITHM);
- PrivateKey priKey = keyf.generatePrivate(priPKCS8);
-
- java.security.Signature signature = java.security.Signature
- .getInstance(getAlgorithms(rsa2));
-
- signature.initSign(priKey);
- signature.update(content.getBytes(DEFAULT_CHARSET));
-
- byte[] signed = signature.sign();
-
- return Base64.encode(signed);
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- return null;
- }
-
- }
-
- public class PayResult {
- private String resultStatus;
- private String result;
- private String memo;
-
- public PayResult(Map<String, String> rawResult) {
- if (rawResult == null) {
- return;
- }
-
- for (String key : rawResult.keySet()) {
- if (TextUtils.equals(key, "resultStatus")) {
- resultStatus = rawResult.get(key);
- } else if (TextUtils.equals(key, "result")) {
- result = rawResult.get(key);
- } else if (TextUtils.equals(key, "memo")) {
- memo = rawResult.get(key);
- }
- }
- }
-
- @Override
- public String toString() {
- return "resultStatus={" + resultStatus + "};memo={" + memo
- + "};result={" + result + "}";
- }
-
- /**
- * @return the resultStatus
- */
- public String getResultStatus() {
- return resultStatus;
- }
-
- /**
- * @return the memo
- */
- public String getMemo() {
- return memo;
- }
-
- /**
- * @return the result
- */
- public String getResult() {
- return result;
- }
- }
-
- public class ExternalFragment extends Fragment {
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.pay_external, container, false);
- }
- }
- <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <Button
- android:id="@+id/payV2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="10dp"
- android:onClick="payV2"
- android:textAllCaps="false"
- android:text="@string/pay_with_alipay" />
-
- </LinearLayout>
-
- </ScrollView>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical"
- android:gravity="center_horizontal"
- android:background="#FFFFFF">
-
- <ImageView
- android:layout_marginTop="16dp"
- android:layout_marginBottom="16dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:scaleType="centerInside"
- android:src="@drawable/alipay_logo" />
-
- <fragment
- android:id="@+id/fragment"
- android:name="com.alipay.sdk.pay.demo.ExternalFragment"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- tools:layout="@layout/pay_external" />
-
- </LinearLayout>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。