WeChat支払い関連

20494 ワード

Androidアプリケーション統合微信決済
  • 商戸応用アクセス微信支払い申請、略、具体的には公式サイトの手順を参照してください(https://open.weixin.qq.com/cgi-bin/frame?t=resource/res_main_tmpl&verify=1&lang=zh_CNモバイルアプリケーション開発->微信支払い機能->微信APP支払いアクセス業者サービスセンター、中には1が含まれている.申請プロセスガイド2.開放類目及び料金基準3.一般的なビジネスアクセスの問題)
  • シーン紹介
  • ユーザーがモバイル端末アプリに微信決済機能を統合するのに適しています.
    商戸APPは微信が提供するSDKを呼び出して微信支払いモジュールを呼び出し、商戸APPは微信にジャンプして支払いを完了する.
    支払いが終わったら、商家アプリに戻り、最後に支払い結果を表示します.
    インタラクションの詳細は次のとおりです.
    手順1:ユーザーは商家アプリに入り、商品の注文を選択し、購入を確認し、支払いの一環に入る.取引先サービスバックグラウンドは支払い注文を生成し、署名した後、データをAPP側に転送する.
    ステップ2:ユーザーがクリックした後に支払い操作を開始して、微信のインタフェースに入って、微信の支払いを調整して、支払いを確認するインタフェースが現れます
    手順3:ユーザーは受取人と金額を確認して、クリックして直ちに支払った後にパスワードのインターフェースを入力して現れて、小銭あるいは銀行カードの支払いを選択することができます
    手順4:正しいパスワードを入力した後、支払いが完了し、ユーザー側の微信に支払い詳細ページが表示される
    手順5:商戸APPに戻り、商戸APPは支払い結果に基づいて注文処理結果を個性的に展示する
  • ソースマップhttp://mch.weixin.qq.com/wiki/doc/api/index.php?chapter=8_3
  • Android開発要点説明
  • 1)    
                    ,         APP     APPID。
              ,                    ,            。
         【    】    【     /      /       】 。
    
        :  APP      AndroidManifest.xml    package ,
      DEMO  package="net.sourceforge.simcpux"。
    
        :               keystore,          32  md5 ,
                  ,          。        
    https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk
    
    
    2)  APPID
      APP       JAR ,  API ,          APPID,    :
    API   ,          APP,    :
    final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null);
    //   app     
    msgApi.registerApp("wxd930ea5d5a258f4f");
    
    
    3)    
               ,       API(   7 )     ,
       prepay_id           APP    。              :
    
    IWXAPI api;
    PayReq request = new PayReq();
    request. appId = "wxd930ea5d5a258f4f";
    request. partnerId = "1900000109";
    request.prepayId= "1101000000140415649af9fc314aa427",;
    request. packageValue = "prepay_id=1101000000140415649af9fc314aa427";
    request.nonceStr= "1101000000140429eb40476f8896f4c9";
    request.timeStamp= "1398746574";
    request.sign= "7ffecb600d7157c5aa49810d2d8f28bc2811827b";
    api.sendReq(req);
    
    
    4)      
        SDK Sample, WXPayEntryActivity    onResp  ,     ,
      APP      APP   onResp  ,              ,
           ,                           。
                         ,                 API       
    

    示例代码解读

    • -> ->android https://res.wx.qq.com/open/zh_CN/htmledition/res/dev/download/sdk/Android2_SDK221cbf.zip
        
    【  APP  】Sample_For_Android //demo,      
    【  APP  】SDK_For_Android //jar  api  
    【  APP  】   demo //  
    【    】     demo //  
    【  APP  】    V1.2_For_Android.pdf //    
    【    】         .pdf //    
    
      
      
      
      
    • 【微信APP支付】Sample_For_Android, (围绕支付,其他略。 sdk demo里面的功能包含有支付 分享 收藏等)
    1.   jar, libammsdk.jar
    
    2. AndroidManifest.xml       
    
    3.            
    3.1  activity WXEntryActivity
            payBtn = (Button) findViewById(R.id.goto_pay_btn);
            payBtn.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
    //     PayActivity finish
                    startActivity(new Intent(WXEntryActivity.this, PayActivity.class));
                    finish();
                }
            });
    
    3.2 PayActivity
    public class PayActivity extends Activity {
    
        private static final String TAG = "MicroMsg.SDKSample.PayActivity";
    
        //key api
        private IWXAPI api;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.pay);
    
            //      ,  APP_ID(           appId)
            api = WXAPIFactory.createWXAPI(this, Constants.APP_ID);
    
            Button payBtn = (Button) findViewById(R.id.pay_btn);
            payBtn.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    //1.   access token
                    new GetAccessTokenTask().execute();
                }
            });
    
            Button checkPayBtn = (Button) findViewById(R.id.check_pay_btn);
            checkPayBtn.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    //            
                    boolean isPaySupported = api.getWXAppSupportAPI() >= Build.PAY_SUPPORTED_SDK_INT;
                    Toast.makeText(PayActivity.this, String.valueOf(isPaySupported), Toast.LENGTH_SHORT).show();
                }
            });
        }
    
        /**
         *                   
         * 
         *   :  hardcode    ,  genPackage           
         */
        private static final String PARTNER_KEY = "8934e7d15453e97507ef794cf7b0519d";
    
        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); //   :  hardcode    ,  genPackage            
    
            //   md5   ,params       ,   url encode  
            String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
    
            return URLEncodedUtils.format(params, "utf-8") + "&sign=" + packageSign;
        }
    
         /**
         *               
         * 
         *   :  hardcode    ,  genSign           
         */
        private static final String APP_SECRET = "db426a9829e4b49a0dcac7b4162da6b6"; // wxd930ea5d5a258f4f      
    
        /**
         *                 
         * 
         *   :  hardcode    ,  genSign           
         */
        private static final String APP_KEY = "L8LrMqqeGRxST5reouB0K66CaYAWpqhAVsq7ggKkxHCOastWksvuX1uvmvQclxaHoYd3ElNBrNO2DHnnzgfVG9Qs473M3DTOZug5er46FhuGofumV8H2FVR9qkjSlC5K"; // wxd930ea5d5a258f4f        
    
        private class GetAccessTokenTask extends AsyncTask<Void, Void, GetAccessTokenResult> {
    
            private ProgressDialog dialog;
    
            @Override
            protected void onPreExecute() {
                //        
                dialog = ProgressDialog.show(PayActivity.this, getString(R.string.app_tip), getString(R.string.getting_access_token));
            }
    
            @Override
            protected void onPostExecute(GetAccessTokenResult result) {
                if (dialog != null) {
                    dialog.dismiss();
                }
    
                if (result.localRetCode == LocalRetCode.ERR_OK) {
                    Toast.makeText(PayActivity.this, R.string.get_access_token_succ, Toast.LENGTH_LONG).show();
                    Log.d(TAG, "onPostExecute, accessToken = " + result.accessToken);
    
                    //3.   access token ,    prePayId
                    GetPrepayIdTask getPrepayId = new GetPrepayIdTask(result.accessToken);
                    getPrepayId.execute();
                } else {
                    Toast.makeText(PayActivity.this, getString(R.string.get_access_token_fail, result.localRetCode.name()), Toast.LENGTH_LONG).show();
                }
            }
    
            @Override
            protected GetAccessTokenResult doInBackground(Void... params) {
                GetAccessTokenResult result = new GetAccessTokenResult();
    
                //2.http get  access token
                String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
                        Constants.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 class GetPrepayIdTask extends AsyncTask<Void, Void, GetPrepayIdResult> {
    
            private ProgressDialog dialog;
            private String accessToken;
    
            public GetPrepayIdTask(String accessToken) {
                this.accessToken = accessToken;
            }
    
            @Override
            protected void onPreExecute() {
                //  prepay id    
                dialog = ProgressDialog.show(PayActivity.this, getString(R.string.app_tip), getString(R.string.getting_prepayid));
            }
    
            @Override
            protected void onPostExecute(GetPrepayIdResult result) {
                if (dialog != null) {
                    dialog.dismiss();
                }
    
                if (result.localRetCode == LocalRetCode.ERR_OK) {
                    Toast.makeText(PayActivity.this, R.string.get_prepayid_succ, Toast.LENGTH_LONG).show();
                    //5.   prepay id       
                    sendPayReq(result);
                } else {
                    Toast.makeText(PayActivity.this, getString(R.string.get_prepayid_fail, result.localRetCode.name()), Toast.LENGTH_LONG).show();
                }
            }
    
            @Override
            protected void onCancelled() {
                super.onCancelled();
            }
    
            @Override
            protected GetPrepayIdResult doInBackground(Void... params) {
    
                //4. http post  prepay id
                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 enum LocalRetCode {
            ERR_OK, ERR_HTTP, ERR_JSON, ERR_OTHER
        }
    
        //     ,    
        private static class GetAccessTokenResult {
    
            private static final String TAG = "MicroMsg.SDKSample.PayActivity.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")) { // success case
                        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;
                }
            }
        }
    
        //     ,    
        private static class GetPrepayIdResult {
    
            private static final String TAG = "MicroMsg.SDKSample.PayActivity.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")) { // success case
                        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;
                }
            }
        }
    
        private String genNonceStr() {
            Random random = new Random();
            return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
        }
    
        private long genTimeStamp() {
            return System.currentTimeMillis() / 1000;
        }
    
        /**
         *    traceid              ,               
         */
        private String getTraceId() {
            return "crestxu_" + genTimeStamp(); 
        }
    
        /**
         *   :          ,32    、     ,         
         */
        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;
        }
    
        private String genProductArgs() {
            JSONObject json = new JSONObject();
    
            try {
                json.put("appid", Constants.APP_ID);
                String traceId = getTraceId();  // traceId        ,           ,             id
                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", "     "));
                packageParams.add(new BasicNameValuePair("fee_type", "1"));
                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", "1900000109"));
                packageParams.add(new BasicNameValuePair("spbill_create_ip", "196.168.1.1"));
                packageParams.add(new BasicNameValuePair("total_fee", "1"));
                packageValue = genPackage(packageParams);
    
                json.put("package", packageValue);
                timeStamp = genTimeStamp();
                json.put("timestamp", timeStamp);
    
                List<NameValuePair> signParams = new LinkedList<NameValuePair>();
                signParams.add(new BasicNameValuePair("appid", Constants.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, ex = " + e.getMessage());
                return null;
            }
    
            return json.toString();
        }
    
        private void sendPayReq(GetPrepayIdResult result) {
    
            PayReq req = new PayReq();
            req.appId = Constants.APP_ID;
            req.partnerId = Constants.PARTNER_ID;
            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);
    
            //      ,           ,     IWXMsg.registerApp        
            api.sendReq(req);
        }
    }
    
  • PayActivity , 1. accessTonken; 2. prePayId; 3. ; 4.

  • 小結
  • 支付宝のapiと比較すると、微信支付のこのバージョンのdemoは粗すぎて、例えば:関連定数の定義が集中していない;apiは簡単ではありません.まずaccessTokenを取得してprePayIdを取得して完全に1つのapiを閉じることができて、それからユーザーは1山の必要なパラメータを入力してapiの内部で判断組織をフィルタして、まだこんなに多くのapiのurlを露出する必要はありません.(後記:上記の総業務フローと併せて見ると、このdemoはまるで開発者を誤導しているようだ.総業務はaccess_tokenの取得がなく、prepayIdの取得は業者のバックグラウンドにあるが、androidのdemoにはaccess_tokenの取得手順があり、APP_SECRETも用いられており、prepayIdの取得もクライアントに置かれている.コードでは重要情報hard codeをコードに渡すことができないことを強調する一方で、これらの重要情報についてはあちこちで...
  • 支払い過程の3部は1.アクセス権を取得します.2.prePayIdを取得する;3.支払いを開始する.(後述のように、1と2をサーバ側で処理することを提案し、クライアントは必要なパラメータを提供する)
  • は支付宝と同じように先に登録しなければならない.詳しくは、上記の商戸応用アクセス微信支付申請
  • を参照してください.
  • 構築バックグラウンド
  • モバイルクライアント
  • を構築する.
  • プロセス全体で使用する情報
  • PARTNER_ID, 
      : demo  sendPayReq   
      :        ,   
    
    PARTNER_KEY, 
      : demo  genPackage   。
              hardcode    
      :   
    
    APP_KEY,
      : demo  prepayID      ,    genProductArgs() +  sendPayReq     。
              hardcode    
      :   
    
    APP_SECRET, 
      : demo    GetAccessTokenTask doInBackground  。
              hardcode    
      :http://mch.weixin.qq.com/wiki/doc/api/index.php?chapter=3_1
        AppSecret APPID       ,          access_token   。
              ,   OAuth2.0      openid, openid                 。
                AppSecret(              )。
    
    APP_ID,
      :        :  IWXAPI,  accessToken,  prepayID,sendPayReq    
      :http://mch.weixin.qq.com/wiki/doc/api/index.php?chapter=3_1
        appid            APP     ,                    APP   ,
                  appid,       。                      。

    後記
  • 上記のパラメータのソース不明の問題に対して、googleの後に一時的な答えを見つけました.結局、バージョンは
  • 更新されています.
             (open.weixin.qq.com)         ,    :
    public static final String APP_ID = “wxd930ea5d5a258f4f”;
    private static final String APP_SECRET = “db426a9829e4b49a0dcac7b4162da6b6″;
    
                   ,         ,           ,          ,     
    private static final String APP_KEY(PaySignKey) = “L8LrMqqeGRxST5reouB0K66CaYAWpqhAVsq7ggKkxHCOastWksvuX1uvmvQclxaHoYd3ElNBrNO2DHnnzgfVG9Qs473M3DTOZug5er46FhuGofumV8H2FVR9qkjSlC5K”; // wxd930ea5d5a258f4f        
    
        ,           ,           :
    public static final String PARTNER_ID = “1900000109″;
    private static final String PARTNER_KEY = “8934e7d15453e97507ef794cf7b0519d”;
  • 同時に私の小結の中の第1点のネットユーザーに対しても既成の提案あるいは方案があります(微信demoは最初からこのように書くと人に回り道をさせません)
  •            ,                   ,
                          ,
              ,      。

    リファレンスリンク
  • 推奨http://fangjie.info/?p=393
  • 微信オープンプラットフォームリソースセンターhttps://open.weixin.qq.com/cgi-bin/frame?t=resource/res_main_tmpl&verify=1&lang=zh_CN
  • ビジネスプラットフォームドキュメントhttp://mch.weixin.qq.com/wiki/doc/api/index.php?chapter=8_1
  • http://blog.csdn.net/janice0529/article/details/38051987
  •