Skip to content

zhongsheng/wechatruby

Repository files navigation

微信开放平台API

Installation

Add this line to your application’s Gemfile:

gem 'wechatruby'

And then execute:

$ bundle

Or install it yourself as:

$ gem install wechatruby

Usage

client

wechat = Wechatruby::Client.new(
  id: ENV.fetch('AppID'),
  secret: ENV.fetch('AppSecret')
)

获取用户信息

# 通过openid获取用户信息
user_info = wechat.get_user_by_id('osip61TslXFOq134R4pc2tI9qQrk')
# =>
# {
#   "openid":" OPENID",
#   "nickname": NICKNAME,
#   "sex":"1",
#   "province":"PROVINCE",
#   "city":"CITY",
#   "country":"COUNTRY",
#   "headimgurl": "http://thirdwx.qlogo.cn/mmopen/xxjx/46",
#   "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
#   "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
# }

微信登录

公众号和网页登录机制不同, 公众号登录需要认证过的服务号appid, 而网页登录需要在开放平台注册一个webapp, 并获取appid. 具体方法参考: https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

个人比较倾向的解决方案是使用公众号生成的临时二维码功能, 结合websocket来做pc网页端登录, 这样的好处是不用再申请开放平台, 而且可以强制用户登录前关注公众号.

公众号登录

callback_url = 'https://exmple.com/wechat/signup'
if request.headers['HTTP_USER_AGENT'].include?('MicroMessenger')
  redirect_to wechat.code_request_url(callback_url)
  return
end

# 处理回调
# 微信服务器 get 访问指定的回调地址, 并传入code参数
# 获取用户信息和openid
user_info = wechat.get_user_info(params[:code])

浏览器扫码登录

callback_url = 'https://exmple.com/wechat/signup'
redirect_to wechat.qr_code_url(callback_url)

# 处理回调
# 微信服务器 get 访问指定的回调地址, 并传入code参数
# 获取用户信息和openid
user_info = wechat.get_user_info(params[:code])

发送信息

# 发送模板信息
params =
  {
    touser: 'sip61TslXFOq134R4pc2tI9qQrk',
    template_id: 'tWRq3Qm-qcEUWw79sSADu6axa38reZUqTWJE2tsos0',
    data: {
      first: {
        value: 'Welcome'
      },
      orderno: {
        value: '123456789'
      },
      amount: {
        value: 123
      },
      remark: {
        value: 'Thanks'
      }
    }
  }
result = wechat.messages.send_template(params)

# 发送图片
result = wechat.assets.tmp_add('image', '/FILE_PATH/a.png')

media_id = result['media_id']
wechat.messages.send_image('sip61TslXFOq134R4pc2tI9qQrk', media_id)

其他功能

# 用户是否关注公众号
wechat.cgi.subscribed?("oY98t6BQs0wbmSgcpn2lseEV9N4k")
#=> false or true

# 短连接
short_url = wechat.cgi.short_url('http://long.url')

# 临时二维码
wechat.cgi.scene_qrcode('message', expire_seconds: 9999)

# 微信回调服务器白名单
ip_array = wechat.ip_list

处理微信推送和事件回调

xml = request.body.read
result = Wechatruby::Xml.parse(xml)
result.event
#=> 'CLICK'

# 触发点击的用户openid
result.openid
# 获取点击事件绑定的值
result.get_value('EventKey')

事件文档 https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html

NameEventValues
关注公众号subscribe
扫码SCANEventKey
上报地理位置LOCATIONLatitude Longitude
菜单点击CLICKEventKey
带网址的菜单VIEWEventKey
公众号文本回复textContent
图片回复imagePicUrl MediaId
从菜单选择地址location_selectLocation_X Location_Y

微信网页开发JS-SDK

获取签名和配置

$(function(){
    $.ajax({
        method: "GET",
        url: '<%= fetch_config_url %>',
        data: { url: location.href.split('#')[0],
                apis: [ 'scanQRCode', 'getLocation', 'openLocation' ]
        }
    }).done(function( res ) {
        console.log(res)
        wx.config(res)
    });

    $("#trigger").click(function(){
        wx.scanQRCode({
            needResult: 1,
            scanType: ["qrCode","barCode"],
            success: function (res) {
                // barcode => CODE_128,xxxxx
            }
        });

    });

    $("#open-location").click(function(){
        wx.openLocation({
            latitude: 31.27850914001465, // 纬度,浮点数,范围为90 ~ -90
            longitude: 121.42569732666016, // 经度,浮点数,范围为180 ~ -18 。
            name: 'Home', // 位置名
            address: '', // 地址详情说明
            scale: 1, // 地图缩放级别 整形值 范围从1~2 。默认为最大
            infoUrl: 'www.web-site.com.cn' // 在查看位置界面底部显示的超链接 可点击跳转
        });
    });
})

访问的页面先加载好, 获取当前url, 传入需要的功能(扫码, 地图..), 异步获取签名. js-sdk 具体使用方法请查看微信文档 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

# WechatController#fetch_config
def fetch_config
  @jsapi_params = wechat.web_jsapi_params(
    params[:url],
    # Rails.env.development?,
    false,
    *params[:apis]
  )
  render json: @jsapi_params
end

微信小店

# 获取订单。
begin_time = Time.now.to_i
end_time = begin_time - 24*3600
orders = wechat.shop.orders(end_time, begin_time, :paid)

# 关闭订单。
result = wechat.shop.close_order 'ORDER_ID'

微信支付

首先设置微信支付功能, 参考: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3

# WechatController#pay
def pay
  @order = Order.find params[:id]

  # 需要预先获取用户openid
  @jsapi_params = wechat.prepay_params(
    current_user.openid,
    ip: request.ip,
    fee: @order.fee,
    redirect_url: wechat_call_back_url(id: @order.id)
  )
end

def call_back
  Order.find_by(id: params[:id], status: :waitting_pay)
  # 处理订单状态
    ...
  render xml: Wechatruby::Xml.pay_success
end
<script type="text/javascript">
 //调用微信JS api 支付
 function jsApiCall()
 {
     WeixinJSBridge.invoke(
         'getBrandWCPayRequest',
         <%= @jsapi_params.to_json.html_safe %>,
         function(res){
             WeixinJSBridge.log(res.err_msg);
             if(res.err_msg == "get_brand_wcpay_request:ok" ){
                 window.location = '<%= pay_success_url %>'
             }

         }
     );
 }

 function callpay()
 {
     if (typeof WeixinJSBridge == "undefined"){
         if( document.addEventListener ){
             document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
         }else if (document.attachEvent){
             document.attachEvent('WeixinJSBridgeReady', jsApiCall);
             document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
         }
     }else{
         jsApiCall();
     }
 }
</script>

<%=link_to  支付#{@order.fee 元", '#', onclick: "callpay()", class: 'btn btn-info'%>

License

The gem is available as open source under the terms of the MITLicense.

Code of Conduct

Everyone interacting in the Wechatruby project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the https://github.com/zhongsheng/wechatruby/blob/master/CODE_OF_CONDUCT.md

Wechatruby.session(code) return a hash object contain

字段类型说明
openidstring用户唯一标识
session_keystring会话密钥
unionidstring用户在开放平台的唯一标识符,
errcodenumber错误码
errMsgstring错误信息

Wechatruby.decrypt encryptedData, return a hash object

{
  "openId": "OPENID",
 "nickName": "NICKNAME",
 "gender": GENDER,
 "city": "CITY",
 "province": "PROVINCE",
 "country": "COUNTRY",
 "avatarUrl": "AVATARURL",
 "unionId": "UNIONID",
 "watermark": {
                "appid": "APPID",
               "timestamp": TIMESTAMP
              }
}