微信SDK使用

由于第一次接微信SDK。沿路踩过一个又一个大大小小的坑,以此做一下记录。

对于安卓版来说。前期一些基本jar导入。xml配置什么的都基本不会有什么问题,按照微信文档来就可以了。

第一个坑在出在签名上,第三方应用要拉起微信必须保证2点:

1.应用中的包名(Mainfext.xml中的package)必须与后台配置的一致。

2.应用生成不能是debug包,必须是正式的签名包。这个签名必须与后台配置的一致。

在第一点上,会出错的概率还是比较小的。

主要出错会在第2点上,微信官方有微信签名检测工具。用检测工具检测到的签名是一串小写并且中间没有冒号的字符串。

而在后台配置的却是直接从在eclipse打签名包时直接复制出来的MD5签名。(大写,并且中间夹杂:)

所以后台配置的签名必须与打包时的签名一致。必须是小写无冒号的字符串


第二个坑出现在接登录的时候,在拉起微信授权登录之后无法自动返回第三方应用。

问题出在判断微信是否安装上。用了api.openWXApp(),导致打开微信后无法返回,修改为 api.isWXAppInstalled()就完美解决问题了。

[java]  view plain  copy
  1. public static void sendMsgtoWX()  
  2. {  
  3.  System.out.println("hwt c-----------------sendMsgtoWX");  
  4.     if(api.isWXAppInstalled())  
  5.     {     
  6.             // send oauth request   
  7.             SendAuth.Req req = new SendAuth.Req();  
  8.             req.scope = "snsapi_userinfo";  
  9.             req.state = "login_state";  
  10.             api.sendReq(req);  
  11.     }  
  12.     else  
  13.     {  
  14.         ShowMsg(1);  
  15.     }  

 
 
 
 

 
 

第三个坑出现在分享图片的时候。微信对于图片分享中,对图片的大小做了限定。图片分享中主要是两部分,一个分享出去就直接能看到的一张比较小的图。还有一张就是点击之后出现的图片。两张图片的具体大小没有做测试。但是知道第一个图片必须比较小。太大就会出现无法拉起分享的情况。第二张图片比较大。基本1M左右应该都没什么问题。

[java]  view plain  copy
  1. //分享图片到微信  
  2.    public void shareImgToWeixin(String path,int type)//type = 1 好友。type = 2 朋友圈  
  3.    {  
  4.      System.out.println("----------shareToWeixin--path:"+path);  
  5.         File file = new File(path);  
  6.         if (!file.exists()) {  
  7.             ShowMsg(2);  
  8.             return;  
  9.         }  
  10.         if(api.isWXAppInstalled())  
  11.         {  
  12.             if(type == 1)  
  13.             {  
  14.                 Bitmap bmp = BitmapFactory.decodeFile(path);  
  15.                 WXImageObject imgObj = new WXImageObject(bmp);  
  16.                   
  17.                         imgObj.setImagePath(path+"screenshot.png");  
  18.                 int num1 =bmp.getByteCount();  
  19.                  int w =bmp.getWidth();  
  20.                  int h =bmp.getHeight();  
  21.                  float scal = 100/(float)w;  
  22.                  w = (int)(w*scal);  
  23.                  h = (int)(h*scal);  
  24.                  System.out.println("----------thumbBmp w:"+w+"h:"+h);  
  25.                 Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, w,h, true);  
  26.                 int num =thumbBmp.getByteCount();  
  27.                  System.out.println("----------thumbBmp num1:"+num1+"------num:"+num);  
  28.                 bmp.recycle();  
  29.                   
  30.                 WXMediaMessage msg = new WXMediaMessage();  
  31.                 msg.mediaObject = imgObj;  
  32.                 msg.thumbData = Util.bmpToByteArray(thumbBmp, true);  
  33.   
  34.                 SendMessageToWX.Req req = new SendMessageToWX.Req();  
  35.                 req.scene = (type == 1)?SendMessageToWX.Req.WXSceneSession:SendMessageToWX.Req.WXSceneTimeline;  
  36.                 req.transaction = buildTransaction("img");  
  37.                 req.message = msg;  
  38.                 api.sendReq(req);    
  39.                   
  40.             }  
  41.         }  
  42.     }  

 
 在微信支付中遇到的问题还是挺多的,因为微信的流程中数据的接收和发送都是xml格式的。由于之前没有对xml格式做过处理,走了不少弯路。 
 

其实流程很简单,就是将数据拼成xml格式post发过去,再解析xml格式的数据获得参数。微信第一部分统一下单,由于各种原因我们放在了客户端中处理。服务端只是生成了一个商户订单号。

由于我们的项目ios和安卓是同一套代码。所以我们将第一部分统一下单放在了cocos中实现。

其中需要注意的几点是:在生成签名的时候,必须把需要发送过去的参数,除了sign本身之外都需要打进去,少一个都不行。签名就按照微信官方文档来就可以了。

需要签名的参数大写与小写所生成的签名是不一样的。所以,我把需要签名的参数都是小写,再在最后转化为大写。还有签名中的key并非AppID或AppSectet,而是在商户平台设置的,官方描述为“key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥置”。

[cpp]  view plain  copy
  1. void WXMessage::SendFirstDate(std::string out_trade_no,std::string price,std::string body)  
  2. {  
  3.     //网络异步连接方法  
  4.     HttpRequest* request = new HttpRequest();  
  5.     request->setUrl("https://api.mch.weixin.qq.com/pay/unifiedorder");  
  6.     request->setRequestType(HttpRequest::Type::POST);  
  7.     request->setResponseCallback(this, httpresponse_selector(WXMessage::onHttpRequestCompleted));  
  8.     std::string postData = "";  
  9.     postData += "<xml>";  
  10.     postData += "\n";  
  11.     postData += "<appid><![CDATA["+(std::string)wx_appid+"]]></appid>";  
  12.     postData += "\n";  
  13.     postData += "<mch_id><![CDATA["+(std::string)wx_mchid+"]]></mch_id>";  
  14.     postData += "\n";  
  15.     postData += "<nonce_str><![CDATA["+rand_str()+"]]></nonce_str>";  
  16.     postData += "\n";  
  17.     postData += "<sign><![CDATA["+Getsign(out_trade_no,price,body)+"]]></sign>";  
  18.     postData += "\n";  
  19.     postData += "<body><![CDATA["+body+"]]></body>";  
  20.     postData += "\n";  
  21.     postData += "<out_trade_no><![CDATA["+out_trade_no+"]]></out_trade_no>";  
  22.     postData += "\n";  
  23.     postData += "<total_fee>"+price+"</total_fee>";  
  24.     postData += "\n";  
  25.     postData += "<spbill_create_ip><![CDATA["+GetIP()+"]]></spbill_create_ip>";  
  26.     postData += "\n";  
  27.     postData += "<notify_url><![CDATA["+(std::string)wx_notify_url+"]]></notify_url>";  
  28.     postData += "\n";  
  29.     postData += "<trade_type><![CDATA["+(std::string)wx_trade_type+"]]></trade_type>";  
  30.     postData += "\n";  
  31.     postData += "</xml>;       <pre name="code" class="cpp">  
request->setRequestData(postData.c_str(),postData.size());
    HttpClient::getInstance()->send(request);
    request->release();
}
 
  
   
 
[cpp]  view plain  copy
  1.  void WXMessage::onHttpRequestCompleted(HttpClient *sender, HttpResponse *response)  
  2. {  
  3.     if (!response) {  
  4.         return;  
  5.           
  6.     }  
  7.       
  8.     if (0 != strlen(response->getHttpRequest()->getTag())) {  
  9.         log("%s completed",response->getHttpRequest()->getTag());  
  10.     }  
  11.       
  12.     long statusCode = response->getResponseCode();  
  13.     char statusString[64] = {};  
  14.       
  15.     sprintf(statusString, "HTTP Status Code: %ld, tag = %s",statusCode,response->getHttpRequest()->getTag());  
  16.     log("response code: %ld",statusCode);  
  17.       
  18.     if (!response->isSucceed()) {  
  19.         log("response failed");  
  20.         log("error buffer: %s",response->getErrorBuffer());  
  21.         return;  
  22.     }  
  23.     if(statusCode == 200)  
  24.     {  
  25.         std::vector<char>* buffer = response->getResponseData();  
  26.         std::string str = &(*buffer)[0];  
  27.           
  28.         int a = (int)str.find("<return_code><![CDATA[");  
  29.         int e = (int)str.find("]]></return_code>");  
  30.         std::string code = &(*buffer)[a];  
  31.         code = code.substr(22,e-a-22);  
  32.         if(code.compare("SUCCESS") == 0)  
  33.         {  
  34.             int start =(int)str.find("<prepay_id><![CDATA[");  
  35.             int end =(int)str.find("]]></prepay_id>");  
  36.             std::string prepay_id =&(*buffer)[start];  
  37.             prepay_id = prepay_id.substr(20,end-start-20);  
  38.             CCLOG("prepay_id:%s",prepay_id.c_str());  
  39.               
  40.             SocialUtils::WXPay(prepay_id,nonce_str);  
  41.         }else{  
  42.             //printf("Http Test, dump data: ");  
  43.             for (unsigned int i = 0 ; i < buffer->size();i++) {  
  44.                 printf("%c",(*buffer)[i]);  
  45.             }  
  46.             printf("\n");  
  47.         }  
  48.     }  
  49. }  
[cpp]  view plain  copy
  1. //随机值  
  2. std::string WXMessage::rand_str()  
  3. {  
  4.     char str[33] = "";  
  5.     int i;  
  6.     srand((unsigned int)time(0));  
  7.     for(i=0;i<32;++i)  
  8.     {  
  9.         if(rand()%2)  
  10.         {  
  11.             str[i]='0'+rand()%10;  
  12.         }else  
  13.         {  
  14.             str[i]='a'+rand()%26;  
  15.         }  
  16.           
  17.     }  
  18.       
  19.     str[++i]='\0';  
  20.     std::string nond = str;  
  21.     return nond;  
  22. }  
[cpp]  view plain  copy
  1. //签名  
  2. std::string WXMessage::Getsign(std::string out_trade_no,std::string price,std::string body)  
  3. {  
  4.     char str[1024] = "";  
  5.     std::string sign = "";  
  6.     std::string str1= "";  
  7.     str1 +="appid="+(std::string)wx_appid;  
  8.     str1 +="&body="+body;  
  9.     str1 +="&mch_id="+(std::string)wx_mchid;  
  10.     str1 +="&nonce_str="+(std::string)nonce_str;  
  11.     str1 +="&notify_url="+(std::string)wx_notify_url;  
  12.     str1 +="&out_trade_no="+out_trade_no;  
  13.     str1 +="&spbill_create_ip="+GetIP();  
  14.     str1 +="&total_fee="+price;  
  15.     str1 +="&trade_type="+(std::string)wx_trade_type;  
  16.     str1 +="&key="+(std::string)wx_key;  
  17.     sprintf(str, "%s",str1.c_str());  
  18.     char md5p[33];  
  19.     md5_passwd(str, md5p);  
  20.     for(int i=0;i<strlen(md5p);i++)  
  21.     {  
  22.        if(islower(md5p[i]))  
  23.        {  
  24.            md5p[i] = toupper(md5p[i]);  
  25.        }  
  26.     }  
  27.     sign = md5p;  
  28.     m_sign = sign;  
  29.     return sign;  
  30. }  


微信支付第一部分统一下单就此完成。在第二部拉起支付中,还需要再次对参数签名。这次签名和第一次的是不一样的,这次是对拉起支付的参数进行签名。其中也需要一个随机数,这个随机数需要和第一次签名的随机数一致(官方文档没有明确说明,我也是百度后这样做的)。这部分就要在安卓和IOS分别完成了。

安卓:

[java]  view plain  copy
  1. public void ToWX_Pay(String m_prepayid,String m_nonce_str)  
  2.          {  
  3. //           nonce_str = m_nonce_str;  
  4. //           prepayid = m_prepayid;  
  5.              timeStamp = Long.toString(System.currentTimeMillis()/ 1000);  
  6.              if(api.isWXAppInstalled())  
  7.              {  
  8.                  PayReq req = new PayReq();  
  9.                     req.appId           = AppConfig.WX_APPID;  
  10.                     req.partnerId       = AppConfig.mch_id;  
  11.                     req.prepayId        = m_prepayid;  
  12.                     req.nonceStr        = m_nonce_str;  
  13.                     req.timeStamp       = timeStamp;  
  14.                     req.packageValue    = "Sign=WXPay";  
  15.                     req.sign            = WX_sign(m_prepayid,m_nonce_str);  
  16. //                  req.extData         = "";  
  17.                      System.out.println("-----------------WX_pay-- \n appId:"+req.appId+"\n"+"--partnerId:"+req.partnerId+"\n"+"--prepayId:"+req.prepayId+"\n"+  
  18.                              "--nonceStr:"+ req.nonceStr+"\n"+"--timeStamp:"+req.timeStamp+"\n"+"--sign:"+req.sign);  
  19.                       
  20.                     api.sendReq(req);  
  21.              }else  
  22.              {  
  23.                  ShowMsg(1);  
  24.              }  
  25.          }  
[java]  view plain  copy
  1. /**  
  2.  * 微信支付签名算法sign  
  3. * @param m_prepayid 
  4. * @param m_nonce_str 
  5. * @return  
  6. */    
  7. public String WX_sign(String m_prepayid,String m_nonce_str)  
  8. {  
  9.  //微信api提供的参数         
  10.         SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();    
  11.         parameters.put("appid", AppConfig.WX_APPID);    
  12.         parameters.put("partnerid", AppConfig.mch_id);  
  13.         parameters.put("prepayid", m_prepayid);   
  14.         parameters.put("package""Sign=WXPay");    
  15.         parameters.put("noncestr", m_nonce_str);   
  16.         parameters.put("timestamp", timeStamp);   
  17.              
  18.         StringBuffer sb = new StringBuffer();    
  19.         Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)    
  20.        Iterator it = es.iterator();    
  21.         while(it.hasNext()) {    
  22.             Map.Entry entry = (Map.Entry)it.next();    
  23.             String k = (String)entry.getKey();    
  24.             Object v = entry.getValue();    
  25.             if(null != v && !"".equals(v)     
  26.                     && !"sign".equals(k) && !"key".equals(k)) {    
  27.                 sb.append(k + "=" + v + "&");    
  28.             }    
  29.         }    
  30.         sb.append("key=" + AppConfig.Key);    
  31.       <span style="white-space:pre">   </span>String sign = Tools.MD5Encode(sb.toString(), "UTF-8").toUpperCase();  
  32. <span style="white-space:pre">    </span>return sign;  
  33.  }  
IOS微信官方的demo中可以参考的还是挺多的。
IOS:

[objc]  view plain  copy
  1. NSString* _time_stamp;  
  2.   
  3. +(void)ToWX_Pay:(NSString*)payid toNoncestr:(NSString*)nonce_str  
  4. {  
  5.     NSLog(@"微信支付--------------》》");  
  6.     if([WXApi isWXAppInstalled])  
  7.     {  
  8.         time_t now;  
  9.         time(&now);  
  10.         _time_stamp  = [NSString stringWithFormat:@"%ld", now];  
  11.         NSMutableString *stamp = (NSMutableString*)_time_stamp;  
  12.         //调起微信支付  
  13.         PayReq* req             = [[PayReq alloc] init];  
  14.         req.openID              = [NSString stringWithUTF8String:wx_appid];  
  15.         req.partnerId           = [NSString stringWithUTF8String:wx_mchid];  
  16.         req.prepayId            = payid;//  
  17.         req.nonceStr            = nonce_str;  
  18.         req.timeStamp           = stamp.intValue;  
  19.         req.package             = @"Sign=WXPay";  
  20.         req.sign                = [self GetSign:payid toNoncestr:nonce_str];  
  21.         [WXApi sendReq:req];  
  22.         //日志输出  
  23.         NSLog(@"appid=%@\npartid=%@\nprepayid=%@\nnoncestr=%@\ntimestamp=%ld\npackage=%@\nsign=%@",req.openID,req.partnerId,req.prepayId,req.nonceStr,(long)req.timeStamp,req.package,req.sign );  
  24.     }else  
  25.     {  
  26.         [AppWXController ShowMsg];  
  27.     }  
  28. }  
[objc]  view plain  copy
  1. +(NSString*)GetSign:(NSString*)payid toNoncestr:(NSString*)m_nonce_str  
  2. {  
  3.     NSString    *appid,*prePayid,*mchid,*package, *time_stamp, *nonce_str;  
  4.     appid = [NSString stringWithUTF8String:wx_appid];  
  5.     mchid = [NSString stringWithUTF8String:wx_mchid];  
  6.     nonce_str = m_nonce_str;  
  7.     package = @"Sign=WXPay";  
  8.     time_stamp = _time_stamp;  
  9.     prePayid = payid;  
  10.       
  11.       
  12.     NSMutableDictionary *signParams = [NSMutableDictionary dictionary];  
  13.     [signParams setObject: appid        forKey:@"appid"];  
  14.     [signParams setObject: nonce_str    forKey:@"noncestr"];  
  15.     [signParams setObject: package      forKey:@"package"];  
  16.     [signParams setObject: mchid        forKey:@"partnerid"];  
  17.     [signParams setObject: time_stamp   forKey:@"timestamp"];  
  18.     [signParams setObject: prePayid     forKey:@"prepayid"];  
  19.     //[signParams setObject: @"MD5"       forKey:@"signType"];  
  20.     //生成签名  
  21.     NSString *sign  = [self createMd5Sign:signParams];  
  22.     return sign;  
  23. }  
[objc]  view plain  copy
  1. //创建package签名  
  2. +(NSString*) createMd5Sign:(NSMutableDictionary*)dict  
  3. {  
  4.     NSMutableString *contentString  =[NSMutableString string];  
  5.     NSArray *keys = [dict allKeys];  
  6.     //按字母顺序排序  
  7.     NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1id obj2) {  
  8.         return [obj1 compare:obj2 options:NSNumericSearch];  
  9.     }];  
  10.     //拼接字符串  
  11.     for (NSString *categoryId in sortedArray) {  
  12.         if (   ![[dict objectForKey:categoryId] isEqualToString:@""]  
  13.             && ![categoryId isEqualToString:@"sign"]  
  14.             && ![categoryId isEqualToString:@"key"]  
  15.             )  
  16.         {  
  17.             [contentString appendFormat:@"%@=%@&", categoryId, [dict objectForKey:categoryId]];  
  18.         }  
  19.           
  20.     }  
  21.     //添加key字段  
  22.     [contentString appendFormat:@"key=%@", [NSString stringWithUTF8String:wx_key]];//  
  23.     //得到MD5 sign签名  
  24.     NSString *md5Sign =[WXUtil md5:contentString];  
  25.       
  26.     return md5Sign;  
  27. }  

就此,微信拉起支付流程基本完成了。

如果拉起微信支付,errCode返回-1,有人说清除微信缓存或切换账户就好了,这种解决方案治标不治本啊,根本不能算解决方案。虽然我没遇到能用这方法解决的问题,但目测是签名的问题,建议还得找到真正的问题所在。

以此记录踩过的一些坑,希望各位能顺利接完微信SDK!


https://blog.csdn.net/wl41206/article/details/52240346

猜你喜欢

转载自blog.csdn.net/larry_zeng1/article/details/80333984