package com.intel.cordova.inAppBilling; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaInterface; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.CordovaWebView; import org.json.JSONArray; import org.json.JSONException; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.LinkedList; import java.util.List; import java.util.Random; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import org.json.JSONObject; import com.tencent.mm.sdk.modelpay.PayReq; import com.tencent.mm.sdk.openapi.IWXAPI; import com.tencent.mm.sdk.openapi.WXAPIFactory; import android.app.Activity; import android.app.ProgressDialog; import android.os.AsyncTask; import android.util.Log; import android.widget.Toast; import android.content.Context; public class InAppBillingPlugin extends CordovaPlugin { public static final String TAG = "InAppBillingPlugin"; public static final String ACTION_SEND_BILLING = "sendBilling"; public static final String ACTION_SEND_REFUND = "sendRefund"; public static final String ACTION_REFUND_DETAIL = "refundDetail"; public static final String ACTION_STATEMENT_ACCOUNT = "statementAccount"; private Context context = null; private Activity thisActivity = null; private CallbackContext callbackContext = null; private JSONArray JSData = null; // This is the product info from js. private JSONObject callbackjsb = null; private IWXAPI api = null; // The four major key to apply access_token and package data for bill private static final String APP_ID = "wxd930ea5d5a258f4f"; private static final String APP_SECRET = "db426a9829e4b49a0dcac7b4162da6b6"; private static final String APP_KEY = "L8LrMqqeGRxST5reouB0K66CaYAWpqhAVsq7ggKkxHCOastWksvuX1uvmvQclxaHoYd3ElNBrNO2DHnnzgfVG9Qs473M3DTOZug5er46FhuGofumV8H2FVR9qkjSlC5K"; private static final String PARTNER_KEY = "8934e7d15453e97507ef794cf7b0519d"; private static enum LocalRetCode { ERR_OK, ERR_HTTP, ERR_JSON, ERR_OTHER } public void initialize(CordovaInterface cordova, CordovaWebView webView) { super.initialize(cordova, webView); context = this.cordova.getActivity().getApplicationContext(); thisActivity = this.cordova.getActivity(); // register the app to wechat with APP_ID api = WXAPIFactory.createWXAPI(context, APP_ID); // api.registerApp(APP_ID); boolean registerResult = api.registerApp(APP_ID); Toast.makeText(context, "Register result = " + registerResult, Toast.LENGTH_LONG).show(); } @Override public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { JSData = args; if(ACTION_SEND_BILLING.equals(action)) { new GetAccessTokenTask().execute(); callbackContext.success("Send payment successfully"); return true; } if(ACTION_SEND_REFUND.equals(action)) { new SendRefundRequestTask().execute(); callbackContext.success(callbackjsb); return true; } if(ACTION_REFUND_DETAIL.equals(action)) { new GetRefundDetailTask().execute(); callbackContext.success(callbackjsb); return true; } if(ACTION_STATEMENT_ACCOUNT.equals(action)) { new GetStatementAccountTask().execute(); callbackContext.success(callbackjsb); return true; } return false; } /* * Get access_token task and result */ private class GetAccessTokenTask extends AsyncTask<Void, Void, GetAccessTokenResult> { private ProgressDialog dialog; @Override protected void onPreExecute() { dialog = ProgressDialog.show(thisActivity, "Tips", "Getting access_token"); } @Override protected void onPostExecute(GetAccessTokenResult result) { if(dialog != null) { dialog.dismiss(); } if(result.localRetCode == LocalRetCode.ERR_OK) { Toast.makeText(context, "Get access_token successfully", Toast.LENGTH_LONG).show(); Log.d(TAG, "onPostExecute, access_token = " + result.accessToken); // here send the billing to wechatPay GetPrepayIdTask getPrepayId = new GetPrepayIdTask(result.accessToken); getPrepayId.execute(); } else { Toast.makeText(context, "Get access_token fail " + result.localRetCode.name(), Toast.LENGTH_LONG).show(); } } @Override protected GetAccessTokenResult doInBackground(Void... params) { GetAccessTokenResult result = new GetAccessTokenResult(); String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", APP_ID, APP_SECRET); Log.d(TAG, "Get access_token, url = " + url); byte[] buf = Util.httpGet(url); if(buf == null || buf.length == 0) { result.localRetCode = LocalRetCode.ERR_HTTP; return result; } String content = new String(buf); result.parseFrom(content); return result; } } private static class GetAccessTokenResult { private static final String TAG = "Crosswalk-cordova.InAppBillingPlugin.GetAccessTokenResult"; public LocalRetCode localRetCode = LocalRetCode.ERR_OTHER; public String accessToken; public int expiresIn; public int errCode; public String errMsg; public void parseFrom(String content) { if(content == null || content.length() <= 0) { Log.e(TAG, "parseFrom fail, content is null"); localRetCode = LocalRetCode.ERR_JSON; return; } try { JSONObject json = new JSONObject(content); if(json.has("access_token")) { accessToken = json.getString("access_token"); expiresIn = json.getInt("expires_in"); localRetCode = LocalRetCode.ERR_OK; } else { errCode = json.getInt("errcode"); errMsg = json.getString("errmsg"); localRetCode = LocalRetCode.ERR_JSON; } } catch(Exception e) { localRetCode = LocalRetCode.ERR_JSON; } } } /* * Get prepayId task and result */ private class GetPrepayIdTask extends AsyncTask<Void, Void, GetPrepayIdResult> { private ProgressDialog dialog; private String accessToken; public GetPrepayIdTask(String accessToken) { this.accessToken = accessToken; } @Override protected void onPreExecute() { dialog = ProgressDialog.show(thisActivity, "Tips", "Getting prepayId"); } @Override protected void onPostExecute(GetPrepayIdResult result) { if(dialog != null) { dialog.dismiss(); } if(result.localRetCode == LocalRetCode.ERR_OK) { Toast.makeText(context, "Get prepayId successfully!", Toast.LENGTH_LONG).show(); sendPayReq(result); } else { Toast.makeText(context, "Get prepayId fail! " + result.localRetCode.name(), Toast.LENGTH_LONG).show(); } } @Override protected void onCancelled() { super.onCancelled(); } @Override protected GetPrepayIdResult doInBackground(Void... params) { String url = String.format("https://api.weixin.qq.com/pay/genprepay?access_token=%s", accessToken); String entity = genProductArgs(); Log.d(TAG, "doInBackground, url = " + url); Log.d(TAG, "doInBackground, entity = " + entity); GetPrepayIdResult result = new GetPrepayIdResult(); byte[] buf = Util.httpPost(url, entity); if(buf == null || buf.length == 0) { result.localRetCode = LocalRetCode.ERR_HTTP; return result; } String content = new String(buf); Log.d(TAG, "doInBackground, content = " + content); result.parseFrom(content); return result; } } private static class GetPrepayIdResult { private static final String TAG = "Crosswalk-cordova.InAppBillingPlugin.GetPrepayIdResult"; public LocalRetCode localRetCode = LocalRetCode.ERR_OTHER; public String prepayId; public int errCode; public String errMsg; public void parseFrom(String content) { if(content == null || content.length() <= 0) { Log.e(TAG, "parseFrom fail, content is null"); localRetCode = LocalRetCode.ERR_JSON; return; } try { JSONObject json = new JSONObject(content); if(json.has("prepayid")) { prepayId = json.getString("prepayid"); localRetCode = LocalRetCode.ERR_OK; } else { localRetCode = LocalRetCode.ERR_JSON; } errCode = json.getInt("errcode"); errMsg = json.getString("errmsg"); } catch(Exception e) { localRetCode = LocalRetCode.ERR_JSON; } } } /* * The next functions for refund */ private class SendRefundRequestTask extends AsyncTask<Void, Void, SendRefundRequestResult> { private ProgressDialog dialog; @Override protected void onPreExecute() { dialog = ProgressDialog.show(thisActivity, "Tips", "Sending refund request"); } @Override protected void onPostExecute(SendRefundRequestResult result) { if(dialog != null) { dialog.dismiss(); } if(result.localRetCode == LocalRetCode.ERR_OK) { Toast.makeText(context, "Refund success and retcode = " + result.retCode, Toast.LENGTH_LONG).show(); // No need to send another request } else { Toast.makeText(context, "Send refund request fail! " + result.localRetCode.name(), Toast.LENGTH_LONG).show(); } } @Override protected void onCancelled() { super.onCancelled(); } @Override protected SendRefundRequestResult doInBackground(Void... params) { SendRefundRequestResult result = new SendRefundRequestResult(); String url = String.format("https://mch.tenpay.com/refundapi/gateway/refund.xml"); String entity = genRefundEntity(); // detail parameter data is in JSONData Log.d(TAG, "doInBackground, url = " + url); Log.d(TAG, "doInBackground, entity = " + entity); // use url and entity to send http request and use post method to send data byte[] buf = Util.httpPost(url, entity); if(buf == null || buf.length == 0) { result.localRetCode = LocalRetCode.ERR_HTTP; return result; } String content = new String(buf); JSONObject jsobj; try { jsobj = new JSONObject(content); setcallbackjsb(jsobj); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } Log.d(TAG, "doInBackground, content = " + content); result.parseFrom(content); return result; } } private static class SendRefundRequestResult { private static final String TAG = "Crosswalk-cordova.InAppBillingPlugin.SendRefundRequestResult"; public LocalRetCode localRetCode = LocalRetCode.ERR_OTHER; public int retCode; public int errCode; public String errMsg; public void parseFrom(String content) { if(content == null || content.length() <= 0) { Log.e(TAG, "parseFrom fail, content is null"); localRetCode = LocalRetCode.ERR_JSON; return; } try { JSONObject json = new JSONObject(content); if(json.has("retcode")) { retCode = json.getInt("retcode"); localRetCode = LocalRetCode.ERR_OK; } else { localRetCode = LocalRetCode.ERR_JSON; } errCode = json.getInt("errcode"); errMsg = json.getString("errmsg"); } catch(Exception e) { localRetCode = LocalRetCode.ERR_JSON; } } } private String genRefundEntity() { JSONObject jsonObj = new JSONObject(); try { jsonObj.put("sign_type", "MD5"); jsonObj.put("input_charset", "utf-8"); jsonObj.put("sign_key_index", 1); List<NameValuePair> packageParams = new LinkedList<NameValuePair>(); packageParams.add(new BasicNameValuePair("partner", JSData.getJSONObject(0).getString("partner"))); packageParams.add(new BasicNameValuePair("out_trade_no", JSData.getJSONObject(0).getString("out_trade_no"))); packageParams.add(new BasicNameValuePair("transaction_id", JSData.getJSONObject(0).getString("transaction_id"))); packageParams.add(new BasicNameValuePair("out_refund_no", JSData.getJSONObject(0).getString("out_refund_no"))); packageParams.add(new BasicNameValuePair("total_fee", JSData.getJSONObject(0).getString("total_fee"))); packageParams.add(new BasicNameValuePair("refund_fee", JSData.getJSONObject(0).getString("refund_fee"))); packageParams.add(new BasicNameValuePair("op_user_id", JSData.getJSONObject(0).getString("op_user_id"))); packageParams.add(new BasicNameValuePair("op_user_passwd", JSData.getJSONObject(0).getString("op_user_passwd"))); packageParams.add(new BasicNameValuePair("recv_user_id", JSData.getJSONObject(0).getString("recv_user_id"))); packageParams.add(new BasicNameValuePair("recv_user_name", JSData.getJSONObject(0).getString("recv_user_name"))); packageParams.add(new BasicNameValuePair("use_spbill_no_flag", JSData.getJSONObject(0).getString("use_spbill_no_flag"))); packageParams.add(new BasicNameValuePair("refund_type", JSData.getJSONObject(0).getString("refund_type"))); packageValue = genPackage(packageParams); jsonObj.put("sign", packageValue); } catch(Exception e) { Log.e(TAG, "genRefundEntity fail, e = " + e.getMessage()); return null; } return jsonObj.toString(); } /* * The next functions for refund Detail request */ private class GetRefundDetailTask extends AsyncTask<Void, Void, GetRefundDetailResult> { private ProgressDialog dialog; @Override protected void onPreExecute() { dialog = ProgressDialog.show(thisActivity, "Tips", "Asking refund detail"); } @Override protected void onPostExecute(GetRefundDetailResult result) { if(dialog != null) { dialog.dismiss(); } if(result.localRetCode == LocalRetCode.ERR_OK) { Toast.makeText(context, "Refund Detail success and retcode = " + result.retCode, Toast.LENGTH_LONG).show(); // No need to send another request } else { Toast.makeText(context, "Ask refund detail fail! " + result.localRetCode.name(), Toast.LENGTH_LONG).show(); } } @Override protected void onCancelled() { super.onCancelled(); } @Override protected GetRefundDetailResult doInBackground(Void... params) { GetRefundDetailResult result = new GetRefundDetailResult(); String url = String.format("https://gw.tenpay.com/gateway/normalrefundquery.xml"); String entity = genRefundDetail(); // detail parameter data is in JSONData Log.d(TAG, "doInBackground, url = " + url); Log.d(TAG, "doInBackground, entity = " + entity); // use url and entity to send http request and use post method to send data byte[] buf = Util.httpPost(url, entity); if(buf == null || buf.length == 0) { result.localRetCode = LocalRetCode.ERR_HTTP; return result; } String content = new String(buf); JSONObject jsobj; try { jsobj = new JSONObject(content); setcallbackjsb(jsobj); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } Log.d(TAG, "doInBackground, content = " + content); result.parseFrom(content); return result; } } private static class GetRefundDetailResult { private static final String TAG = "Crosswalk-cordova.InAppBillingPlugin.GetRefundDetailResult"; public LocalRetCode localRetCode = LocalRetCode.ERR_OTHER; public int retCode; public int errCode; public String errMsg; public void parseFrom(String content) { if(content == null || content.length() <= 0) { Log.e(TAG, "parseFrom fail, content is null"); localRetCode = LocalRetCode.ERR_JSON; return; } try { JSONObject json = new JSONObject(content); if(json.has("retcode")) { retCode = json.getInt("retcode"); localRetCode = LocalRetCode.ERR_OK; } else { localRetCode = LocalRetCode.ERR_JSON; } errCode = json.getInt("errcode"); errMsg = json.getString("errmsg"); } catch(Exception e) { localRetCode = LocalRetCode.ERR_JSON; } } } private String genRefundDetail() { JSONObject jsonObj = new JSONObject(); try { jsonObj.put("sign_type", "MD5"); jsonObj.put("input_charset", "utf-8"); jsonObj.put("sign_key_index", 1); List<NameValuePair> packageParams = new LinkedList<NameValuePair>(); packageParams.add(new BasicNameValuePair("partner", JSData.getJSONObject(0).getString("partner"))); packageParams.add(new BasicNameValuePair("out_trade_no", JSData.getJSONObject(0).getString("out_trade_no"))); packageParams.add(new BasicNameValuePair("transaction_id", JSData.getJSONObject(0).getString("transaction_id"))); packageParams.add(new BasicNameValuePair("out_refund_no", JSData.getJSONObject(0).getString("out_refund_no"))); packageParams.add(new BasicNameValuePair("refund_id", JSData.getJSONObject(0).getString("refund_id"))); packageParams.add(new BasicNameValuePair("use_spbill_no_flag", JSData.getJSONObject(0).getString("use_spbill_no_flag"))); packageValue = genPackage(packageParams); jsonObj.put("sign", packageValue); } catch(Exception e) { Log.e(TAG, "genRefundDetail fail, e = " + e.getMessage()); return null; } return jsonObj.toString(); } /* * The next functions for statement account */ private class GetStatementAccountTask extends AsyncTask<Void, Void, GetStatementAccountResult> { private ProgressDialog dialog; @Override protected void onPreExecute() { dialog = ProgressDialog.show(thisActivity, "Tips", "Asking statement account detail"); } @Override protected void onPostExecute(GetStatementAccountResult result) { if(dialog != null) { dialog.dismiss(); } if(result.localRetCode == LocalRetCode.ERR_OK) { Toast.makeText(context, "Statement account success and retcode = " + result.retCode, Toast.LENGTH_LONG).show(); // No need to send another request } else { Toast.makeText(context, "Ask statement account fail! " + result.localRetCode.name(), Toast.LENGTH_LONG).show(); } } @Override protected void onCancelled() { super.onCancelled(); } @Override protected GetStatementAccountResult doInBackground(Void... params) { GetStatementAccountResult result = new GetStatementAccountResult(); String url = String.format("http://mch.tenpay.com/cgi-bin/mchdown_real_new.cgi"); String entity = genStatementAccount(); // detail parameter data is in JSONData Log.d(TAG, "doInBackground, url = " + url); Log.d(TAG, "doInBackground, entity = " + entity); // use url and entity to send http request and use post method to send data byte[] buf = Util.httpPost(url, entity); if(buf == null || buf.length == 0) { result.localRetCode = LocalRetCode.ERR_HTTP; return result; } String content = new String(buf); JSONObject jsobj; try { jsobj = new JSONObject(content); setcallbackjsb(jsobj); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } Log.d(TAG, "doInBackground, content = " + content); result.parseFrom(content); return result; } } private static class GetStatementAccountResult { private static final String TAG = "Crosswalk-cordova.InAppBillingPlugin.GetStatementAccountResult"; public LocalRetCode localRetCode = LocalRetCode.ERR_OTHER; public int retCode; public int errCode; public String errMsg; public void parseFrom(String content) { if(content == null || content.length() <= 0) { Log.e(TAG, "parseFrom fail, content is null"); localRetCode = LocalRetCode.ERR_JSON; return; } try { JSONObject json = new JSONObject(content); if(json.has("retcode")) { retCode = json.getInt("retcode"); localRetCode = LocalRetCode.ERR_OK; } else { localRetCode = LocalRetCode.ERR_JSON; } errCode = json.getInt("errcode"); errMsg = json.getString("errmsg"); } catch(Exception e) { localRetCode = LocalRetCode.ERR_JSON; } } } private String genStatementAccount() { JSONObject jsonObj = new JSONObject(); try { jsonObj.put("sign_type", "MD5"); jsonObj.put("input_charset", "utf-8"); jsonObj.put("sign_key_index", 1); List<NameValuePair> packageParams = new LinkedList<NameValuePair>(); packageParams.add(new BasicNameValuePair("spid", JSData.getJSONObject(0).getString("spid"))); packageParams.add(new BasicNameValuePair("trans_time", JSData.getJSONObject(0).getString("trans_time"))); packageParams.add(new BasicNameValuePair("stamp", JSData.getJSONObject(0).getString("stamp"))); packageParams.add(new BasicNameValuePair("cft_signtype", JSData.getJSONObject(0).getString("cft_signtype"))); packageParams.add(new BasicNameValuePair("mchtype", JSData.getJSONObject(0).getString("mchtype"))); packageValue = genPackage(packageParams); jsonObj.put("sign", packageValue); } catch(Exception e) { Log.e(TAG, "genRefundDetail fail, e = " + e.getMessage()); return null; } return jsonObj.toString(); } /* * Functions to generate parameters for the billing package post to wechat server via http */ private String genNonceStr() { Random random = new Random(); return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); } private long genTimeStamp() { return System.currentTimeMillis() / 1000; // Get timestamp in seconds } private String getTraceId() { return "crestxu_" + genTimeStamp(); } private String genOutTradNo() { Random random = new Random(); return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes()); } private long timeStamp; private String nonceStr, packageValue; private String genSign(List<NameValuePair> params) { StringBuilder sb = new StringBuilder(); int i = 0; for(; i < params.size() - 1; i++) { sb.append(params.get(i).getName()); sb.append('='); sb.append(params.get(i).getValue()); sb.append('&'); } sb.append(params.get(i).getName()); sb.append('='); sb.append(params.get(i).getValue()); String sha1 = Util.sha1(sb.toString()); Log.d(TAG, "genSign, sha1 = " + sha1); return sha1; } // Here is the Product info, need to change to get from the third party app // maybe there should only export an interface to the third party, and they need to complete it. private String genProductArgs() { JSONObject json = new JSONObject(); try { json.put("appid", APP_ID); String traceId = getTraceId(); json.put("traceid", traceId); nonceStr = genNonceStr(); json.put("noncestr", nonceStr); List<NameValuePair> packageParams = new LinkedList<NameValuePair>(); packageParams.add(new BasicNameValuePair("bank_type", "WX")); packageParams.add(new BasicNameValuePair("body", JSData.getJSONObject(0).getString("body"))); packageParams.add(new BasicNameValuePair("fee_type", "1")); // default currency type : RMB packageParams.add(new BasicNameValuePair("input_charset", "UTF-8")); packageParams.add(new BasicNameValuePair("notify_url", "http://weixin.qq.com")); packageParams.add(new BasicNameValuePair("out_trade_no", genOutTradNo())); packageParams.add(new BasicNameValuePair("partner", JSData.getJSONObject(0).getString("partner"))); packageParams.add(new BasicNameValuePair("spbill_create_ip", JSData.getJSONObject(0).getString("IP"))); // user pubilc internet ip packageParams.add(new BasicNameValuePair("total_fee", JSData.getJSONObject(0).getString("totalFee"))); // total fee 1 = 0.01 RMB. packageValue = genPackage(packageParams); json.put("package", packageValue); timeStamp = genTimeStamp(); json.put("timestamp", timeStamp); List<NameValuePair> signParams = new LinkedList<NameValuePair>(); signParams.add(new BasicNameValuePair("appid", APP_ID)); signParams.add(new BasicNameValuePair("appkey", APP_KEY)); signParams.add(new BasicNameValuePair("noncestr", nonceStr)); signParams.add(new BasicNameValuePair("package", packageValue)); signParams.add(new BasicNameValuePair("timestamp", String.valueOf(timeStamp))); signParams.add(new BasicNameValuePair("traceid", traceId)); json.put("app_signature", genSign(signParams)); json.put("sign_method", "sha1"); } catch(Exception e) { Log.e(TAG, "genProductArgs fail, e = " + e.getMessage()); return null; } return json.toString(); } private String genPackage(List<NameValuePair> params) { StringBuilder sb = new StringBuilder(); for(int i = 0; i < params.size(); i++) { sb.append(params.get(i).getName()); sb.append('='); sb.append(params.get(i).getValue()); sb.append('&'); } sb.append("key="); sb.append(PARTNER_KEY); String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase(); return URLEncodedUtils.format(params, "utf-8") + "&sign=" + packageSign; } private void sendPayReq(GetPrepayIdResult result) { PayReq req = new PayReq(); req.appId = APP_ID; req.partnerId = PARTNER_KEY; req.prepayId = result.prepayId; req.nonceStr = nonceStr; req.timeStamp = String.valueOf(timeStamp); req.packageValue = "Sign=" + packageValue; List<NameValuePair> signParams = new LinkedList<NameValuePair>(); signParams.add(new BasicNameValuePair("appid", req.appId)); signParams.add(new BasicNameValuePair("appkey", APP_KEY)); signParams.add(new BasicNameValuePair("noncestr", req.nonceStr)); signParams.add(new BasicNameValuePair("package", req.packageValue)); signParams.add(new BasicNameValuePair("partnerid", req.partnerId)); signParams.add(new BasicNameValuePair("prepayid", req.prepayId)); signParams.add(new BasicNameValuePair("timestamp", req.timeStamp)); req.sign = genSign(signParams); api.sendReq(req); } private void setcallbackjsb(JSONObject jsobj) { callbackjsb = jsobj; } }