接入APP支付能力前,开发者需要完成以下前置步骤。
本文档展示了如何从零开始,使用支付宝开放平台服务端 SDK 快速接入App支付产品,完成与支付宝对接的部分。
接入准备——支付宝开发能力
一.下载官方sdk,将sdk放入自己工程libs文件中: 并且在我们的app/build.gradle里配置一下 // 支付宝 SDK AAR 包所需的配置
compile (name: 'alipaysdk-15.8.03.210428205839', ext: 'aar')
//这里alipaysdk-15.8.03.210428205839必须和导入的sdk名字一样
二.配置清单文件AndroidManifest.xml:
①添加Activity声明:
②添加权限声明:
如果想混淆代码,在工程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 {
;
;
}
-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.** { *;}
三.支付接口调用
PayDemoActivity.java
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) 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 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 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();
}
}
OrderInfoUtil2_0.java
public class OrderInfoUtil2_0 {
/**
* 构造授权参数列表
*
* @param pid
* @param app_id
* @param target_id
* @return
*/
public static Map buildAuthInfoMap(String pid, String app_id, String target_id, boolean rsa2) {
Map keyValues = new HashMap();
// 商户签约拿到的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 buildOrderParamMap(String app_id, boolean rsa2,int price) {
Map keyValues = new HashMap();
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 map) {
List keys = new ArrayList(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 map, String rsaKey, boolean rsa2) {
List keys = new ArrayList(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;
}
}
工具类
1.SignUtils.java
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;
}
}
2.PayResult.java
public class PayResult {
private String resultStatus;
private String result;
private String memo;
public PayResult(Map 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;
}
}
3.ExternalFragment.java
public class ExternalFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.pay_external, container, false);
}
}
4.在 Android_Demo中移过来这三个
五.布局文件
pay_external.xml
pay_main.xml
本方法调用的返回结果,参数说明见"客户端同步返回参数说明"。
至此,支付宝支付代码已完成!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)