天天看點

android 支付寶的植入 《曾經踩過的坑》

最近公司有需求在項目中要植入支付寶支付等功能。 在完成植入的過程中,遇到了一些坑,今天趁趁任務不多做了個總結。分享給大家,希望以小夥伴不要陷入這些坑中以免浪費很多的時間。

首先說一下遇到的坑及其碰到的問題

1.java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag ClassCastException: com.android.org.bouncycastle.asn1.DLSequence cannot be cast to com.android.org.bouncycastle.asn1.ASN1Integer

原因:

public class SignUtils {
   private static final String ALGORITHM = "RSA";
   private static final String SIGN_ALGORITHMS = "SHA1WithRSA";
   private static final String DEFAULT_CHARSET = "UTF-8";
   public static String sign(String content, String privateKey) {
      try {
         java.security.Signature signature = java.security.Signature
               .getInstance(SIGN_ALGORITHMS);
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(PayBase64.decode(privateKey));
      KeyFactory keyf = KeyFactory.getInstance(ALGORITHM);
      PrivateKey priKey = keyf.generatePrivate(priPKCS8);
         PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(PayBase64.decode(privateKey));
         KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
         PrivateKey priKey = keyFactory.generatePrivate(privSpec);
         signature.initSign(priKey);
         signature.update(content.getBytes(DEFAULT_CHARSET));
         byte[] signed = signature.sign();
         return PayBase64.encode(signed);
      } catch (Exception e) {
         e.printStackTrace();
      }
      return null;
   }
           

修改之後,發現

com.android.org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException: unable to process key spec: java.lang.ClassCastException: com.android.org.bouncycastle.asn1.DLSequence cannot be cast to com.android.org.bouncycastle.asn1.ASN1Integer

又這個錯誤,總麼辦?

最終是因為:

最終因為傳入私鑰錯誤。需要重新生成私鑰:

2.在handler裡面接受消息的時候,PayResult 轉換失敗,原因是你在進行

調用支付寶接口的時候,所發送的參數類型不一緻導緻的。eg:

PayTask payTask = new PayTask(DocPayConunselActivity.this);
// String result = payTask.pay(signInfo, true);
Map<String, String> result = payTask.payV2(signInfo, true);
Message message = mHandler.obtainMessage();
message.what = SDK_PAY_FLAG;
message.obj = result;
mHandler.sendMessage(message);
           

另外 如果傳回的resultStatus是6002的時候,網絡出錯,或者是手機沒有安裝支付寶的時候,彈不出來網頁版的支付登入框 這個時候也是會提示網絡錯誤 。這時候你要查找你的配置檔案看一下是否配置了以下檔案:

<activityandroid:name="com.alipay.sdk.app.H5PayActivity"android:configChanges="orientation|keyboardHidden|navigation"android:exported="false"android:screenOrientation="behind" ></activity>
<activityandroid:name="com.alipay.sdk.auth.AuthActivity"android:configChanges="orientation|keyboardHidden|navigation"android:exported="false"android:screenOrientation="behind" ></activity>
添加必要權限
<uses-permissionandroid:name="android.permission.INTERNET" />
<uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permissionandroid:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permissionandroid:name="android.permission.READ_PHONE_STATE" />
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE" />
           

Android快捷支付SDK Demo resultStatus={4001};memo={參數錯誤};result={}問題

分析:填寫的支付寶pkcs8編碼的私鑰 有問題,或者對應的公鑰沒有上傳至支付寶造成的。 

背景處理的必須有這個步驟。上傳公鑰到支付寶

java.lang.NoClassDefFoundError: com.alipay.android.app.lib.ResourceMap

分析:沒有加入android_lib 沒有加入項目依賴項

resultStatus={7001};memo={商戶沒有開通移動快捷支付服務,請使用其他支付工具};result={}!

內建的基本流程如下:

第一步:2.1 導入jar包資源

目前最新版支付寶開發jar包下載下傳位址:androidstarjack_支付寶內建過程詳解— 運作DEMO.zip

下載下傳後将之拷貝libs目錄,Eclipse會自動添加依賴,Android Studio需在app的gradle中添加一行

compilefiles('libs/alipaySdk-20160223.jar')

點選右上角:Sync Now,稍等片刻

第二步:修改AndroidManifest.xml清單

聲明必要Activity

<!--支付相關-->

 <activity

     android:name="com.alipay.sdk.app.H5PayActivity" android:configChanges="orientation|keyboardHidden|navigation"

     android:exported="false" android:screenOrientation="behind" />

 <activity

     android:name="com.alipay.sdk.auth.AuthActivity" android:configChanges="orientation|keyboardHidden|navigation"

     android:exported="false" android:screenOrientation="behind" />

添加必要權限

<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />

<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<uses-permission android:name="android.permission.BROADCAST_STICKY" />

<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />

第四步:

private void payToOrderService(final String signInfo){

    new Thread() {

        @Override

        public void run() {

            super.run();

            PayTask payTask = new PayTask(DocPayConunselActivity.this);

            // String result = payTask.pay(signInfo, true);

            Map<String, String> result = payTask.payV2(signInfo, true);

            Message message = mHandler.obtainMessage();

            message.what = SDK_PAY_FLAG;

            message.obj = result;

            mHandler.sendMessage(message);

        }

    }.start();

}

app攜帶支付資訊調用支付接口請求支付寶用戶端調起支付界面;

使用者操作,輸入密碼支付,支付成功;直接傳回取消支付;出現錯誤,支付失敗;進入支付界面,但輸入密碼支付,支付待确認;

支付寶用戶端将支付結果告訴app用戶端,商戶伺服器通知app伺服器支付結果;

app用戶端處理支付結果;

app伺服器處理支付結果。

注意請求是異步的:x

<pre name="code" class="java">PayTask payTask = new PayTask(DocPayConunselActivity.this);
// String result = payTask.pay(signInfo, true);
Map<String, String> result = payTask.payV2(signInfo, true);
Message message = mHandler.obtainMessage();
message.what = SDK_PAY_FLAG;
message.obj = result;
mHandler.sendMessage(message)
           

傳回的結果:

private Handler mHandler =new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case SDK_PAY_FLAG:
                PayResult payResult = null;
                        try{
                            payResult = new PayResult((Map<String, String>) msg.obj);
                        }catch (Exception e){
                            e.printStackTrace();
                        }


                /**
                 對于支付結果,請商戶依賴服務端的異步通知結果。同步通知結果,僅作為支付結束的通知。
                 */
                String resultInfo = payResult.getResult();// 同步傳回需要驗證的資訊
                String resultStatus = payResult.getResultStatus();
                // 判斷resultStatus 為9000則代表支付成功
                if (TextUtils.equals(resultStatus, PAY_OK)) {//----------------------------------->支付成功
                    // 該筆訂單是否真實支付成功,需要依賴服務端的異步通知。
                    GetToast.useString(DocPayConunselActivity.this, "購買服務成功");
                } else if (TextUtils.equals(resultStatus, PAY_FAILED)) {//------------------------->支付失敗
                    // 該筆訂單真實的支付結果,需要依賴服務端的異步通知。
                    GetToast.useString(DocPayConunselActivity.this, ""+payResult.getMemo());
                } else if (TextUtils.equals(resultStatus, PAY_CANCLE)) {//-------------------------->交易取消
                    GetToast.useString(DocPayConunselActivity.this, ""+payResult.getMemo());
                } else if (TextUtils.equals(resultStatus, PAY_NET_ERR)) {//------------------------->網絡出現錯誤
                    GetToast.useString(DocPayConunselActivity.this, ""+payResult.getMemo());
                } else if (TextUtils.equals(resultStatus, PAY_WAIT_CONFIRM)) {//--------------------->交替等待
                }
                break;
        }
    }
};
           
最後注意的是,有些手機沒有安裝支付寶用戶端,如牽扯到支付功能的時候,我們直接天轉到網頁版的支付進行去輸入密碼去支付 。當然你也可以判斷利用支付的sdk進行判斷,如沒有安裝支付寶,提示去安裝支付寶子產品也是可以的。          
           

這樣就完美無缺了。

QQ交流群 :232203809,歡迎入群 

android 支付寶的植入 《曾經踩過的坑》

微信公衆号:終端研發部 

(歡迎關注學習和交流)

繼續閱讀