Android 微信支付&支付寶支付

因爲項目需求,加入這2個功能記錄一些須要注意的地方java

 

一.微信支付android

微信支付在2016年4月份左右稍微調整了一下支付過程,可是文檔卻沒怎麼更新,這也是百度上爲何那麼多開發者都說微信是個大坑. 身爲一個大型互聯網公司,作的事卻沒法讓人理解.express

相比之下,支付寶就好太多了.json

 

微信支付須要注意地方:api

1.要先申請 "商家端"帳戶, 須要提交公司信息, 我的很差申請的. 申請成功後,須要去 建立一個應用服務器

建立應用須要 注意2個地方 微信

1>包名, 若是是Android studio開發 ,這個包名要用以下圖所示位置的包名, 而不是 androidmanifest.xml中的,由於他倆可能不同,要如下圖爲準,固然若是是eclipse開發那就以androidmanifest.xml裏面的包名爲準了.網絡

2>簽名, 這個簽名不能用 debug.keystore(Eclipse的簽名後綴是.keystore), 或者 debug.jks(Androidstudio把後綴名換了), 要用本身建立的的簽名文件,好比 shop.jsk , shop.keystore去生成簽名,或者選擇之前本身建立好的,都行,只有不是debug的就行.app

android studio生成簽名截圖以下: 點擊Teminal 啓動後,輸入圖中命令,後面是你jks所在位置. 以後回車 輸入密碼, 獲得MD5值, 它就是微信建立應用時用到的簽名,須要去掉冒號,把大寫所有改爲小寫便可. 固然微信還給咱們提供了簽名工具apk, 你能夠把本身的工程打包後,安裝到手機,而後啓動微信的簽名apk,輸入包名便可獲得簽名, 你能夠拿它對比一下用命令行獲得的簽名是否一致, 若是不一致那就說明一個問題 " 你的應用沒有通過打包" , 不要經過編譯工具直接部署 到手機,這樣獲得的簽名是不對的. 必定要是打包後的.eclipse

 

當測試微信的時候,也須要把打包後的apk安裝到手機才能測試支付,若是隻能調起一次微信,第二次沒法調起,那就是簽名或者 appid這一塊有問題,檢查一下. 不過我發現IOS不存在這個問題, 每次都能調起微信.

 

二.下面說下微信在工程中建立須要注意地方:

1. 若是你的包名是com.xxx.text 那麼你須要在test以後建立一個包名 com.xxx.text.wxapi, 必須是wxapi,不能錯了. 而後必須拷貝一個類過來:WXPayEntryActivity.java ,這個類的做用是微信支付後,接收微信的支付結果的. 你能夠不作任何修改,直接拿來用就行,固然若是你想更改裏面的佈局,也是徹底OK的, 我對他作了一下修改,代碼以下, 我修改了2個地方,代碼中給出了註釋

public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler{

    private static final String TAG = "MicroMsg.SDKSample.WXPayEntryActivity";

    private IWXAPI api;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                                //1.第一個修改的地方 我刪掉了,它自帶的 佈局, 固然若是你想保留,徹底OK.由於佈局太難看因此我幹掉他了
        api = WXAPIFactory.createWXAPI(this, Constants.APP_ID);
        api.handleIntent(getIntent(), this);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        api.handleIntent(intent, this);
    }

    @Override
    public void onReq(BaseReq req) {}

    @Override
    public void onResp(BaseResp resp) {
  //2.這是我修改的第二個地方, 原版的是彈出一個對話框, 我以爲太醜,而且原版也沒有給出詳細問題提示,只給出了 0, -1 ,-2 這樣會讓客戶不明因此,因此我替換成以下3個文本. 此外   //原版支付後,不會直接跳轉到 你的應用,須要按一次 返回鍵,才行, 因此我加入了finish()便於在提示後,直接返回個人應用
        if(resp.errCode==0){
            Toast.makeText(this,"支付成功!",Toast.LENGTH_SHORT).show();
           
        }else if(resp.errCode==-1){
            Toast.makeText(this,"支付失敗!",Toast.LENGTH_SHORT).show();
            
        }else if(resp.errCode==-2){
            Toast.makeText(this,"取消支付!",Toast.LENGTH_SHORT).show();
            
        }
        finish();
    }
}

2. androidmainfest.xml 的配置,直接上代碼,這裏只須要注意一個地方那就是 appid

 <activity
            android:name=".wxapi.WXPayEntryActivity"
            android:label="@string/app_name"
            android:exported="true"      //必須爲true
            android:launchMode="singleTop">    //必須單例
        </activity>

        <receiver
            android:name=".wxapi.AppRegister">
            <intent-filter>
                <action android:name="com.tencent.mm.plugin.openapi.Intent.ACTION_REFRESH_WXAPP" />
            </intent-filter>
        </receiver>
 <activity android:name=".ui.PayActivity"    //這是我本身定義的支付Activity, 本身修更名字便可
            android:exported="true"
            android:launchMode="singleTop"
            >
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:scheme="wxbdc42b2a35e9884e"/>  //這裏就是 APPID ,必須和你申請的 應用的 appid保持一致 .不然沒法支付,注意,注意,注意
            </intent-filter>
        </activity>

3.下面是我項目中的支付代碼, 先說下支付流程, 首先你要 讓負責接口的,給你一個接口, 這個接口 須要app端傳遞 商品的基本信息過去,好比 商品名字 , 描述,訂單號 ,價格等等.也不須要傳遞太多東西, 我就傳遞了 以上我列舉的4個 ,有人會問 "微信不是幫咱們生成了一個 訂單號嗎?" 我幹嗎還要傳遞給他, 我傳遞的這個訂單號,是用於退款使用的. 因此我要傳遞一個, 這個訂單號,在我 下單的同時, 會生成一個隨機數, 固然這都是 後臺 接口弄得,你只須要拿來使用就好了.

說的有點亂了,給個步驟吧

1>傳遞商品信息給咱們本身的後臺

2>咱們本身的後臺會拿着這些商品信息 而後加上 + 商戶號id+商戶祕鑰 (申請商家端時獲取的), 給咱們app端返回一個json,該json中包含7個字段,須要解析,後面給出代碼

3>咱們解析後, 經過 api.sendReq(req); 調用微信支付 

代碼以下:

float total3 = orderTotalPrice * 100;  //注意微信支付付款 是按照分爲單位的,須要把商品價格 乘以100 ,而後強轉爲 int類型 ,這裏(int)total3
param ="?ordertype="+"old"+"&sworkOrderCode="+out_trade_no+"&serviceFee=" +(int)total3+"&serviceItem="+orderItem.orderName.trim()+"&serviceClass="+orderItem.serviceItem.trim(); 
testWxPay(v);//開始解析接口給咱們返回的json

參數:old 是,一個版本區分,由於公司的多個app都用到了微信支付,而且他們都有關聯,因此你能夠直接無視該參數,該參數僅用於我本身的項目
參數:
out_trade_no 是我從咱們的接口獲取到的隨機訂單號
參數:(int)total3 是商品價格, "分" 爲單位,必須轉爲 整形, 也不知道 int會不會越界,反正我用了int,你可用long
參數:serviceItem 商品名字
參數:serviceClass商品描述
 
 public void testWxPay(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                String url = HttpUrl.host1+"WeiXinApi.asmx/CreatePrePay_id"+param;
                Log.e("xxx",url);
                ToastUtil.shortToastInBackgroundThread(getActivity(), "獲取訂單中...");
                try {
                    byte[] buf = Util.httpGet(url);
                    if (buf != null && buf.length > 0) {
                        String content = new String(buf);
                        Log.e("get server pay params", content);
                        JSONObject json = new JSONObject(content);
                        if (null != json && !json.has("retcode")) {
                            req = new PayReq();
                            req.appId = json.getString("appid");    //appid
                            req.partnerId = json.getString("partnerid"); //商戶號
                            req.prepayId = json.getString("prepayid"); //預支付交易會話id
                            req.nonceStr = json.getString("noncestr"); //隨機字符串,不超過32位
                            req.timeStamp = json.getString("timestamp");//時間戳
                            req.packageValue = json.getString("package");//擴展字段
                            req.sign = json.getString("sign");//簽名信息MD5加密後的

                            ToastUtil.shortToastInBackgroundThread(getActivity(), "正常調起支付");
                            toPay();
                        } else {
                            Log.d("PAY_GET", "返回錯誤" + json.getString("retmsg"));
                            ToastUtil.shortToastInBackgroundThread(getActivity(), "返回錯誤" + json.getString("retmsg"));
                        }
                    } else {
                        Log.d("PAY_GET", "服務器請求錯誤");
                        ToastUtil.shortToastInBackgroundThread(getActivity(), "服務器請求錯誤");
                    }
                } catch (Exception e) {
                    Log.e("PAY_GET", "異常:" + e.getMessage());
                    ToastUtil.shortToastInBackgroundThread(getActivity(), "異常:" + e.getMessage());
                }
            }
        }).start();}
    private void toPay() {
        // 在支付以前,若是應用沒有註冊到微信,應該先調用IWXMsg.registerApp將應用註冊到微信
        api.registerApp(Constants.APP_ID);
        api.sendReq(req);
        Log.e("跳轉結果--",api.sendReq(req)+"");
    }
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            toPay();
        }
    };

整個支付代碼很是少,一共就這麼多.  須要注意的一點是, 解析的 7個 參數中, sign 是咱們本身服務端 二次加密獲得的,這裏容易出錯, 固然我說的是接口裏面容易出錯,和咱們app端沒有半毛錢關係,  由於這個 加密,老版本微信是咱們 app端生成的, 新版的 是由接口生成的,咱們直接拿來用.

sign 生成過程是: 前6個參數+ 商家祕鑰 通過MD5加密就獲得了. (這個加密用的前6個參數,須要安裝字母排序,不能亂用,商家祕鑰不需排序放到最後便可,固然這都是接口的須要完成的,咱們app端 瞭解便可)

若是這個sign 接口沒有弄好, 極容易出錯,沒法調起支付頁. 我在作的時候,就是由於接口的生成sign時,少寫一個 = 鏈接符形成的.

------------------------------------------------------------------------------------------------------------------------------------------

 

三.支付寶支付

支付寶支付相對來講要簡單的多了, 比較穩定寫得清晰明瞭,一看即懂.  直接上代碼吧 ,我去網絡太卡了,剛纔寫了半天,圖片沒法加載,把我寫得從新毀了,先保存吧,等會再上支付寶的.

流程以下:

1.申請帳號,一樣須要提交一些公司資料

2.下載須要資源,sdk ,文檔什麼的, 而後去配置工程

1>在工程中建立一個包存放支付寶所需資源,好比個人

導入alipaySdk-20160427.jar , 目前最新版.

2>androidmainfest.xml中的配置

<!--支付寶-->
        <activity
            android:name="com.alipay.sdk.app.H5PayActivity"  //H5頁面, 若是手機沒有安裝支付寶,調起這個
            android:configChanges="orientation|keyboardHidden|navigation"
            android:exported="false"
            android:screenOrientation="behind" >
        </activity>

        <activity
            android:name="com.alipay.sdk.auth.AuthActivity"
            android:configChanges="orientation|keyboardHidden|navigation"
            android:exported="false"
            android:screenOrientation="behind" >
        </activity>
   權限信息
   <uses-permission android:name="android.permission.INTERNET" />  
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

3.獲取私鑰, 公鑰

命令以下:

RSA密鑰生成命令
生成RSA私鑰
openssl>genrsa -out rsa_private_key.pem 1024
生成RSA公鑰
openssl>rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
將RSA私鑰轉換成PKCS8格式
openssl>pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt

命令使用的工具在 這裏: E:\支付寶錢包支付接口開發包2.0標準版(20160428)\DEMO\openssl\bin -->  openssl.exe

雙擊啓動,截圖以下: 而後輸入上面命令,就能夠獲得了.最後會生成相應的文件,可是後綴好像不是txt,你改爲txt就能看了.具體過程文檔說的很清楚,我也記不太清了,作了1周就忘記了,這記性 ...

打開紅框框中的2個文件,裏面就用公鑰和私鑰信息了, 注意紅色部分不能要,只要中間的, 你最好把中間部分回車去掉,改爲1行,否則可能會由於回車形成出錯

配置貌似也就這麼多了吧. 比較少,文檔也很清楚.

4.下面給出代碼吧,截圖了後面數據不能泄露了,公司的信息

 

 此處點擊 : "支付寶"支付這個 線性佈局,執行支付功能

rlZfb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                pay(v);
            }
        });
 /**
     * call alipay sdk pay. 調用SDK支付
     */
    public void pay(View v) {
        if (TextUtils.isEmpty(PARTNER) || TextUtils.isEmpty(RSA_PRIVATE) || TextUtils.isEmpty(SELLER)) {
            new AlertDialog.Builder(this).setTitle("警告").setMessage("須要配置PARTNER | RSA_PRIVATE| SELLER")
                    .setPositiveButton("肯定", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialoginterface, int i) {
                            //
                            finish();
                        }
                    }).show();
            return;
        }
        //獲得訂單信息
        String orderInfo = null;
        //待支付列表item對象
        orderInfo = getOrderInfo(orderItem.getServiceCode(), orderTotalPrice);
        
        String sign = sign(orderInfo);
        try {
            /**
             * 僅需對sign 作URL編碼
             */
            sign = URLEncoder.encode(sign, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        /**
         * 完整的符合支付寶參數規範的訂單信息
         */
        final String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getSignType();
        Runnable payRunnable = new Runnable() {
            @Override
            public void run() {
                // 構造PayTask 對象--該對象主要爲商戶提供訂單支付功能
                PayTask alipay = new PayTask(getActivity());
                // 調用支付接口,獲取支付結果
                String result = alipay.pay(payInfo, true);

                Message msg = new Message();
                msg.what = SDK_PAY_FLAG;
                msg.obj = result;
                mHandler.sendMessage(msg);
            }
        };

        // 必須異步調用
        Thread payThread = new Thread(payRunnable);
        payThread.start();
    }
/**
     * create the order info. 建立訂單信息
     * subject 商品名字
     */
    private String getOrderInfo(String subject, float price) {
        // 簽約合做者身份ID
        String orderInfo = "partner=" + "\"" + PARTNER + "\"";
        // 簽約賣家支付寶帳號
        orderInfo += "&seller_id=" + "\"" + SELLER + "\"";
        // 商戶網站惟一訂單號
        //orderInfo += "&out_trade_no=" + "\"" + getOutTradeNo() + "\"";
        orderInfo += "&out_trade_no=" + "\"" + out_trade_no + "\"";
        // 商品名稱
        orderInfo += "&subject=" + "\"" + subject + "\"";
        // 商品詳情
        //orderInfo += "&body=" + "\"" + body + "\"";
        // 商品金額
        orderInfo += "&total_fee=" + "\"" + price + "\"";
        // 服務器異步通知頁面路徑 --- 調用服務端地址
        //orderInfo += "&notify_url=" + "\"" + "http://notify.msp.hk/notify.htm" + "\"";
        //ToastUtils.show(getActivity(),subject+price);
        Log.e("xxxx", subject + price);
        orderInfo += "&notify_url=" + "\"" + "http://xxx.xxx.xxx/HomeWorkOrder.asmx/WorkOrderPayed" + "\"";//此處是接口端給的一個 地址,找他們要吧....

        // 服務接口名稱, 固定值
        orderInfo += "&service=\"mobile.securitypay.pay\"";
        // 支付類型, 固定值
        orderInfo += "&payment_type=\"1\"";
        // 參數編碼, 固定值
        orderInfo += "&_input_charset=\"utf-8\"";
        // 設置未付款交易的超時時間
        // 默認30分鐘,一旦超時,該筆交易就會自動被關閉。
        // 取值範圍:1m~15d。
        // m-分鐘,h-小時,d-天,1c-當天(不管交易什麼時候建立,都在0點關閉)。
        // 該參數數值不接受小數點,如1.5h,可轉換爲90m。
        orderInfo += "&it_b_pay=\"30m\"";
        // extern_token爲通過快登受權獲取到的alipay_open_id,帶上此參數用戶將使用受權的帳戶進行支付
        // orderInfo += "&extern_token=" + "\"" + extern_token + "\"";
        // 支付寶處理完請求後,當前頁面跳轉到商戶指定頁面的路徑,可空
        orderInfo += "&return_url=\"m.alipay.com\"";
        // 調用銀行卡支付,需配置此參數,參與簽名, 固定值 (須要簽約《無線銀行卡快捷支付》才能使用)
        // orderInfo += "&paymethod=\"expressGateway\"";
        return orderInfo;
    }

大多數都是支付寶代碼,貼着也沒意思, 只不過修改了訂單信息而已. 後面的再也不貼了. demo和文檔已經很是清楚了. 支付寶退款很簡單,只須要發送訂單號給咱們本身的接口便可,其餘的由接口去實現.

以上就是全部代碼了.寫得很差 ,勿噴!!

相關文章
相關標籤/搜索