客户端接入文档:https://docs.qq.com/doc/DYkRQZHBrckhRbXhk
大厅启动游戏,会传命令行参数给程序,如果参数不正确,需要关闭游戏。
部分代码如下:
变量声明:
protected string[] argsName = { "id", "key", "pfkey", "port" }; protected Dictionary<string, string> _kQQHallArgsDic = new Dictionary<string, string>();
id为openid,key为openkey。
protected void ParseCommondLine() { _kQQHallArgsDic.Clear(); var args = Environment.GetCommandLineArgs(); for (int i = 0; i < args.Length; i++) { var item = args[i]; if (string.IsNullOrEmpty(item)) { continue; } bool isFind = false; string tempKey = string.Empty; string tempValue = string.Empty; for (int j = 0; j < argsName.Length; j++) { var itemArgsName = argsName[j]; if (string.IsNullOrEmpty(itemArgsName)) { continue; } if (item.StartsWith(itemArgsName + "=") && item.Length > itemArgsName.Length + 1) { isFind = true; tempKey = itemArgsName; tempValue = item.Substring(itemArgsName.Length + 1); break; } } if (!isFind) { continue; } if (!_kQQHallArgsDic.ContainsKey(tempKey)) { _kQQHallArgsDic.Add(tempKey, tempValue); } else { _kQQHallArgsDic[tempKey] = tempValue; } } }
获取大厅传过来的参数:
protected bool CheckOrGetArgs(string key, out string value) { value = string.Empty; if (!_kQQHallArgsDic.ContainsKey(key)) { return false; } value = _kQQHallArgsDic[key]; return true; }
如果参数不正确,都要关闭游戏。
登录和支付都是和本地的QQ游戏大厅进行通信,使用的是websocket。
url组合方式:
_kWebURL = string.Format("ws://localhost:{0}/websocket/{1}", _kPort, _kId);
_kPort:大厅传过来的端口参数。
_kId:大厅传过来的id,即openid。
websocket使用了BestHTTP插件。
登录使用的是openid来标识玩家。
先向米大师发送拉取订单,使用的是GET请求。
订单拉取成功后,通过websocket向大厅发送支付消息。
注意事项:
由于支付回调中并没有透传参数,所以游戏内的订单通过的是payitem来组合传递。
由于支付回调中发货完后,需要通知发货完毕。所以在拉取游戏中的订单的时候,注意将openkey传上去存储起来。
部分代码如下:
//向米大师获取请求充值的参数 protected void RequestPayInfo(string serverID, string serverName, string gameUserLevel, string charid, string playerName, string price, string orderid, string productid, string productName, string productDescription, Action<JsonData> callback) { int amt = 0; amt = (int)Convert.ToDouble(price); amt = amt * 10;//Q点为单位 var goodsMeta = string.Format("{0}*{1}", productName, productDescription); ; var goodsURL = string.Empty; var payItem = string.Format("{0}_{1}*{2}*1", productid, orderid, amt); var pf = "qqgame"; var ts = QQHallUltility.GetTimestamps().ToString(); Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("amt", amt.ToString()); dic.Add("appid", AppId.ToString()); dic.Add("appmode", "1"); dic.Add("format", "json"); dic.Add("goodsmeta", goodsMeta); dic.Add("goodsurl", goodsURL); dic.Add("openid", _kId); dic.Add("openkey", _kKey); dic.Add("payitem", payItem); dic.Add("pf", pf); dic.Add("pfkey", _kPfKey); dic.Add("ts", ts); dic.Add("zoneid", ZoneId); //对dic的key进行字典排序 List<string> keyList = new List<string>(); foreach (var item in dic) { keyList.Add(item.Key); } keyList.Sort((x, y) => { return x.CompareTo(y); }); StringBuilder sbOri = new StringBuilder(); StringBuilder sbURLEncode = new StringBuilder(); for (int i = 0; i < keyList.Count; i++) { var tempKey = keyList[i]; if (i>0) { sbOri.Append('&'); sbURLEncode.Append('&'); } sbOri.Append(tempKey + "=" + dic[tempKey]); sbURLEncode.Append(tempKey + "=" + QQHallUltility.URLEncode(dic[tempKey])); } var sig = QQHallUltility.GenerateSig("/v3/pay/buy_goods", sbOri.ToString(), AppKey, QQHallUltility.GET); StringBuilder sb2 = new StringBuilder(); sb2.Append(_kBUY_GOODS_URL); sb2.Append('?'); sb2.Append(sbURLEncode.ToString()); sb2.Append("&sig="); sb2.Append(QQHallUltility.URLEncode(sig)); string url = sb2.ToString(); StartCoroutine(IE_SendGET(url, callback)); }
需要注意签名时的编码问题。
部分源码如下:
/// <summary> /// 生成签名 /// </summary> /// <returns></returns> public static string GenerateSig(string uri, string param, string appKey,string httpMethodType) { StringBuilder sb = new StringBuilder(); sb.Append(httpMethodType); sb.Append('&'); sb.Append(URLEncode(uri)); sb.Append('&'); sb.Append(URLEncode(param)); appKey = appKey + "&"; var cipherText = HMACSHA1_Base64Crypt(sb.ToString(), appKey); return cipherText; } //将字符串按照QQ官方提供的【腾讯开放平台第三方应用签名参数sig的说明】进行URL编码 public static string URLEncode(string data) { StringBuilder sb = new StringBuilder(); byte[] byStr = System.Text.Encoding.UTF8.GetBytes(data); for (int i = 0; i < byStr.Length; i++) { if (!CheckCanEncode(byStr[i])) { sb.Append((char)byStr[i]); continue; } sb.Append("%" + Convert.ToString(byStr[i], 16).ToUpper()); } return sb.ToString(); } static bool CheckCanEncode(int byteNumber) { char item = (char)byteNumber; if (item == '-' || item == '_' || item == '.') { return false; } //数字 if (item >= '0' && item <= '9') { return false; } if (item >= 'a' && item <= 'z') { return false; } if (item >= 'A' && item <= 'Z') { return false; } return true; } /// <summary> /// HMAC-SHA1+Base64加密字符串 /// </summary> /// <param name="text"></param> /// <param name="key"></param> /// <returns></returns> static string HMACSHA1_Base64Crypt(string text, string key) { //HMACSHA1加密 HMACSHA1 hmacsha1 = new HMACSHA1(); hmacsha1.Key = System.Text.Encoding.UTF8.GetBytes(key); byte[] dataBuffer = System.Text.Encoding.UTF8.GetBytes(text); byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer); return Convert.ToBase64String(hashBytes); }
全部源码