Commit 168034d408c4cae6303f0a088cf1d7589bd9ac17
1 parent
739bb62b
u
Showing
1 changed file
with
617 additions
and
1 deletions
06.支付云/4.2app.md
| @@ -244,4 +244,620 @@ WXApiManager.m代码 | @@ -244,4 +244,620 @@ WXApiManager.m代码 | ||
| 244 | ``` | 244 | ``` |
| 245 | 245 | ||
| 246 | 246 | ||
| 247 | -#### demo Android | ||
| 248 | \ No newline at end of file | 247 | \ No newline at end of file |
| 248 | +#### demo Android | ||
| 249 | +1)根据[预支付](http://console.open.cnlive.com/open/doc/api/931661df-a9a0-4289-bb82-8c4134469cac) 接口生成map 参数集合 | ||
| 250 | +2) 对所有传入参数(含系统参数和接口参数)按照字段名的 ASCII 码从小到大排序 | ||
| 251 | + | ||
| 252 | +```java | ||
| 253 | +/** | ||
| 254 | + * Map key 排序 | ||
| 255 | + * | ||
| 256 | + * @param map | ||
| 257 | + * @return | ||
| 258 | + */ | ||
| 259 | + private static Map<String, String> order(Map<String, String> map) { | ||
| 260 | + HashMap<String, String> tempMap = new LinkedHashMap<>(); | ||
| 261 | + List<Map.Entry<String, String>> infoIds = new ArrayList<>(map.entrySet()); | ||
| 262 | + | ||
| 263 | + Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() { | ||
| 264 | + public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) { | ||
| 265 | + return o1.getKey().compareTo(o2.getKey()); | ||
| 266 | + } | ||
| 267 | + }); | ||
| 268 | + | ||
| 269 | + for (int i = 0; i < infoIds.size(); i++) { | ||
| 270 | + Map.Entry<String, String> item = infoIds.get(i); | ||
| 271 | + tempMap.put(item.getKey(), item.getValue()); | ||
| 272 | + } | ||
| 273 | + return tempMap; | ||
| 274 | + } | ||
| 275 | +``` | ||
| 276 | +3)参数的串联 | ||
| 277 | +使用 URL 键值 对的格式。 (即 key1=value1&key2=value2…)拼接成字符串 string1, 注意:值为空的参数不参与签名,所有请求参数值都需要进行URL编码 | ||
| 278 | + | ||
| 279 | +```java | ||
| 280 | + private static String mapJoin(Map<String, String> map, boolean keyLower, boolean valueUrlencode) { | ||
| 281 | + StringBuilder stringBuilder = new StringBuilder(); | ||
| 282 | + for (String key : map.keySet()) { | ||
| 283 | + if (map.get(key) != null && !"".equals(map.get(key))) { | ||
| 284 | + try { | ||
| 285 | + stringBuilder.append(key) | ||
| 286 | + .append("=") | ||
| 287 | + .append(valueUrlencode ? URLEncoder.encode(map.get(key), "utf-8").replace("+", "%20") : map.get(key)) | ||
| 288 | + .append("&"); | ||
| 289 | + } catch (UnsupportedEncodingException e) { | ||
| 290 | + LOGE("PAY:" + e.getMessage(), e); | ||
| 291 | + } | ||
| 292 | + } | ||
| 293 | + } | ||
| 294 | + if (stringBuilder.length() > 0) { | ||
| 295 | + stringBuilder.deleteCharAt(stringBuilder.length() - 1); | ||
| 296 | + } | ||
| 297 | + LOGD("PAY:" + stringBuilder.toString()); | ||
| 298 | + return stringBuilder.toString(); | ||
| 299 | + } | ||
| 300 | +``` | ||
| 301 | + | ||
| 302 | +4)拼接key=app_key,进行sha1运算 | ||
| 303 | +在 string1 最 后 拼 接 上 key=app_key得 到 stringSignTemp 字 符 串 , 并 对 stringSignTemp 进行 sha1 运算,再将得到的字符串所有字符转换为大写, 得到 sign 值 signValue | ||
| 304 | + | ||
| 305 | +```java | ||
| 306 | + | ||
| 307 | +SHA1.SHA1Digest(mapJoin(map, true, false) | ||
| 308 | + .concat("&key=") | ||
| 309 | + .concat(sp_key)) | ||
| 310 | + .toUpperCase(Locale.getDefault()); //备注(sha1运算代码不做详述附上下面代码)。 | ||
| 311 | +``` | ||
| 312 | + | ||
| 313 | +SHA1代码 | ||
| 314 | +```java | ||
| 315 | +public class SHA1 { | ||
| 316 | + private final int[] abcde = {0x67452301, 0xefcdab89, 0x98badcfe, | ||
| 317 | + 0x10325476, 0xc3d2e1f0}; | ||
| 318 | + | ||
| 319 | + // 摘要数据存储数组 | ||
| 320 | + private int[] digestInt = new int[5]; | ||
| 321 | + | ||
| 322 | + // 计算过程中的临时数据存储数组 | ||
| 323 | + private int[] tmpData = new int[80]; | ||
| 324 | + | ||
| 325 | + /** | ||
| 326 | + * 将字节转换为十六进制字符串 | ||
| 327 | + * | ||
| 328 | + * @param ib | ||
| 329 | + * @return | ||
| 330 | + */ | ||
| 331 | + private static String byteToHexString(byte ib) { | ||
| 332 | + char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', | ||
| 333 | + 'B', 'C', 'D', 'E', 'F'}; | ||
| 334 | + char[] ob = new char[2]; | ||
| 335 | + ob[0] = Digit[(ib >>> 4) & 0X0F]; | ||
| 336 | + ob[1] = Digit[ib & 0X0F]; | ||
| 337 | + String s = new String(ob); | ||
| 338 | + return s; | ||
| 339 | + } | ||
| 340 | + | ||
| 341 | + /** | ||
| 342 | + * 将字节数组转换为十六进制字符串 | ||
| 343 | + * | ||
| 344 | + * @param bytearray | ||
| 345 | + * @return | ||
| 346 | + */ | ||
| 347 | + private static String byteArrayToHexString(byte[] bytearray) { | ||
| 348 | + String strDigest = ""; | ||
| 349 | + for (int i = 0; i < bytearray.length; i++) { | ||
| 350 | + strDigest += byteToHexString(bytearray[i]); | ||
| 351 | + } | ||
| 352 | + return strDigest; | ||
| 353 | + } | ||
| 354 | + | ||
| 355 | + /** | ||
| 356 | + * @param text | ||
| 357 | + * @return | ||
| 358 | + */ | ||
| 359 | + public static String SHA1Digest(String text) { | ||
| 360 | + String pwd = ""; | ||
| 361 | + try { | ||
| 362 | + MessageDigest md = MessageDigest.getInstance("SHA1"); | ||
| 363 | + md.update(text.getBytes()); | ||
| 364 | + pwd = new BigInteger(1, md.digest()).toString(16); | ||
| 365 | + } catch (NoSuchAlgorithmException e) { | ||
| 366 | + e.printStackTrace(); | ||
| 367 | + } | ||
| 368 | + return pwd; | ||
| 369 | + } | ||
| 370 | + | ||
| 371 | + /** | ||
| 372 | + * 计算sha-1摘要 | ||
| 373 | + * | ||
| 374 | + * @param bytedata | ||
| 375 | + * @return | ||
| 376 | + */ | ||
| 377 | + private int process_input_bytes(byte[] bytedata) { | ||
| 378 | + // 初试化常量 | ||
| 379 | + System.arraycopy(abcde, 0, digestInt, 0, abcde.length); | ||
| 380 | + // 格式化输入字节数组,补10及长度数据 | ||
| 381 | + byte[] newbyte = byteArrayFormatData(bytedata); | ||
| 382 | + // 获取数据摘要计算的数据单元个数 | ||
| 383 | + int MCount = newbyte.length / 64; | ||
| 384 | + // 循环对每个数据单元进行摘要计算 | ||
| 385 | + for (int pos = 0; pos < MCount; pos++) { | ||
| 386 | + // 将每个单元的数据转换成16个整型数据,并保存到tmpData的前16个数组元素中 | ||
| 387 | + for (int j = 0; j < 16; j++) { | ||
| 388 | + tmpData[j] = byteArrayToInt(newbyte, (pos * 64) + (j * 4)); | ||
| 389 | + } | ||
| 390 | + // 摘要计算函数 | ||
| 391 | + encrypt(); | ||
| 392 | + } | ||
| 393 | + return 20; | ||
| 394 | + } | ||
| 395 | + | ||
| 396 | + /** | ||
| 397 | + * 格式化输入字节数组格式 | ||
| 398 | + * | ||
| 399 | + * @param bytedata | ||
| 400 | + * @return | ||
| 401 | + */ | ||
| 402 | + private byte[] byteArrayFormatData(byte[] bytedata) { | ||
| 403 | + // 补0数量 | ||
| 404 | + int zeros = 0; | ||
| 405 | + // 补位后总位数 | ||
| 406 | + int size = 0; | ||
| 407 | + // 原始数据长度 | ||
| 408 | + int n = bytedata.length; | ||
| 409 | + // 模64后的剩余位数 | ||
| 410 | + int m = n % 64; | ||
| 411 | + // 计算添加0的个数以及添加10后的总长度 | ||
| 412 | + if (m < 56) { | ||
| 413 | + zeros = 55 - m; | ||
| 414 | + size = n - m + 64; | ||
| 415 | + } else if (m == 56) { | ||
| 416 | + zeros = 63; | ||
| 417 | + size = n + 8 + 64; | ||
| 418 | + } else { | ||
| 419 | + zeros = 63 - m + 56; | ||
| 420 | + size = (n + 64) - m + 64; | ||
| 421 | + } | ||
| 422 | + // 补位后生成的新数组内容 | ||
| 423 | + byte[] newbyte = new byte[size]; | ||
| 424 | + // 复制数组的前面部分 | ||
| 425 | + System.arraycopy(bytedata, 0, newbyte, 0, n); | ||
| 426 | + // 获得数组Append数据元素的位置 | ||
| 427 | + int l = n; | ||
| 428 | + // 补1操作 | ||
| 429 | + newbyte[l++] = (byte) 0x80; | ||
| 430 | + // 补0操作 | ||
| 431 | + for (int i = 0; i < zeros; i++) { | ||
| 432 | + newbyte[l++] = (byte) 0x00; | ||
| 433 | + } | ||
| 434 | + // 计算数据长度,补数据长度位共8字节,长整型 | ||
| 435 | + long N = (long) n * 8; | ||
| 436 | + byte h8 = (byte) (N & 0xFF); | ||
| 437 | + byte h7 = (byte) ((N >> 8) & 0xFF); | ||
| 438 | + byte h6 = (byte) ((N >> 16) & 0xFF); | ||
| 439 | + byte h5 = (byte) ((N >> 24) & 0xFF); | ||
| 440 | + byte h4 = (byte) ((N >> 32) & 0xFF); | ||
| 441 | + byte h3 = (byte) ((N >> 40) & 0xFF); | ||
| 442 | + byte h2 = (byte) ((N >> 48) & 0xFF); | ||
| 443 | + byte h1 = (byte) (N >> 56); | ||
| 444 | + newbyte[l++] = h1; | ||
| 445 | + newbyte[l++] = h2; | ||
| 446 | + newbyte[l++] = h3; | ||
| 447 | + newbyte[l++] = h4; | ||
| 448 | + newbyte[l++] = h5; | ||
| 449 | + newbyte[l++] = h6; | ||
| 450 | + newbyte[l++] = h7; | ||
| 451 | + newbyte[l++] = h8; | ||
| 452 | + return newbyte; | ||
| 453 | + } | ||
| 454 | + | ||
| 455 | + private int f1(int x, int y, int z) { | ||
| 456 | + return (x & y) | (~x & z); | ||
| 457 | + } | ||
| 458 | + | ||
| 459 | + private int f2(int x, int y, int z) { | ||
| 460 | + return x ^ y ^ z; | ||
| 461 | + } | ||
| 462 | + | ||
| 463 | + private int f3(int x, int y, int z) { | ||
| 464 | + return (x & y) | (x & z) | (y & z); | ||
| 465 | + } | ||
| 466 | + | ||
| 467 | + // | ||
| 468 | + | ||
| 469 | + private int f4(int x, int y) { | ||
| 470 | + return (x << y) | x >>> (32 - y); | ||
| 471 | + } | ||
| 472 | + | ||
| 473 | + /** | ||
| 474 | + * 单元摘要计算函数 | ||
| 475 | + */ | ||
| 476 | + private void encrypt() { | ||
| 477 | + for (int i = 16; i <= 79; i++) { | ||
| 478 | + tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14] | ||
| 479 | + ^ tmpData[i - 16], 1); | ||
| 480 | + } | ||
| 481 | + int[] tmpabcde = new int[5]; | ||
| 482 | + for (int i1 = 0; i1 < tmpabcde.length; i1++) { | ||
| 483 | + tmpabcde[i1] = digestInt[i1]; | ||
| 484 | + } | ||
| 485 | + for (int j = 0; j <= 19; j++) { | ||
| 486 | + int tmp = f4(tmpabcde[0], 5) | ||
| 487 | + + f1(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] | ||
| 488 | + + tmpData[j] + 0x5a827999; | ||
| 489 | + tmpabcde[4] = tmpabcde[3]; | ||
| 490 | + tmpabcde[3] = tmpabcde[2]; | ||
| 491 | + tmpabcde[2] = f4(tmpabcde[1], 30); | ||
| 492 | + tmpabcde[1] = tmpabcde[0]; | ||
| 493 | + tmpabcde[0] = tmp; | ||
| 494 | + } | ||
| 495 | + for (int k = 20; k <= 39; k++) { | ||
| 496 | + int tmp = f4(tmpabcde[0], 5) | ||
| 497 | + + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] | ||
| 498 | + + tmpData[k] + 0x6ed9eba1; | ||
| 499 | + tmpabcde[4] = tmpabcde[3]; | ||
| 500 | + tmpabcde[3] = tmpabcde[2]; | ||
| 501 | + tmpabcde[2] = f4(tmpabcde[1], 30); | ||
| 502 | + tmpabcde[1] = tmpabcde[0]; | ||
| 503 | + tmpabcde[0] = tmp; | ||
| 504 | + } | ||
| 505 | + for (int l = 40; l <= 59; l++) { | ||
| 506 | + int tmp = f4(tmpabcde[0], 5) | ||
| 507 | + + f3(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] | ||
| 508 | + + tmpData[l] + 0x8f1bbcdc; | ||
| 509 | + tmpabcde[4] = tmpabcde[3]; | ||
| 510 | + tmpabcde[3] = tmpabcde[2]; | ||
| 511 | + tmpabcde[2] = f4(tmpabcde[1], 30); | ||
| 512 | + tmpabcde[1] = tmpabcde[0]; | ||
| 513 | + tmpabcde[0] = tmp; | ||
| 514 | + } | ||
| 515 | + for (int m = 60; m <= 79; m++) { | ||
| 516 | + int tmp = f4(tmpabcde[0], 5) | ||
| 517 | + + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] | ||
| 518 | + + tmpData[m] + 0xca62c1d6; | ||
| 519 | + tmpabcde[4] = tmpabcde[3]; | ||
| 520 | + tmpabcde[3] = tmpabcde[2]; | ||
| 521 | + tmpabcde[2] = f4(tmpabcde[1], 30); | ||
| 522 | + tmpabcde[1] = tmpabcde[0]; | ||
| 523 | + tmpabcde[0] = tmp; | ||
| 524 | + } | ||
| 525 | + for (int i2 = 0; i2 < tmpabcde.length; i2++) { | ||
| 526 | + digestInt[i2] = digestInt[i2] + tmpabcde[i2]; | ||
| 527 | + } | ||
| 528 | + for (int n = 0; n < tmpData.length; n++) { | ||
| 529 | + tmpData[n] = 0; | ||
| 530 | + } | ||
| 531 | + } | ||
| 532 | + | ||
| 533 | + /** | ||
| 534 | + * 4字节数组转换为整数 | ||
| 535 | + * | ||
| 536 | + * @param bytedata | ||
| 537 | + * @param i | ||
| 538 | + * @return | ||
| 539 | + */ | ||
| 540 | + private int byteArrayToInt(byte[] bytedata, int i) { | ||
| 541 | + return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16) | ||
| 542 | + | ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff); | ||
| 543 | + } | ||
| 544 | + | ||
| 545 | + /** | ||
| 546 | + * 整数转换为4字节数组 | ||
| 547 | + * | ||
| 548 | + * @param intValue | ||
| 549 | + * @param byteData | ||
| 550 | + * @param i | ||
| 551 | + */ | ||
| 552 | + private void intToByteArray(int intValue, byte[] byteData, int i) { | ||
| 553 | + byteData[i] = (byte) (intValue >>> 24); | ||
| 554 | + byteData[i + 1] = (byte) (intValue >>> 16); | ||
| 555 | + byteData[i + 2] = (byte) (intValue >>> 8); | ||
| 556 | + byteData[i + 3] = (byte) intValue; | ||
| 557 | + } | ||
| 558 | + | ||
| 559 | + /** | ||
| 560 | + * 计算sha-1摘要,返回相应的字节数组 | ||
| 561 | + * | ||
| 562 | + * @param byteData | ||
| 563 | + * @return | ||
| 564 | + */ | ||
| 565 | + public byte[] getDigestOfBytes(byte[] byteData) { | ||
| 566 | + process_input_bytes(byteData); | ||
| 567 | + byte[] digest = new byte[20]; | ||
| 568 | + for (int i = 0; i < digestInt.length; i++) { | ||
| 569 | + intToByteArray(digestInt[i], digest, i * 4); | ||
| 570 | + } | ||
| 571 | + return digest; | ||
| 572 | + } | ||
| 573 | + | ||
| 574 | + /** | ||
| 575 | + * 计算sha-1摘要,返回相应的十六进制字符串 | ||
| 576 | + * | ||
| 577 | + * @param byteData | ||
| 578 | + * @return | ||
| 579 | + */ | ||
| 580 | + public String getDigestOfString(byte[] byteData) { | ||
| 581 | + return byteArrayToHexString(getDigestOfBytes(byteData)); | ||
| 582 | + } | ||
| 583 | + | ||
| 584 | + /** | ||
| 585 | + * @param data | ||
| 586 | + * @return | ||
| 587 | + */ | ||
| 588 | + public String Digest(String data) { | ||
| 589 | + return this.getDigestOfString(data.getBytes()); | ||
| 590 | + } | ||
| 591 | + | ||
| 592 | + /** | ||
| 593 | + * @param data | ||
| 594 | + * @return | ||
| 595 | + */ | ||
| 596 | + public String Digest(String data, String encode) { | ||
| 597 | + try { | ||
| 598 | + return this.getDigestOfString(data.getBytes(encode)); | ||
| 599 | + } catch (UnsupportedEncodingException e) { | ||
| 600 | + return this.Digest(data); | ||
| 601 | + } | ||
| 602 | + } | ||
| 603 | +} | ||
| 604 | + | ||
| 605 | +``` | ||
| 606 | + | ||
| 607 | +5)将sign=signValue拼接到map 参数 <br> | ||
| 608 | +将 sign=signValue拼接到string2后面得到最终的 参数 字符串 | ||
| 609 | +map.put("sign", getSign(map, TOKEN_KEY)); | ||
| 610 | + | ||
| 611 | +6)预支付调用 | ||
| 612 | + | ||
| 613 | +```java | ||
| 614 | +//订单生成: | ||
| 615 | +public static String getOrderId(String frmId) { | ||
| 616 | + StringBuilder sb = new StringBuilder(); | ||
| 617 | + String timestamp = String.valueOf(System.currentTimeMillis()); | ||
| 618 | + sb.append(SPID).append(frmId) | ||
| 619 | + .append(android.text.format.DateFormat.format("yyyyMMdd", new Date()).toString()) | ||
| 620 | + .append(timestamp.substring(timestamp.length() - 8)) | ||
| 621 | + .append((int) (Math.random() * 999)); | ||
| 622 | + LOGD("order id:" + sb.toString()); | ||
| 623 | + return sb.toString(); | ||
| 624 | + } | ||
| 625 | +//Map生成 | ||
| 626 | + public static Map<String, String> getPayVideoOnceToken(String account, | ||
| 627 | + String sid, | ||
| 628 | + String frmId, | ||
| 629 | + ProductInfo info, | ||
| 630 | + String type, | ||
| 631 | + String version | ||
| 632 | + ) { | ||
| 633 | + | ||
| 634 | + String out_trade_no = getOrderId(frmId);//上一步生成的订单 | ||
| 635 | + Map<String, String> map = new LinkedHashMap<>(); | ||
| 636 | + if (!TextUtils.isEmpty(account)) | ||
| 637 | + map.put("account", account); | ||
| 638 | + | ||
| 639 | + map.put("attach.plat", "a"); //附加字段 | ||
| 640 | + map.put("attach.prdId", info.getPrdId()); //附加字段 | ||
| 641 | + map.put("attach.version",version ); //附加字段 | ||
| 642 | + map.put("attach.sid", String.valueOf(sid)); //附加字段 | ||
| 643 | + map.put("attach.spId", USER_SPID); //附加字段 | ||
| 644 | + map.put("body", info.getTitle()); //订单信息 | ||
| 645 | + map.put("frmId", frmId); //渠道 | ||
| 646 | + map.put("notify_url", "http://apps.pay.cnlive.com/upappnotify/notify/orderForVideo"); //回调通知URL | ||
| 647 | + map.put("out_trade_no", out_trade_no); //业务系统中的 订单号 | ||
| 648 | + map.put("sp_id", SPID); | ||
| 649 | + if (BuildConfig.DEBUG){ | ||
| 650 | + map.put("total_fee", "1"); //订单总价 | ||
| 651 | + } else { | ||
| 652 | + map.put("total_fee", "" + info.getRmb()); //订单总价 | ||
| 653 | + } | ||
| 654 | + map.put("type", type); //渠道 | ||
| 655 | + map.put("sign", getSign(map, TOKEN_KEY));//签名上面生成的sign | ||
| 656 | + | ||
| 657 | + return map; | ||
| 658 | +} | ||
| 659 | +/**预支付: | ||
| 660 | +网络请求代码如下:(各团队网络请求封装不一样这里只显示最简单网络请求相应的第三方库如下: (compile 'com.squareup.retrofit2:retrofit:2.0.2' | ||
| 661 | + compile 'com.squareup.retrofit2:converter-gson:2.0.2' | ||
| 662 | + compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2') | ||
| 663 | +代码 | ||
| 664 | +**/ | ||
| 665 | + | ||
| 666 | + RestAdapter restAdapter = new RestAdapter.Builder() | ||
| 667 | + .setLogLevel(RestAdapter.LogLevel.FULL) | ||
| 668 | + .setEndpoint("http://unifypay.cnlive.com") | ||
| 669 | + .setClient(new OkClient(new OkHttpClient())) | ||
| 670 | + .build(); | ||
| 671 | + restAdapter.create(VipPayService.class).newWay2PayVideo(map, new Callback<UnifyPayMessage>() { | ||
| 672 | + @Override | ||
| 673 | + public void success(UnifyPayMessage unifyPayMessage, Response response) { | ||
| 674 | + Logger.e(response.getUrl()); | ||
| 675 | + Logger.e(unifyPayMessage.toString()); | ||
| 676 | + if (unifyPayMessage != null && unifyPayMessage.getStatus().equals("0")) { | ||
| 677 | + LOGD("=====================aplipay ====================="); | ||
| 678 | + | ||
| 679 | + startPay(unifyPayMessage); | ||
| 680 | + } else { | ||
| 681 | + LOGE("支付错误:" + unifyPayMessage.getMsg() + ", url:" + response.getUrl()); | ||
| 682 | + } | ||
| 683 | + } | ||
| 684 | + | ||
| 685 | + @Override | ||
| 686 | + public void failure(RetrofitError error) { | ||
| 687 | + LOGE("支付错误:" + error.getUrl() + ", msg:" + error.getMessage()); | ||
| 688 | + | ||
| 689 | + } | ||
| 690 | + }); | ||
| 691 | + | ||
| 692 | + | ||
| 693 | +//辅助类如下: | ||
| 694 | +//接口类: | ||
| 695 | + | ||
| 696 | + | ||
| 697 | +public interface VipPayService { | ||
| 698 | + @GET("/prepay") | ||
| 699 | + void newWay2PayVideo(@QueryMap Map<String, String> options, | ||
| 700 | + Callback<UnifyPayMessage> callback); | ||
| 701 | + | ||
| 702 | +} | ||
| 703 | +//bean类: | ||
| 704 | +public class UnifyPayMessage { | ||
| 705 | + | ||
| 706 | + private String status; | ||
| 707 | + private String msg; | ||
| 708 | + private String notify_url; | ||
| 709 | + private String order_id; | ||
| 710 | + private String alipay_app; | ||
| 711 | + private WXPrepayInfo wx_app; | ||
| 712 | + | ||
| 713 | + public String getStatus() { | ||
| 714 | + return status; | ||
| 715 | + } | ||
| 716 | + | ||
| 717 | + public void setStatus(String status) { | ||
| 718 | + this.status = status; | ||
| 719 | + } | ||
| 720 | + | ||
| 721 | + public String getMsg() { | ||
| 722 | + return msg; | ||
| 723 | + } | ||
| 724 | + | ||
| 725 | + public void setMsg(String msg) { | ||
| 726 | + this.msg = msg; | ||
| 727 | + } | ||
| 728 | + | ||
| 729 | + public String getNotify_url() { | ||
| 730 | + return notify_url; | ||
| 731 | + } | ||
| 732 | + | ||
| 733 | + public void setNotify_url(String notify_url) { | ||
| 734 | + this.notify_url = notify_url; | ||
| 735 | + } | ||
| 736 | + | ||
| 737 | + public String getOrder_id() { | ||
| 738 | + return order_id; | ||
| 739 | + } | ||
| 740 | + | ||
| 741 | + public void setOrder_id(String order_id) { | ||
| 742 | + this.order_id = order_id; | ||
| 743 | + } | ||
| 744 | + | ||
| 745 | + public WXPrepayInfo getWx_app() { | ||
| 746 | + return wx_app; | ||
| 747 | + } | ||
| 748 | + | ||
| 749 | + public void setWx_app(WXPrepayInfo wx_app) { | ||
| 750 | + this.wx_app = wx_app; | ||
| 751 | + } | ||
| 752 | + | ||
| 753 | + public String getAlipay_app() { | ||
| 754 | + return alipay_app; | ||
| 755 | + } | ||
| 756 | + | ||
| 757 | + public void setAlipay_app(String alipay_app) { | ||
| 758 | + this.alipay_app = alipay_app; | ||
| 759 | + } | ||
| 760 | + | ||
| 761 | + @Override | ||
| 762 | + public String toString() { | ||
| 763 | + return "UnifyPayMessage{" + | ||
| 764 | + "status='" + status + '\'' + | ||
| 765 | + ", msg='" + msg + '\'' + | ||
| 766 | + ", notify_url='" + notify_url + '\'' + | ||
| 767 | + ", order_id='" + order_id + '\'' + | ||
| 768 | + ", alipay_app='" + alipay_app + '\'' + | ||
| 769 | + ", wx_app=" + wx_app + | ||
| 770 | + '}'; | ||
| 771 | + } | ||
| 772 | +} | ||
| 773 | + | ||
| 774 | +``` | ||
| 775 | + | ||
| 776 | +7)支付以及结果判断 | ||
| 777 | +支付宝支付: | ||
| 778 | +第一步为异步支付,第二步异步支付结果判断是否成功 | ||
| 779 | +支付: | ||
| 780 | + | ||
| 781 | +```java | ||
| 782 | + private void startPay(final UnifyPayMessage unifyPayMessage) { | ||
| 783 | + if(unifyPayMessage == null || unifyPayMessage.getAlipay_app() == null)return; | ||
| 784 | + try { | ||
| 785 | + //签名拼接支付信息操作交由后台 | ||
| 786 | + LOGD("ExternalPartner start pay"); | ||
| 787 | + // start the pay. | ||
| 788 | + Runnable payRunnable = new Runnable() { | ||
| 789 | + @Override | ||
| 790 | + public void run() { | ||
| 791 | + PayTask alipay = new PayTask(mActivity); | ||
| 792 | + String result = alipay.pay(unifyPayMessage.getAlipay_app()); | ||
| 793 | + | ||
| 794 | + Message msg = new Message(); | ||
| 795 | + msg.what = SDK_PAY_FLAG; | ||
| 796 | + msg.obj = result; | ||
| 797 | + alipayHandler.sendMessage(msg); | ||
| 798 | + } | ||
| 799 | + }; | ||
| 800 | + | ||
| 801 | + Thread payThread = new Thread(payRunnable); | ||
| 802 | + payThread.start(); | ||
| 803 | + | ||
| 804 | + } catch (Exception ex) { | ||
| 805 | + LOGE("alipay error".concat(ex.getMessage()), ex); | ||
| 806 | + ToastUtil.show(mActivity, | ||
| 807 | +mActivity.getString(R.string.remote_call_failed)); | ||
| 808 | + } | ||
| 809 | +} | ||
| 810 | +//结果判断: | ||
| 811 | + private Handler alipayHandler = new Handler() { | ||
| 812 | + @Override | ||
| 813 | + public void handleMessage(Message msg) { | ||
| 814 | + switch (msg.what) { | ||
| 815 | + case SDK_PAY_FLAG: | ||
| 816 | + closeProgress(); | ||
| 817 | + if (mActivity != null) { | ||
| 818 | + Result resultObj = new Result((String) msg.obj); | ||
| 819 | + String resultStatus = resultObj.resultStatus; | ||
| 820 | + | ||
| 821 | + // 判断resultStatus 为“9000”则代表支付成功,具 | ||
| 822 | +体状态码代表含义可参考接口文档 | ||
| 823 | + if (resultStatus.equals("9000")) { | ||
| 824 | + ToastUtil.show(mActivity, "支付成功"); | ||
| 825 | + EventBus.getDefault().post(new | ||
| 826 | +EventPayment(PayUtil.PAY_TYPE_ALIPAY, PayUtil.PAY_RESULT_STATUS_SUCCESS)); | ||
| 827 | + } else { | ||
| 828 | + // 判断resultStatus 为非“9000”则代表可能支付失败 | ||
| 829 | + // “8000” 代表支付结果因为支付渠道原因或 | ||
| 830 | +者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准 | ||
| 831 | +(小概率状态) | ||
| 832 | + if (resultStatus.equals("8000")) { | ||
| 833 | + ToastUtil.show(mActivity, "支付结果确认中"); | ||
| 834 | + } else { | ||
| 835 | + ToastUtil.show(mActivity, "支付失败"); | ||
| 836 | + EventBus.getDefault().post(new | ||
| 837 | +EventPayment(PayUtil.PAY_TYPE_ALIPAY, PayUtil.PAY_RESULT_STATUS_FAIL)); | ||
| 838 | + } | ||
| 839 | + } | ||
| 840 | + } | ||
| 841 | + break; | ||
| 842 | + default: | ||
| 843 | + break; | ||
| 844 | + } | ||
| 845 | + } | ||
| 846 | + }; | ||
| 847 | +//微信支付: | ||
| 848 | +//预支付订单生成之后调用支付订单 | ||
| 849 | +private void genPayReq(UnifyPayMessage unifyPayMessage) { | ||
| 850 | + PayReq req = new PayReq(); | ||
| 851 | + req.appId = unifyPayMessage.getWx_app().getAppid(); | ||
| 852 | + req.partnerId = unifyPayMessage.getWx_app().getPartnerid(); | ||
| 853 | + req.prepayId = unifyPayMessage.getWx_app().getPrepayid(); | ||
| 854 | + req.packageValue = "Sign=WXPay"; | ||
| 855 | + req.nonceStr = unifyPayMessage.getWx_app().getNoncestr(); | ||
| 856 | + req.timeStamp = unifyPayMessage.getWx_app().getTimestamp(); | ||
| 857 | + req.sign = unifyPayMessage.getWx_app().getSign(); | ||
| 858 | + | ||
| 859 | + // 发起支付请求 | ||
| 860 | + msgApi.registerApp(Constants.APP_ID); | ||
| 861 | + msgApi.sendReq(req); | ||
| 862 | + } | ||
| 863 | + | ||
| 864 | +``` | ||
| 249 | \ No newline at end of file | 865 | \ No newline at end of file |