相信相同过App获取利润的都会需要接入计费SDK,下边就跟大家走一遍完整的支付宝SDK接入,支付系列均通过计费Button触发,计费所有代码均放到一个java文件实现,这样虽然会有点违背java面向对象及封装性,但这样做的一个好处是可以快速集成到不同的游戏中,将改动的文件降到最低,各有利弊吧,如果大家有什么更好的方法,望一起交流,好了,废话不多说了,开始干活。

PS:初次写博文,各方面还不够完善,看到此博文的朋友有什么意见或者建议请回复或者留言,你们的支持是我最大的动力。
注意事项
1.添加android.permission.INTERNET权限和android.permission.ACCESS_NETWORK_STATE权限
2.代码中出现注释的地方重点看,没注释的地方可以不看
3.想获取支付宝合作商户ID,及支付宝公钥请点击支付宝链接,生成密钥及PKCS8转码工具在文档中
代码
 
MainActivity:
[java]  view plain copy
  1. package com.example.blogforzfb;
  2. import android.os.Bundle;
  3. import android.view.View;
  4. import android.app.Activity;
  5. public class MainActivity extends Activity {
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_main);
  10. findViewById(R.id.button1).setOnClickListener(
  11. new View.OnClickListener() {
  12. @Override
  13. public void onClick(View v) {
  14. // TODO Auto-generated method stub
  15. // 拿到Fiap对象并传入容器
  16. Fiap fiap = new Fiap(MainActivity.this);
  17. // 调用支付方法,并传入支付金额
  18. fiap.android_pay(0.01);
  19. }
  20. });
  21. }
  22. }

Fiap.java(支付逻辑所在文件)
 
[java]  view plain copy
  1. package com.example.blogforzfb;
  2. // 支付宝应用支付
  3. // 2012-09-20 14:41:47
  4. // (c) 2012 Catcap
  5. import java.io.BufferedReader;
  6. import java.io.File;
  7. import java.io.FileOutputStream;
  8. import java.io.IOException;
  9. import java.io.InputStream;
  10. import java.io.InputStreamReader;
  11. import java.io.OutputStream;
  12. import java.net.HttpURLConnection;
  13. import java.net.InetSocketAddress;
  14. import java.net.Proxy;
  15. import java.net.URL;
  16. import java.net.URLEncoder;
  17. import java.security.KeyFactory;
  18. import java.security.PrivateKey;
  19. import java.security.PublicKey;
  20. import java.security.spec.PKCS8EncodedKeySpec;
  21. import java.security.spec.X509EncodedKeySpec;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. import javax.net.ssl.HostnameVerifier;
  25. import javax.net.ssl.HttpsURLConnection;
  26. import javax.net.ssl.SSLSession;
  27. import org.apache.http.client.entity.UrlEncodedFormEntity;
  28. import org.apache.http.message.BasicNameValuePair;
  29. import org.json.JSONException;
  30. import org.json.JSONObject;
  31. import com.alipay.android.app.IAlixPay;
  32. import com.alipay.android.app.IRemoteServiceCallback;
  33. import android.annotation.SuppressLint;
  34. import android.app.Activity;
  35. import android.app.AlertDialog;
  36. import android.app.ProgressDialog;
  37. import android.content.ComponentName;
  38. import android.content.Context;
  39. import android.content.DialogInterface;
  40. import android.content.Intent;
  41. import android.content.ServiceConnection;
  42. import android.content.pm.PackageInfo;
  43. import android.content.pm.PackageManager;
  44. import android.net.ConnectivityManager;
  45. import android.net.NetworkInfo;
  46. import android.net.Uri;
  47. import android.os.Bundle;
  48. import android.os.Handler;
  49. import android.os.IBinder;
  50. import android.os.Looper;
  51. import android.os.Message;
  52. import android.os.RemoteException;
  53. import android.util.Log;
  54. import android.view.KeyEvent;
  55. import android.widget.Toast;
  56. @SuppressLint ("HandlerLeak")
  57. public class Fiap{
  58. Activity mActivity = null;
  59. // ===================================
  60. // JAVA 的接口
  61. // ===================================
  62. public Fiap(Activity activity){
  63. mActivity = activity;
  64. }
  65. //这里传过来的是想支付多少钱(最好定义成double的,方便调试,毕竟每次测试都支付几元大洋不是每个人都负担的起的)
  66. public void android_pay (double coin){
  67. //支付宝支付必须依赖网络,所以在这里必须加网络判定
  68. if (!is_can_internet (mActivity)){
  69. fiapHandler.sendEmptyMessage(1);
  70. return;
  71. }
  72. Message msg = new Message ();
  73. Bundle bundle = new Bundle();
  74. bundle.putDouble("coin", coin);
  75. msg.setData(bundle);
  76. msg.what = 1;
  77. fss.sendMessage (msg);
  78. }
  79. private Handler fiapHandler = new Handler(){
  80. public void handleMessage(Message msg) {
  81. if (msg.what == 1) {
  82. new AlertDialog.Builder (mActivity).setTitle ("提示").setMessage ("连接不到网络。").setPositiveButton ("确定", new DialogInterface.OnClickListener() {
  83. @Override
  84. public void onClick(DialogInterface dialog, int which) {
  85. // TODO Auto-generated method stub
  86. Intent intent = new Intent(
  87. "android.settings.WIFI_SETTINGS");
  88. mActivity.startActivity(intent);
  89. }
  90. }).create ().show ();
  91. }
  92. };
  93. };
  94. // ===================================
  95. // 支付宝
  96. // ===================================
  97. public class PartnerConfig {
  98. //以下配置涉及到公司内容,所以略去,需自己配置
  99. // 合作商户ID。用签约支付宝账号登录ms.alipay.com后,在账户信息页面获取。
  100. public static final String PARTNER = "";
  101. // 商户收款的支付宝账号
  102. public static final String SELLER = "";
  103. // 商户(RSA)私钥(注意一定要转PKCS8格式,否则在Android4.0及以上系统会支付失败)
  104. public static final String RSA_PRIVATE = "";
  105. // 支付宝(RSA)公钥用签约支付宝账号登录ms.alipay.com后,在密钥管理页面获取。
  106. public static final String RSA_ALIPAY_PUBLIC = "";
  107. }
  108. private ProgressDialog mProgress = null;
  109. public static class AlixOnCancelListener implements DialogInterface.OnCancelListener {
  110. Activity mcontext;
  111. AlixOnCancelListener (Activity context){
  112. mcontext = context;
  113. }
  114. public void onCancel (DialogInterface dialog){
  115. mcontext.onKeyDown (KeyEvent.KEYCODE_BACK, null);
  116. }
  117. }
  118. private Handler fss = new Handler (){
  119. @SuppressWarnings ("deprecation")
  120. public void handleMessage (Message msg){
  121. MobileSecurePayHelper mspHelper = new MobileSecurePayHelper (mActivity);
  122. boolean isMobile_spExist = mspHelper.detectMobile_sp ();
  123. if (!isMobile_spExist)
  124. return;
  125. // 根据订单信息开始进行支付
  126. try{
  127. // 准备订单信息
  128. Bundle bundle = msg.getData();
  129. double _coin = bundle.getDouble("coin");
  130. String orderInfo = getOrderInfo(_coin);
  131. // 这里根据签名方式对订单信息进行签名
  132. String signType = getSignType ();
  133. String strsign = sign (signType, orderInfo);
  134. // 对签名进行编码
  135. strsign = URLEncoder.encode (strsign);
  136. // 组装好参数
  137. String info = orderInfo + "&sign=" + """ + strsign + """ + "&" + getSignType ();
  138. // 调用pay方法进行支付
  139. MobileSecurePayer msp = new MobileSecurePayer ();
  140. boolean bRet = msp.pay (info, mHandler, AlixId.RQF_PAY, mActivity);
  141. if (bRet){
  142. // 显示“正在支付”进度条
  143. closeProgress ();
  144. mProgress = BaseHelper.showProgress (mActivity, null, "正在支付", false, true);
  145. }
  146. } catch (Exception ex){
  147. ex.printStackTrace ();
  148. }
  149. }
  150. };
  151. private Handler mHandler = new Handler (){
  152. public void handleMessage (Message msg){
  153. try{
  154. String strRet = (String) msg.obj;
  155. switch (msg.what){
  156. case AlixId.RQF_PAY:{
  157. //
  158. closeProgress ();
  159. // 处理交易结果
  160. try{
  161. // 获取交易状态码,具体状态代码请参看文档
  162. String tradeStatus = "resultStatus={";
  163. int imemoStart = strRet.indexOf ("resultStatus=");
  164. imemoStart += tradeStatus.length ();
  165. int imemoEnd = strRet.indexOf ("};memo=");
  166. tradeStatus = strRet.substring (imemoStart, imemoEnd);
  167. //先验签通知
  168. ResultChecker resultChecker = new ResultChecker (strRet);
  169. int retVal = resultChecker.checkSign ();
  170. if (retVal == ResultChecker.RESULT_CHECK_SIGN_FAILED){
  171. BaseHelper.showDialog (mActivity, "提示", "您的订单信息已被非法篡改。", android.R.drawable.ic_dialog_alert);
  172. } else{
  173. if (tradeStatus.equals ("9000")){
  174. //程序到这里表示支付已经成功了,想干什么就在这里干吧 -v-
  175. Toast.makeText(mActivity, "支付成功",Toast.LENGTH_LONG).show();
  176. Log.i("result of this pay:", "successful");
  177. } else if (!tradeStatus.equals ("4000")){
  178. //程序到这里表示此次支付失败,查看具体原因可以从这里打印个log
  179. Toast.makeText(mActivity, "支付失败,交易状态码为:" + tradeStatus, Toast.LENGTH_LONG).show();
  180. Log.e("result of this pay", "falied");
  181. }
  182. }
  183. } catch (Exception e){
  184. e.printStackTrace ();
  185. }
  186. }
  187. break;
  188. }
  189. super.handleMessage (msg);
  190. } catch (Exception e){
  191. e.printStackTrace ();
  192. }
  193. }
  194. };
  195. String getSignType (){
  196. String getSignType = "sign_type=" + """ + "RSA" + """;
  197. return getSignType;
  198. }
  199. void closeProgress (){
  200. try{
  201. if (mProgress != null){
  202. mProgress.dismiss ();
  203. mProgress = null;
  204. }
  205. } catch (Exception e){
  206. e.printStackTrace ();
  207. }
  208. }
  209. String getOrderInfo (double position){
  210. String strOrderInfo = "partner=" + """ + PartnerConfig.PARTNER + """;
  211. strOrderInfo += "&";
  212. strOrderInfo += "seller=" + """ + PartnerConfig.SELLER + """;
  213. strOrderInfo += "&";
  214. strOrderInfo += "out_trade_no=" + """ + get_order_id () + """;
  215. strOrderInfo += "&";
  216. //这里是显示到支付宝支付界面上的付费信息提示(这里一定要严格按照此格式填写)
  217. strOrderInfo += "subject=" + ""猫币"";
  218. strOrderInfo += "&";
  219. strOrderInfo += "body=" + ""购买猫币"";
  220. strOrderInfo += "&";
  221. strOrderInfo += "total_fee=" + """ + position + """;
  222. strOrderInfo += "&";
  223. strOrderInfo += "notify_url=" + """ + "http://notify.java.jpxx.org/index.jsp" + """;
  224. return strOrderInfo;
  225. }
  226. String sign (String signType, String content){
  227. return Rsa.sign (content, PartnerConfig.RSA_PRIVATE);
  228. }
  229. public boolean is_can_internet (final Context context){
  230. try{
  231. ConnectivityManager manger = (ConnectivityManager) context.getSystemService (Context.CONNECTIVITY_SERVICE);
  232. NetworkInfo info = manger.getActiveNetworkInfo ();
  233. return (info != null && info.isConnected ());
  234. } catch (Exception e){
  235. return false;
  236. }
  237. }
  238. public String get_order_id (){
  239. long ran1 = get_round (1111, 9999);
  240. long ran2 = get_round (1111, 9999);
  241. //注掉的这里是返回的渠道号(我们用的友盟)+随机数和当前系统时间组合
  242. //return android_get_umeng_channel () + "_" + ran1 + System.currentTimeMillis () + ran2;
  243. return "_"+ran1 + System.currentTimeMillis () + ran2;
  244. }
  245. public long get_round (int min, int max){
  246. return Math.round (Math.random () * (max - min) + min);
  247. }
  248. =================================================================================================
  249. //
  250. // 支付宝不用动的
  251. // ==================================================================================================
  252. public final class AlixId {
  253. public static final int BASE_ID = 0;
  254. public static final int RQF_PAY = BASE_ID + 1;
  255. public static final int RQF_INSTALL_CHECK = RQF_PAY + 1;
  256. }
  257. final class AlixDefine {
  258. public static final String IMEI = "imei";
  259. public static final String IMSI = "imsi";
  260. public static final String KEY = "key";
  261. public static final String USER_AGENT = "user_agent";
  262. public static final String VERSION = "version";
  263. public static final String DEVICE = "device";
  264. public static final String SID = "sid";
  265. public static final String partner = "partner";
  266. public static final String charset = "charset";
  267. public static final String sign_type = "sign_type";
  268. public static final String sign = "sign";
  269. public static final String URL = "URL";
  270. public static final String split = "&";
  271. public static final String AlixPay = "AlixPay";
  272. public static final String action = "action";
  273. public static final String actionUpdate = "update";
  274. public static final String data = "data";
  275. public static final String platform = "platform";
  276. }
  277. public static final class Base64 {
  278. static private final int BASELENGTH = 128;
  279. static private final int LOOKUPLENGTH = 64;
  280. static private final int TWENTYFOURBITGROUP = 24;
  281. static private final int EIGHTBIT = 8;
  282. static private final int SIXTEENBIT = 16;
  283. static private final int FOURBYTE = 4;
  284. static private final int SIGN = -128;
  285. static private final char PAD = '=';
  286. static private final boolean fDebug = false;
  287. static final private byte[] base64Alphabet = new byte[BASELENGTH];
  288. static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
  289. static{
  290. for (int i = 0; i < BASELENGTH; ++i){
  291. base64Alphabet[i] = -1;
  292. }
  293. for (int i = 'Z'; i >= 'A'; i--){
  294. base64Alphabet[i] = (byte) (i - 'A');
  295. }
  296. for (int i = 'z'; i >= 'a'; i--){
  297. base64Alphabet[i] = (byte) (i - 'a' + 26);
  298. }
  299. for (int i = '9'; i >= '0'; i--){
  300. base64Alphabet[i] = (byte) (i - '0' + 52);
  301. }
  302. base64Alphabet['+'] = 62;
  303. base64Alphabet['/'] = 63;
  304. for (int i = 0; i <= 25; i++){
  305. lookUpBase64Alphabet[i] = (char) ('A' + i);
  306. }
  307. for (int i = 26, j = 0; i <= 51; i++, j++){
  308. lookUpBase64Alphabet[i] = (char) ('a' + j);
  309. }
  310. for (int i = 52, j = 0; i <= 61; i++, j++){
  311. lookUpBase64Alphabet[i] = (char) ('0' + j);
  312. }
  313. lookUpBase64Alphabet[62] = (char) '+';
  314. lookUpBase64Alphabet[63] = (char) '/';
  315. }
  316. private static boolean isWhiteSpace (char octect){
  317. return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
  318. }
  319. private static boolean isPad (char octect){
  320. return (octect == PAD);
  321. }
  322. private static boolean isData (char octect){
  323. return (octect < BASELENGTH && base64Alphabet[octect] != -1);
  324. }
  325. public static String encode (byte[] binaryData){
  326. if (binaryData == null){
  327. return null;
  328. }
  329. int lengthDataBits = binaryData.length * EIGHTBIT;
  330. if (lengthDataBits == 0){
  331. return "";
  332. }
  333. int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
  334. int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
  335. int numberQuartet = fewerThan24bits != 0? numberTriplets + 1 : numberTriplets;
  336. char encodedData[] = null;
  337. encodedData = new char[numberQuartet * 4];
  338. byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
  339. int encodedIndex = 0;
  340. int dataIndex = 0;
  341. if (fDebug){
  342. System.out.println ("number of triplets = " + numberTriplets);
  343. }
  344. for (int i = 0; i < numberTriplets; i++){
  345. b1 = binaryData[dataIndex++];
  346. b2 = binaryData[dataIndex++];
  347. b3 = binaryData[dataIndex++];
  348. if (fDebug){
  349. System.out.println ("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
  350. }
  351. l = (byte) (b2 & 0x0f);
  352. k = (byte) (b1 & 0x03);
  353. byte val1 = ((b1 & SIGN) == 0)? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
  354. byte val2 = ((b2 & SIGN) == 0)? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
  355. byte val3 = ((b3 & SIGN) == 0)? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
  356. if (fDebug){
  357. System.out.println ("val2 = " + val2);
  358. System.out.println ("k4   = " + (k << 4));
  359. System.out.println ("vak  = " + (val2 | (k << 4)));
  360. }
  361. encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
  362. encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
  363. encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
  364. encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
  365. }
  366. // form integral number of 6-bit groups
  367. if (fewerThan24bits == EIGHTBIT){
  368. b1 = binaryData[dataIndex];
  369. k = (byte) (b1 & 0x03);
  370. if (fDebug){
  371. System.out.println ("b1=" + b1);
  372. System.out.println ("b1<<2 = " + (b1 >> 2));
  373. }
  374. byte val1 = ((b1 & SIGN) == 0)? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
  375. encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
  376. encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
  377. encodedData[encodedIndex++] = PAD;
  378. encodedData[encodedIndex++] = PAD;
  379. } else if (fewerThan24bits == SIXTEENBIT){
  380. b1 = binaryData[dataIndex];
  381. b2 = binaryData[dataIndex + 1];
  382. l = (byte) (b2 & 0x0f);
  383. k = (byte) (b1 & 0x03);
  384. byte val1 = ((b1 & SIGN) == 0)? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
  385. byte val2 = ((b2 & SIGN) == 0)? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
  386. encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
  387. encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
  388. encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
  389. encodedData[encodedIndex++] = PAD;
  390. }
  391. return new String (encodedData);
  392. }
  393. public static byte[] decode (String encoded){
  394. if (encoded == null){
  395. return null;
  396. }
  397. char[] base64Data = encoded.toCharArray ();
  398. // remove white spaces
  399. int len = removeWhiteSpace (base64Data);
  400. if (len % FOURBYTE != 0){
  401. return null;// should be divisible by four
  402. }
  403. int numberQuadruple = (len / FOURBYTE);
  404. if (numberQuadruple == 0){
  405. return new byte[0];
  406. }
  407. byte decodedData[] = null;
  408. byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
  409. char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
  410. int i = 0;
  411. int encodedIndex = 0;
  412. int dataIndex = 0;
  413. decodedData = new byte[(numberQuadruple) * 3];
  414. for (; i < numberQuadruple - 1; i++){
  415. if (!isData ((d1 = base64Data[dataIndex++])) || !isData ((d2 = base64Data[dataIndex++])) || !isData ((d3 = base64Data[dataIndex++])) || !isData ((d4 = base64Data[dataIndex++]))){
  416. return null;
  417. }// if found "no data" just return null
  418. b1 = base64Alphabet[d1];
  419. b2 = base64Alphabet[d2];
  420. b3 = base64Alphabet[d3];
  421. b4 = base64Alphabet[d4];
  422. decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
  423. decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
  424. decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
  425. }
  426. if (!isData ((d1 = base64Data[dataIndex++])) || !isData ((d2 = base64Data[dataIndex++]))){
  427. return null;// if found "no data" just return null
  428. }
  429. b1 = base64Alphabet[d1];
  430. b2 = base64Alphabet[d2];
  431. d3 = base64Data[dataIndex++];
  432. d4 = base64Data[dataIndex++];
  433. if (!isData ((d3)) || !isData ((d4))){// Check if they are PAD characters
  434. if (isPad (d3) && isPad (d4)){
  435. if ((b2 & 0xf) != 0)// last 4 bits should be zero
  436. {
  437. return null;
  438. }
  439. byte[] tmp = new byte[i * 3 + 1];
  440. System.arraycopy (decodedData, 0, tmp, 0, i * 3);
  441. tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
  442. return tmp;
  443. } else if (!isPad (d3) && isPad (d4)){
  444. b3 = base64Alphabet[d3];
  445. if ((b3 & 0x3) != 0)// last 2 bits should be zero
  446. {
  447. return null;
  448. }
  449. byte[] tmp = new byte[i * 3 + 2];
  450. System.arraycopy (decodedData, 0, tmp, 0, i * 3);
  451. tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
  452. tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
  453. return tmp;
  454. } else{
  455. return null;
  456. }
  457. } else{ // No PAD e.g 3cQl
  458. b3 = base64Alphabet[d3];
  459. b4 = base64Alphabet[d4];
  460. decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
  461. decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
  462. decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
  463. }
  464. return decodedData;
  465. }
  466. private static int removeWhiteSpace (char[] data){
  467. if (data == null){
  468. return 0;
  469. }
  470. // count characters that's not whitespace
  471. int newSize = 0;
  472. int len = data.length;
  473. for (int i = 0; i < len; i++){
  474. if (!isWhiteSpace (data[i])){
  475. data[newSize++] = data[i];
  476. }
  477. }
  478. return newSize;
  479. }
  480. }
  481. public static class BaseHelper {
  482. public static String convertStreamToString (InputStream is){
  483. BufferedReader reader = new BufferedReader (new InputStreamReader (is));
  484. StringBuilder sb = new StringBuilder ();
  485. String line = null;
  486. try{
  487. while ((line = reader.readLine ()) != null){
  488. sb.append (line);
  489. }
  490. } catch (IOException e){
  491. e.printStackTrace ();
  492. } finally{
  493. try{
  494. is.close ();
  495. } catch (IOException e){
  496. e.printStackTrace ();
  497. }
  498. }
  499. return sb.toString ();
  500. }
  501. public static void showDialog (Activity context, String strTitle, String strText, int icon){
  502. AlertDialog.Builder tDialog = new AlertDialog.Builder (context);
  503. tDialog.setIcon (icon);
  504. tDialog.setTitle (strTitle);
  505. tDialog.setMessage (strText);
  506. tDialog.setPositiveButton ("确定", null);
  507. tDialog.show ();
  508. }
  509. public static void log (String tag, String info){
  510. // Log.d(tag, info);
  511. }
  512. public static void chmod (String permission, String path){
  513. try{
  514. String command = "chmod " + permission + " " + path;
  515. Runtime runtime = Runtime.getRuntime ();
  516. runtime.exec (command);
  517. } catch (IOException e){
  518. e.printStackTrace ();
  519. }
  520. }
  521. //
  522. // show the progress bar.
  523. public static ProgressDialog showProgress (Context context, CharSequence title, CharSequence message, boolean indeterminate, boolean cancelable){
  524. ProgressDialog dialog = new ProgressDialog (context);
  525. dialog.setTitle (title);
  526. dialog.setMessage (message);
  527. dialog.setIndeterminate (indeterminate);
  528. dialog.setCancelable (false);
  529. // dialog.setDefaultButton(false);
  530. dialog.setOnCancelListener (new Fiap.AlixOnCancelListener ((Activity) context));
  531. dialog.show ();
  532. return dialog;
  533. }
  534. public static JSONObject string2JSON (String str, String split){
  535. JSONObject json = new JSONObject ();
  536. try{
  537. String[] arrStr = str.split (split);
  538. for (int i = 0; i < arrStr.length; i++){
  539. String[] arrKeyValue = arrStr[i].split ("=");
  540. json.put (arrKeyValue[0], arrStr[i].substring (arrKeyValue[0].length () + 1));
  541. }
  542. } catch (Exception e){
  543. e.printStackTrace ();
  544. }
  545. return json;
  546. }
  547. }
  548. public class Constant {
  549. public final static String server_url = "https://msp.alipay.com/x.htm";
  550. }
  551. public class MobileSecurePayer {
  552. Integer lock = 0;
  553. IAlixPay mAlixPay = null;
  554. boolean mbPaying = false;
  555. Activity mActivity = null;
  556. // 和安全支付服务建立连接
  557. private ServiceConnection mAlixPayConnection = new ServiceConnection (){
  558. public void onServiceConnected (ComponentName className, IBinder service){
  559. //
  560. // wake up the binder to continue.
  561. // 获得通信通道
  562. synchronized (lock){
  563. mAlixPay = IAlixPay.Stub.asInterface (service);
  564. lock.notify ();
  565. }
  566. }
  567. public void onServiceDisconnected (ComponentName className){
  568. mAlixPay = null;
  569. }
  570. };
  571. public boolean pay (final String strOrderInfo, final Handler callback, final int myWhat, final Activity activity){
  572. if (mbPaying)
  573. return false;
  574. mbPaying = true;
  575. //
  576. mActivity = activity;
  577. // bind the service.
  578. // 绑定服务
  579. if (mAlixPay == null){
  580. // 绑定安全支付服务需要获取上下文环境,
  581. // 如果绑定不成功使用mActivity.getApplicationContext().bindService
  582. // 解绑时同理
  583. mActivity.getApplicationContext ().bindService (new Intent (IAlixPay.class.getName ()), mAlixPayConnection, Context.BIND_AUTO_CREATE);
  584. }
  585. // else ok.
  586. // 实例一个线程来进行支付
  587. new Thread (new Runnable (){
  588. public void run (){
  589. try{
  590. // wait for the service bind operation to completely
  591. // finished.
  592. // Note: this is important,otherwise the next mAlixPay.Pay()
  593. // will fail.
  594. // 等待安全支付服务绑定操作结束
  595. // 注意:这里很重要,否则mAlixPay.Pay()方法会失败
  596. synchronized (lock){
  597. if (mAlixPay == null)
  598. lock.wait ();
  599. }
  600. // register a Callback for the service.
  601. // 为安全支付服务注册一个回调
  602. mAlixPay.registerCallback (mCallback);
  603. // call the MobileSecurePay service.
  604. // 调用安全支付服务的pay方法
  605. String strRet = mAlixPay.Pay (strOrderInfo);
  606. // set the flag to indicate that we have finished.
  607. // unregister the Callback, and unbind the service.
  608. // 将mbPaying置为false,表示支付结束
  609. // 移除回调的注册,解绑安全支付服务
  610. mbPaying = false;
  611. mAlixPay.unregisterCallback (mCallback);
  612. mActivity.getApplicationContext ().unbindService (mAlixPayConnection);
  613. // send the result back to caller.
  614. // 发送交易结果
  615. Message msg = new Message ();
  616. msg.what = myWhat;
  617. msg.obj = strRet;
  618. callback.sendMessage (msg);
  619. } catch (Exception e){
  620. e.printStackTrace ();
  621. // send the result back to caller.
  622. // 发送交易结果
  623. Message msg = new Message ();
  624. msg.what = myWhat;
  625. msg.obj = e.toString ();
  626. callback.sendMessage (msg);
  627. }
  628. }
  629. }).start ();
  630. return true;
  631. }
  632. private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub (){
  633. public void startActivity (String packageName, String className, int iCallingPid, Bundle bundle) throws RemoteException{
  634. Intent intent = new Intent (Intent.ACTION_MAIN, null);
  635. if (bundle == null)
  636. bundle = new Bundle ();
  637. // else ok.
  638. try{
  639. bundle.putInt ("CallingPid", iCallingPid);
  640. intent.putExtras (bundle);
  641. } catch (Exception e){
  642. e.printStackTrace ();
  643. }
  644. intent.setClassName (packageName, className);
  645. mActivity.startActivity (intent);
  646. }
  647. @Override
  648. public boolean isHideLoadingScreen () throws RemoteException{
  649. return false;
  650. }
  651. @Override
  652. public void payEnd (boolean arg0, String arg1) throws RemoteException{
  653. }
  654. };
  655. }
  656. public class MobileSecurePayHelper {
  657. static final String TAG = "MobileSecurePayHelper";
  658. private ProgressDialog mProgress = null;
  659. Context mContext = null;
  660. public MobileSecurePayHelper (Context context){
  661. this.mContext = context;
  662. }
  663. public boolean detectMobile_sp (){
  664. boolean isMobile_spExist = isMobile_spExist ();
  665. if (!isMobile_spExist){
  666. // 获取系统缓冲绝对路径获取/data/data//cache目录
  667. File cacheDir = mContext.getCacheDir ();
  668. final String cachePath = cacheDir.getAbsolutePath () + "/temp.apk";
  669. mProgress = BaseHelper.showProgress (mContext, null, "正在检测安全支付服务版本", false, true);
  670. // 实例新线程检测是否有新版本进行下载
  671. new Thread (new Runnable (){
  672. public void run (){
  673. // 检测是否有新的版本。
  674. String newApkdlUrl = checkNewUpdate ();
  675. closeProgress ();
  676. // 动态下载
  677. if (newApkdlUrl != null)
  678. retrieveApkFromNet (mContext, newApkdlUrl, cachePath);
  679. showInstallConfirmDialog (mContext, cachePath);
  680. }
  681. }).start ();
  682. }
  683. return isMobile_spExist;
  684. }
  685. public void showInstallConfirmDialog (final Context context, final String cachePath){
  686. Looper.prepare ();
  687. AlertDialog.Builder tDialog = new AlertDialog.Builder (context);
  688. tDialog.setTitle ("安装提示");
  689. tDialog.setMessage ("为保证您的交易安全,需要您安装支付宝安全支付服务,才能进行付款。\n\n点击确定,立即安装。");
  690. tDialog.setPositiveButton ("确定", new DialogInterface.OnClickListener (){
  691. public void onClick (DialogInterface dialog, int which){
  692. //
  693. // 修改apk权限
  694. BaseHelper.chmod ("777", cachePath);
  695. //
  696. // install the apk.
  697. // 安装安全支付服务APK
  698. Intent intent = new Intent (Intent.ACTION_VIEW);
  699. intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
  700. intent.setDataAndType (Uri.parse ("file://" + cachePath), "application/vnd.android.package-archive");
  701. context.startActivity (intent);
  702. }
  703. });
  704. tDialog.setNegativeButton ("取消", new DialogInterface.OnClickListener (){
  705. public void onClick (DialogInterface dialog, int which){}
  706. });
  707. tDialog.show ();
  708. Looper.loop ();
  709. }
  710. public boolean isMobile_spExist (){
  711. PackageManager manager = mContext.getPackageManager ();
  712. List<PackageInfo> pkgList = manager.getInstalledPackages (0);
  713. for (int i = 0; i < pkgList.size (); i++){
  714. PackageInfo pI = pkgList.get (i);
  715. if (pI.packageName.equalsIgnoreCase ("com.alipay.android.app"))
  716. return true;
  717. }
  718. return false;
  719. }
  720. public boolean retrieveApkFromAssets (Context context, String fileName, String path){
  721. boolean bRet = false;
  722. try{
  723. InputStream is = context.getAssets ().open (fileName);
  724. File file = new File (path);
  725. file.createNewFile ();
  726. FileOutputStream fos = new FileOutputStream (file);
  727. byte[] temp = new byte[1024];
  728. int i = 0;
  729. while ((i = is.read (temp)) > 0){
  730. fos.write (temp, 0, i);
  731. }
  732. fos.close ();
  733. is.close ();
  734. bRet = true;
  735. } catch (IOException e){
  736. e.printStackTrace ();
  737. }
  738. return bRet;
  739. }
  740. public PackageInfo getApkInfo (Context context, String archiveFilePath){
  741. PackageManager pm = context.getPackageManager ();
  742. PackageInfo apkInfo = pm.getPackageArchiveInfo (archiveFilePath, PackageManager.GET_META_DATA);
  743. return apkInfo;
  744. }
  745. public String checkNewUpdate (){
  746. String url = null;
  747. try{
  748. //                JSONObject resp = sendCheckNewUpdate (packageInfo.versionName);
  749. JSONObject resp = sendCheckNewUpdate("1.0.0");
  750. if (resp.getString ("needUpdate").equalsIgnoreCase ("true")){
  751. url = resp.getString ("updateUrl");
  752. }
  753. // else ok.
  754. } catch (Exception e){
  755. e.printStackTrace ();
  756. }
  757. return url;
  758. }
  759. public JSONObject sendCheckNewUpdate (String versionName){
  760. JSONObject objResp = null;
  761. try{
  762. JSONObject req = new JSONObject ();
  763. req.put (AlixDefine.action, AlixDefine.actionUpdate);
  764. JSONObject data = new JSONObject ();
  765. data.put (AlixDefine.platform, "android");
  766. data.put (AlixDefine.VERSION, versionName);
  767. data.put (AlixDefine.partner, "");
  768. req.put (AlixDefine.data, data);
  769. objResp = sendRequest (req.toString ());
  770. } catch (JSONException e){
  771. e.printStackTrace ();
  772. }
  773. return objResp;
  774. }
  775. public JSONObject sendRequest (final String content){
  776. NetworkManager nM = new NetworkManager (this.mContext);
  777. //
  778. JSONObject jsonResponse = null;
  779. try{
  780. String response = null;
  781. synchronized (nM){
  782. //
  783. response = nM.SendAndWaitResponse (content, Constant.server_url);
  784. }
  785. jsonResponse = new JSONObject (response);
  786. } catch (Exception e){
  787. e.printStackTrace ();
  788. }
  789. //
  790. if (jsonResponse != null)
  791. BaseHelper.log (TAG, jsonResponse.toString ());
  792. return jsonResponse;
  793. }
  794. public boolean retrieveApkFromNet (Context context, String strurl, String filename){
  795. boolean bRet = false;
  796. try{
  797. NetworkManager nM = new NetworkManager (this.mContext);
  798. bRet = nM.urlDownloadToFile (context, strurl, filename);
  799. } catch (Exception e){
  800. e.printStackTrace ();
  801. }
  802. return bRet;
  803. }
  804. //
  805. // close the progress bar
  806. void closeProgress (){
  807. try{
  808. if (mProgress != null){
  809. mProgress.dismiss ();
  810. mProgress = null;
  811. }
  812. } catch (Exception e){
  813. e.printStackTrace ();
  814. }
  815. }
  816. }
  817. public class NetworkManager {
  818. static final String TAG = "NetworkManager";
  819. private int connectTimeout = 30 * 1000;
  820. private int readTimeout = 30 * 1000;
  821. Proxy mProxy = null;
  822. Context mContext;
  823. public NetworkManager (Context context){
  824. this.mContext = context;
  825. setDefaultHostnameVerifier ();
  826. }
  827. @SuppressWarnings ("deprecation")
  828. private void detectProxy (){
  829. ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService (Context.CONNECTIVITY_SERVICE);
  830. NetworkInfo ni = cm.getActiveNetworkInfo ();
  831. if (ni != null && ni.isAvailable () && ni.getType () == ConnectivityManager.TYPE_MOBILE){
  832. String proxyHost = android.net.Proxy.getDefaultHost ();
  833. int port = android.net.Proxy.getDefaultPort ();
  834. if (proxyHost != null){
  835. final InetSocketAddress sa = new InetSocketAddress (proxyHost, port);
  836. mProxy = new Proxy (Proxy.Type.HTTP, sa);
  837. }
  838. }
  839. }
  840. private void setDefaultHostnameVerifier (){
  841. //
  842. HostnameVerifier hv = new HostnameVerifier (){
  843. public boolean verify (String hostname, SSLSession session){
  844. return true;
  845. }
  846. };
  847. HttpsURLConnection.setDefaultHostnameVerifier (hv);
  848. }
  849. public String SendAndWaitResponse (String strReqData, String strUrl){
  850. //
  851. detectProxy ();
  852. String strResponse = null;
  853. ArrayList<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair> ();
  854. pairs.add (new BasicNameValuePair ("requestData", strReqData));
  855. HttpURLConnection httpConnect = null;
  856. UrlEncodedFormEntity p_entity;
  857. try{
  858. p_entity = new UrlEncodedFormEntity (pairs, "utf-8");
  859. URL url = new URL (strUrl);
  860. if (mProxy != null){
  861. httpConnect = (HttpURLConnection) url.openConnection (mProxy);
  862. } else{
  863. httpConnect = (HttpURLConnection) url.openConnection ();
  864. }
  865. httpConnect.setConnectTimeout (connectTimeout);
  866. httpConnect.setReadTimeout (readTimeout);
  867. httpConnect.setDoOutput (true);
  868. httpConnect.addRequestProperty ("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
  869. httpConnect.connect ();
  870. OutputStream os = httpConnect.getOutputStream ();
  871. p_entity.writeTo (os);
  872. os.flush ();
  873. InputStream content = httpConnect.getInputStream ();
  874. strResponse = BaseHelper.convertStreamToString (content);
  875. BaseHelper.log (TAG, "response " + strResponse);
  876. } catch (IOException e){
  877. e.printStackTrace ();
  878. } finally{
  879. httpConnect.disconnect ();
  880. }
  881. return strResponse;
  882. }
  883. public boolean urlDownloadToFile (Context context, String strurl, String path){
  884. boolean bRet = false;
  885. //
  886. detectProxy ();
  887. try{
  888. URL url = new URL (strurl);
  889. HttpURLConnection conn = null;
  890. if (mProxy != null){
  891. conn = (HttpURLConnection) url.openConnection (mProxy);
  892. } else{
  893. conn = (HttpURLConnection) url.openConnection ();
  894. }
  895. conn.setConnectTimeout (connectTimeout);
  896. conn.setReadTimeout (readTimeout);
  897. conn.setDoInput (true);
  898. conn.connect ();
  899. InputStream is = conn.getInputStream ();
  900. File file = new File (path);
  901. file.createNewFile ();
  902. FileOutputStream fos = new FileOutputStream (file);
  903. byte[] temp = new byte[1024];
  904. int i = 0;
  905. while ((i = is.read (temp)) > 0){
  906. fos.write (temp, 0, i);
  907. }
  908. fos.close ();
  909. is.close ();
  910. bRet = true;
  911. } catch (IOException e){
  912. e.printStackTrace ();
  913. }
  914. return bRet;
  915. }
  916. }
  917. public class ResultChecker {
  918. public static final int RESULT_INVALID_PARAM = 0;
  919. public static final int RESULT_CHECK_SIGN_FAILED = 1;
  920. public static final int RESULT_CHECK_SIGN_SUCCEED = 2;
  921. String mContent;
  922. public ResultChecker (String content){
  923. this.mContent = content;
  924. }
  925. int checkSign (){
  926. int retVal = RESULT_CHECK_SIGN_SUCCEED;
  927. try{
  928. JSONObject objContent = BaseHelper.string2JSON (this.mContent, ";");
  929. String result = objContent.getString ("result");
  930. result = result.substring (1, result.length () - 1);
  931. // 获取待签名数据
  932. int iSignContentEnd = result.indexOf ("&sign_type=");
  933. String signContent = result.substring (0, iSignContentEnd);
  934. // 获取签名
  935. JSONObject objResult = BaseHelper.string2JSON (result, "&");
  936. String signType = objResult.getString ("sign_type");
  937. signType = signType.replace (""", "");
  938. String sign = objResult.getString ("sign");
  939. sign = sign.replace (""", "");
  940. // 进行验签 返回验签结果
  941. if (signType.equalsIgnoreCase ("RSA")){
  942. if (!Rsa.doCheck (signContent, sign, PartnerConfig.RSA_ALIPAY_PUBLIC))
  943. retVal = RESULT_CHECK_SIGN_FAILED;
  944. }
  945. } catch (Exception e){
  946. retVal = RESULT_INVALID_PARAM;
  947. e.printStackTrace ();
  948. }
  949. return retVal;
  950. }
  951. }
  952. public static class Rsa {
  953. public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
  954. public static String sign (String content, String privateKey){
  955. String charset = "utf-8";
  956. try{
  957. PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec (Base64.decode (privateKey));
  958. KeyFactory keyf = KeyFactory.getInstance ("RSA");
  959. PrivateKey priKey = keyf.generatePrivate (priPKCS8);
  960. java.security.Signature signature = java.security.Signature.getInstance (SIGN_ALGORITHMS);
  961. signature.initSign (priKey);
  962. signature.update (content.getBytes (charset));
  963. byte[] signed = signature.sign ();
  964. return Base64.encode (signed);
  965. } catch (Exception e){
  966. e.printStackTrace ();
  967. }
  968. return null;
  969. }
  970. public static boolean doCheck (String content, String sign, String publicKey){
  971. try{
  972. KeyFactory keyFactory = KeyFactory.getInstance ("RSA");
  973. byte[] encodedKey = Base64.decode (publicKey);
  974. PublicKey pubKey = keyFactory.generatePublic (new X509EncodedKeySpec (encodedKey));
  975. java.security.Signature signature = java.security.Signature.getInstance (SIGN_ALGORITHMS);
  976. signature.initVerify (pubKey);
  977. signature.update (content.getBytes ("utf-8"));
  978. boolean bverify = signature.verify (Base64.decode (sign));
  979. return bverify;
  980. } catch (Exception e){
  981. e.printStackTrace ();
  982. }
  983. return false;
  984. }
  985. }
  986. }

以上即为支付宝SDK的接入流程

Android的支付接入(一):支付宝相关推荐

  1. 第三方支付接入之支付宝当面付

    第三方支付接入之支付宝当面付 首先对于支付大家都是比较了解的.目前市面上很多支付方式,云闪付,微信,支付宝,易支付,码支付等等第三方第四方的支付接口,但是大家在接入的时候会发现一个问题也就是需要企业认 ...

  2. 支付宝、微信Android APP支付接入流程

    支付类型: 一次性支付 自动续费(支付宝周期扣款.微信委托扣款):1.支付并签约 2.先签约后扣费 注:微信委托扣款中先签约后扣费:自动续费.授权扣款.免密支付 支付宝 支付流程中各端交互逻辑 支付流 ...

  3. android 微信支付过程,android 微信 支付 接入流程总结

    [TOC] 客户端微信支付 登录微信官方开放平台微信,注册账号,在微信开放平台申请应用,输入已上线app的正式的应用包名和签名,微信提供了一个签名工具,一般使用它提供的签名工具生成签名,然后填写到对应 ...

  4. android googleplay 支付接入

    今天跟大家一起看下Google的in-app Billing V3支付.   如果没有GooglePlay此处附上安装Google Play的一键安装器的链接(需要Root权限):http://www ...

  5. 个人开发者支付接入方案——支付宝当面付

    前言 个人开发者由于没有企业资质,所以无法使用支付宝支付和微信支付接口. 解决方案 使用支付宝当面付接口,这是为个体商户准备的一个支付接口,只要有营业执照签约之后收款无限额. 如果没有营业执照,只要有 ...

  6. 第三方支付接入(微信,支付宝)

    第三方API 时间 2022年3月30 目前很多企业在做支付的时候为了方便已经开始直接对接第四方了 但是也有一些开源大神们对支付甚至是整个微信开发提供了API 笔者公司的微信支付目前使用的第三方API ...

  7. Android Payme支付接入

    公司新项目需要接入HK的payme支付,一开始说没资料自己网上找,搜了一圈,发现啥都可以参考的案例,就参照后台的来撸了一把,再次记录下.坑多得很... 首先申请密钥啥的都不说了,申请下来即可. 第一步 ...

  8. android微信支付回调方法,Android接入支付宝和微信支付的方法

    前言 很多APP都需要支付功能,国内一般就是支付宝和微信了.目前这2种接入方式对于APP端来说都已经比较方便了,因为大部分的安全校验之类的逻辑都在服务端. APP端总结起来就是三步走: 接入支付的库 ...

  9. Android App支付系列(二):支付宝SDK接入详细指南(附官方支付demo)

    前言 一家移动互联网公司,说到底,要盈利总是需要付费用户的,自己开发支付系统对于资源有限的公司来说显然不太明智,国内已经有多家成熟的移动支付提供商,阿里就是其中之一. 继< Android Ap ...

最新文章

  1. Java 读写Properties配置文件(转)
  2. run as gradle test,未执行@Test中的内容(待解决)
  3. Http请求url参数字符集
  4. MAP Protocol 协议(1)初步介绍
  5. ❗HTML引入JavaScript的三种常用方式汇总❗
  6. [云炬创业学笔记]第一章创业是什么测试11
  7. 12年前的 Linux bug 复活,DNS 缓存投毒攻击重现
  8. 苹果激活锁功能可被长字符串溢出
  9. ||分享一些百度云下载不限速神器||
  10. python取字母以及数字随机数
  11. 我的毕业设计历程——基于Unity3D的MOBA游戏设计(二)
  12. SQL语句(五) 索引建立
  13. 占问事宜:我买的择日书籍何时能到?
  14. Python爬取百度文库并存储为word文档
  15. matlab实验报告的总结,一些数字信号处理实例(学校实验报告总结)
  16. 【大气湍流强弱的划分】
  17. 6-2 两个字符串穿插 (10 分) pta c语言
  18. 第六章 网上银行与电子支付-2
  19. 中国地质大学(武汉)地信GIS考研(891、892)经验分享
  20. 超简单lua (LOL)

热门文章

  1. 基于stknx 的 usb to knx 调试
  2. 云桌面口碑崩坏的三大原因
  3. Linux的qt安装包下载
  4. 计算机三网络技术选择题题库,2017年计算机三级《网络技术》选择题题库
  5. 在记事本中编写出Plan.java程序,输出你本周的学习计划
  6. Hadoop环境搭建之本地运行模式
  7. 资源搜索-网站set
  8. 本地自建服务器劫持验证,使用自建DNS服务器来防止ISP的DNS劫持
  9. openssl-p12证书
  10. 测试tensorflow-gpu是否可用