提交 b115f927 作者: 王进

新版SDK,config文件加入域名配置,优化授权

上级 a9dcef24
/**
* 鲸鱼游戏微信小游戏接入库
* @author 推广技术部
*/
class WechatSDK {
public constructor() {
this.sdkInit()
}
private sdkInit() {
const _selt = this
_selt.ReportParams.productCode = _selt.sdkParams.product_code = SDKConfig.productCode
_selt.sdkParams.appid = SDKConfig.appid
_selt.sdkParams.version = SDKConfig.sdkVersion
const options = _selt.getOptionsInfo() // 返回参数对象
_selt.ReportParams.from = options.from || 0
_selt.ReportParams.tag = options.tag || 0
_selt.ReportParams.fromOpenId = options.fromOpenId || ''
_selt.getNetworkType()
_selt.getSystemInfo()
console.log("@@SDK初始化结束", _selt.ReportParams)
}
private async Login(LoginCallBack) {
const _selt = this
const loginPromise = await _selt._login() // 微信登录换取code
let loginPostData = _selt.deepCopy({}, _selt.sdkParams, { // 拼上appid和code
appid: SDKConfig.appid,
code: loginPromise.code
})
_selt.sdkRequest(Links.init, loginPostData).then(res => {
if (res.code == 0) {
_selt.ReportParams.openId = _selt.sdkParams.open_id = _selt.sdkParams.uniqueid = res.data.openid
_selt.sdkParams.session_key = res.data.session_key
_selt.sdkActive(LoginCallBack) // SDK激活
}
}, err => {
_selt.sdkAlert('网络异常,重连中..')
_selt.Login(LoginCallBack)
})
}
// SDK激活
private sdkActive(LoginCallBack) {
const _selt = this
console.log("@@SDK激活", _selt.sdkParams)
this.sdkRequest(Links.active, this.sdkParams).then(res => {
_selt.sdkParams.pay_channel = res.data.default_pay_channel
_selt.sdkLogin(LoginCallBack)
}, err => { console.log(err) })
}
private sdkLogin(LoginCallBack) {
const _selt = this
// 获取用户信息
_selt.sdkParams.token = '' // 强制清空登录toekn
_selt.sdkRequest(Links.login, _selt.sdkParams)
.then(res => {
if (res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
_selt.sdkParams.token = res.data.token // 记录用户toekn
_selt.ReportParams.userId = res.data.uid // 记录用户ID
_selt.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(_selt.deepCopy({}, res.data, {
os: _selt.sdkParams.os, // 返回系统类型IOS或者android
session_key: _selt.sdkParams.session_key // 返回session_key
})) // 将用户信息拼上平台用户信息返回
}
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const _selt = this
_selt.MidasPaymentParams.offerId = SDKConfig.offerid
_selt.LoadingOn();
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
_selt.sdkRequest(Links.order, _selt.deepCopy({}, _selt.sdkParams, Params)).then(res => {
console.log("@@订单返回---->", res)
if (res.code == 0) {
if (res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = _selt.deepCopy({}, _selt.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: SDKConfig.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: SDKConfig.navPayEnv, //跳转方式
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
_selt.LoadingOff();
_selt.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
_selt.MidasPaymentParams.buyQuantity = <number>(Params.money / 100) * <number>res.data.weixin_proportion // 充值金额
console.log("@@SDK -> 发起支付参数:", _selt.MidasPaymentParams);
// 调微信米大师支付接口
(wx as any).requestMidasPayment(_selt.deepCopy({}, _selt.MidasPaymentParams, {
success: function (data) {
console.log("@@SDK -> 支付成功:", data)
_selt.getCoins(_selt.deepCopy({}, _selt.sdkParams, { order_num: res.data.order_num }))
},
fail: function (err) {
console.log("SDK -> 支付失败:", err)
}
}));
_selt.LoadingOff();
} else { // 已有未完成订单,弹窗提示
_selt.LoadingOff();
const params = {
title: SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
_selt.showModal(params)
}
}
} else { // 输出订单失败消息
_selt.LoadingOff();
const errmsg = res.msg || '支付失败..'
_selt.sdkAlert(errmsg)
}
}, err => {
_selt.LoadingOff();
console.log(err)
})
}
private getCoins(orderParams) { // 通知服务端扣费
console.log("@@SDK通知扣费", orderParams)
this.sdkRequest(Links.pay, orderParams).then(res => {
console.log("@@SDK -> 扣费成功:")
})
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: SDKConfig.midasPayEnv, // 米大师环境
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
//把字符串转换成json
private toJson(str: string) {
let json = {}
const jsonArr = str.split('&')
for (let i = 0; i < jsonArr.length; i++) {
const keyArr = jsonArr[i].split('=')
json[keyArr[0]] = keyArr[1] || '' // 附上key和对应的value
}
return json
}
//接口签名,直接返回完整对象
private md5_sign(obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url = "";
for (let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + SDKConfig.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
public deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 获取启动参数
public getOptionsInfo(all?) {
const _selt = this
const options = (wx as any).getLaunchOptionsSync()
console.log("@@启动参数--->", options)
if (all) return options
if (options.query && Object.keys(options.query).length > 0) {
if (options.query.scene && options.query.scene != '') { // 扫码参数
const scene = _selt.toJson(decodeURIComponent(options.query.scene))
return scene
} else return options.query // 普通url参数
} else if (options.referrerInfo && Object.keys(options.referrerInfo).length > 0 && options.referrerInfo.extraData && Object.keys(options.referrerInfo.extraData).length > 0) {
return options.referrerInfo.extraData // 小程序跳转附带参数
} else {
return 0
}
}
private async getNetworkType() {
const _selt = this
await (wx as any).getNetworkType({
success: (res) => {
_selt.ReportParams.networkType = res.networkType
},
fail: (err) => {
console.log("@@SDK错误->getNetworkType", err)
}
})
}
private async getSystemInfo() {
const _selt = this
await (wx as any).getSystemInfo({
success: (res) => {
_selt.ReportParams.model = _selt.sdkParams.equipmentname = res.model
_selt.ReportParams.screenWidth = res.screenWidth
_selt.ReportParams.screenHeight = res.screenHeight
_selt.ReportParams.language = res.language
_selt.ReportParams.system = _selt.sdkParams.equipmentos = res.system
_selt.ReportParams.version = res.version
_selt.ReportParams.SDKVersion = res.SDKVersion
_selt.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}
})
}
private _login(): Promise<any> {
return new Promise((resolve, reject) => {
try {
(wx as any).login({
success: (res) => {
if (res.code) {
resolve(res);
} else {
reject("执行wx.login返回成功,但无code参数");
}
},
fail: () => {
reject("执行wx.login返回失败");
},
complete: (res) => {
console.log("@@SDK执行登录,微信返回数据:", res);
}
});
} catch (err) { }
});
}
// 退出小游戏
public async exitApp(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).exitMiniProgram({
success: (res) => {
console.log('退出成功')
resolve(res)
},
fail: (res) => {
console.log('退出失败')
reject(res)
}
})
})
}
// SDK上报接口
private sdkRequest(link: string, portData) {
this.md5_sign(portData) // 附上签名参数
console.log("##SDK激活上报参数", portData)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData(portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
console.log("##SDK统计上报参数", portData)
this.request(SDKConfig.report, portData, 'POST')
}
// 调用微信请求接口
private request(URI: string, Params: any, Method = 'GET') {
return this.fetchUri(URI, Params, Method).then(res => res.data)
}
private fetchUri(URI, DATA, METHOD): Promise<any> {
return new Promise((resolve, reject) => {
try {
(wx as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
} catch (err) {
reject(err)
}
})
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
private showMsg(str) {
(wx as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
// 客服
public Customer() {
try {
(wx as any).openCustomerServiceConversation({})
} catch (err) {
console.log("访问客服异常-->", err)
}
}
private navigateToMiniProgram(params) {
if (this.ReportParams.SDKVersion < '2.2') {
this.sdkAlert('微信版本不兼容,请升级..')
} else {
(wx as any).navigateToMiniProgram(params)
}
}
private LoadingOn() {
(wx as any).showLoading({
title: '请稍候..',
mask: true
})
}
private LoadingOff() {
(wx as any).hideLoading()
}
private showModal(DATA) {
(wx as any).showModal(this.deepCopy({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
// 定义wechat方法
public async getUserInfo(): Promise<any> {
const _selt = this
return new Promise(async function (resolve, reject) {
let status = await _selt._getSetting();
switch (status) {
case 1:
// 用户已授权,可以直接调用相关 API
var userInfo = await _selt._getUserInfo();
// 上报用户授权
_selt.ReportData(_selt.deepCopy({}, userInfo, {
action: 'authorize',
nickName: encodeURI(userInfo.nickName)
}))
resolve(userInfo);
break;
case 0:
// 用户已拒绝授权,再调用相关 API 或者 wx.authorize 会失败,需要引导用户到设置页面打开授权开关
var w = (wx as any).getSystemInfoSync().windowWidth;
var h = (wx as any).getSystemInfoSync().windowHeight;
var OpenSettingButton = (wx as any).createOpenSettingButton({
type: "text",
text: "",
style: {
left: 0,
top: 0,
width: w,
height: h
}
});
OpenSettingButton.onTap(async function (res) {
let t_status = await _selt._getSetting();
console.log("@@SDK:点击设置按钮返回t_status=", t_status);
if (t_status == 1) {
OpenSettingButton.offTap(this);
OpenSettingButton.destroy();
OpenSettingButton = null;
var userInfo = await _selt._getUserInfo();
// 上报用户授权
_selt.ReportData(_selt.deepCopy({}, userInfo, {
action: 'authorize',
nickName: encodeURI(userInfo.nickName)
}))
resolve(userInfo);
}
});
break;
case -1:
// 未询问过用户授权,调用相关 API 或者 wx.authorize 会弹窗询问用户
var w = (wx as any).getSystemInfoSync().windowWidth;
var h = (wx as any).getSystemInfoSync().windowHeight;
let userBtn = (wx as any).createUserInfoButton({
type: "text",
text: "",
withCredentials: false,
style: {
left: 0,
top: 0,
width: w,
height: h
},
});
userBtn.onTap(
function (res) {
if (res.userInfo) {
//上报授权
userBtn.offTap(this);
userBtn.destroy();
userBtn = null;
var userInfo = res["userInfo"];
// 上报用户授权
_selt.ReportData(_selt.deepCopy({}, userInfo, {
action: 'authorize',
nickName: encodeURI(userInfo.nickName)
}))
resolve(userInfo);
}
}
);
break;
}
})
}
private async _getUserInfo(): Promise<any> {
var thisObj = this;
return new Promise(async function (resolve, reject) {
(wx as any).getUserInfo({
withCredentials: false,//获取用户信息,withCredentials 为 true 时需要先调用 wx.login 接口。需要用户授权 scope.userInfo。
success: (res) => {
var userInfo = res["userInfo"];
resolve(userInfo);
},
fail: (res: any) => {
console.log("@@SDK:玩家头像等数据失败,用户未授权");
reject();
}
});
});
}
/**
* 检查授权配置
*/
private async _getSetting(): Promise<any> {
return new Promise(async function (resolve, reject) {
(wx as any).getSetting({
success: function (res) {
var authSetting = res.authSetting;
if (authSetting['scope.userInfo'] === true) {
resolve(1);
}
else if (authSetting['scope.userInfo'] === false) {
resolve(0);
}
else {
resolve(-1);
}
},
fail: function () {
reject();
},
complete: function () { }
});
});
}
private async share(DATA): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
try {
(wx as any).shareAppMessage(that.deepCopy(DATA, {
withShareTicket: true,
success: res => {
resolve(res)
},
fail: res => {
reject(res)
},
complete() { }
}))
} catch (err) {
reject(err)
}
})
}
private shareInit() {
(wx as any).showShareMenu({
withShareTicket: 'true',
success: () => { },
fail: () => { },
complete: () => { }
})
}
// 分享
public addShareEvent(CALLBACK, DATA?: string) {
const that = this;
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + DATA ? DATA : ''
};
(wx as any).onShareAppMessage(() => {
return that.deepCopy(ShareParams, CALLBACK)
})
that.shareInit()
}
public ShareApp(params?: string) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + (params ? params : '')
}
return this.share(ShareParams)
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
SDKVersion: null, // 选填,微信客户端基础库版本
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame', // 客户端类型
session_key: '' // 用户session_key
}
}
// SDK后端接口(勿改)
const Links = {
init: SDKConfig.sdk_domain + '/weixin/access_token.php', // 获取openid
active: SDKConfig.sdk_domain + '/appInit.php', // SDK初始化接口
login: SDKConfig.sdk_domain + '/login.php', // SDK登录接口,获取用户平台信息
order: SDKConfig.pay_domain + '/pay.php', //订单接口
pay: SDKConfig.pay_domain + '/notify/midas/pay.php' //扣费接口
}
// md5加密
const rotateLeft = (lValue, iShiftBits) => { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)) }; var addUnsigned = function (lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 2147483648); lY8 = (lY & 2147483648); lX4 = (lX & 1073741824); lY4 = (lY & 1073741824); lResult = (lX & 1073741823) + (lY & 1073741823); if (lX4 & lY4) { return (lResult ^ 2147483648 ^ lX8 ^ lY8) } if (lX4 | lY4) { if (lResult & 1073741824) { return (lResult ^ 3221225472 ^ lX8 ^ lY8) } else { return (lResult ^ 1073741824 ^ lX8 ^ lY8) } } else { return (lResult ^ lX8 ^ lY8) } }; var F = function (x, y, z) { return (x & y) | ((~x) & z) }; var G = function (x, y, z) { return (x & z) | (y & (~z)) }; var H = function (x, y, z) { return (x ^ y ^ z) }; var I = function (x, y, z) { return (y ^ (x | (~z))) }; var FF = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var GG = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var HH = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var II = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var convertToWordArray = function (string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWordsTempOne = lMessageLength + 8; var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64; var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++ } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (128 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray }; var wordToHex = function (lValue) { var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValueTemp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2) } return WordToHexValue }; var uTF8Encode = function (string) { string = string.replace(/\x0d\x0a/g, "\x0a"); var output = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { output += String.fromCharCode(c) } else { if ((c > 127) && (c < 2048)) { output += String.fromCharCode((c >> 6) | 192); output += String.fromCharCode((c & 63) | 128) } else { output += String.fromCharCode((c >> 12) | 224); output += String.fromCharCode(((c >> 6) & 63) | 128); output += String.fromCharCode((c & 63) | 128) } } } return output }; function md5(string) { var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = uTF8Encode(string); x = convertToWordArray(string); a = 1732584193; b = 4023233417; c = 2562383102; d = 271733878; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 3614090360); d = FF(d, a, b, c, x[k + 1], S12, 3905402710); c = FF(c, d, a, b, x[k + 2], S13, 606105819); b = FF(b, c, d, a, x[k + 3], S14, 3250441966); a = FF(a, b, c, d, x[k + 4], S11, 4118548399); d = FF(d, a, b, c, x[k + 5], S12, 1200080426); c = FF(c, d, a, b, x[k + 6], S13, 2821735955); b = FF(b, c, d, a, x[k + 7], S14, 4249261313); a = FF(a, b, c, d, x[k + 8], S11, 1770035416); d = FF(d, a, b, c, x[k + 9], S12, 2336552879); c = FF(c, d, a, b, x[k + 10], S13, 4294925233); b = FF(b, c, d, a, x[k + 11], S14, 2304563134); a = FF(a, b, c, d, x[k + 12], S11, 1804603682); d = FF(d, a, b, c, x[k + 13], S12, 4254626195); c = FF(c, d, a, b, x[k + 14], S13, 2792965006); b = FF(b, c, d, a, x[k + 15], S14, 1236535329); a = GG(a, b, c, d, x[k + 1], S21, 4129170786); d = GG(d, a, b, c, x[k + 6], S22, 3225465664); c = GG(c, d, a, b, x[k + 11], S23, 643717713); b = GG(b, c, d, a, x[k + 0], S24, 3921069994); a = GG(a, b, c, d, x[k + 5], S21, 3593408605); d = GG(d, a, b, c, x[k + 10], S22, 38016083); c = GG(c, d, a, b, x[k + 15], S23, 3634488961); b = GG(b, c, d, a, x[k + 4], S24, 3889429448); a = GG(a, b, c, d, x[k + 9], S21, 568446438); d = GG(d, a, b, c, x[k + 14], S22, 3275163606); c = GG(c, d, a, b, x[k + 3], S23, 4107603335); b = GG(b, c, d, a, x[k + 8], S24, 1163531501); a = GG(a, b, c, d, x[k + 13], S21, 2850285829); d = GG(d, a, b, c, x[k + 2], S22, 4243563512); c = GG(c, d, a, b, x[k + 7], S23, 1735328473); b = GG(b, c, d, a, x[k + 12], S24, 2368359562); a = HH(a, b, c, d, x[k + 5], S31, 4294588738); d = HH(d, a, b, c, x[k + 8], S32, 2272392833); c = HH(c, d, a, b, x[k + 11], S33, 1839030562); b = HH(b, c, d, a, x[k + 14], S34, 4259657740); a = HH(a, b, c, d, x[k + 1], S31, 2763975236); d = HH(d, a, b, c, x[k + 4], S32, 1272893353); c = HH(c, d, a, b, x[k + 7], S33, 4139469664); b = HH(b, c, d, a, x[k + 10], S34, 3200236656); a = HH(a, b, c, d, x[k + 13], S31, 681279174); d = HH(d, a, b, c, x[k + 0], S32, 3936430074); c = HH(c, d, a, b, x[k + 3], S33, 3572445317); b = HH(b, c, d, a, x[k + 6], S34, 76029189); a = HH(a, b, c, d, x[k + 9], S31, 3654602809); d = HH(d, a, b, c, x[k + 12], S32, 3873151461); c = HH(c, d, a, b, x[k + 15], S33, 530742520); b = HH(b, c, d, a, x[k + 2], S34, 3299628645); a = II(a, b, c, d, x[k + 0], S41, 4096336452); d = II(d, a, b, c, x[k + 7], S42, 1126891415); c = II(c, d, a, b, x[k + 14], S43, 2878612391); b = II(b, c, d, a, x[k + 5], S44, 4237533241); a = II(a, b, c, d, x[k + 12], S41, 1700485571); d = II(d, a, b, c, x[k + 3], S42, 2399980690); c = II(c, d, a, b, x[k + 10], S43, 4293915773); b = II(b, c, d, a, x[k + 1], S44, 2240044497); a = II(a, b, c, d, x[k + 8], S41, 1873313359); d = II(d, a, b, c, x[k + 15], S42, 4264355552); c = II(c, d, a, b, x[k + 6], S43, 2734768916); b = II(b, c, d, a, x[k + 13], S44, 1309151649); a = II(a, b, c, d, x[k + 4], S41, 4149444226); d = II(d, a, b, c, x[k + 11], S42, 3174756917); c = II(c, d, a, b, x[k + 2], S43, 718787259); b = II(b, c, d, a, x[k + 9], S44, 3951481745); a = addUnsigned(a, AA); b = addUnsigned(b, BB); c = addUnsigned(c, CC); d = addUnsigned(d, DD) } var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); return tempValue.toLowerCase() };
\ No newline at end of file
const SDKConfig = {
const SDKConfig = {
const SDKConfig = {
// 配置项目参数
const SDKConfig = {
// 配置项目参数
sdk_domain: 'https://account.jinsdk.com', // SDK上报的接口域名
pay_domain: 'https://pay.jinsdk.com', // 支付接口域名
report: 'https://s.jinsdk.com/weixinmp/api.php', // 数据上报接口域名
appid: "wx953104af9b9484c8", // 换openid
appName: "推广部测试应用", // 应用名称
......@@ -21,5 +27,5 @@
shareTitle: "鲸鱼推广部", // 分享标题
shareImageUrl: "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3903587193,374462562&fm=27&gp=0.jpg" //分享图片链接
// 结束
// 结束
}
\ No newline at end of file
const Config = {
++ /dev/null
const Config = {
// 配置项目参数
appid: "wx8ccb2ef82e44df92", // 换openid
appName: "测试应用", // 应用名称
productCode: "b5488a667a66561aa97ce2a70137487e", // 产品code
productKey: "d0e3e7998c6b3b47dd9e42c3769edd2c", // 产品key,用于生成签名
appVersion: "产品版本号(cp)", // 产品版本号
offerid: "1450016203", // 支付
sdkVersion: "1.0.0", // SDK版本号,SDK接口需要
shareTitle: "鲸鱼游戏棒棒棒", // 分享标题
shareImageUrl: "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3903587193,374462562&fm=27&gp=0.jpg" //分享图片链接
// 结束
}
\ No newline at end of file
/**
++ /dev/null
/**
* 平台数据接口。
* 由于每款游戏通常需要发布到多个平台上,所以提取出一个统一的接口用于开发者获取平台数据信息
* 推荐开发者通过这种方式封装平台逻辑,以保证整体结构的稳定
* 由于不同平台的接口形式各有不同,白鹭推荐开发者将所有接口封装为基于 Promise 的异步形式
*/
declare interface Platform {
getUserInfo(): Promise<any>;
login(): Promise<any>
getNetworkType(): Promise<any>
getSystemInfo(): Promise<any>
onShow(): Promise<any>
request(uri, data, method): Promise<any>
showModal(obj): Promise<any>
share(obj): Promise<any>
pay(params): Promise<any>
shareInit(): Promise<any>
addShareEvent(params): Promise<any>
customer(params): Promise<any>
navigateToMiniProgram(params): Promise<any>
showToast(params): Promise<any>
showMsg(str): Promise<any>
exitWechatApp(): Promise<any>
getLaunchOptionsSync(): Promise<any>
}
class DebugPlatform implements Platform {
async getUserInfo() {}
async login() {}
async getNetworkType(){}
async getSystemInfo(){}
async onShow() {}
async request(uri, data, method){}
async showModal(obj) {}
async share(obj) {}
async pay(params) {}
async shareInit() {}
async addShareEvent(params) {}
async customer(params) {}
async navigateToMiniProgram(params) {}
async showToast(params) {}
async showMsg(str) {}
async exitWechatApp() {}
async getLaunchOptionsSync() {}
}
if (!window.platform) {
window.platform = new DebugPlatform();
}
declare let platform: Platform;
declare interface Window {
platform: Platform
}
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?){
this.printf("SDK START...", 0)
this.debug = config&&config.debug? config.debug : 0
this.sdkinit()
}
private debug:number // 1是测试模式,用于printf函数输出
private sdkinit() {
const that = this
platform.shareInit()
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = Config.productCode
that.sdkParams.appid = Config.appid
that.sdkParams.version = Config.sdkVersion
const p1 = platform.getLaunchOptionsSync().then(res => {
let queryObj = res.referrerInfo && res.referrerInfo.extraData && Object.keys(res.referrerInfo.extraData).length > 0 ? res.referrerInfo.extraData : {}
res = that.deepCopy({}, res.query, queryObj)
that.printf("SDK -> p1:", 0)
that.printf(res, 0)
that.ReportParams.from = res.from || ''
that.ReportParams.tag = res.tag || ''
that.ReportParams.fromOpenId = res.fromId || ''
}, err => { console.log(err) })
const p2 = platform.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = platform.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p1, p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}, err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId () {
const that = this
platform.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: Config.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkActive() // SDK激活
const ShareParams = {
title: Config.shareTitle,
imageUrl: Config.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0'
}
// 监听右上角的分享按钮
platform.addShareEvent(ShareParams)
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val:number = 0
if( this.obj.initReady == 1) { // 已经激活成功
that.doLogin(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady',{
enumerable:true,
configurable:true,
get:function getter() { return val; },
set:function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if(newVal===val){ return; }
that.doLogin(LoginCallBack)
}
})
}
}
private doLogin(LoginCallBack) {
const that = this
// 用户授权
platform.getUserInfo().then(res => {
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if(res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, userInfo, {
os: (that.ReportParams.system).split(' ')[0] // 返回系统类型IOS或者android
})) // 将用户信息拼上平台用户信息返回
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = Config.offerid
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
if (res.code == 0) {
if(res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: Config.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
platform.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money/100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0)
// 调微信米大师支付接口
platform.pay(that.MidasPaymentParams)
.then(() => { // 支付成功
this.printf("SDK -> 支付成功:", 0)
this.printf(res, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
}, err => { // 支付失败
this.printf("SDK -> 支付失败:", 0)
this.printf(err, 0)
})
} else { // 已有未完成订单,弹窗提示
const params = {
title: Config.shareTitle,
content: '订单发货中,请稍候下单..'
}
platform.showModal(params)
}
}
} else { // 继续未完成订单
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}
private getCoins(orderParams) { // 通知服务端扣费
this.sdkRequest(sdkPortLinks.order, orderParams).then(res => {})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
platform.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
platform.showMsg(str)
}
// 获取分享参数
public getShareParams() {
return platform.getLaunchOptionsSync()
}
// 分享
public ShareApp(params?) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: Config.shareTitle,
imageUrl: Config.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&'+params
}
return platform.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return platform.exitWechatApp()
}
// SDK上报接口
private sdkRequest (link:string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData (portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI:string, Params:any, Method = 'GET') {
return platform.request(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
public printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level){
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
platform.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign (obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url="";
for(let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + Config.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
private deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame' // 客户端类型
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: '1', // 米大师环境配置, 0:正式环境, 1:沙盒模式
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
}
// md5加密
const rotateLeft = (lValue,iShiftBits) => {return(lValue<<iShiftBits)|(lValue>>>(32-iShiftBits))};var addUnsigned=function(lX,lY){var lX4,lY4,lX8,lY8,lResult;lX8=(lX&2147483648);lY8=(lY&2147483648);lX4=(lX&1073741824);lY4=(lY&1073741824);lResult=(lX&1073741823)+(lY&1073741823);if(lX4&lY4){return(lResult^2147483648^lX8^lY8)}if(lX4|lY4){if(lResult&1073741824){return(lResult^3221225472^lX8^lY8)}else{return(lResult^1073741824^lX8^lY8)}}else{return(lResult^lX8^lY8)}};var F=function(x,y,z){return(x&y)|((~x)&z)};var G=function(x,y,z){return(x&z)|(y&(~z))};var H=function(x,y,z){return(x^y^z)};var I=function(x,y,z){return(y^(x|(~z)))};var FF=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(F(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var GG=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(G(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var HH=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(H(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var II=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(I(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var convertToWordArray=function(string){var lWordCount;var lMessageLength=string.length;var lNumberOfWordsTempOne=lMessageLength+8;var lNumberOfWordsTempTwo=(lNumberOfWordsTempOne-(lNumberOfWordsTempOne%64))/64;var lNumberOfWords=(lNumberOfWordsTempTwo+1)*16;var lWordArray=Array(lNumberOfWords-1);var lBytePosition=0;var lByteCount=0;while(lByteCount<lMessageLength){lWordCount=(lByteCount-(lByteCount%4))/4;lBytePosition=(lByteCount%4)*8;lWordArray[lWordCount]=(lWordArray[lWordCount]|(string.charCodeAt(lByteCount)<<lBytePosition));lByteCount++}lWordCount=(lByteCount-(lByteCount%4))/4;lBytePosition=(lByteCount%4)*8;lWordArray[lWordCount]=lWordArray[lWordCount]|(128<<lBytePosition);lWordArray[lNumberOfWords-2]=lMessageLength<<3;lWordArray[lNumberOfWords-1]=lMessageLength>>>29;return lWordArray};var wordToHex=function(lValue){var WordToHexValue="",WordToHexValueTemp="",lByte,lCount;for(lCount=0;lCount<=3;lCount++){lByte=(lValue>>>(lCount*8))&255;WordToHexValueTemp="0"+lByte.toString(16);WordToHexValue=WordToHexValue+WordToHexValueTemp.substr(WordToHexValueTemp.length-2,2)}return WordToHexValue};var uTF8Encode=function(string){string=string.replace(/\x0d\x0a/g,"\x0a");var output="";for(var n=0;n<string.length;n++){var c=string.charCodeAt(n);if(c<128){output+=String.fromCharCode(c)}else{if((c>127)&&(c<2048)){output+=String.fromCharCode((c>>6)|192);output+=String.fromCharCode((c&63)|128)}else{output+=String.fromCharCode((c>>12)|224);output+=String.fromCharCode(((c>>6)&63)|128);output+=String.fromCharCode((c&63)|128)}}}return output};function md5(string){var x=Array();var k,AA,BB,CC,DD,a,b,c,d;var S11=7,S12=12,S13=17,S14=22;var S21=5,S22=9,S23=14,S24=20;var S31=4,S32=11,S33=16,S34=23;var S41=6,S42=10,S43=15,S44=21;string=uTF8Encode(string);x=convertToWordArray(string);a=1732584193;b=4023233417;c=2562383102;d=271733878;for(k=0;k<x.length;k+=16){AA=a;BB=b;CC=c;DD=d;a=FF(a,b,c,d,x[k+0],S11,3614090360);d=FF(d,a,b,c,x[k+1],S12,3905402710);c=FF(c,d,a,b,x[k+2],S13,606105819);b=FF(b,c,d,a,x[k+3],S14,3250441966);a=FF(a,b,c,d,x[k+4],S11,4118548399);d=FF(d,a,b,c,x[k+5],S12,1200080426);c=FF(c,d,a,b,x[k+6],S13,2821735955);b=FF(b,c,d,a,x[k+7],S14,4249261313);a=FF(a,b,c,d,x[k+8],S11,1770035416);d=FF(d,a,b,c,x[k+9],S12,2336552879);c=FF(c,d,a,b,x[k+10],S13,4294925233);b=FF(b,c,d,a,x[k+11],S14,2304563134);a=FF(a,b,c,d,x[k+12],S11,1804603682);d=FF(d,a,b,c,x[k+13],S12,4254626195);c=FF(c,d,a,b,x[k+14],S13,2792965006);b=FF(b,c,d,a,x[k+15],S14,1236535329);a=GG(a,b,c,d,x[k+1],S21,4129170786);d=GG(d,a,b,c,x[k+6],S22,3225465664);c=GG(c,d,a,b,x[k+11],S23,643717713);b=GG(b,c,d,a,x[k+0],S24,3921069994);a=GG(a,b,c,d,x[k+5],S21,3593408605);d=GG(d,a,b,c,x[k+10],S22,38016083);c=GG(c,d,a,b,x[k+15],S23,3634488961);b=GG(b,c,d,a,x[k+4],S24,3889429448);a=GG(a,b,c,d,x[k+9],S21,568446438);d=GG(d,a,b,c,x[k+14],S22,3275163606);c=GG(c,d,a,b,x[k+3],S23,4107603335);b=GG(b,c,d,a,x[k+8],S24,1163531501);a=GG(a,b,c,d,x[k+13],S21,2850285829);d=GG(d,a,b,c,x[k+2],S22,4243563512);c=GG(c,d,a,b,x[k+7],S23,1735328473);b=GG(b,c,d,a,x[k+12],S24,2368359562);a=HH(a,b,c,d,x[k+5],S31,4294588738);d=HH(d,a,b,c,x[k+8],S32,2272392833);c=HH(c,d,a,b,x[k+11],S33,1839030562);b=HH(b,c,d,a,x[k+14],S34,4259657740);a=HH(a,b,c,d,x[k+1],S31,2763975236);d=HH(d,a,b,c,x[k+4],S32,1272893353);c=HH(c,d,a,b,x[k+7],S33,4139469664);b=HH(b,c,d,a,x[k+10],S34,3200236656);a=HH(a,b,c,d,x[k+13],S31,681279174);d=HH(d,a,b,c,x[k+0],S32,3936430074);c=HH(c,d,a,b,x[k+3],S33,3572445317);b=HH(b,c,d,a,x[k+6],S34,76029189);a=HH(a,b,c,d,x[k+9],S31,3654602809);d=HH(d,a,b,c,x[k+12],S32,3873151461);c=HH(c,d,a,b,x[k+15],S33,530742520);b=HH(b,c,d,a,x[k+2],S34,3299628645);a=II(a,b,c,d,x[k+0],S41,4096336452);d=II(d,a,b,c,x[k+7],S42,1126891415);c=II(c,d,a,b,x[k+14],S43,2878612391);b=II(b,c,d,a,x[k+5],S44,4237533241);a=II(a,b,c,d,x[k+12],S41,1700485571);d=II(d,a,b,c,x[k+3],S42,2399980690);c=II(c,d,a,b,x[k+10],S43,4293915773);b=II(b,c,d,a,x[k+1],S44,2240044497);a=II(a,b,c,d,x[k+8],S41,1873313359);d=II(d,a,b,c,x[k+15],S42,4264355552);c=II(c,d,a,b,x[k+6],S43,2734768916);b=II(b,c,d,a,x[k+13],S44,1309151649);a=II(a,b,c,d,x[k+4],S41,4149444226);d=II(d,a,b,c,x[k+11],S42,3174756917);c=II(c,d,a,b,x[k+2],S43,718787259);b=II(b,c,d,a,x[k+9],S44,3951481745);a=addUnsigned(a,AA);b=addUnsigned(b,BB);c=addUnsigned(c,CC);d=addUnsigned(d,DD)}var tempValue=wordToHex(a)+wordToHex(b)+wordToHex(c)+wordToHex(d);return tempValue.toLowerCase()};
\ No newline at end of file
/**
++ /dev/null
/**
* 请在白鹭引擎的Main.ts中调用 platform.login() 方法调用至此处。
*/
class WxgamePlatform {
name = 'wxgame'
login() {
return new Promise((resolve, reject) => {
wx.login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
getUserInfo() {
return new Promise((resolve, reject) => {
wx.getUserInfo({
withCredentials: true,
success: function(res) {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
onShow() {
return new Promise((resolve, reject) => {
wx.onShow(res => {
const exParams = res.referrerInfo && res.referrerInfo.extraData && Object.keys(res.referrerInfo.extraData).length > 0 ? res.referrerInfo.extraData : {}
// url参数
resolve(Object.assign({}, res.query, exParams))
})
}).catch((error) => {
console.error(error);
})
}
getSystemInfo() {
return new Promise((resolve, reject) => {
wx.getSystemInfo({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
getNetworkType() {
return new Promise((resolve, reject) => {
wx.getNetworkType({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
request(URI, DATA, METHOD) {
return new Promise((resolve, reject) => {
wx.request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
}).catch((error) => {
reject(error)
})
}
showModal(DATA) {
wx.showModal(Object.assign({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
showMsg(str) {
wx.showToast({
title: str,
duration: 1500
})
}
share(DATA) {
return new Promise((resolve, reject) => {
wx.shareAppMessage(Object.assign(DATA, {
success: function(res) {
resolve(res)
},
fail: function(res) {
reject(res)
},
complete() {}
}))
})
}
shareInit() {
wx.showShareMenu({
withShareTicket: true,
success: () => {},
fail: () => {},
complete: () => {}
})
}
addShareEvent(DATA) {
wx.onShareAppMessage(() => {
return Object.assign(DATA, {
success: function() {},
fail: function() {},
complete() {}
})
})
}
getLaunchOptionsSync() {
return new Promise((resolve, reject) => {
const options = wx.getLaunchOptionsSync()
if (Object.keys(options.query).length > 0 || Object.keys(options.referrerInfo).length > 0) {
const obj = {}
Object.assign(obj, options.query, options.referrerInfo.extraData) // 合并数据
resolve(obj)
} else {
reject(options)
}
})
}
pay(params) {
return new Promise((resolve, reject) => {
wx.requestMidasPayment(Object.assign(params, {
success: function(res) {
resolve(res)
},
fail: function(res) {
reject(res)
},
complete: function() {
console.log("Rechare")
}
}))
})
}
customer(params) {
wx.openCustomerServiceConversation(params)
}
navigateToMiniProgram(params) {
wx.navigateToMiniProgram(params)
}
exitWechatApp() {
return new Promise((resolve, reject) => {
wx.exitMiniProgram({
success: function(res) {
console.log('退出成功')
resolve(res)
},
fail: function(res) {
console.log('退出失败')
reject(res)
}
})
})
}
openDataContext = new WxgameOpenDataContext();
}
class WxgameOpenDataContext {
createDisplayObject(type, width, height) {
const bitmapdata = new egret.BitmapData(sharedCanvas);
bitmapdata.$deleteSource = false;
const texture = new egret.Texture();
texture._setBitmapData(bitmapdata);
const bitmap = new egret.Bitmap(texture);
bitmap.width = width;
bitmap.height = height;
if (egret.Capabilities.renderMode == "webgl") {
const renderContext = egret.wxgame.WebGLRenderContext.getInstance();
const context = renderContext.context;
////需要用到最新的微信版本
////调用其接口WebGLRenderingContext.wxBindCanvasTexture(number texture, Canvas canvas)
////如果没有该接口,会进行如下处理,保证画面渲染正确,但会占用内存。
if (!context.wxBindCanvasTexture) {
egret.startTick((timeStarmp) => {
egret.WebGLUtils.deleteWebGLTexture(bitmapdata.webGLTexture);
bitmapdata.webGLTexture = null;
return false;
}, this);
}
}
return bitmap;
}
postMessage(data) {
const openDataContext = wx.getOpenDataContext();
openDataContext.postMessage(data);
}
}
window.platform = new WxgamePlatform();
\ No newline at end of file
const Config = {
++ /dev/null
const Config = {
// 配置项目参数
appid: "wx8ccb2ef82e44df92", // 换openid
appName: "测试应用", // 应用名称
productCode: "b5488a667a66561aa97ce2a70137487e", // 产品code
productKey: "d0e3e7998c6b3b47dd9e42c3769edd2c", // 产品key,用于生成签名
appVersion: "产品版本号(cp)", // 产品版本号
offerid: "1450016203", // 支付
sdkVersion: "1.0.0", // SDK版本号,SDK接口需要
shareTitle: "鲸鱼游戏棒棒棒", // 分享标题
shareImageUrl: "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3903587193,374462562&fm=27&gp=0.jpg" //分享图片链接
// 结束
}
\ No newline at end of file
/**
++ /dev/null
/**
* 平台数据接口。
* 由于每款游戏通常需要发布到多个平台上,所以提取出一个统一的接口用于开发者获取平台数据信息
* 推荐开发者通过这种方式封装平台逻辑,以保证整体结构的稳定
* 由于不同平台的接口形式各有不同,白鹭推荐开发者将所有接口封装为基于 Promise 的异步形式
*/
declare interface Platform {
getUserInfo(): Promise<any>;
login(): Promise<any>
getNetworkType(): Promise<any>
getSystemInfo(): Promise<any>
onShow(): Promise<any>
request(uri, data, method): Promise<any>
showModal(obj): Promise<any>
share(obj): Promise<any>
pay(params): Promise<any>
shareInit(): Promise<any>
addShareEvent(params): Promise<any>
customer(params): Promise<any>
navigateToMiniProgram(params): Promise<any>
showToast(params): Promise<any>
showMsg(str): Promise<any>
exitWechatApp(): Promise<any>
getLaunchOptionsSync(): Promise<any>
createUserInfoButton(): Promise<any>
}
class DebugPlatform implements Platform {
async getUserInfo() {}
async login() {}
async getNetworkType(){}
async getSystemInfo(){}
async onShow() {}
async request(uri, data, method){}
async showModal(obj) {}
async share(obj) {}
async pay(params) {}
async shareInit() {}
async addShareEvent(params) {}
async customer(params) {}
async navigateToMiniProgram(params) {}
async showToast(params) {}
async showMsg(str) {}
async exitWechatApp() {}
async getLaunchOptionsSync() {}
async createUserInfoButton() {}
}
if (!window.platform) {
window.platform = new DebugPlatform();
}
declare let platform: Platform;
declare interface Window {
platform: Platform
}
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?){
this.printf("SDK START...", 0)
this.debug = config&&config.debug? config.debug : 0
this.sdkinit()
}
private debug:number // 1是测试模式,用于printf函数输出
private userBtn:any // 用户授权按钮
private sdkinit() {
const that = this
platform.shareInit()
that.userBtn = platform.createUserInfoButton() // 创建用户授权按钮
that.userBtn.hide() // 隐藏按钮
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = Config.productCode
that.sdkParams.appid = Config.appid
that.sdkParams.version = Config.sdkVersion
const p1 = platform.getLaunchOptionsSync().then(res => {
let queryObj = res.referrerInfo && res.referrerInfo.extraData && Object.keys(res.referrerInfo.extraData).length > 0 ? res.referrerInfo.extraData : {}
res = that.deepCopy({}, res.query, queryObj)
that.printf("SDK -> p1:", 0)
that.printf(res, 0)
that.ReportParams.from = res.from || ''
that.ReportParams.tag = res.tag || ''
that.ReportParams.fromOpenId = res.fromId || ''
}, err => { console.log(err) })
const p2 = platform.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = platform.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
that.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p1, p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}, err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId () {
const that = this
platform.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: Config.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkActive() // SDK激活
const ShareParams = {
title: Config.shareTitle,
imageUrl: Config.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0'
}
// 监听右上角的分享按钮
platform.addShareEvent(ShareParams)
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val:number = 0
if( this.obj.initReady == 1) { // 已经激活成功
that.doAuthorize(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady',{
enumerable:true,
configurable:true,
get:function getter() { return val; },
set:function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if(newVal===val){ return; }
that.doAuthorize(LoginCallBack)
}
})
}
}
//用户授权操作
private doAuthorize(LoginCallBack) {
const that = this
// 用户授权
platform.getUserInfo().then(res => {
if(res) { // 用户确认授权
that.doLogin(res, LoginCallBack)
} else {
console.log('用户取消授权。。。')
that.userBtn.show() // 显示授权按钮
that.userBtn.onTap(res => {
if(res.userInfo) that.doLogin(res, LoginCallBack)
})
}
}, err => {
console.log(err)
})
}
private doLogin(res, LoginCallBack) {
const that = this
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if(res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, userInfo, {
os: (that.ReportParams.system).split(' ')[0] // 返回系统类型IOS或者android
})) // 将用户信息拼上平台用户信息返回
that.userBtn.destroy() //登录成功后摧毁按钮
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = Config.offerid
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
if (res.code == 0) {
if(res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: Config.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: 'trial', //跳转到体验版
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
platform.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money/100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0)
// 调微信米大师支付接口
platform.pay(that.MidasPaymentParams)
.then(() => { // 支付成功
this.printf("SDK -> 支付成功:", 0)
this.printf(res, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
}, err => { // 支付失败
this.printf("SDK -> 支付失败:", 0)
this.printf(err, 0)
})
} else { // 已有未完成订单,弹窗提示
const params = {
title: Config.shareTitle,
content: '订单发货中,请稍候下单..'
}
platform.showModal(params)
}
}
} else { // 输出订单失败消息
that.printf(res.msg, 1)
that.sdkAlert(res.msg)
}
}, err => { console.log(err) })
}
private getCoins(orderParams) { // 通知服务端扣费
this.printf("SDK -> 通知扣费:", 0)
this.printf(orderParams, 0)
this.sdkRequest(sdkPortLinks.pay, orderParams).then(res => {
this.printf("SDK -> 扣费成功:", 0)
})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
platform.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
platform.showMsg(str)
}
// 获取分享参数
public getShareParams() {
return platform.getLaunchOptionsSync()
}
// 分享
public ShareApp(params?) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: Config.shareTitle,
imageUrl: Config.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&'+params
}
return platform.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return platform.exitWechatApp()
}
// SDK上报接口
private sdkRequest (link:string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData (portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI:string, Params:any, Method = 'GET') {
return platform.request(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
public printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level){
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
platform.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign (obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url="";
for(let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + Config.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
private deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame' // 客户端类型
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: '1', // 米大师环境配置, 0:正式环境, 1:沙盒模式
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
}
// md5加密
const rotateLeft = (lValue,iShiftBits) => {return(lValue<<iShiftBits)|(lValue>>>(32-iShiftBits))};var addUnsigned=function(lX,lY){var lX4,lY4,lX8,lY8,lResult;lX8=(lX&2147483648);lY8=(lY&2147483648);lX4=(lX&1073741824);lY4=(lY&1073741824);lResult=(lX&1073741823)+(lY&1073741823);if(lX4&lY4){return(lResult^2147483648^lX8^lY8)}if(lX4|lY4){if(lResult&1073741824){return(lResult^3221225472^lX8^lY8)}else{return(lResult^1073741824^lX8^lY8)}}else{return(lResult^lX8^lY8)}};var F=function(x,y,z){return(x&y)|((~x)&z)};var G=function(x,y,z){return(x&z)|(y&(~z))};var H=function(x,y,z){return(x^y^z)};var I=function(x,y,z){return(y^(x|(~z)))};var FF=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(F(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var GG=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(G(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var HH=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(H(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var II=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(I(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var convertToWordArray=function(string){var lWordCount;var lMessageLength=string.length;var lNumberOfWordsTempOne=lMessageLength+8;var lNumberOfWordsTempTwo=(lNumberOfWordsTempOne-(lNumberOfWordsTempOne%64))/64;var lNumberOfWords=(lNumberOfWordsTempTwo+1)*16;var lWordArray=Array(lNumberOfWords-1);var lBytePosition=0;var lByteCount=0;while(lByteCount<lMessageLength){lWordCount=(lByteCount-(lByteCount%4))/4;lBytePosition=(lByteCount%4)*8;lWordArray[lWordCount]=(lWordArray[lWordCount]|(string.charCodeAt(lByteCount)<<lBytePosition));lByteCount++}lWordCount=(lByteCount-(lByteCount%4))/4;lBytePosition=(lByteCount%4)*8;lWordArray[lWordCount]=lWordArray[lWordCount]|(128<<lBytePosition);lWordArray[lNumberOfWords-2]=lMessageLength<<3;lWordArray[lNumberOfWords-1]=lMessageLength>>>29;return lWordArray};var wordToHex=function(lValue){var WordToHexValue="",WordToHexValueTemp="",lByte,lCount;for(lCount=0;lCount<=3;lCount++){lByte=(lValue>>>(lCount*8))&255;WordToHexValueTemp="0"+lByte.toString(16);WordToHexValue=WordToHexValue+WordToHexValueTemp.substr(WordToHexValueTemp.length-2,2)}return WordToHexValue};var uTF8Encode=function(string){string=string.replace(/\x0d\x0a/g,"\x0a");var output="";for(var n=0;n<string.length;n++){var c=string.charCodeAt(n);if(c<128){output+=String.fromCharCode(c)}else{if((c>127)&&(c<2048)){output+=String.fromCharCode((c>>6)|192);output+=String.fromCharCode((c&63)|128)}else{output+=String.fromCharCode((c>>12)|224);output+=String.fromCharCode(((c>>6)&63)|128);output+=String.fromCharCode((c&63)|128)}}}return output};function md5(string){var x=Array();var k,AA,BB,CC,DD,a,b,c,d;var S11=7,S12=12,S13=17,S14=22;var S21=5,S22=9,S23=14,S24=20;var S31=4,S32=11,S33=16,S34=23;var S41=6,S42=10,S43=15,S44=21;string=uTF8Encode(string);x=convertToWordArray(string);a=1732584193;b=4023233417;c=2562383102;d=271733878;for(k=0;k<x.length;k+=16){AA=a;BB=b;CC=c;DD=d;a=FF(a,b,c,d,x[k+0],S11,3614090360);d=FF(d,a,b,c,x[k+1],S12,3905402710);c=FF(c,d,a,b,x[k+2],S13,606105819);b=FF(b,c,d,a,x[k+3],S14,3250441966);a=FF(a,b,c,d,x[k+4],S11,4118548399);d=FF(d,a,b,c,x[k+5],S12,1200080426);c=FF(c,d,a,b,x[k+6],S13,2821735955);b=FF(b,c,d,a,x[k+7],S14,4249261313);a=FF(a,b,c,d,x[k+8],S11,1770035416);d=FF(d,a,b,c,x[k+9],S12,2336552879);c=FF(c,d,a,b,x[k+10],S13,4294925233);b=FF(b,c,d,a,x[k+11],S14,2304563134);a=FF(a,b,c,d,x[k+12],S11,1804603682);d=FF(d,a,b,c,x[k+13],S12,4254626195);c=FF(c,d,a,b,x[k+14],S13,2792965006);b=FF(b,c,d,a,x[k+15],S14,1236535329);a=GG(a,b,c,d,x[k+1],S21,4129170786);d=GG(d,a,b,c,x[k+6],S22,3225465664);c=GG(c,d,a,b,x[k+11],S23,643717713);b=GG(b,c,d,a,x[k+0],S24,3921069994);a=GG(a,b,c,d,x[k+5],S21,3593408605);d=GG(d,a,b,c,x[k+10],S22,38016083);c=GG(c,d,a,b,x[k+15],S23,3634488961);b=GG(b,c,d,a,x[k+4],S24,3889429448);a=GG(a,b,c,d,x[k+9],S21,568446438);d=GG(d,a,b,c,x[k+14],S22,3275163606);c=GG(c,d,a,b,x[k+3],S23,4107603335);b=GG(b,c,d,a,x[k+8],S24,1163531501);a=GG(a,b,c,d,x[k+13],S21,2850285829);d=GG(d,a,b,c,x[k+2],S22,4243563512);c=GG(c,d,a,b,x[k+7],S23,1735328473);b=GG(b,c,d,a,x[k+12],S24,2368359562);a=HH(a,b,c,d,x[k+5],S31,4294588738);d=HH(d,a,b,c,x[k+8],S32,2272392833);c=HH(c,d,a,b,x[k+11],S33,1839030562);b=HH(b,c,d,a,x[k+14],S34,4259657740);a=HH(a,b,c,d,x[k+1],S31,2763975236);d=HH(d,a,b,c,x[k+4],S32,1272893353);c=HH(c,d,a,b,x[k+7],S33,4139469664);b=HH(b,c,d,a,x[k+10],S34,3200236656);a=HH(a,b,c,d,x[k+13],S31,681279174);d=HH(d,a,b,c,x[k+0],S32,3936430074);c=HH(c,d,a,b,x[k+3],S33,3572445317);b=HH(b,c,d,a,x[k+6],S34,76029189);a=HH(a,b,c,d,x[k+9],S31,3654602809);d=HH(d,a,b,c,x[k+12],S32,3873151461);c=HH(c,d,a,b,x[k+15],S33,530742520);b=HH(b,c,d,a,x[k+2],S34,3299628645);a=II(a,b,c,d,x[k+0],S41,4096336452);d=II(d,a,b,c,x[k+7],S42,1126891415);c=II(c,d,a,b,x[k+14],S43,2878612391);b=II(b,c,d,a,x[k+5],S44,4237533241);a=II(a,b,c,d,x[k+12],S41,1700485571);d=II(d,a,b,c,x[k+3],S42,2399980690);c=II(c,d,a,b,x[k+10],S43,4293915773);b=II(b,c,d,a,x[k+1],S44,2240044497);a=II(a,b,c,d,x[k+8],S41,1873313359);d=II(d,a,b,c,x[k+15],S42,4264355552);c=II(c,d,a,b,x[k+6],S43,2734768916);b=II(b,c,d,a,x[k+13],S44,1309151649);a=II(a,b,c,d,x[k+4],S41,4149444226);d=II(d,a,b,c,x[k+11],S42,3174756917);c=II(c,d,a,b,x[k+2],S43,718787259);b=II(b,c,d,a,x[k+9],S44,3951481745);a=addUnsigned(a,AA);b=addUnsigned(b,BB);c=addUnsigned(c,CC);d=addUnsigned(d,DD)}var tempValue=wordToHex(a)+wordToHex(b)+wordToHex(c)+wordToHex(d);return tempValue.toLowerCase()};
\ No newline at end of file
/**
++ /dev/null
/**
* 请在白鹭引擎的Main.ts中调用 platform.login() 方法调用至此处。
*/
class WxgamePlatform {
name = 'wxgame'
login() {
return new Promise((resolve, reject) => {
wx.login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
getUserInfo() {
return new Promise((resolve, reject) => {
wx.getUserInfo({
withCredentials: true,
success: function(res) {
resolve(res);
},
fail: function(res) {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
getSystemInfo() {
return new Promise((resolve, reject) => {
wx.getSystemInfo({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
getNetworkType() {
return new Promise((resolve, reject) => {
wx.getNetworkType({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
request(URI, DATA, METHOD) {
return new Promise((resolve, reject) => {
wx.request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
}).catch((error) => {
reject(error)
})
}
showModal(DATA) {
wx.showModal(Object.assign({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
showMsg(str) {
wx.showToast({
title: str,
icon: 'none',
duration: 3000
})
}
share(DATA) {
return new Promise((resolve, reject) => {
wx.shareAppMessage(Object.assign(DATA, {
success: function(res) {
resolve(res)
},
fail: function(res) {
reject(res)
},
complete() {}
}))
})
}
shareInit() {
wx.showShareMenu({
withShareTicket: true,
success: () => {},
fail: () => {},
complete: () => {}
})
}
addShareEvent(DATA) {
wx.onShareAppMessage(() => {
return Object.assign(DATA, {
success: function() {},
fail: function() {},
complete() {}
})
})
}
getLaunchOptionsSync() {
return new Promise((resolve) => {
const options = wx.getLaunchOptionsSync()
if (Object.keys(options.query).length > 0 || Object.keys(options.referrerInfo).length > 0) {
const obj = {}
Object.assign(obj, options.query, options.referrerInfo.extraData) // 合并数据
resolve(obj)
} else {
resolve(options)
}
})
}
pay(params) {
return new Promise((resolve, reject) => {
wx.requestMidasPayment(Object.assign(params, {
success: function(res) {
resolve(res)
},
fail: function(res) {
reject(res)
},
complete: function() {
console.log("Rechare")
}
}))
})
}
customer(params) {
wx.openCustomerServiceConversation(params)
}
navigateToMiniProgram(params) {
wx.navigateToMiniProgram(params)
}
exitWechatApp() {
return new Promise((resolve, reject) => {
wx.exitMiniProgram({
success: function(res) {
console.log('退出成功')
resolve(res)
},
fail: function(res) {
console.log('退出失败')
reject(res)
}
})
})
}
createUserInfoButton() {
const UserInfoButton = wx.createUserInfoButton({
type: 'text',
text: ' ',
style: {
left: 0,
top: 0,
width: 800,
height: 1200,
backgroundColor: 'rgba(0, 0, 0, 0)',
color: '#ffffff'
}
})
return UserInfoButton
}
openDataContext = new WxgameOpenDataContext();
}
class WxgameOpenDataContext {
createDisplayObject(type, width, height) {
const bitmapdata = new egret.BitmapData(sharedCanvas);
bitmapdata.$deleteSource = false;
const texture = new egret.Texture();
texture._setBitmapData(bitmapdata);
const bitmap = new egret.Bitmap(texture);
bitmap.width = width;
bitmap.height = height;
if (egret.Capabilities.renderMode == "webgl") {
const renderContext = egret.wxgame.WebGLRenderContext.getInstance();
const context = renderContext.context;
////需要用到最新的微信版本
////调用其接口WebGLRenderingContext.wxBindCanvasTexture(number texture, Canvas canvas)
////如果没有该接口,会进行如下处理,保证画面渲染正确,但会占用内存。
if (!context.wxBindCanvasTexture) {
egret.startTick((timeStarmp) => {
egret.WebGLUtils.deleteWebGLTexture(bitmapdata.webGLTexture);
bitmapdata.webGLTexture = null;
return false;
}, this);
}
}
return bitmap;
}
postMessage(data) {
const openDataContext = wx.getOpenDataContext();
openDataContext.postMessage(data);
}
}
window.platform = new WxgamePlatform();
\ No newline at end of file
const SDKConfig = {
++ /dev/null
const SDKConfig = {
// 配置项目参数
appid: "wx8ccb2ef82e44df92", // 换openid
appName: "测试应用", // 应用名称
productCode: "b5488a667a66561aa97ce2a70137487e", // 产品code
productKey: "d0e3e7998c6b3b47dd9e42c3769edd2c", // 产品key,用于生成签名
appVersion: "产品版本号(cp)", // 产品版本号
offerid: "1450016203", // 支付
sdkVersion: "1.0.0", // SDK版本号,SDK接口需要
shareTitle: "鲸鱼游戏棒棒棒", // 分享标题
shareImageUrl: "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3903587193,374462562&fm=27&gp=0.jpg" //分享图片链接
// 结束
}
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?){
this.printf("SDK START...", 0)
this.debug = config&&config.debug? config.debug : 0
this.sdkinit()
}
private debug:number // 1是测试模式,用于printf函数输出
private userBtn:any // 用户授权按钮
private sdkinit() {
const that = this
that.userBtn = this.createUserInfoButton() // 创建用户授权按钮
that.userBtn.hide() // 隐藏按钮
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = SDKConfig.productCode
that.sdkParams.appid = SDKConfig.appid
that.sdkParams.version = SDKConfig.sdkVersion
const options = this.getOptionsInfo()
let queryObj = options.referrerInfo && options.referrerInfo.extraData && Object.keys(options.referrerInfo.extraData).length > 0 ? options.referrerInfo.extraData : {}
queryObj = that.deepCopy({}, options.query, queryObj)
that.printf("SDK -> p1:", 0)
that.printf(queryObj, 0)
that.ReportParams.from = queryObj.from || ''
that.ReportParams.tag = queryObj.tag || ''
that.ReportParams.fromOpenId = queryObj.fromId || ''
const p2 = this.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = this.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
that.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}, err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId () {
const that = this
this.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: SDKConfig.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkParams.session_key = res.data.session_key
that.sdkActive() // SDK激活
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val:number = 0
if( this.obj.initReady == 1) { // 已经激活成功
that.doAuthorize(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady',{
enumerable:true,
configurable:true,
get:function getter() { return val; },
set:function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if(newVal===val){ return; }
that.doAuthorize(LoginCallBack)
}
})
}
}
//用户授权操作
private doAuthorize(LoginCallBack) {
const that = this
// 用户授权
this.getUserInfo().then(res => {
if(res) { // 用户确认授权
that.doLogin(res, LoginCallBack)
} else {
console.log('用户取消授权。。。')
that.userBtn.show() // 显示授权按钮
that.userBtn.onTap(res => {
if(res.userInfo) that.doLogin(res, LoginCallBack)
})
}
}, err => {
console.log(err)
})
}
private doLogin(res, LoginCallBack) {
const that = this
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if(res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, that.getOptionsInfo(), userInfo, {
os: (that.ReportParams.system).split(' ')[0], // 返回系统类型IOS或者android
session_key: that.sdkParams.session_key // 返回session_key
})) // 将用户信息拼上平台用户信息返回
that.userBtn.destroy() //登录成功后摧毁按钮
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = SDKConfig.offerid
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
console.log("订单返回---->", res)
if (res.code == 0) {
if(res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: SDKConfig.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: 'trial', //跳转到体验版
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
that.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money/100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0)
// 调微信米大师支付接口
that.pay(that.MidasPaymentParams)
.then(() => { // 支付成功
this.printf("SDK -> 支付成功:", 0)
this.printf(res, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
}, err => { // 支付失败
this.printf("SDK -> 支付失败:", 0)
this.printf(err, 0)
})
} else { // 已有未完成订单,弹窗提示
const params = {
title: SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
that.showModal(params)
}
}
} else { // 输出订单失败消息
that.printf(res.msg, 1)
that.sdkAlert(res.msg)
}
}, err => { console.log(err) })
}
private getCoins(orderParams) { // 通知服务端扣费
this.printf("SDK -> 通知扣费:", 0)
this.printf(orderParams, 0)
this.sdkRequest(sdkPortLinks.pay, orderParams).then(res => {
this.printf("SDK -> 扣费成功:", 0)
})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
this.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
// 分享
public ShareApp(params?) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&'+params
}
return this.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return this.exitWechatApp()
}
// SDK上报接口
private sdkRequest (link:string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData (portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI:string, Params:any, Method = 'GET') {
return this.fetchUri(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
private printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level){
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
this.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign (obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url="";
for(let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + SDKConfig.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
public deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame', // 客户端类型
session_key: '' // 用户session_key
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: '1', // 米大师环境配置, 0:正式环境, 1:沙盒模式
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
// 定义wechat方法
private async getUserInfo():Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getUserInfo({
withCredentials: true,
success: function(res) {
resolve(res);
},
fail: function(res) {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async login():Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async getNetworkType():Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getNetworkType({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async getSystemInfo():Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getSystemInfo({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async fetchUri(URI, DATA, METHOD):Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
}).catch((error) => {
console.log(error)
})
}
private showModal(DATA) {
(wx as any).showModal(this.deepCopy({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
private async share(DATA):Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).shareAppMessage(that.deepCopy(DATA, {
success: function(res) {
resolve(res)
},
fail: function(res) {
reject(res)
},
complete() {}
}))
})
}
private async pay(params):Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).requestMidasPayment(that.deepCopy(params, {
success: function(res) {
resolve(res)
},
fail: function(res) {
reject(res)
},
complete: function() {
console.log("Rechare")
}
}))
})
}
private shareInit() {
(wx as any).showShareMenu({
withShareTicket: true,
success: () => {},
fail: () => {},
complete: () => {}
})
}
// 分享
public addShareEvent(DATA, CALLBACK) {
const that = this;
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0'
};
(wx as any).onShareAppMessage(() => {
return that.deepCopy(DATA, CALLBACK)
})
that.shareInit()
}
private customer(params) {
(wx as any).openCustomerServiceConversation(params)
}
private navigateToMiniProgram(params) {
(wx as any).navigateToMiniProgram(params)
}
private showMsg(str) {
(wx as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
private async exitWechatApp():Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).exitMiniProgram({
success: function(res) {
console.log('退出成功')
resolve(res)
},
fail: function(res) {
console.log('退出失败')
reject(res)
}
})
})
}
// 获取启动参数
public getOptionsInfo() {
const that = this
const options = (wx as any).getLaunchOptionsSync()
if (Object.keys(options.query).length > 0 || Object.keys(options.referrerInfo).length > 0) {
const obj = {}
that.deepCopy(obj, options.query, options.referrerInfo.extraData) // 合并数据
return obj
} else {
return options
}
}
private createUserInfoButton() {
const UserInfoButton = (wx as any).createUserInfoButton({
type: 'text',
text: ' ',
style: {
left: 0,
top: 0,
width: 800,
height: 1200,
backgroundColor: 'rgba(0, 0, 0, 0)',
color: '#ffffff'
}
})
return UserInfoButton
}
}
// md5加密
const rotateLeft = (lValue,iShiftBits) => {return(lValue<<iShiftBits)|(lValue>>>(32-iShiftBits))};var addUnsigned=function(lX,lY){var lX4,lY4,lX8,lY8,lResult;lX8=(lX&2147483648);lY8=(lY&2147483648);lX4=(lX&1073741824);lY4=(lY&1073741824);lResult=(lX&1073741823)+(lY&1073741823);if(lX4&lY4){return(lResult^2147483648^lX8^lY8)}if(lX4|lY4){if(lResult&1073741824){return(lResult^3221225472^lX8^lY8)}else{return(lResult^1073741824^lX8^lY8)}}else{return(lResult^lX8^lY8)}};var F=function(x,y,z){return(x&y)|((~x)&z)};var G=function(x,y,z){return(x&z)|(y&(~z))};var H=function(x,y,z){return(x^y^z)};var I=function(x,y,z){return(y^(x|(~z)))};var FF=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(F(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var GG=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(G(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var HH=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(H(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var II=function(a,b,c,d,x,s,ac){a=addUnsigned(a,addUnsigned(addUnsigned(I(b,c,d),x),ac));return addUnsigned(rotateLeft(a,s),b)};var convertToWordArray=function(string){var lWordCount;var lMessageLength=string.length;var lNumberOfWordsTempOne=lMessageLength+8;var lNumberOfWordsTempTwo=(lNumberOfWordsTempOne-(lNumberOfWordsTempOne%64))/64;var lNumberOfWords=(lNumberOfWordsTempTwo+1)*16;var lWordArray=Array(lNumberOfWords-1);var lBytePosition=0;var lByteCount=0;while(lByteCount<lMessageLength){lWordCount=(lByteCount-(lByteCount%4))/4;lBytePosition=(lByteCount%4)*8;lWordArray[lWordCount]=(lWordArray[lWordCount]|(string.charCodeAt(lByteCount)<<lBytePosition));lByteCount++}lWordCount=(lByteCount-(lByteCount%4))/4;lBytePosition=(lByteCount%4)*8;lWordArray[lWordCount]=lWordArray[lWordCount]|(128<<lBytePosition);lWordArray[lNumberOfWords-2]=lMessageLength<<3;lWordArray[lNumberOfWords-1]=lMessageLength>>>29;return lWordArray};var wordToHex=function(lValue){var WordToHexValue="",WordToHexValueTemp="",lByte,lCount;for(lCount=0;lCount<=3;lCount++){lByte=(lValue>>>(lCount*8))&255;WordToHexValueTemp="0"+lByte.toString(16);WordToHexValue=WordToHexValue+WordToHexValueTemp.substr(WordToHexValueTemp.length-2,2)}return WordToHexValue};var uTF8Encode=function(string){string=string.replace(/\x0d\x0a/g,"\x0a");var output="";for(var n=0;n<string.length;n++){var c=string.charCodeAt(n);if(c<128){output+=String.fromCharCode(c)}else{if((c>127)&&(c<2048)){output+=String.fromCharCode((c>>6)|192);output+=String.fromCharCode((c&63)|128)}else{output+=String.fromCharCode((c>>12)|224);output+=String.fromCharCode(((c>>6)&63)|128);output+=String.fromCharCode((c&63)|128)}}}return output};function md5(string){var x=Array();var k,AA,BB,CC,DD,a,b,c,d;var S11=7,S12=12,S13=17,S14=22;var S21=5,S22=9,S23=14,S24=20;var S31=4,S32=11,S33=16,S34=23;var S41=6,S42=10,S43=15,S44=21;string=uTF8Encode(string);x=convertToWordArray(string);a=1732584193;b=4023233417;c=2562383102;d=271733878;for(k=0;k<x.length;k+=16){AA=a;BB=b;CC=c;DD=d;a=FF(a,b,c,d,x[k+0],S11,3614090360);d=FF(d,a,b,c,x[k+1],S12,3905402710);c=FF(c,d,a,b,x[k+2],S13,606105819);b=FF(b,c,d,a,x[k+3],S14,3250441966);a=FF(a,b,c,d,x[k+4],S11,4118548399);d=FF(d,a,b,c,x[k+5],S12,1200080426);c=FF(c,d,a,b,x[k+6],S13,2821735955);b=FF(b,c,d,a,x[k+7],S14,4249261313);a=FF(a,b,c,d,x[k+8],S11,1770035416);d=FF(d,a,b,c,x[k+9],S12,2336552879);c=FF(c,d,a,b,x[k+10],S13,4294925233);b=FF(b,c,d,a,x[k+11],S14,2304563134);a=FF(a,b,c,d,x[k+12],S11,1804603682);d=FF(d,a,b,c,x[k+13],S12,4254626195);c=FF(c,d,a,b,x[k+14],S13,2792965006);b=FF(b,c,d,a,x[k+15],S14,1236535329);a=GG(a,b,c,d,x[k+1],S21,4129170786);d=GG(d,a,b,c,x[k+6],S22,3225465664);c=GG(c,d,a,b,x[k+11],S23,643717713);b=GG(b,c,d,a,x[k+0],S24,3921069994);a=GG(a,b,c,d,x[k+5],S21,3593408605);d=GG(d,a,b,c,x[k+10],S22,38016083);c=GG(c,d,a,b,x[k+15],S23,3634488961);b=GG(b,c,d,a,x[k+4],S24,3889429448);a=GG(a,b,c,d,x[k+9],S21,568446438);d=GG(d,a,b,c,x[k+14],S22,3275163606);c=GG(c,d,a,b,x[k+3],S23,4107603335);b=GG(b,c,d,a,x[k+8],S24,1163531501);a=GG(a,b,c,d,x[k+13],S21,2850285829);d=GG(d,a,b,c,x[k+2],S22,4243563512);c=GG(c,d,a,b,x[k+7],S23,1735328473);b=GG(b,c,d,a,x[k+12],S24,2368359562);a=HH(a,b,c,d,x[k+5],S31,4294588738);d=HH(d,a,b,c,x[k+8],S32,2272392833);c=HH(c,d,a,b,x[k+11],S33,1839030562);b=HH(b,c,d,a,x[k+14],S34,4259657740);a=HH(a,b,c,d,x[k+1],S31,2763975236);d=HH(d,a,b,c,x[k+4],S32,1272893353);c=HH(c,d,a,b,x[k+7],S33,4139469664);b=HH(b,c,d,a,x[k+10],S34,3200236656);a=HH(a,b,c,d,x[k+13],S31,681279174);d=HH(d,a,b,c,x[k+0],S32,3936430074);c=HH(c,d,a,b,x[k+3],S33,3572445317);b=HH(b,c,d,a,x[k+6],S34,76029189);a=HH(a,b,c,d,x[k+9],S31,3654602809);d=HH(d,a,b,c,x[k+12],S32,3873151461);c=HH(c,d,a,b,x[k+15],S33,530742520);b=HH(b,c,d,a,x[k+2],S34,3299628645);a=II(a,b,c,d,x[k+0],S41,4096336452);d=II(d,a,b,c,x[k+7],S42,1126891415);c=II(c,d,a,b,x[k+14],S43,2878612391);b=II(b,c,d,a,x[k+5],S44,4237533241);a=II(a,b,c,d,x[k+12],S41,1700485571);d=II(d,a,b,c,x[k+3],S42,2399980690);c=II(c,d,a,b,x[k+10],S43,4293915773);b=II(b,c,d,a,x[k+1],S44,2240044497);a=II(a,b,c,d,x[k+8],S41,1873313359);d=II(d,a,b,c,x[k+15],S42,4264355552);c=II(c,d,a,b,x[k+6],S43,2734768916);b=II(b,c,d,a,x[k+13],S44,1309151649);a=II(a,b,c,d,x[k+4],S41,4149444226);d=II(d,a,b,c,x[k+11],S42,3174756917);c=II(c,d,a,b,x[k+2],S43,718787259);b=II(b,c,d,a,x[k+9],S44,3951481745);a=addUnsigned(a,AA);b=addUnsigned(b,BB);c=addUnsigned(c,CC);d=addUnsigned(d,DD)}var tempValue=wordToHex(a)+wordToHex(b)+wordToHex(c)+wordToHex(d);return tempValue.toLowerCase()};
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?) {
this.printf("SDK START...", 0)
this.debug = config && config.debug ? config.debug : 0
this.sdkinit()
}
private debug: number // 1是测试模式,用于printf函数输出
private userBtn: any // 用户授权按钮
private sdkinit() {
const that = this
that.userBtn = this.createUserInfoButton() // 创建用户授权按钮
that.userBtn.hide() // 隐藏按钮
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = SDKConfig.productCode
that.sdkParams.appid = SDKConfig.appid
that.sdkParams.version = SDKConfig.sdkVersion
const options = this.getOptionsInfo()
let queryObj = options.referrerInfo && options.referrerInfo.extraData && Object.keys(options.referrerInfo.extraData).length > 0 ? options.referrerInfo.extraData : {}
queryObj = that.deepCopy({}, options.query, queryObj)
that.printf("SDK -> p1:", 0)
that.printf(queryObj, 0)
that.ReportParams.from = queryObj.from || ''
that.ReportParams.tag = queryObj.tag || ''
that.ReportParams.fromOpenId = queryObj.fromId || ''
const p2 = this.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = this.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
that.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}, err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId() {
const that = this
this.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: SDKConfig.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkParams.session_key = res.data.session_key
that.sdkActive() // SDK激活
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val: number = 0
if (this.obj.initReady == 1) { // 已经激活成功
that.doAuthorize(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady', {
enumerable: true,
configurable: true,
get: function getter() { return val; },
set: function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if (newVal === val) { return; }
that.doAuthorize(LoginCallBack)
}
})
}
}
//用户授权操作
private doAuthorize(LoginCallBack) {
const that = this
// 用户授权
this.getUserInfo().then(res => {
if (res) { // 用户确认授权
that.doLogin(res, LoginCallBack)
} else {
console.log('用户取消授权。。。')
that.userBtn.show() // 显示授权按钮
that.userBtn.onTap(res => {
if (res.userInfo) that.doLogin(res, LoginCallBack)
})
}
}, err => {
console.log(err)
})
}
private doLogin(res, LoginCallBack) {
const that = this
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if (res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, that.getOptionsInfo(), userInfo, {
os: (that.ReportParams.system).split(' ')[0], // 返回系统类型IOS或者android
session_key: that.sdkParams.session_key // 返回session_key
})) // 将用户信息拼上平台用户信息返回
that.userBtn.destroy() //登录成功后摧毁按钮
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = SDKConfig.offerid
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
console.log("订单返回---->", res)
if (res.code == 0) {
if (res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: SDKConfig.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: 'trial', //跳转到体验版
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
that.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money / 100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0)
// 调微信米大师支付接口
that.pay(that.MidasPaymentParams)
.then(() => { // 支付成功
this.printf("SDK -> 支付成功:", 0)
this.printf(res, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
}, err => { // 支付失败
this.printf("SDK -> 支付失败:", 0)
this.printf(err, 0)
})
} else { // 已有未完成订单,弹窗提示
const params = {
title: SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
that.showModal(params)
}
}
} else { // 输出订单失败消息
that.printf(res.msg, 1)
that.sdkAlert(res.msg)
}
}, err => { console.log(err) })
}
private getCoins(orderParams) { // 通知服务端扣费
this.printf("SDK -> 通知扣费:", 0)
this.printf(orderParams, 0)
this.sdkRequest(sdkPortLinks.pay, orderParams).then(res => {
this.printf("SDK -> 扣费成功:", 0)
})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
this.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
// 分享
public ShareApp(params?) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + params
}
return this.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return this.exitWechatApp()
}
// SDK上报接口
private sdkRequest(link: string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData(portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI: string, Params: any, Method = 'GET') {
return this.fetchUri(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
private printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level) {
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
this.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign(obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url = "";
for (let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + SDKConfig.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
public deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame', // 客户端类型
session_key: '' // 用户session_key
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: '1', // 米大师环境配置, 0:正式环境, 1:沙盒模式
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
// 定义wechat方法
private async getUserInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getUserInfo({
withCredentials: true,
success: function (res) {
resolve(res);
},
fail: function (res) {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async login(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async getNetworkType(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getNetworkType({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async getSystemInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getSystemInfo({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async fetchUri(URI, DATA, METHOD): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
}).catch((error) => {
console.log(error)
})
}
private showModal(DATA) {
(wx as any).showModal(this.deepCopy({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
private async share(DATA): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).shareAppMessage(that.deepCopy(DATA, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete() { }
}))
})
}
private async pay(params): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).requestMidasPayment(that.deepCopy(params, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete: function () {
console.log("Rechare")
}
}))
})
}
private shareInit() {
(wx as any).showShareMenu({
withShareTicket: true,
success: () => { },
fail: () => { },
complete: () => { }
})
}
// 分享
public addShareEvent(CALLBACK, DATA?) {
const that = this;
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + DATA
};
(wx as any).onShareAppMessage(() => {
return that.deepCopy(ShareParams, CALLBACK)
})
that.shareInit()
}
private customer(params) {
(wx as any).openCustomerServiceConversation(params)
}
private navigateToMiniProgram(params) {
(wx as any).navigateToMiniProgram(params)
}
private showMsg(str) {
(wx as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
private async exitWechatApp(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).exitMiniProgram({
success: function (res) {
console.log('退出成功')
resolve(res)
},
fail: function (res) {
console.log('退出失败')
reject(res)
}
})
})
}
// 获取启动参数
public getOptionsInfo() {
const that = this
const options = (wx as any).getLaunchOptionsSync()
if (!options.query || !options.referrerInfo || Object.keys(options.query).length == 0 || Object.keys(options.referrerInfo).length == 0) {
return options
} else {
const obj = {}
that.deepCopy(obj, options.query, options.referrerInfo.extraData) // 合并数据
return obj
}
}
private createUserInfoButton() {
const UserInfoButton = (wx as any).createUserInfoButton({
type: 'text',
text: ' ',
style: {
left: 0,
top: 0,
width: 800,
height: 1200,
backgroundColor: 'rgba(0, 0, 0, 0)',
color: '#ffffff'
}
})
return UserInfoButton
}
}
// md5加密
const rotateLeft = (lValue, iShiftBits) => { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)) }; var addUnsigned = function (lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 2147483648); lY8 = (lY & 2147483648); lX4 = (lX & 1073741824); lY4 = (lY & 1073741824); lResult = (lX & 1073741823) + (lY & 1073741823); if (lX4 & lY4) { return (lResult ^ 2147483648 ^ lX8 ^ lY8) } if (lX4 | lY4) { if (lResult & 1073741824) { return (lResult ^ 3221225472 ^ lX8 ^ lY8) } else { return (lResult ^ 1073741824 ^ lX8 ^ lY8) } } else { return (lResult ^ lX8 ^ lY8) } }; var F = function (x, y, z) { return (x & y) | ((~x) & z) }; var G = function (x, y, z) { return (x & z) | (y & (~z)) }; var H = function (x, y, z) { return (x ^ y ^ z) }; var I = function (x, y, z) { return (y ^ (x | (~z))) }; var FF = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var GG = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var HH = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var II = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var convertToWordArray = function (string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWordsTempOne = lMessageLength + 8; var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64; var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++ } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (128 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray }; var wordToHex = function (lValue) { var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValueTemp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2) } return WordToHexValue }; var uTF8Encode = function (string) { string = string.replace(/\x0d\x0a/g, "\x0a"); var output = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { output += String.fromCharCode(c) } else { if ((c > 127) && (c < 2048)) { output += String.fromCharCode((c >> 6) | 192); output += String.fromCharCode((c & 63) | 128) } else { output += String.fromCharCode((c >> 12) | 224); output += String.fromCharCode(((c >> 6) & 63) | 128); output += String.fromCharCode((c & 63) | 128) } } } return output }; function md5(string) { var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = uTF8Encode(string); x = convertToWordArray(string); a = 1732584193; b = 4023233417; c = 2562383102; d = 271733878; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 3614090360); d = FF(d, a, b, c, x[k + 1], S12, 3905402710); c = FF(c, d, a, b, x[k + 2], S13, 606105819); b = FF(b, c, d, a, x[k + 3], S14, 3250441966); a = FF(a, b, c, d, x[k + 4], S11, 4118548399); d = FF(d, a, b, c, x[k + 5], S12, 1200080426); c = FF(c, d, a, b, x[k + 6], S13, 2821735955); b = FF(b, c, d, a, x[k + 7], S14, 4249261313); a = FF(a, b, c, d, x[k + 8], S11, 1770035416); d = FF(d, a, b, c, x[k + 9], S12, 2336552879); c = FF(c, d, a, b, x[k + 10], S13, 4294925233); b = FF(b, c, d, a, x[k + 11], S14, 2304563134); a = FF(a, b, c, d, x[k + 12], S11, 1804603682); d = FF(d, a, b, c, x[k + 13], S12, 4254626195); c = FF(c, d, a, b, x[k + 14], S13, 2792965006); b = FF(b, c, d, a, x[k + 15], S14, 1236535329); a = GG(a, b, c, d, x[k + 1], S21, 4129170786); d = GG(d, a, b, c, x[k + 6], S22, 3225465664); c = GG(c, d, a, b, x[k + 11], S23, 643717713); b = GG(b, c, d, a, x[k + 0], S24, 3921069994); a = GG(a, b, c, d, x[k + 5], S21, 3593408605); d = GG(d, a, b, c, x[k + 10], S22, 38016083); c = GG(c, d, a, b, x[k + 15], S23, 3634488961); b = GG(b, c, d, a, x[k + 4], S24, 3889429448); a = GG(a, b, c, d, x[k + 9], S21, 568446438); d = GG(d, a, b, c, x[k + 14], S22, 3275163606); c = GG(c, d, a, b, x[k + 3], S23, 4107603335); b = GG(b, c, d, a, x[k + 8], S24, 1163531501); a = GG(a, b, c, d, x[k + 13], S21, 2850285829); d = GG(d, a, b, c, x[k + 2], S22, 4243563512); c = GG(c, d, a, b, x[k + 7], S23, 1735328473); b = GG(b, c, d, a, x[k + 12], S24, 2368359562); a = HH(a, b, c, d, x[k + 5], S31, 4294588738); d = HH(d, a, b, c, x[k + 8], S32, 2272392833); c = HH(c, d, a, b, x[k + 11], S33, 1839030562); b = HH(b, c, d, a, x[k + 14], S34, 4259657740); a = HH(a, b, c, d, x[k + 1], S31, 2763975236); d = HH(d, a, b, c, x[k + 4], S32, 1272893353); c = HH(c, d, a, b, x[k + 7], S33, 4139469664); b = HH(b, c, d, a, x[k + 10], S34, 3200236656); a = HH(a, b, c, d, x[k + 13], S31, 681279174); d = HH(d, a, b, c, x[k + 0], S32, 3936430074); c = HH(c, d, a, b, x[k + 3], S33, 3572445317); b = HH(b, c, d, a, x[k + 6], S34, 76029189); a = HH(a, b, c, d, x[k + 9], S31, 3654602809); d = HH(d, a, b, c, x[k + 12], S32, 3873151461); c = HH(c, d, a, b, x[k + 15], S33, 530742520); b = HH(b, c, d, a, x[k + 2], S34, 3299628645); a = II(a, b, c, d, x[k + 0], S41, 4096336452); d = II(d, a, b, c, x[k + 7], S42, 1126891415); c = II(c, d, a, b, x[k + 14], S43, 2878612391); b = II(b, c, d, a, x[k + 5], S44, 4237533241); a = II(a, b, c, d, x[k + 12], S41, 1700485571); d = II(d, a, b, c, x[k + 3], S42, 2399980690); c = II(c, d, a, b, x[k + 10], S43, 4293915773); b = II(b, c, d, a, x[k + 1], S44, 2240044497); a = II(a, b, c, d, x[k + 8], S41, 1873313359); d = II(d, a, b, c, x[k + 15], S42, 4264355552); c = II(c, d, a, b, x[k + 6], S43, 2734768916); b = II(b, c, d, a, x[k + 13], S44, 1309151649); a = II(a, b, c, d, x[k + 4], S41, 4149444226); d = II(d, a, b, c, x[k + 11], S42, 3174756917); c = II(c, d, a, b, x[k + 2], S43, 718787259); b = II(b, c, d, a, x[k + 9], S44, 3951481745); a = addUnsigned(a, AA); b = addUnsigned(b, BB); c = addUnsigned(c, CC); d = addUnsigned(d, DD) } var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); return tempValue.toLowerCase() };
\ No newline at end of file
const SDKConfig = {
++ /dev/null
const SDKConfig = {
// 配置项目参数
appid: "wx8ccb2ef82e44df92", // 换openid
appName: "测试应用", // 应用名称
productCode: "b5488a667a66561aa97ce2a70137487e", // 产品code
productKey: "d0e3e7998c6b3b47dd9e42c3769edd2c", // 产品key,用于生成签名
appVersion: "产品版本号(cp)", // 产品版本号
offerid: "1450016203", // 支付
sdkVersion: "1.0.0", // SDK版本号,SDK接口需要
shareTitle: "鲸鱼游戏棒棒棒", // 分享标题
shareImageUrl: "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3903587193,374462562&fm=27&gp=0.jpg" //分享图片链接
// 结束
}
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?) {
this.printf("SDK START...", 0)
this.debug = config && config.debug ? config.debug : 0
this.sdkinit()
}
private debug: number // 1是测试模式,用于printf函数输出
private userBtn: any // 用户授权按钮
private sdkinit() {
const that = this
that.userBtn = this.createUserInfoButton() // 创建用户授权按钮
that.userBtn.hide() // 隐藏按钮
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = SDKConfig.productCode
that.sdkParams.appid = SDKConfig.appid
that.sdkParams.version = SDKConfig.sdkVersion
const options = this.getOptionsInfo()
let queryObj = options.referrerInfo && options.referrerInfo.extraData && Object.keys(options.referrerInfo.extraData).length > 0 ? options.referrerInfo.extraData : {}
queryObj = that.deepCopy({}, options.query, queryObj)
that.printf("SDK -> p1:", 0)
that.printf(queryObj, 0)
that.ReportParams.from = queryObj.from || ''
that.ReportParams.tag = queryObj.tag || ''
that.ReportParams.fromOpenId = queryObj.fromId || ''
const p2 = this.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = this.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
that.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}, err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId() {
const that = this
this.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: SDKConfig.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkParams.session_key = res.data.session_key
that.sdkActive() // SDK激活
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val: number = 0
if (this.obj.initReady == 1) { // 已经激活成功
that.doAuthorize(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady', {
enumerable: true,
configurable: true,
get: function getter() { return val; },
set: function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if (newVal === val) { return; }
that.doAuthorize(LoginCallBack)
}
})
}
}
//用户授权操作
private doAuthorize(LoginCallBack) {
const that = this
// 用户授权
this.getUserInfo().then(res => {
if (res) { // 用户确认授权
that.doLogin(res, LoginCallBack)
} else {
console.log('用户取消授权。。。')
that.userBtn.show() // 显示授权按钮
that.userBtn.onTap(res => {
if (res.userInfo) that.doLogin(res, LoginCallBack)
})
}
}, err => {
console.log(err)
})
}
private doLogin(res, LoginCallBack) {
const that = this
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if (res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, that.getOptionsInfo(), userInfo, {
os: (that.ReportParams.system).split(' ')[0], // 返回系统类型IOS或者android
session_key: that.sdkParams.session_key // 返回session_key
})) // 将用户信息拼上平台用户信息返回
that.userBtn.destroy() //登录成功后摧毁按钮
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = SDKConfig.offerid
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
console.log("订单返回---->", res)
if (res.code == 0) {
if (res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: SDKConfig.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: 'trial', //跳转到体验版
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
that.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money / 100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0)
// 调微信米大师支付接口
that.pay(that.MidasPaymentParams)
.then(() => { // 支付成功
this.printf("SDK -> 支付成功:", 0)
this.printf(res, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
}, err => { // 支付失败
this.printf("SDK -> 支付失败:", 0)
this.printf(err, 0)
})
} else { // 已有未完成订单,弹窗提示
const params = {
title: SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
that.showModal(params)
}
}
} else { // 输出订单失败消息
that.printf(res.msg, 1)
that.sdkAlert(res.msg)
}
}, err => { console.log(err) })
}
private getCoins(orderParams) { // 通知服务端扣费
this.printf("SDK -> 通知扣费:", 0)
this.printf(orderParams, 0)
this.sdkRequest(sdkPortLinks.pay, orderParams).then(res => {
this.printf("SDK -> 扣费成功:", 0)
})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
this.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
// 分享
public ShareApp(params?) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + params
}
return this.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return this.exitWechatApp()
}
// SDK上报接口
private sdkRequest(link: string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData(portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI: string, Params: any, Method = 'GET') {
return this.fetchUri(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
private printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level) {
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
this.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign(obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url = "";
for (let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + SDKConfig.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
public deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame', // 客户端类型
session_key: '' // 用户session_key
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: '0', // 米大师环境配置, 0:正式环境, 1:沙盒模式
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
// 定义wechat方法
private async getUserInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getUserInfo({
withCredentials: true,
success: function (res) {
resolve(res);
},
fail: function (res) {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async login(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async getNetworkType(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getNetworkType({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async getSystemInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getSystemInfo({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async fetchUri(URI, DATA, METHOD): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
}).catch((error) => {
console.log(error)
})
}
private showModal(DATA) {
(wx as any).showModal(this.deepCopy({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
private async share(DATA): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).shareAppMessage(that.deepCopy(DATA, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete() { }
}))
})
}
private async pay(params): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).requestMidasPayment(that.deepCopy(params, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete: function () {
console.log("Rechare")
}
}))
})
}
private shareInit() {
(wx as any).showShareMenu({
withShareTicket: true,
success: () => { },
fail: () => { },
complete: () => { }
})
}
// 分享
public addShareEvent(CALLBACK, DATA?) {
const that = this;
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + DATA
};
(wx as any).onShareAppMessage(() => {
return that.deepCopy(ShareParams, CALLBACK)
})
that.shareInit()
}
private customer(params) {
(wx as any).openCustomerServiceConversation(params)
}
private navigateToMiniProgram(params) {
(wx as any).navigateToMiniProgram(params)
}
private showMsg(str) {
(wx as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
private async exitWechatApp(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).exitMiniProgram({
success: function (res) {
console.log('退出成功')
resolve(res)
},
fail: function (res) {
console.log('退出失败')
reject(res)
}
})
})
}
// 获取启动参数
public getOptionsInfo() {
const that = this
const options = (wx as any).getLaunchOptionsSync()
if (!options.query || !options.referrerInfo || Object.keys(options.query).length == 0 || Object.keys(options.referrerInfo).length == 0) {
return options
} else {
const obj = {}
that.deepCopy(obj, options.query, options.referrerInfo.extraData) // 合并数据
return obj
}
}
private createUserInfoButton() {
const UserInfoButton = (wx as any).createUserInfoButton({
type: 'text',
text: ' ',
style: {
left: 0,
top: 0,
width: 800,
height: 1200,
backgroundColor: 'rgba(0, 0, 0, 0)',
color: '#ffffff'
}
})
return UserInfoButton
}
}
// md5加密
const rotateLeft = (lValue, iShiftBits) => { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)) }; var addUnsigned = function (lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 2147483648); lY8 = (lY & 2147483648); lX4 = (lX & 1073741824); lY4 = (lY & 1073741824); lResult = (lX & 1073741823) + (lY & 1073741823); if (lX4 & lY4) { return (lResult ^ 2147483648 ^ lX8 ^ lY8) } if (lX4 | lY4) { if (lResult & 1073741824) { return (lResult ^ 3221225472 ^ lX8 ^ lY8) } else { return (lResult ^ 1073741824 ^ lX8 ^ lY8) } } else { return (lResult ^ lX8 ^ lY8) } }; var F = function (x, y, z) { return (x & y) | ((~x) & z) }; var G = function (x, y, z) { return (x & z) | (y & (~z)) }; var H = function (x, y, z) { return (x ^ y ^ z) }; var I = function (x, y, z) { return (y ^ (x | (~z))) }; var FF = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var GG = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var HH = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var II = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var convertToWordArray = function (string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWordsTempOne = lMessageLength + 8; var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64; var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++ } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (128 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray }; var wordToHex = function (lValue) { var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValueTemp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2) } return WordToHexValue }; var uTF8Encode = function (string) { string = string.replace(/\x0d\x0a/g, "\x0a"); var output = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { output += String.fromCharCode(c) } else { if ((c > 127) && (c < 2048)) { output += String.fromCharCode((c >> 6) | 192); output += String.fromCharCode((c & 63) | 128) } else { output += String.fromCharCode((c >> 12) | 224); output += String.fromCharCode(((c >> 6) & 63) | 128); output += String.fromCharCode((c & 63) | 128) } } } return output }; function md5(string) { var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = uTF8Encode(string); x = convertToWordArray(string); a = 1732584193; b = 4023233417; c = 2562383102; d = 271733878; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 3614090360); d = FF(d, a, b, c, x[k + 1], S12, 3905402710); c = FF(c, d, a, b, x[k + 2], S13, 606105819); b = FF(b, c, d, a, x[k + 3], S14, 3250441966); a = FF(a, b, c, d, x[k + 4], S11, 4118548399); d = FF(d, a, b, c, x[k + 5], S12, 1200080426); c = FF(c, d, a, b, x[k + 6], S13, 2821735955); b = FF(b, c, d, a, x[k + 7], S14, 4249261313); a = FF(a, b, c, d, x[k + 8], S11, 1770035416); d = FF(d, a, b, c, x[k + 9], S12, 2336552879); c = FF(c, d, a, b, x[k + 10], S13, 4294925233); b = FF(b, c, d, a, x[k + 11], S14, 2304563134); a = FF(a, b, c, d, x[k + 12], S11, 1804603682); d = FF(d, a, b, c, x[k + 13], S12, 4254626195); c = FF(c, d, a, b, x[k + 14], S13, 2792965006); b = FF(b, c, d, a, x[k + 15], S14, 1236535329); a = GG(a, b, c, d, x[k + 1], S21, 4129170786); d = GG(d, a, b, c, x[k + 6], S22, 3225465664); c = GG(c, d, a, b, x[k + 11], S23, 643717713); b = GG(b, c, d, a, x[k + 0], S24, 3921069994); a = GG(a, b, c, d, x[k + 5], S21, 3593408605); d = GG(d, a, b, c, x[k + 10], S22, 38016083); c = GG(c, d, a, b, x[k + 15], S23, 3634488961); b = GG(b, c, d, a, x[k + 4], S24, 3889429448); a = GG(a, b, c, d, x[k + 9], S21, 568446438); d = GG(d, a, b, c, x[k + 14], S22, 3275163606); c = GG(c, d, a, b, x[k + 3], S23, 4107603335); b = GG(b, c, d, a, x[k + 8], S24, 1163531501); a = GG(a, b, c, d, x[k + 13], S21, 2850285829); d = GG(d, a, b, c, x[k + 2], S22, 4243563512); c = GG(c, d, a, b, x[k + 7], S23, 1735328473); b = GG(b, c, d, a, x[k + 12], S24, 2368359562); a = HH(a, b, c, d, x[k + 5], S31, 4294588738); d = HH(d, a, b, c, x[k + 8], S32, 2272392833); c = HH(c, d, a, b, x[k + 11], S33, 1839030562); b = HH(b, c, d, a, x[k + 14], S34, 4259657740); a = HH(a, b, c, d, x[k + 1], S31, 2763975236); d = HH(d, a, b, c, x[k + 4], S32, 1272893353); c = HH(c, d, a, b, x[k + 7], S33, 4139469664); b = HH(b, c, d, a, x[k + 10], S34, 3200236656); a = HH(a, b, c, d, x[k + 13], S31, 681279174); d = HH(d, a, b, c, x[k + 0], S32, 3936430074); c = HH(c, d, a, b, x[k + 3], S33, 3572445317); b = HH(b, c, d, a, x[k + 6], S34, 76029189); a = HH(a, b, c, d, x[k + 9], S31, 3654602809); d = HH(d, a, b, c, x[k + 12], S32, 3873151461); c = HH(c, d, a, b, x[k + 15], S33, 530742520); b = HH(b, c, d, a, x[k + 2], S34, 3299628645); a = II(a, b, c, d, x[k + 0], S41, 4096336452); d = II(d, a, b, c, x[k + 7], S42, 1126891415); c = II(c, d, a, b, x[k + 14], S43, 2878612391); b = II(b, c, d, a, x[k + 5], S44, 4237533241); a = II(a, b, c, d, x[k + 12], S41, 1700485571); d = II(d, a, b, c, x[k + 3], S42, 2399980690); c = II(c, d, a, b, x[k + 10], S43, 4293915773); b = II(b, c, d, a, x[k + 1], S44, 2240044497); a = II(a, b, c, d, x[k + 8], S41, 1873313359); d = II(d, a, b, c, x[k + 15], S42, 4264355552); c = II(c, d, a, b, x[k + 6], S43, 2734768916); b = II(b, c, d, a, x[k + 13], S44, 1309151649); a = II(a, b, c, d, x[k + 4], S41, 4149444226); d = II(d, a, b, c, x[k + 11], S42, 3174756917); c = II(c, d, a, b, x[k + 2], S43, 718787259); b = II(b, c, d, a, x[k + 9], S44, 3951481745); a = addUnsigned(a, AA); b = addUnsigned(b, BB); c = addUnsigned(c, CC); d = addUnsigned(d, DD) } var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); return tempValue.toLowerCase() };
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?) {
this.printf("SDK START...", 0)
this.debug = config && config.debug ? config.debug : 0
this.sdkinit()
}
private debug: number // 1是测试模式,用于printf函数输出
private sdkinit() {
const that = this
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = SDKConfig.productCode
that.sdkParams.appid = SDKConfig.appid
that.sdkParams.version = SDKConfig.sdkVersion
const options = this.getOptionsInfo()
let queryObj = options.referrerInfo && options.referrerInfo.extraData && Object.keys(options.referrerInfo.extraData).length > 0 ? options.referrerInfo.extraData : {}
queryObj = that.deepCopy({}, options.query, queryObj)
that.printf("SDK -> p1:", 0)
that.printf(queryObj, 0)
that.ReportParams.from = queryObj.from || ''
that.ReportParams.tag = queryObj.tag || ''
that.ReportParams.fromOpenId = queryObj.fromId || ''
const p2 = this.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = this.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
that.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}, err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId() {
const that = this
this.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: SDKConfig.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkParams.session_key = res.data.session_key
that.sdkActive() // SDK激活
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val: number = 0
if (this.obj.initReady == 1) { // 已经激活成功
that.doAuthorize(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady', {
enumerable: true,
configurable: true,
get: function getter() { return val; },
set: function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if (newVal === val) { return; }
that.doAuthorize(LoginCallBack)
}
})
}
}
//用户授权操作
private doAuthorize(LoginCallBack) {
const that = this
// 用户授权
this.getUserInfo().then(res => {
if (res) { // 用户确认授权
that.doLogin(res, LoginCallBack)
} else {
console.log('用户取消授权。。。')
this.createUserInfoButton(LoginCallBack) // 创建用户授权按钮
}
}, err => {
console.log(err)
})
}
private doLogin(res, LoginCallBack) {
const that = this
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if (res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, that.getOptionsInfo(), userInfo, {
os: (that.ReportParams.system).split(' ')[0], // 返回系统类型IOS或者android
session_key: that.sdkParams.session_key // 返回session_key
})) // 将用户信息拼上平台用户信息返回
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = SDKConfig.offerid
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
console.log("订单返回---->", res)
if (res.code == 0) {
if (res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: SDKConfig.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: 'trial', //跳转到体验版
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
that.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money / 100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0)
// 调微信米大师支付接口
that.pay(that.MidasPaymentParams)
.then(() => { // 支付成功
this.printf("SDK -> 支付成功:", 0)
this.printf(res, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
}, err => { // 支付失败
this.printf("SDK -> 支付失败:", 0)
this.printf(err, 0)
})
} else { // 已有未完成订单,弹窗提示
const params = {
title: SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
that.showModal(params)
}
}
} else { // 输出订单失败消息
that.printf(res.msg, 1)
that.sdkAlert(res.msg)
}
}, err => { console.log(err) })
}
private getCoins(orderParams) { // 通知服务端扣费
this.printf("SDK -> 通知扣费:", 0)
this.printf(orderParams, 0)
this.sdkRequest(sdkPortLinks.pay, orderParams).then(res => {
this.printf("SDK -> 扣费成功:", 0)
})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
this.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
// 分享
public ShareApp(params?) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + params
}
return this.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return this.exitWechatApp()
}
// SDK上报接口
private sdkRequest(link: string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData(portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI: string, Params: any, Method = 'GET') {
return this.fetchUri(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
private printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level) {
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
this.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign(obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url = "";
for (let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + SDKConfig.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
public deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame', // 客户端类型
session_key: '' // 用户session_key
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: '1', // 米大师环境配置, 0:正式环境, 1:沙盒模式
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
// 定义wechat方法
private async getUserInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getUserInfo({
success: function (res) {
resolve(res);
},
fail: function (res) {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async login(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async getNetworkType(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getNetworkType({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async getSystemInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getSystemInfo({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async fetchUri(URI, DATA, METHOD): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
}).catch((error) => {
console.log(error)
})
}
private showModal(DATA) {
(wx as any).showModal(this.deepCopy({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
private async share(DATA): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).shareAppMessage(that.deepCopy(DATA, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete() { }
}))
})
}
private async pay(params): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).requestMidasPayment(that.deepCopy(params, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete: function () {
console.log("Rechare")
}
}))
})
}
private shareInit() {
(wx as any).showShareMenu({
withShareTicket: true,
success: () => { },
fail: () => { },
complete: () => { }
})
}
// 分享
public addShareEvent(CALLBACK, DATA?) {
const that = this;
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + DATA
};
(wx as any).onShareAppMessage(() => {
return that.deepCopy(ShareParams, CALLBACK)
})
that.shareInit()
}
private customer(params) {
(wx as any).openCustomerServiceConversation(params)
}
private navigateToMiniProgram(params) {
(wx as any).navigateToMiniProgram(params)
}
private showMsg(str) {
(wx as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
private async exitWechatApp(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).exitMiniProgram({
success: function (res) {
console.log('退出成功')
resolve(res)
},
fail: function (res) {
console.log('退出失败')
reject(res)
}
})
})
}
// 获取启动参数
public getOptionsInfo() {
const that = this
const options = (wx as any).getLaunchOptionsSync()
if (!options.query || !options.referrerInfo || Object.keys(options.query).length == 0 || Object.keys(options.referrerInfo).length == 0) {
return options
} else {
const obj = {}
that.deepCopy(obj, options.query, options.referrerInfo.extraData) // 合并数据
return obj
}
}
private createUserInfoButton(LoginCallBack) {
const that = this
const w = (wx as any).getSystemInfoSync().windowWidth
const h = (wx as any).getSystemInfoSync().windowHeight
if ((wx as any).createUserInfoButton) { // 做兼容
const UserInfoButton = (wx as any).createUserInfoButton({ // 按钮样式
type: 'text',
text: ' ',
style: {
left: 0,
top: 0,
width: w,
height: h,
backgroundColor: 'rgba(0, 0, 0, 0)',
color: '#ffffff'
}
})
UserInfoButton.onTap(res => {
UserInfoButton.destroy()
if (res.userInfo) that.doLogin(res, LoginCallBack) // 用户重新授权
})
} else {
that.sdkAlert('微信版本过低,请升级客户端。')
}
}
}
// md5加密
const rotateLeft = (lValue, iShiftBits) => { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)) }; var addUnsigned = function (lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 2147483648); lY8 = (lY & 2147483648); lX4 = (lX & 1073741824); lY4 = (lY & 1073741824); lResult = (lX & 1073741823) + (lY & 1073741823); if (lX4 & lY4) { return (lResult ^ 2147483648 ^ lX8 ^ lY8) } if (lX4 | lY4) { if (lResult & 1073741824) { return (lResult ^ 3221225472 ^ lX8 ^ lY8) } else { return (lResult ^ 1073741824 ^ lX8 ^ lY8) } } else { return (lResult ^ lX8 ^ lY8) } }; var F = function (x, y, z) { return (x & y) | ((~x) & z) }; var G = function (x, y, z) { return (x & z) | (y & (~z)) }; var H = function (x, y, z) { return (x ^ y ^ z) }; var I = function (x, y, z) { return (y ^ (x | (~z))) }; var FF = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var GG = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var HH = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var II = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var convertToWordArray = function (string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWordsTempOne = lMessageLength + 8; var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64; var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++ } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (128 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray }; var wordToHex = function (lValue) { var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValueTemp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2) } return WordToHexValue }; var uTF8Encode = function (string) { string = string.replace(/\x0d\x0a/g, "\x0a"); var output = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { output += String.fromCharCode(c) } else { if ((c > 127) && (c < 2048)) { output += String.fromCharCode((c >> 6) | 192); output += String.fromCharCode((c & 63) | 128) } else { output += String.fromCharCode((c >> 12) | 224); output += String.fromCharCode(((c >> 6) & 63) | 128); output += String.fromCharCode((c & 63) | 128) } } } return output }; function md5(string) { var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = uTF8Encode(string); x = convertToWordArray(string); a = 1732584193; b = 4023233417; c = 2562383102; d = 271733878; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 3614090360); d = FF(d, a, b, c, x[k + 1], S12, 3905402710); c = FF(c, d, a, b, x[k + 2], S13, 606105819); b = FF(b, c, d, a, x[k + 3], S14, 3250441966); a = FF(a, b, c, d, x[k + 4], S11, 4118548399); d = FF(d, a, b, c, x[k + 5], S12, 1200080426); c = FF(c, d, a, b, x[k + 6], S13, 2821735955); b = FF(b, c, d, a, x[k + 7], S14, 4249261313); a = FF(a, b, c, d, x[k + 8], S11, 1770035416); d = FF(d, a, b, c, x[k + 9], S12, 2336552879); c = FF(c, d, a, b, x[k + 10], S13, 4294925233); b = FF(b, c, d, a, x[k + 11], S14, 2304563134); a = FF(a, b, c, d, x[k + 12], S11, 1804603682); d = FF(d, a, b, c, x[k + 13], S12, 4254626195); c = FF(c, d, a, b, x[k + 14], S13, 2792965006); b = FF(b, c, d, a, x[k + 15], S14, 1236535329); a = GG(a, b, c, d, x[k + 1], S21, 4129170786); d = GG(d, a, b, c, x[k + 6], S22, 3225465664); c = GG(c, d, a, b, x[k + 11], S23, 643717713); b = GG(b, c, d, a, x[k + 0], S24, 3921069994); a = GG(a, b, c, d, x[k + 5], S21, 3593408605); d = GG(d, a, b, c, x[k + 10], S22, 38016083); c = GG(c, d, a, b, x[k + 15], S23, 3634488961); b = GG(b, c, d, a, x[k + 4], S24, 3889429448); a = GG(a, b, c, d, x[k + 9], S21, 568446438); d = GG(d, a, b, c, x[k + 14], S22, 3275163606); c = GG(c, d, a, b, x[k + 3], S23, 4107603335); b = GG(b, c, d, a, x[k + 8], S24, 1163531501); a = GG(a, b, c, d, x[k + 13], S21, 2850285829); d = GG(d, a, b, c, x[k + 2], S22, 4243563512); c = GG(c, d, a, b, x[k + 7], S23, 1735328473); b = GG(b, c, d, a, x[k + 12], S24, 2368359562); a = HH(a, b, c, d, x[k + 5], S31, 4294588738); d = HH(d, a, b, c, x[k + 8], S32, 2272392833); c = HH(c, d, a, b, x[k + 11], S33, 1839030562); b = HH(b, c, d, a, x[k + 14], S34, 4259657740); a = HH(a, b, c, d, x[k + 1], S31, 2763975236); d = HH(d, a, b, c, x[k + 4], S32, 1272893353); c = HH(c, d, a, b, x[k + 7], S33, 4139469664); b = HH(b, c, d, a, x[k + 10], S34, 3200236656); a = HH(a, b, c, d, x[k + 13], S31, 681279174); d = HH(d, a, b, c, x[k + 0], S32, 3936430074); c = HH(c, d, a, b, x[k + 3], S33, 3572445317); b = HH(b, c, d, a, x[k + 6], S34, 76029189); a = HH(a, b, c, d, x[k + 9], S31, 3654602809); d = HH(d, a, b, c, x[k + 12], S32, 3873151461); c = HH(c, d, a, b, x[k + 15], S33, 530742520); b = HH(b, c, d, a, x[k + 2], S34, 3299628645); a = II(a, b, c, d, x[k + 0], S41, 4096336452); d = II(d, a, b, c, x[k + 7], S42, 1126891415); c = II(c, d, a, b, x[k + 14], S43, 2878612391); b = II(b, c, d, a, x[k + 5], S44, 4237533241); a = II(a, b, c, d, x[k + 12], S41, 1700485571); d = II(d, a, b, c, x[k + 3], S42, 2399980690); c = II(c, d, a, b, x[k + 10], S43, 4293915773); b = II(b, c, d, a, x[k + 1], S44, 2240044497); a = II(a, b, c, d, x[k + 8], S41, 1873313359); d = II(d, a, b, c, x[k + 15], S42, 4264355552); c = II(c, d, a, b, x[k + 6], S43, 2734768916); b = II(b, c, d, a, x[k + 13], S44, 1309151649); a = II(a, b, c, d, x[k + 4], S41, 4149444226); d = II(d, a, b, c, x[k + 11], S42, 3174756917); c = II(c, d, a, b, x[k + 2], S43, 718787259); b = II(b, c, d, a, x[k + 9], S44, 3951481745); a = addUnsigned(a, AA); b = addUnsigned(b, BB); c = addUnsigned(c, CC); d = addUnsigned(d, DD) } var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); return tempValue.toLowerCase() };
\ No newline at end of file
const SDKConfig = {
++ /dev/null
const SDKConfig = {
// 配置项目参数
appid: "wx8ccb2ef82e44df92", // 换openid
appName: "测试应用", // 应用名称
productCode: "b5488a667a66561aa97ce2a70137487e", // 产品code
productKey: "d0e3e7998c6b3b47dd9e42c3769edd2c", // 产品key,用于生成签名
appVersion: "产品版本号(cp)", // 产品版本号
offerid: "1450016203", // 支付
sdkVersion: "1.0.0", // SDK版本号,SDK接口需要
shareTitle: "鲸鱼游戏棒棒棒", // 分享标题
shareImageUrl: "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3903587193,374462562&fm=27&gp=0.jpg" //分享图片链接
// 结束
}
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?) {
this.printf("SDK START...", 0)
this.debug = config && config.debug ? config.debug : 0
this.sdkinit()
}
private debug: number // 1是测试模式,用于printf函数输出
private sdkinit() {
const that = this
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = SDKConfig.productCode
that.sdkParams.appid = SDKConfig.appid
that.sdkParams.version = SDKConfig.sdkVersion
const options = this.getOptionsInfo()
let queryObj = options.referrerInfo && options.referrerInfo.extraData && Object.keys(options.referrerInfo.extraData).length > 0 ? options.referrerInfo.extraData : {}
queryObj = that.deepCopy({}, options.query, queryObj)
that.printf("SDK -> p1:", 0)
that.printf(queryObj, 0)
that.ReportParams.from = queryObj.from || ''
that.ReportParams.tag = queryObj.tag || ''
that.ReportParams.fromOpenId = queryObj.fromId || ''
const p2 = this.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = this.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
that.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}, err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId() {
const that = this
this.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: SDKConfig.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkParams.session_key = res.data.session_key
that.sdkActive() // SDK激活
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val: number = 0
if (this.obj.initReady == 1) { // 已经激活成功
that.doAuthorize(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady', {
enumerable: true,
configurable: true,
get: function getter() { return val; },
set: function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if (newVal === val) { return; }
that.doAuthorize(LoginCallBack)
}
})
}
}
//用户授权操作
private doAuthorize(LoginCallBack) {
const that = this
// 用户授权
this.getUserInfo().then(res => {
if (res) { // 用户确认授权
that.doLogin(res, LoginCallBack)
} else {
console.log('用户取消授权。。。')
this.createUserInfoButton(LoginCallBack) // 创建用户授权按钮
}
}, err => {
console.log(err)
})
}
private doLogin(res, LoginCallBack) {
const that = this
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if (res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, that.getOptionsInfo(), userInfo, {
os: (that.ReportParams.system).split(' ')[0], // 返回系统类型IOS或者android
session_key: that.sdkParams.session_key // 返回session_key
})) // 将用户信息拼上平台用户信息返回
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = SDKConfig.offerid
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
console.log("订单返回---->", res)
if (res.code == 0) {
if (res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: SDKConfig.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: 'trial', //跳转到体验版
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
that.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money / 100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0)
// 调微信米大师支付接口
that.pay(that.MidasPaymentParams)
.then(() => { // 支付成功
this.printf("SDK -> 支付成功:", 0)
this.printf(res, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
}, err => { // 支付失败
this.printf("SDK -> 支付失败:", 0)
this.printf(err, 0)
})
} else { // 已有未完成订单,弹窗提示
const params = {
title: SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
that.showModal(params)
}
}
} else { // 输出订单失败消息
that.printf(res.msg, 1)
that.sdkAlert(res.msg)
}
}, err => { console.log(err) })
}
private getCoins(orderParams) { // 通知服务端扣费
this.printf("SDK -> 通知扣费:", 0)
this.printf(orderParams, 0)
this.sdkRequest(sdkPortLinks.pay, orderParams).then(res => {
this.printf("SDK -> 扣费成功:", 0)
})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
this.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
// 分享
public ShareApp(params?) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + params
}
return this.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return this.exitWechatApp()
}
// SDK上报接口
private sdkRequest(link: string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData(portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI: string, Params: any, Method = 'GET') {
return this.fetchUri(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
private printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level) {
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
this.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign(obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url = "";
for (let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + SDKConfig.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
public deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame', // 客户端类型
session_key: '' // 用户session_key
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: '1', // 米大师环境配置, 0:正式环境, 1:沙盒模式
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
// 定义wechat方法
private async getUserInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getUserInfo({
success: function (res) {
resolve(res);
},
fail: function (res) {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async login(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async getNetworkType(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getNetworkType({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async getSystemInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getSystemInfo({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async fetchUri(URI, DATA, METHOD): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
}).catch((error) => {
console.log(error)
})
}
private showModal(DATA) {
(wx as any).showModal(this.deepCopy({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
private async share(DATA): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).shareAppMessage(that.deepCopy(DATA, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete() { }
}))
})
}
private async pay(params): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).requestMidasPayment(that.deepCopy(params, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete: function () {
console.log("Rechare")
}
}))
})
}
private shareInit() {
(wx as any).showShareMenu({
withShareTicket: true,
success: () => { },
fail: () => { },
complete: () => { }
})
}
// 分享
public addShareEvent(CALLBACK, DATA?) {
const that = this;
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + DATA
};
(wx as any).onShareAppMessage(() => {
return that.deepCopy(ShareParams, CALLBACK)
})
that.shareInit()
}
private customer(params) {
(wx as any).openCustomerServiceConversation(params)
}
private navigateToMiniProgram(params) {
(wx as any).navigateToMiniProgram(params)
}
private showMsg(str) {
(wx as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
private async exitWechatApp(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).exitMiniProgram({
success: function (res) {
console.log('退出成功')
resolve(res)
},
fail: function (res) {
console.log('退出失败')
reject(res)
}
})
})
}
// 获取启动参数
public getOptionsInfo() {
const that = this
const options = (wx as any).getLaunchOptionsSync() || {}
if (!options.query && !options.referrerInfo && Object.keys(options.query).length == 0 && Object.keys(options.referrerInfo).length == 0) {
return options
} else {
const obj = {}
that.deepCopy(obj, options.query, options.referrerInfo.extraData) // 合并数据
return obj
}
}
private createUserInfoButton(LoginCallBack) {
const that = this
const w = (wx as any).getSystemInfoSync().windowWidth
const h = (wx as any).getSystemInfoSync().windowHeight
if ((wx as any).createUserInfoButton) { // 做兼容
const UserInfoButton = (wx as any).createUserInfoButton({ // 按钮样式
type: 'text',
text: ' ',
style: {
left: 0,
top: 0,
width: w,
height: h,
backgroundColor: 'rgba(0, 0, 0, 0)',
color: '#ffffff'
}
})
UserInfoButton.onTap(res => {
if (res.userInfo) { // 根据返回数据判断用户是否授权
that.doLogin(res, LoginCallBack) // 用户重新授权
UserInfoButton.destroy()
}
})
} else {
that.sdkAlert('微信版本过低,请升级客户端。')
}
}
}
// md5加密
const rotateLeft = (lValue, iShiftBits) => { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)) }; var addUnsigned = function (lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 2147483648); lY8 = (lY & 2147483648); lX4 = (lX & 1073741824); lY4 = (lY & 1073741824); lResult = (lX & 1073741823) + (lY & 1073741823); if (lX4 & lY4) { return (lResult ^ 2147483648 ^ lX8 ^ lY8) } if (lX4 | lY4) { if (lResult & 1073741824) { return (lResult ^ 3221225472 ^ lX8 ^ lY8) } else { return (lResult ^ 1073741824 ^ lX8 ^ lY8) } } else { return (lResult ^ lX8 ^ lY8) } }; var F = function (x, y, z) { return (x & y) | ((~x) & z) }; var G = function (x, y, z) { return (x & z) | (y & (~z)) }; var H = function (x, y, z) { return (x ^ y ^ z) }; var I = function (x, y, z) { return (y ^ (x | (~z))) }; var FF = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var GG = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var HH = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var II = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var convertToWordArray = function (string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWordsTempOne = lMessageLength + 8; var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64; var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++ } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (128 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray }; var wordToHex = function (lValue) { var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValueTemp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2) } return WordToHexValue }; var uTF8Encode = function (string) { string = string.replace(/\x0d\x0a/g, "\x0a"); var output = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { output += String.fromCharCode(c) } else { if ((c > 127) && (c < 2048)) { output += String.fromCharCode((c >> 6) | 192); output += String.fromCharCode((c & 63) | 128) } else { output += String.fromCharCode((c >> 12) | 224); output += String.fromCharCode(((c >> 6) & 63) | 128); output += String.fromCharCode((c & 63) | 128) } } } return output }; function md5(string) { var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = uTF8Encode(string); x = convertToWordArray(string); a = 1732584193; b = 4023233417; c = 2562383102; d = 271733878; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 3614090360); d = FF(d, a, b, c, x[k + 1], S12, 3905402710); c = FF(c, d, a, b, x[k + 2], S13, 606105819); b = FF(b, c, d, a, x[k + 3], S14, 3250441966); a = FF(a, b, c, d, x[k + 4], S11, 4118548399); d = FF(d, a, b, c, x[k + 5], S12, 1200080426); c = FF(c, d, a, b, x[k + 6], S13, 2821735955); b = FF(b, c, d, a, x[k + 7], S14, 4249261313); a = FF(a, b, c, d, x[k + 8], S11, 1770035416); d = FF(d, a, b, c, x[k + 9], S12, 2336552879); c = FF(c, d, a, b, x[k + 10], S13, 4294925233); b = FF(b, c, d, a, x[k + 11], S14, 2304563134); a = FF(a, b, c, d, x[k + 12], S11, 1804603682); d = FF(d, a, b, c, x[k + 13], S12, 4254626195); c = FF(c, d, a, b, x[k + 14], S13, 2792965006); b = FF(b, c, d, a, x[k + 15], S14, 1236535329); a = GG(a, b, c, d, x[k + 1], S21, 4129170786); d = GG(d, a, b, c, x[k + 6], S22, 3225465664); c = GG(c, d, a, b, x[k + 11], S23, 643717713); b = GG(b, c, d, a, x[k + 0], S24, 3921069994); a = GG(a, b, c, d, x[k + 5], S21, 3593408605); d = GG(d, a, b, c, x[k + 10], S22, 38016083); c = GG(c, d, a, b, x[k + 15], S23, 3634488961); b = GG(b, c, d, a, x[k + 4], S24, 3889429448); a = GG(a, b, c, d, x[k + 9], S21, 568446438); d = GG(d, a, b, c, x[k + 14], S22, 3275163606); c = GG(c, d, a, b, x[k + 3], S23, 4107603335); b = GG(b, c, d, a, x[k + 8], S24, 1163531501); a = GG(a, b, c, d, x[k + 13], S21, 2850285829); d = GG(d, a, b, c, x[k + 2], S22, 4243563512); c = GG(c, d, a, b, x[k + 7], S23, 1735328473); b = GG(b, c, d, a, x[k + 12], S24, 2368359562); a = HH(a, b, c, d, x[k + 5], S31, 4294588738); d = HH(d, a, b, c, x[k + 8], S32, 2272392833); c = HH(c, d, a, b, x[k + 11], S33, 1839030562); b = HH(b, c, d, a, x[k + 14], S34, 4259657740); a = HH(a, b, c, d, x[k + 1], S31, 2763975236); d = HH(d, a, b, c, x[k + 4], S32, 1272893353); c = HH(c, d, a, b, x[k + 7], S33, 4139469664); b = HH(b, c, d, a, x[k + 10], S34, 3200236656); a = HH(a, b, c, d, x[k + 13], S31, 681279174); d = HH(d, a, b, c, x[k + 0], S32, 3936430074); c = HH(c, d, a, b, x[k + 3], S33, 3572445317); b = HH(b, c, d, a, x[k + 6], S34, 76029189); a = HH(a, b, c, d, x[k + 9], S31, 3654602809); d = HH(d, a, b, c, x[k + 12], S32, 3873151461); c = HH(c, d, a, b, x[k + 15], S33, 530742520); b = HH(b, c, d, a, x[k + 2], S34, 3299628645); a = II(a, b, c, d, x[k + 0], S41, 4096336452); d = II(d, a, b, c, x[k + 7], S42, 1126891415); c = II(c, d, a, b, x[k + 14], S43, 2878612391); b = II(b, c, d, a, x[k + 5], S44, 4237533241); a = II(a, b, c, d, x[k + 12], S41, 1700485571); d = II(d, a, b, c, x[k + 3], S42, 2399980690); c = II(c, d, a, b, x[k + 10], S43, 4293915773); b = II(b, c, d, a, x[k + 1], S44, 2240044497); a = II(a, b, c, d, x[k + 8], S41, 1873313359); d = II(d, a, b, c, x[k + 15], S42, 4264355552); c = II(c, d, a, b, x[k + 6], S43, 2734768916); b = II(b, c, d, a, x[k + 13], S44, 1309151649); a = II(a, b, c, d, x[k + 4], S41, 4149444226); d = II(d, a, b, c, x[k + 11], S42, 3174756917); c = II(c, d, a, b, x[k + 2], S43, 718787259); b = II(b, c, d, a, x[k + 9], S44, 3951481745); a = addUnsigned(a, AA); b = addUnsigned(b, BB); c = addUnsigned(c, CC); d = addUnsigned(d, DD) } var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); return tempValue.toLowerCase() };
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?) {
this.printf("SDK START...", 0)
this.debug = config && config.debug ? config.debug : 0
this.sdkinit()
}
private debug: number // 1是测试模式,用于printf函数输出
private sdkinit() {
const that = this
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = SDKConfig.productCode
that.sdkParams.appid = SDKConfig.appid
that.sdkParams.version = SDKConfig.sdkVersion
const options = this.getOptionsInfo()
let queryObj = options.referrerInfo && options.referrerInfo.extraData && Object.keys(options.referrerInfo.extraData).length > 0 ? options.referrerInfo.extraData : {}
queryObj = that.deepCopy({}, options.query, queryObj)
that.printf("SDK -> p1:", 0)
that.printf(queryObj, 0)
that.ReportParams.from = queryObj.from || ''
that.ReportParams.tag = queryObj.tag || ''
that.ReportParams.fromOpenId = queryObj.fromId || ''
const p2 = this.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = this.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
that.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}, err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId() {
const that = this
this.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: SDKConfig.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkParams.session_key = res.data.session_key
that.sdkActive() // SDK激活
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val: number = 0
if (this.obj.initReady == 1) { // 已经激活成功
that.doAuthorize(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady', {
enumerable: true,
configurable: true,
get: function getter() { return val; },
set: function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if (newVal === val) { return; }
that.doAuthorize(LoginCallBack)
}
})
}
}
//用户授权操作
private doAuthorize(LoginCallBack) {
const that = this
// 用户授权
this.getUserInfo().then(res => {
if (res) { // 用户确认授权
that.doLogin(res, LoginCallBack)
} else {
console.log('用户取消授权。。。')
this.createUserInfoButton(LoginCallBack) // 创建用户授权按钮
}
}, err => {
console.log(err)
})
}
private doLogin(res, LoginCallBack) {
const that = this
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if (res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, that.getOptionsInfo(), userInfo, {
os: (that.ReportParams.system).split(' ')[0], // 返回系统类型IOS或者android
session_key: that.sdkParams.session_key // 返回session_key
})) // 将用户信息拼上平台用户信息返回
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = SDKConfig.offerid
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
console.log("订单返回---->", res)
if (res.code == 0) {
if (res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: SDKConfig.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: 'trial', //跳转到体验版
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
that.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money / 100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0)
// 调微信米大师支付接口
that.pay(that.MidasPaymentParams)
.then(() => { // 支付成功
this.printf("SDK -> 支付成功:", 0)
this.printf(res, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
}, err => { // 支付失败
this.printf("SDK -> 支付失败:", 0)
this.printf(err, 0)
})
} else { // 已有未完成订单,弹窗提示
const params = {
title: SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
that.showModal(params)
}
}
} else { // 输出订单失败消息
that.printf(res.msg, 1)
that.sdkAlert(res.msg)
}
}, err => { console.log(err) })
}
private getCoins(orderParams) { // 通知服务端扣费
this.printf("SDK -> 通知扣费:", 0)
this.printf(orderParams, 0)
this.sdkRequest(sdkPortLinks.pay, orderParams).then(res => {
this.printf("SDK -> 扣费成功:", 0)
})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
this.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
// 分享
public ShareApp(params?) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + params
}
return this.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return this.exitWechatApp()
}
// SDK上报接口
private sdkRequest(link: string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData(portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI: string, Params: any, Method = 'GET') {
return this.fetchUri(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
private printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level) {
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
this.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign(obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url = "";
for (let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + SDKConfig.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
public deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame', // 客户端类型
session_key: '' // 用户session_key
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: '1', // 米大师环境配置, 0:正式环境, 1:沙盒模式
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
// 定义wechat方法
private async getUserInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getUserInfo({
success: function (res) {
resolve(res);
},
fail: function (res) {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async login(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async getNetworkType(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getNetworkType({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async getSystemInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getSystemInfo({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async fetchUri(URI, DATA, METHOD): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
}).catch((error) => {
console.log(error)
})
}
private showModal(DATA) {
(wx as any).showModal(this.deepCopy({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
private async share(DATA): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).shareAppMessage(that.deepCopy(DATA, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete() { }
}))
})
}
private async pay(params): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).requestMidasPayment(that.deepCopy(params, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete: function () {
console.log("Rechare")
}
}))
})
}
private shareInit() {
(wx as any).showShareMenu({
withShareTicket: true,
success: () => { },
fail: () => { },
complete: () => { }
})
}
// 分享
public addShareEvent(CALLBACK, DATA?) {
const that = this;
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + DATA
};
(wx as any).onShareAppMessage(() => {
return that.deepCopy(ShareParams, CALLBACK)
})
that.shareInit()
}
private customer(params) {
(wx as any).openCustomerServiceConversation(params)
}
private navigateToMiniProgram(params) {
(wx as any).navigateToMiniProgram(params)
}
private showMsg(str) {
(wx as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
private async exitWechatApp(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).exitMiniProgram({
success: function (res) {
console.log('退出成功')
resolve(res)
},
fail: function (res) {
console.log('退出失败')
reject(res)
}
})
})
}
// 获取启动参数
public getOptionsInfo() {
const that = this
const options = (wx as any).getLaunchOptionsSync() || {}
if (!options.query && !options.referrerInfo && Object.keys(options.query).length == 0 && Object.keys(options.referrerInfo).length == 0) {
return options
} else {
const obj = options.referrerInfo && options.referrerInfo.extraData ? options.referrerInfo.extraData : {}
return that.deepCopy({}, options.query, obj) // 合并数据
}
}
private createUserInfoButton(LoginCallBack) {
const that = this
const w = (wx as any).getSystemInfoSync().windowWidth
const h = (wx as any).getSystemInfoSync().windowHeight
if ((wx as any).createUserInfoButton) { // 做兼容
const UserInfoButton = (wx as any).createUserInfoButton({ // 按钮样式
type: 'text',
text: ' ',
style: {
left: 0,
top: 0,
width: w,
height: h,
backgroundColor: 'rgba(0, 0, 0, 0)',
color: '#ffffff'
}
})
UserInfoButton.onTap(res => {
if (res.userInfo) { // 根据返回数据判断用户是否授权
that.doLogin(res, LoginCallBack) // 用户重新授权
UserInfoButton.destroy()
}
})
} else {
that.sdkAlert('微信版本过低,请升级客户端。')
}
}
}
// md5加密
const rotateLeft = (lValue, iShiftBits) => { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)) }; var addUnsigned = function (lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 2147483648); lY8 = (lY & 2147483648); lX4 = (lX & 1073741824); lY4 = (lY & 1073741824); lResult = (lX & 1073741823) + (lY & 1073741823); if (lX4 & lY4) { return (lResult ^ 2147483648 ^ lX8 ^ lY8) } if (lX4 | lY4) { if (lResult & 1073741824) { return (lResult ^ 3221225472 ^ lX8 ^ lY8) } else { return (lResult ^ 1073741824 ^ lX8 ^ lY8) } } else { return (lResult ^ lX8 ^ lY8) } }; var F = function (x, y, z) { return (x & y) | ((~x) & z) }; var G = function (x, y, z) { return (x & z) | (y & (~z)) }; var H = function (x, y, z) { return (x ^ y ^ z) }; var I = function (x, y, z) { return (y ^ (x | (~z))) }; var FF = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var GG = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var HH = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var II = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var convertToWordArray = function (string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWordsTempOne = lMessageLength + 8; var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64; var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++ } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (128 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray }; var wordToHex = function (lValue) { var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValueTemp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2) } return WordToHexValue }; var uTF8Encode = function (string) { string = string.replace(/\x0d\x0a/g, "\x0a"); var output = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { output += String.fromCharCode(c) } else { if ((c > 127) && (c < 2048)) { output += String.fromCharCode((c >> 6) | 192); output += String.fromCharCode((c & 63) | 128) } else { output += String.fromCharCode((c >> 12) | 224); output += String.fromCharCode(((c >> 6) & 63) | 128); output += String.fromCharCode((c & 63) | 128) } } } return output }; function md5(string) { var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = uTF8Encode(string); x = convertToWordArray(string); a = 1732584193; b = 4023233417; c = 2562383102; d = 271733878; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 3614090360); d = FF(d, a, b, c, x[k + 1], S12, 3905402710); c = FF(c, d, a, b, x[k + 2], S13, 606105819); b = FF(b, c, d, a, x[k + 3], S14, 3250441966); a = FF(a, b, c, d, x[k + 4], S11, 4118548399); d = FF(d, a, b, c, x[k + 5], S12, 1200080426); c = FF(c, d, a, b, x[k + 6], S13, 2821735955); b = FF(b, c, d, a, x[k + 7], S14, 4249261313); a = FF(a, b, c, d, x[k + 8], S11, 1770035416); d = FF(d, a, b, c, x[k + 9], S12, 2336552879); c = FF(c, d, a, b, x[k + 10], S13, 4294925233); b = FF(b, c, d, a, x[k + 11], S14, 2304563134); a = FF(a, b, c, d, x[k + 12], S11, 1804603682); d = FF(d, a, b, c, x[k + 13], S12, 4254626195); c = FF(c, d, a, b, x[k + 14], S13, 2792965006); b = FF(b, c, d, a, x[k + 15], S14, 1236535329); a = GG(a, b, c, d, x[k + 1], S21, 4129170786); d = GG(d, a, b, c, x[k + 6], S22, 3225465664); c = GG(c, d, a, b, x[k + 11], S23, 643717713); b = GG(b, c, d, a, x[k + 0], S24, 3921069994); a = GG(a, b, c, d, x[k + 5], S21, 3593408605); d = GG(d, a, b, c, x[k + 10], S22, 38016083); c = GG(c, d, a, b, x[k + 15], S23, 3634488961); b = GG(b, c, d, a, x[k + 4], S24, 3889429448); a = GG(a, b, c, d, x[k + 9], S21, 568446438); d = GG(d, a, b, c, x[k + 14], S22, 3275163606); c = GG(c, d, a, b, x[k + 3], S23, 4107603335); b = GG(b, c, d, a, x[k + 8], S24, 1163531501); a = GG(a, b, c, d, x[k + 13], S21, 2850285829); d = GG(d, a, b, c, x[k + 2], S22, 4243563512); c = GG(c, d, a, b, x[k + 7], S23, 1735328473); b = GG(b, c, d, a, x[k + 12], S24, 2368359562); a = HH(a, b, c, d, x[k + 5], S31, 4294588738); d = HH(d, a, b, c, x[k + 8], S32, 2272392833); c = HH(c, d, a, b, x[k + 11], S33, 1839030562); b = HH(b, c, d, a, x[k + 14], S34, 4259657740); a = HH(a, b, c, d, x[k + 1], S31, 2763975236); d = HH(d, a, b, c, x[k + 4], S32, 1272893353); c = HH(c, d, a, b, x[k + 7], S33, 4139469664); b = HH(b, c, d, a, x[k + 10], S34, 3200236656); a = HH(a, b, c, d, x[k + 13], S31, 681279174); d = HH(d, a, b, c, x[k + 0], S32, 3936430074); c = HH(c, d, a, b, x[k + 3], S33, 3572445317); b = HH(b, c, d, a, x[k + 6], S34, 76029189); a = HH(a, b, c, d, x[k + 9], S31, 3654602809); d = HH(d, a, b, c, x[k + 12], S32, 3873151461); c = HH(c, d, a, b, x[k + 15], S33, 530742520); b = HH(b, c, d, a, x[k + 2], S34, 3299628645); a = II(a, b, c, d, x[k + 0], S41, 4096336452); d = II(d, a, b, c, x[k + 7], S42, 1126891415); c = II(c, d, a, b, x[k + 14], S43, 2878612391); b = II(b, c, d, a, x[k + 5], S44, 4237533241); a = II(a, b, c, d, x[k + 12], S41, 1700485571); d = II(d, a, b, c, x[k + 3], S42, 2399980690); c = II(c, d, a, b, x[k + 10], S43, 4293915773); b = II(b, c, d, a, x[k + 1], S44, 2240044497); a = II(a, b, c, d, x[k + 8], S41, 1873313359); d = II(d, a, b, c, x[k + 15], S42, 4264355552); c = II(c, d, a, b, x[k + 6], S43, 2734768916); b = II(b, c, d, a, x[k + 13], S44, 1309151649); a = II(a, b, c, d, x[k + 4], S41, 4149444226); d = II(d, a, b, c, x[k + 11], S42, 3174756917); c = II(c, d, a, b, x[k + 2], S43, 718787259); b = II(b, c, d, a, x[k + 9], S44, 3951481745); a = addUnsigned(a, AA); b = addUnsigned(b, BB); c = addUnsigned(c, CC); d = addUnsigned(d, DD) } var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); return tempValue.toLowerCase() };
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?) {
this.printf("SDK START...", 0)
this.debug = config && config.debug ? config.debug : 0
this.sdkinit()
}
private debug: number // 1是测试模式,用于printf函数输出
private isPaying: boolean = false // 支付状态
private sdkinit() {
const that = this
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = SDKConfig.productCode
that.sdkParams.appid = SDKConfig.appid
that.sdkParams.version = SDKConfig.sdkVersion
const options = this.getOptionsInfo()
that.printf("SDK -> p1:", 0)
that.printf(options, 0)
that.ReportParams.from = options.from || ''
that.ReportParams.tag = options.tag || ''
that.ReportParams.fromOpenId = options.fromId || ''
const p2 = this.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = this.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
that.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}).catch(err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId() {
const that = this
this.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: SDKConfig.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkParams.session_key = res.data.session_key
that.sdkActive() // SDK激活
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val: number = 0
if (this.obj.initReady == 1) { // 已经激活成功
that.doAuthorize(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady', {
enumerable: true,
configurable: true,
get: function getter() { return val; },
set: function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if (newVal === val) { return; }
that.doAuthorize(LoginCallBack)
}
})
}
}
//用户授权操作
private doAuthorize(LoginCallBack) {
const that = this
// 用户授权
this.getUserInfo().then(res => {
if (res) { // 用户确认授权
that.doLogin(res, LoginCallBack)
} else {
console.log('用户取消授权。。。')
this.createUserInfoButton(LoginCallBack) // 创建用户授权按钮
}
}, err => {
console.log(err)
})
}
private doLogin(res, LoginCallBack) {
const that = this
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if (res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, userInfo, {
os: (that.ReportParams.system).split(' ')[0], // 返回系统类型IOS或者android
session_key: that.sdkParams.session_key // 返回session_key
})) // 将用户信息拼上平台用户信息返回
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = SDKConfig.offerid
//根据支付状态来判断是否发起订单请求
if (!that.isPaying) {
that.isPaying = true
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
that.isPaying = false
console.log("订单返回---->", res)
if (res.code == 0) {
if (res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: SDKConfig.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: 'trial', //跳转到体验版
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
that.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money / 100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0);
// 调微信米大师支付接口
(wx as any).requestMidasPayment(that.deepCopy({}, that.MidasPaymentParams, {
success: function (data) {
that.printf("SDK -> 支付成功:", 0)
that.printf(data, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
},
fail: function (err) {
that.printf("SDK -> 支付失败:", 0)
that.printf(err, 0)
}
}));
} else { // 已有未完成订单,弹窗提示
const params = {
title: SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
that.showModal(params)
}
}
} else { // 输出订单失败消息
that.printf(res.msg, 1)
that.sdkAlert(res.msg)
}
}, err => {
that.isPaying = false
console.log(err)
})
}
}
private getCoins(orderParams) { // 通知服务端扣费
this.printf("SDK -> 通知扣费:", 0)
this.printf(orderParams, 0)
this.sdkRequest(sdkPortLinks.pay, orderParams).then(res => {
this.printf("SDK -> 扣费成功:", 0)
})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
this.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
// 分享
public ShareApp(params?: string) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + params ? params : ''
}
return this.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return this.exitWechatApp()
}
// SDK上报接口
private sdkRequest(link: string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData(portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI: string, Params: any, Method = 'GET') {
return this.fetchUri(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
private printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level) {
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
this.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign(obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url = "";
for (let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + SDKConfig.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
public deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame', // 客户端类型
session_key: '' // 用户session_key
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: '0', // 米大师环境配置, 0:正式环境, 1:沙盒模式
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
// 定义wechat方法
private async getUserInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getUserInfo({
success: function (res) {
resolve(res);
},
fail: function (res) {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async login(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async getNetworkType(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getNetworkType({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async getSystemInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getSystemInfo({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async fetchUri(URI, DATA, METHOD): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
}).catch((error) => {
console.log(error)
})
}
private showModal(DATA) {
(wx as any).showModal(this.deepCopy({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
private async share(DATA): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).shareAppMessage(that.deepCopy(DATA, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete() { }
}))
}).catch((error) => {
console.log(error)
})
}
private shareInit() {
(wx as any).showShareMenu({
withShareTicket: true,
success: () => { },
fail: () => { },
complete: () => { }
})
}
// 分享
public addShareEvent(CALLBACK, DATA?) {
const that = this;
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + DATA
};
(wx as any).onShareAppMessage(() => {
return that.deepCopy(ShareParams, CALLBACK)
})
that.shareInit()
}
private customer(params) {
(wx as any).openCustomerServiceConversation(params)
}
private navigateToMiniProgram(params) {
(wx as any).navigateToMiniProgram(params)
}
private showMsg(str) {
(wx as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
private async exitWechatApp(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).exitMiniProgram({
success: function (res) {
console.log('退出成功')
resolve(res)
},
fail: function (res) {
console.log('退出失败')
reject(res)
}
})
}).catch((error) => {
console.log(error)
})
}
// 获取启动参数
public getOptionsInfo() {
const that = this
const options = (wx as any).getLaunchOptionsSync()
if (!options.query && !options.referrerInfo && Object.keys(options.query).length == 0 && Object.keys(options.referrerInfo).length == 0) {
return {}
} else {
if (options.query) {
console.log("From Query..")
return options.query
} else if (options.referrerInfo && options.referrerInfo.extraData) {
console.log("From ReferrerInfo..")
return options.referrerInfo.extraData
}
}
}
private createUserInfoButton(LoginCallBack) {
const that = this
const w = (wx as any).getSystemInfoSync().windowWidth
const h = (wx as any).getSystemInfoSync().windowHeight
if ((wx as any).createUserInfoButton) { // 做兼容
const UserInfoButton = (wx as any).createUserInfoButton({ // 按钮样式
type: 'text',
text: ' ',
style: {
left: 0,
top: 0,
width: w,
height: h,
backgroundColor: 'rgba(0, 0, 0, 0)',
color: '#ffffff'
}
})
UserInfoButton.onTap(res => {
if (res.userInfo) { // 根据返回数据判断用户是否授权
that.doLogin(res, LoginCallBack) // 用户重新授权
UserInfoButton.destroy()
}
})
} else {
that.sdkAlert('微信版本过低,请升级客户端。')
}
}
}
// md5加密
const rotateLeft = (lValue, iShiftBits) => { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)) }; var addUnsigned = function (lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 2147483648); lY8 = (lY & 2147483648); lX4 = (lX & 1073741824); lY4 = (lY & 1073741824); lResult = (lX & 1073741823) + (lY & 1073741823); if (lX4 & lY4) { return (lResult ^ 2147483648 ^ lX8 ^ lY8) } if (lX4 | lY4) { if (lResult & 1073741824) { return (lResult ^ 3221225472 ^ lX8 ^ lY8) } else { return (lResult ^ 1073741824 ^ lX8 ^ lY8) } } else { return (lResult ^ lX8 ^ lY8) } }; var F = function (x, y, z) { return (x & y) | ((~x) & z) }; var G = function (x, y, z) { return (x & z) | (y & (~z)) }; var H = function (x, y, z) { return (x ^ y ^ z) }; var I = function (x, y, z) { return (y ^ (x | (~z))) }; var FF = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var GG = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var HH = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var II = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var convertToWordArray = function (string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWordsTempOne = lMessageLength + 8; var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64; var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++ } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (128 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray }; var wordToHex = function (lValue) { var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValueTemp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2) } return WordToHexValue }; var uTF8Encode = function (string) { string = string.replace(/\x0d\x0a/g, "\x0a"); var output = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { output += String.fromCharCode(c) } else { if ((c > 127) && (c < 2048)) { output += String.fromCharCode((c >> 6) | 192); output += String.fromCharCode((c & 63) | 128) } else { output += String.fromCharCode((c >> 12) | 224); output += String.fromCharCode(((c >> 6) & 63) | 128); output += String.fromCharCode((c & 63) | 128) } } } return output }; function md5(string) { var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = uTF8Encode(string); x = convertToWordArray(string); a = 1732584193; b = 4023233417; c = 2562383102; d = 271733878; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 3614090360); d = FF(d, a, b, c, x[k + 1], S12, 3905402710); c = FF(c, d, a, b, x[k + 2], S13, 606105819); b = FF(b, c, d, a, x[k + 3], S14, 3250441966); a = FF(a, b, c, d, x[k + 4], S11, 4118548399); d = FF(d, a, b, c, x[k + 5], S12, 1200080426); c = FF(c, d, a, b, x[k + 6], S13, 2821735955); b = FF(b, c, d, a, x[k + 7], S14, 4249261313); a = FF(a, b, c, d, x[k + 8], S11, 1770035416); d = FF(d, a, b, c, x[k + 9], S12, 2336552879); c = FF(c, d, a, b, x[k + 10], S13, 4294925233); b = FF(b, c, d, a, x[k + 11], S14, 2304563134); a = FF(a, b, c, d, x[k + 12], S11, 1804603682); d = FF(d, a, b, c, x[k + 13], S12, 4254626195); c = FF(c, d, a, b, x[k + 14], S13, 2792965006); b = FF(b, c, d, a, x[k + 15], S14, 1236535329); a = GG(a, b, c, d, x[k + 1], S21, 4129170786); d = GG(d, a, b, c, x[k + 6], S22, 3225465664); c = GG(c, d, a, b, x[k + 11], S23, 643717713); b = GG(b, c, d, a, x[k + 0], S24, 3921069994); a = GG(a, b, c, d, x[k + 5], S21, 3593408605); d = GG(d, a, b, c, x[k + 10], S22, 38016083); c = GG(c, d, a, b, x[k + 15], S23, 3634488961); b = GG(b, c, d, a, x[k + 4], S24, 3889429448); a = GG(a, b, c, d, x[k + 9], S21, 568446438); d = GG(d, a, b, c, x[k + 14], S22, 3275163606); c = GG(c, d, a, b, x[k + 3], S23, 4107603335); b = GG(b, c, d, a, x[k + 8], S24, 1163531501); a = GG(a, b, c, d, x[k + 13], S21, 2850285829); d = GG(d, a, b, c, x[k + 2], S22, 4243563512); c = GG(c, d, a, b, x[k + 7], S23, 1735328473); b = GG(b, c, d, a, x[k + 12], S24, 2368359562); a = HH(a, b, c, d, x[k + 5], S31, 4294588738); d = HH(d, a, b, c, x[k + 8], S32, 2272392833); c = HH(c, d, a, b, x[k + 11], S33, 1839030562); b = HH(b, c, d, a, x[k + 14], S34, 4259657740); a = HH(a, b, c, d, x[k + 1], S31, 2763975236); d = HH(d, a, b, c, x[k + 4], S32, 1272893353); c = HH(c, d, a, b, x[k + 7], S33, 4139469664); b = HH(b, c, d, a, x[k + 10], S34, 3200236656); a = HH(a, b, c, d, x[k + 13], S31, 681279174); d = HH(d, a, b, c, x[k + 0], S32, 3936430074); c = HH(c, d, a, b, x[k + 3], S33, 3572445317); b = HH(b, c, d, a, x[k + 6], S34, 76029189); a = HH(a, b, c, d, x[k + 9], S31, 3654602809); d = HH(d, a, b, c, x[k + 12], S32, 3873151461); c = HH(c, d, a, b, x[k + 15], S33, 530742520); b = HH(b, c, d, a, x[k + 2], S34, 3299628645); a = II(a, b, c, d, x[k + 0], S41, 4096336452); d = II(d, a, b, c, x[k + 7], S42, 1126891415); c = II(c, d, a, b, x[k + 14], S43, 2878612391); b = II(b, c, d, a, x[k + 5], S44, 4237533241); a = II(a, b, c, d, x[k + 12], S41, 1700485571); d = II(d, a, b, c, x[k + 3], S42, 2399980690); c = II(c, d, a, b, x[k + 10], S43, 4293915773); b = II(b, c, d, a, x[k + 1], S44, 2240044497); a = II(a, b, c, d, x[k + 8], S41, 1873313359); d = II(d, a, b, c, x[k + 15], S42, 4264355552); c = II(c, d, a, b, x[k + 6], S43, 2734768916); b = II(b, c, d, a, x[k + 13], S44, 1309151649); a = II(a, b, c, d, x[k + 4], S41, 4149444226); d = II(d, a, b, c, x[k + 11], S42, 3174756917); c = II(c, d, a, b, x[k + 2], S43, 718787259); b = II(b, c, d, a, x[k + 9], S44, 3951481745); a = addUnsigned(a, AA); b = addUnsigned(b, BB); c = addUnsigned(c, CC); d = addUnsigned(d, DD) } var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); return tempValue.toLowerCase() };
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?) {
this.printf("SDK START...", 0)
this.debug = config && config.debug ? config.debug : 0
this.sdkinit()
}
private debug: number // 1是测试模式,用于printf函数输出
private isPaying: boolean = false // 支付状态
private sdkinit() {
const that = this
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = SDKConfig.productCode
that.sdkParams.appid = SDKConfig.appid
that.sdkParams.version = SDKConfig.sdkVersion
const options = this.getOptionsInfo()
that.printf("SDK -> p1:", 0)
that.printf(options, 0)
that.ReportParams.from = options.from || ''
that.ReportParams.tag = options.tag || ''
that.ReportParams.fromOpenId = options.fromOpenId || ''
const p2 = this.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = this.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
that.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}).catch(err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId() {
const that = this
this.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: SDKConfig.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkParams.session_key = res.data.session_key
that.sdkActive() // SDK激活
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val: number = 0
if (this.obj.initReady == 1) { // 已经激活成功
that.doAuthorize(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady', {
enumerable: true,
configurable: true,
get: function getter() { return val; },
set: function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if (newVal === val) { return; }
that.doAuthorize(LoginCallBack)
}
})
}
}
//用户授权操作
private doAuthorize(LoginCallBack) {
const that = this
// 用户授权
this.getUserInfo().then(res => {
if (res) { // 用户确认授权
that.doLogin(res, LoginCallBack)
} else {
console.log('用户取消授权。。。')
this.createUserInfoButton(LoginCallBack) // 创建用户授权按钮
}
}, err => {
console.log(err)
})
}
private doLogin(res, LoginCallBack) {
const that = this
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if (res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, userInfo, {
os: (that.ReportParams.system).split(' ')[0], // 返回系统类型IOS或者android
session_key: that.sdkParams.session_key // 返回session_key
})) // 将用户信息拼上平台用户信息返回
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = SDKConfig.offerid
//根据支付状态来判断是否发起订单请求
if (!that.isPaying) {
that.isPaying = true
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
that.isPaying = false
console.log("订单返回---->", res)
if (res.code == 0) {
if (res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: SDKConfig.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: 'trial', //跳转到体验版
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
that.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money / 100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0);
// 调微信米大师支付接口
(wx as any).requestMidasPayment(that.deepCopy({}, that.MidasPaymentParams, {
success: function (data) {
that.printf("SDK -> 支付成功:", 0)
that.printf(data, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
},
fail: function (err) {
that.printf("SDK -> 支付失败:", 0)
that.printf(err, 0)
}
}));
} else { // 已有未完成订单,弹窗提示
const params = {
title: SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
that.showModal(params)
}
}
} else { // 输出订单失败消息
that.printf(res.msg, 1)
that.sdkAlert(res.msg)
}
}, err => {
that.isPaying = false
console.log(err)
})
}
}
private getCoins(orderParams) { // 通知服务端扣费
this.printf("SDK -> 通知扣费:", 0)
this.printf(orderParams, 0)
this.sdkRequest(sdkPortLinks.pay, orderParams).then(res => {
this.printf("SDK -> 扣费成功:", 0)
})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
this.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
// 分享
public ShareApp(params?: string) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + params ? params : ''
}
return this.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return this.exitWechatApp()
}
// SDK上报接口
private sdkRequest(link: string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData(portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI: string, Params: any, Method = 'GET') {
return this.fetchUri(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
private printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level) {
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
this.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign(obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url = "";
for (let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + SDKConfig.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
public deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame', // 客户端类型
session_key: '' // 用户session_key
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: '0', // 米大师环境配置, 0:正式环境, 1:沙盒模式
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
// 定义wechat方法
private async getUserInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getUserInfo({
success: function (res) {
resolve(res);
},
fail: function (res) {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async login(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async getNetworkType(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getNetworkType({
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err)
}
})
}).catch((error) => {
console.error(error);
})
}
private async getSystemInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getSystemInfo({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async fetchUri(URI, DATA, METHOD): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
}).catch((error) => {
console.log(error)
})
}
private showModal(DATA) {
(wx as any).showModal(this.deepCopy({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
private async share(DATA): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).shareAppMessage(that.deepCopy(DATA, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete() { }
}))
}).catch((error) => {
console.log(error)
})
}
private shareInit() {
(wx as any).showShareMenu({
withShareTicket: true,
success: () => { },
fail: () => { },
complete: () => { }
})
}
// 分享
public addShareEvent(CALLBACK, DATA?: string) {
const that = this;
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + DATA ? DATA : ''
};
(wx as any).onShareAppMessage(() => {
return that.deepCopy(ShareParams, CALLBACK)
})
that.shareInit()
}
private customer(params) {
(wx as any).openCustomerServiceConversation(params)
}
private navigateToMiniProgram(params) {
(wx as any).navigateToMiniProgram(params)
}
private showMsg(str) {
(wx as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
private async exitWechatApp(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).exitMiniProgram({
success: function (res) {
console.log('退出成功')
resolve(res)
},
fail: function (res) {
console.log('退出失败')
reject(res)
}
})
}).catch((error) => {
console.log(error)
})
}
// 获取启动参数
public getOptionsInfo() {
const that = this
const options = (wx as any).getLaunchOptionsSync()
if (!options.query && !options.referrerInfo && Object.keys(options.query).length == 0 && Object.keys(options.referrerInfo).length == 0) {
return {}
} else {
if (options.query) {
console.log("From Query..")
return options.query
} else if (options.referrerInfo && options.referrerInfo.extraData) {
console.log("From ReferrerInfo..")
return options.referrerInfo.extraData
}
}
}
private createUserInfoButton(LoginCallBack) {
const that = this
const w = (wx as any).getSystemInfoSync().windowWidth
const h = (wx as any).getSystemInfoSync().windowHeight
if ((wx as any).createUserInfoButton) { // 做兼容
const UserInfoButton = (wx as any).createUserInfoButton({ // 按钮样式
type: 'text',
text: ' ',
style: {
left: 0,
top: 0,
width: w,
height: h,
backgroundColor: 'rgba(0, 0, 0, 0)',
color: '#ffffff'
}
})
UserInfoButton.onTap(res => {
if (res.userInfo) { // 根据返回数据判断用户是否授权
that.doLogin(res, LoginCallBack) // 用户重新授权
UserInfoButton.destroy()
}
})
} else {
that.sdkAlert('微信版本过低,请升级客户端。')
}
}
}
// md5加密
const rotateLeft = (lValue, iShiftBits) => { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)) }; var addUnsigned = function (lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 2147483648); lY8 = (lY & 2147483648); lX4 = (lX & 1073741824); lY4 = (lY & 1073741824); lResult = (lX & 1073741823) + (lY & 1073741823); if (lX4 & lY4) { return (lResult ^ 2147483648 ^ lX8 ^ lY8) } if (lX4 | lY4) { if (lResult & 1073741824) { return (lResult ^ 3221225472 ^ lX8 ^ lY8) } else { return (lResult ^ 1073741824 ^ lX8 ^ lY8) } } else { return (lResult ^ lX8 ^ lY8) } }; var F = function (x, y, z) { return (x & y) | ((~x) & z) }; var G = function (x, y, z) { return (x & z) | (y & (~z)) }; var H = function (x, y, z) { return (x ^ y ^ z) }; var I = function (x, y, z) { return (y ^ (x | (~z))) }; var FF = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var GG = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var HH = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var II = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var convertToWordArray = function (string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWordsTempOne = lMessageLength + 8; var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64; var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++ } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (128 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray }; var wordToHex = function (lValue) { var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValueTemp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2) } return WordToHexValue }; var uTF8Encode = function (string) { string = string.replace(/\x0d\x0a/g, "\x0a"); var output = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { output += String.fromCharCode(c) } else { if ((c > 127) && (c < 2048)) { output += String.fromCharCode((c >> 6) | 192); output += String.fromCharCode((c & 63) | 128) } else { output += String.fromCharCode((c >> 12) | 224); output += String.fromCharCode(((c >> 6) & 63) | 128); output += String.fromCharCode((c & 63) | 128) } } } return output }; function md5(string) { var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = uTF8Encode(string); x = convertToWordArray(string); a = 1732584193; b = 4023233417; c = 2562383102; d = 271733878; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 3614090360); d = FF(d, a, b, c, x[k + 1], S12, 3905402710); c = FF(c, d, a, b, x[k + 2], S13, 606105819); b = FF(b, c, d, a, x[k + 3], S14, 3250441966); a = FF(a, b, c, d, x[k + 4], S11, 4118548399); d = FF(d, a, b, c, x[k + 5], S12, 1200080426); c = FF(c, d, a, b, x[k + 6], S13, 2821735955); b = FF(b, c, d, a, x[k + 7], S14, 4249261313); a = FF(a, b, c, d, x[k + 8], S11, 1770035416); d = FF(d, a, b, c, x[k + 9], S12, 2336552879); c = FF(c, d, a, b, x[k + 10], S13, 4294925233); b = FF(b, c, d, a, x[k + 11], S14, 2304563134); a = FF(a, b, c, d, x[k + 12], S11, 1804603682); d = FF(d, a, b, c, x[k + 13], S12, 4254626195); c = FF(c, d, a, b, x[k + 14], S13, 2792965006); b = FF(b, c, d, a, x[k + 15], S14, 1236535329); a = GG(a, b, c, d, x[k + 1], S21, 4129170786); d = GG(d, a, b, c, x[k + 6], S22, 3225465664); c = GG(c, d, a, b, x[k + 11], S23, 643717713); b = GG(b, c, d, a, x[k + 0], S24, 3921069994); a = GG(a, b, c, d, x[k + 5], S21, 3593408605); d = GG(d, a, b, c, x[k + 10], S22, 38016083); c = GG(c, d, a, b, x[k + 15], S23, 3634488961); b = GG(b, c, d, a, x[k + 4], S24, 3889429448); a = GG(a, b, c, d, x[k + 9], S21, 568446438); d = GG(d, a, b, c, x[k + 14], S22, 3275163606); c = GG(c, d, a, b, x[k + 3], S23, 4107603335); b = GG(b, c, d, a, x[k + 8], S24, 1163531501); a = GG(a, b, c, d, x[k + 13], S21, 2850285829); d = GG(d, a, b, c, x[k + 2], S22, 4243563512); c = GG(c, d, a, b, x[k + 7], S23, 1735328473); b = GG(b, c, d, a, x[k + 12], S24, 2368359562); a = HH(a, b, c, d, x[k + 5], S31, 4294588738); d = HH(d, a, b, c, x[k + 8], S32, 2272392833); c = HH(c, d, a, b, x[k + 11], S33, 1839030562); b = HH(b, c, d, a, x[k + 14], S34, 4259657740); a = HH(a, b, c, d, x[k + 1], S31, 2763975236); d = HH(d, a, b, c, x[k + 4], S32, 1272893353); c = HH(c, d, a, b, x[k + 7], S33, 4139469664); b = HH(b, c, d, a, x[k + 10], S34, 3200236656); a = HH(a, b, c, d, x[k + 13], S31, 681279174); d = HH(d, a, b, c, x[k + 0], S32, 3936430074); c = HH(c, d, a, b, x[k + 3], S33, 3572445317); b = HH(b, c, d, a, x[k + 6], S34, 76029189); a = HH(a, b, c, d, x[k + 9], S31, 3654602809); d = HH(d, a, b, c, x[k + 12], S32, 3873151461); c = HH(c, d, a, b, x[k + 15], S33, 530742520); b = HH(b, c, d, a, x[k + 2], S34, 3299628645); a = II(a, b, c, d, x[k + 0], S41, 4096336452); d = II(d, a, b, c, x[k + 7], S42, 1126891415); c = II(c, d, a, b, x[k + 14], S43, 2878612391); b = II(b, c, d, a, x[k + 5], S44, 4237533241); a = II(a, b, c, d, x[k + 12], S41, 1700485571); d = II(d, a, b, c, x[k + 3], S42, 2399980690); c = II(c, d, a, b, x[k + 10], S43, 4293915773); b = II(b, c, d, a, x[k + 1], S44, 2240044497); a = II(a, b, c, d, x[k + 8], S41, 1873313359); d = II(d, a, b, c, x[k + 15], S42, 4264355552); c = II(c, d, a, b, x[k + 6], S43, 2734768916); b = II(b, c, d, a, x[k + 13], S44, 1309151649); a = II(a, b, c, d, x[k + 4], S41, 4149444226); d = II(d, a, b, c, x[k + 11], S42, 3174756917); c = II(c, d, a, b, x[k + 2], S43, 718787259); b = II(b, c, d, a, x[k + 9], S44, 3951481745); a = addUnsigned(a, AA); b = addUnsigned(b, BB); c = addUnsigned(c, CC); d = addUnsigned(d, DD) } var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); return tempValue.toLowerCase() };
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?) {
this.printf("SDK START...", 0)
this.debug = config && config.debug ? config.debug : 0
this.sdkinit()
}
private debug: number // 1是测试模式,用于printf函数输出
private sdkinit() {
const that = this
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = SDKConfig.productCode
that.sdkParams.appid = SDKConfig.appid
that.sdkParams.version = SDKConfig.sdkVersion
const options = this.getOptionsInfo()
that.printf("SDK -> p1:", 0)
that.printf(options, 0)
that.ReportParams.from = options.from || ''
that.ReportParams.tag = options.tag || ''
that.ReportParams.fromOpenId = options.fromOpenId || ''
const p2 = this.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = this.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
that.ReportParams.SDKVersion = res.SDKVersion
that.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}).catch(err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId() {
const that = this
this.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: SDKConfig.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkParams.session_key = res.data.session_key
that.sdkActive() // SDK激活
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val: number = 0
if (this.obj.initReady == 1) { // 已经激活成功
that.doAuthorize(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady', {
enumerable: true,
configurable: true,
get: function getter() { return val; },
set: function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if (newVal === val) { return; }
that.doAuthorize(LoginCallBack)
}
})
}
}
//用户授权操作
private doAuthorize(LoginCallBack) {
const that = this
// 用户授权
this.getUserInfo().then(res => {
if (res) { // 用户确认授权
that.doLogin(res, LoginCallBack)
} else {
console.log('用户取消授权。。。')
this.createUserInfoButton(LoginCallBack) // 创建用户授权按钮
}
}, err => {
console.log(err)
})
}
private doLogin(res, LoginCallBack) {
const that = this
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if (res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, userInfo, {
os: (that.ReportParams.system).split(' ')[0], // 返回系统类型IOS或者android
session_key: that.sdkParams.session_key // 返回session_key
})) // 将用户信息拼上平台用户信息返回
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = SDKConfig.offerid
that.LoadingOn();
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
console.log("订单返回---->", res)
if (res.code == 0) {
if (res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: SDKConfig.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: SDKConfig.navPayEnv, //跳转方式
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
that.LoadingOff();
that.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money / 100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0);
// 调微信米大师支付接口
(wx as any).requestMidasPayment(that.deepCopy({}, that.MidasPaymentParams, {
success: function (data) {
that.printf("SDK -> 支付成功:", 0)
that.printf(data, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
},
fail: function (err) {
that.printf("SDK -> 支付失败:", 0)
that.printf(err, 0)
}
}));
that.LoadingOff();
} else { // 已有未完成订单,弹窗提示
that.LoadingOff();
const params = {
title: SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
that.showModal(params)
}
}
} else { // 输出订单失败消息
that.LoadingOff();
const errmsg = res.msg || '支付失败..'
that.printf(res.msg, 1)
that.sdkAlert(errmsg)
}
}, err => {
that.LoadingOff();
console.log(err)
})
}
private getCoins(orderParams) { // 通知服务端扣费
this.printf("SDK -> 通知扣费:", 0)
this.printf(orderParams, 0)
this.sdkRequest(sdkPortLinks.pay, orderParams).then(res => {
this.printf("SDK -> 扣费成功:", 0)
})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
this.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
// 分享
public ShareApp(params?: string) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + params ? params : ''
}
return this.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return this.exitWechatApp()
}
// SDK上报接口
private sdkRequest(link: string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData(portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI: string, Params: any, Method = 'GET') {
return this.fetchUri(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
private printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level) {
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
this.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign(obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url = "";
for (let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + SDKConfig.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
public deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
SDKVersion: null, // 选填,微信客户端基础库版本
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame', // 客户端类型
session_key: '' // 用户session_key
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: SDKConfig.midasPayEnv, // 米大师环境
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
// 定义wechat方法
private async getUserInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getUserInfo({
success: function (res) {
resolve(res);
},
fail: function (res) {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async login(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
}).catch((error) => {
console.error(error);
})
}
private async getNetworkType(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getNetworkType({
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err)
}
})
}).catch((error) => {
console.error(error);
})
}
private async getSystemInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getSystemInfo({
success: (res) => {
resolve(res);
}
})
}).catch((error) => {
console.error(error);
})
}
private async fetchUri(URI, DATA, METHOD): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
}).catch((error) => {
console.log(error)
})
}
private showModal(DATA) {
(wx as any).showModal(this.deepCopy({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
private async share(DATA): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
(wx as any).shareAppMessage(that.deepCopy(DATA, {
success: function (res) {
resolve(res)
},
fail: function (res) {
reject(res)
},
complete() { }
}))
}).catch((error) => {
console.log(error)
})
}
private shareInit() {
(wx as any).showShareMenu({
withShareTicket: true,
success: () => { },
fail: () => { },
complete: () => { }
})
}
// 分享
public addShareEvent(CALLBACK, DATA?: string) {
const that = this;
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + DATA ? DATA : ''
};
(wx as any).onShareAppMessage(() => {
return that.deepCopy(ShareParams, CALLBACK)
})
that.shareInit()
}
private customer(params) {
(wx as any).openCustomerServiceConversation(params)
}
private navigateToMiniProgram(params) {
if(this.ReportParams.SDKVersion < '2.2') {
this.sdkAlert('微信版本不兼容,请升级..')
} else {
(wx as any).navigateToMiniProgram(params)
}
}
private showMsg(str) {
(wx as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
private async exitWechatApp(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).exitMiniProgram({
success: function (res) {
console.log('退出成功')
resolve(res)
},
fail: function (res) {
console.log('退出失败')
reject(res)
}
})
}).catch((error) => {
console.log(error)
})
}
// 获取启动参数
public getOptionsInfo() {
const that = this
const options = (wx as any).getLaunchOptionsSync()
if (!options.query && !options.referrerInfo && Object.keys(options.query).length == 0 && Object.keys(options.referrerInfo).length == 0) {
return {}
} else {
if (options.query) {
console.log("From Query..")
return options.query
} else if (options.referrerInfo && options.referrerInfo.extraData) {
console.log("From ReferrerInfo..")
return options.referrerInfo.extraData
}
}
}
private createUserInfoButton(LoginCallBack) {
const that = this
const w = (wx as any).getSystemInfoSync().windowWidth
const h = (wx as any).getSystemInfoSync().windowHeight
if ((wx as any).createUserInfoButton) { // 做兼容
const UserInfoButton = (wx as any).createUserInfoButton({ // 按钮样式
type: 'text',
text: ' ',
style: {
left: 0,
top: 0,
width: w,
height: h,
backgroundColor: 'rgba(0, 0, 0, 0)',
color: '#ffffff'
}
})
UserInfoButton.onTap(res => {
if (res.userInfo) { // 根据返回数据判断用户是否授权
that.doLogin(res, LoginCallBack) // 用户重新授权
UserInfoButton.destroy()
}
})
} else {
that.sdkAlert('微信版本不兼容,请升级..')
}
}
private LoadingOn() {
(wx as any).showLoading({
title: '请稍候..',
mask: true
})
}
private LoadingOff() {
(wx as any).hideLoading()
}
}
// md5加密
const rotateLeft = (lValue, iShiftBits) => { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)) }; var addUnsigned = function (lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 2147483648); lY8 = (lY & 2147483648); lX4 = (lX & 1073741824); lY4 = (lY & 1073741824); lResult = (lX & 1073741823) + (lY & 1073741823); if (lX4 & lY4) { return (lResult ^ 2147483648 ^ lX8 ^ lY8) } if (lX4 | lY4) { if (lResult & 1073741824) { return (lResult ^ 3221225472 ^ lX8 ^ lY8) } else { return (lResult ^ 1073741824 ^ lX8 ^ lY8) } } else { return (lResult ^ lX8 ^ lY8) } }; var F = function (x, y, z) { return (x & y) | ((~x) & z) }; var G = function (x, y, z) { return (x & z) | (y & (~z)) }; var H = function (x, y, z) { return (x ^ y ^ z) }; var I = function (x, y, z) { return (y ^ (x | (~z))) }; var FF = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var GG = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var HH = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var II = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var convertToWordArray = function (string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWordsTempOne = lMessageLength + 8; var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64; var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++ } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (128 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray }; var wordToHex = function (lValue) { var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValueTemp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2) } return WordToHexValue }; var uTF8Encode = function (string) { string = string.replace(/\x0d\x0a/g, "\x0a"); var output = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { output += String.fromCharCode(c) } else { if ((c > 127) && (c < 2048)) { output += String.fromCharCode((c >> 6) | 192); output += String.fromCharCode((c & 63) | 128) } else { output += String.fromCharCode((c >> 12) | 224); output += String.fromCharCode(((c >> 6) & 63) | 128); output += String.fromCharCode((c & 63) | 128) } } } return output }; function md5(string) { var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = uTF8Encode(string); x = convertToWordArray(string); a = 1732584193; b = 4023233417; c = 2562383102; d = 271733878; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 3614090360); d = FF(d, a, b, c, x[k + 1], S12, 3905402710); c = FF(c, d, a, b, x[k + 2], S13, 606105819); b = FF(b, c, d, a, x[k + 3], S14, 3250441966); a = FF(a, b, c, d, x[k + 4], S11, 4118548399); d = FF(d, a, b, c, x[k + 5], S12, 1200080426); c = FF(c, d, a, b, x[k + 6], S13, 2821735955); b = FF(b, c, d, a, x[k + 7], S14, 4249261313); a = FF(a, b, c, d, x[k + 8], S11, 1770035416); d = FF(d, a, b, c, x[k + 9], S12, 2336552879); c = FF(c, d, a, b, x[k + 10], S13, 4294925233); b = FF(b, c, d, a, x[k + 11], S14, 2304563134); a = FF(a, b, c, d, x[k + 12], S11, 1804603682); d = FF(d, a, b, c, x[k + 13], S12, 4254626195); c = FF(c, d, a, b, x[k + 14], S13, 2792965006); b = FF(b, c, d, a, x[k + 15], S14, 1236535329); a = GG(a, b, c, d, x[k + 1], S21, 4129170786); d = GG(d, a, b, c, x[k + 6], S22, 3225465664); c = GG(c, d, a, b, x[k + 11], S23, 643717713); b = GG(b, c, d, a, x[k + 0], S24, 3921069994); a = GG(a, b, c, d, x[k + 5], S21, 3593408605); d = GG(d, a, b, c, x[k + 10], S22, 38016083); c = GG(c, d, a, b, x[k + 15], S23, 3634488961); b = GG(b, c, d, a, x[k + 4], S24, 3889429448); a = GG(a, b, c, d, x[k + 9], S21, 568446438); d = GG(d, a, b, c, x[k + 14], S22, 3275163606); c = GG(c, d, a, b, x[k + 3], S23, 4107603335); b = GG(b, c, d, a, x[k + 8], S24, 1163531501); a = GG(a, b, c, d, x[k + 13], S21, 2850285829); d = GG(d, a, b, c, x[k + 2], S22, 4243563512); c = GG(c, d, a, b, x[k + 7], S23, 1735328473); b = GG(b, c, d, a, x[k + 12], S24, 2368359562); a = HH(a, b, c, d, x[k + 5], S31, 4294588738); d = HH(d, a, b, c, x[k + 8], S32, 2272392833); c = HH(c, d, a, b, x[k + 11], S33, 1839030562); b = HH(b, c, d, a, x[k + 14], S34, 4259657740); a = HH(a, b, c, d, x[k + 1], S31, 2763975236); d = HH(d, a, b, c, x[k + 4], S32, 1272893353); c = HH(c, d, a, b, x[k + 7], S33, 4139469664); b = HH(b, c, d, a, x[k + 10], S34, 3200236656); a = HH(a, b, c, d, x[k + 13], S31, 681279174); d = HH(d, a, b, c, x[k + 0], S32, 3936430074); c = HH(c, d, a, b, x[k + 3], S33, 3572445317); b = HH(b, c, d, a, x[k + 6], S34, 76029189); a = HH(a, b, c, d, x[k + 9], S31, 3654602809); d = HH(d, a, b, c, x[k + 12], S32, 3873151461); c = HH(c, d, a, b, x[k + 15], S33, 530742520); b = HH(b, c, d, a, x[k + 2], S34, 3299628645); a = II(a, b, c, d, x[k + 0], S41, 4096336452); d = II(d, a, b, c, x[k + 7], S42, 1126891415); c = II(c, d, a, b, x[k + 14], S43, 2878612391); b = II(b, c, d, a, x[k + 5], S44, 4237533241); a = II(a, b, c, d, x[k + 12], S41, 1700485571); d = II(d, a, b, c, x[k + 3], S42, 2399980690); c = II(c, d, a, b, x[k + 10], S43, 4293915773); b = II(b, c, d, a, x[k + 1], S44, 2240044497); a = II(a, b, c, d, x[k + 8], S41, 1873313359); d = II(d, a, b, c, x[k + 15], S42, 4264355552); c = II(c, d, a, b, x[k + 6], S43, 2734768916); b = II(b, c, d, a, x[k + 13], S44, 1309151649); a = II(a, b, c, d, x[k + 4], S41, 4149444226); d = II(d, a, b, c, x[k + 11], S42, 3174756917); c = II(c, d, a, b, x[k + 2], S43, 718787259); b = II(b, c, d, a, x[k + 9], S44, 3951481745); a = addUnsigned(a, AA); b = addUnsigned(b, BB); c = addUnsigned(c, CC); d = addUnsigned(d, DD) } var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); return tempValue.toLowerCase() };
\ No newline at end of file
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
++ /dev/null
const domain = 'https://account.jinsdk.com' // SDK上报的接口域名
const pay_domain = 'https://pay.jinsdk.com' // 支付接口域名
const report = 'https://s.jinsdk.com/weixinmp/api.php' // 数据上报接口域名
const sdkPortLinks = {
init: domain + '/weixin/access_token.php', // 获取openid
active: domain + '/appInit.php', // SDK初始化接口
login: domain + '/login.php', // SDK登录接口,获取用户平台信息
order: pay_domain + '/pay.php', //订单接口
pay: pay_domain + '/notify/midas/pay.php' //扣费接口
}
class WechatSDK {
constructor(config?) {
this.printf("SDK START...", 0)
this.debug = config && config.debug ? config.debug : 0
this.sdkinit()
}
private debug: number // 1是测试模式,用于printf函数输出
private sdkinit() {
const that = this
//配置默认参数
that.ReportParams.productCode = that.sdkParams.product_code = SDKConfig.productCode
that.sdkParams.appid = SDKConfig.appid
that.sdkParams.version = SDKConfig.sdkVersion
const options = this.getOptionsInfo()
that.printf("SDK -> p1:", 0)
that.printf(options, 0)
that.ReportParams.from = options.from || ''
that.ReportParams.tag = options.tag || ''
that.ReportParams.fromOpenId = options.fromOpenId || ''
const p2 = this.getNetworkType().then(res => {
that.printf("SDK -> p2:", 0)
that.printf(res, 0)
that.ReportParams.networkType = res.networkType
}, err => { console.log(err) })
const p3 = this.getSystemInfo().then(res => {
that.printf("SDK -> p3:", 0)
that.printf(res, 0)
that.ReportParams.model = that.sdkParams.equipmentname = res.model
that.ReportParams.screenWidth = res.screenWidth
that.ReportParams.screenHeight = res.screenHeight
that.ReportParams.language = res.language
that.ReportParams.system = that.sdkParams.equipmentos = res.system
that.ReportParams.version = res.version
that.ReportParams.SDKVersion = res.SDKVersion
that.sdkParams.os = (res.system).split(' ')[0].toLowerCase()
}, err => { console.log(err) })
// 同步完所有参数后调用getUserOpenId
Promise.all([p2, p3]).then(res => {
console.log("队列结束....")
that.getUserOpenId()
}).catch(err => { console.log(err) })
}
// 微信登录获取code,用code激活SDK换取openid
private getUserOpenId() {
const that = this
this.login().then(res => {
that.printf("SDK -> wechat login:", 0)
that.printf(res, 0)
const data = that.deepCopy({}, that.sdkParams, { // 拼上appid和code
appid: SDKConfig.appid,
code: res.code
})
that.sdkRequest(sdkPortLinks.init, data).then(res => {
if (res.code == 0) {
that.ReportParams.openId = that.sdkParams.open_id = that.sdkParams.uniqueid = res.data.openid
that.sdkParams.session_key = res.data.session_key
that.sdkActive() // SDK激活
} else {
that.printf(res.msg, 1)
}
}, err => { console.log(err) })
}, err => { console.log(err) })
}
// SDK激活
private sdkActive() {
var that = this
this.printf("SDK -> 激活:", 0)
this.printf(this.sdkParams, 0)
this.sdkRequest(sdkPortLinks.active, this.sdkParams).then(res => {
that.sdkParams.pay_channel = res.data.default_pay_channel
that.obj.initReady = 1 // 改变obj对象initReady状态
that.ReportData({ // 上报统计授权
action: 'activation'
})
}, err => { console.log(err) })
}
private obj = { initReady: 0 }
// 用户登陆接口,返回用户平台信息
public Login(LoginCallBack) {
const that = this
let val: number = 0
if (this.obj.initReady == 1) { // 已经激活成功
that.doAuthorize(LoginCallBack)
} else { // 监听SDK激活,等激活完成之后才执行登录操作
Object.defineProperty(that.obj, 'initReady', {
enumerable: true,
configurable: true,
get: function getter() { return val; },
set: function setter(newVal) {
//如果新设置的值跟之前的值是相等的,则不需要
if (newVal === val) { return; }
that.doAuthorize(LoginCallBack)
}
})
}
}
//用户授权操作
private doAuthorize(LoginCallBack) {
const that = this
// 用户授权
this.getUserInfo().then(res => {
if (res) { // 用户确认授权
that.doLogin(res, LoginCallBack)
} else {
console.log('用户取消授权。。。')
this.createUserInfoButton(LoginCallBack) // 创建用户授权按钮
}
}, err => {
console.log(err)
})
}
private doLogin(res, LoginCallBack) {
const that = this
// 获取用户信息
const userInfo = res
const UserObj = {
action: 'authorize',
nickName: encodeURI(res.userInfo.nickName), // 避免表情昵称
city: res.userInfo.city,
country: res.userInfo.country,
avatarUrl: res.userInfo.avatarUrl,
gender: res.userInfo.gender,
province: res.userInfo.province,
}
// 上报用户授权
that.ReportData(UserObj)
that.sdkParams.token = '' // 强制清空登录toekn
that.sdkRequest(sdkPortLinks.login, that.deepCopy({}, that.sdkParams, { nickname: UserObj.nickName }))
.then(res => {
if (res.code == 0) {
// 根据SDK返回用户状态来判断统计接口是走注册还是登录
const type = res.data.action == 'login' ? 'login' : 'register'
that.sdkParams.token = res.data.token // 记录用户toekn
that.ReportParams.userId = res.data.uid // 记录用户ID
that.ReportData({ action: type }) // 上报登录/注册
LoginCallBack(that.deepCopy({}, res.data, userInfo, {
os: (that.ReportParams.system).split(' ')[0], // 返回系统类型IOS或者android
session_key: that.sdkParams.session_key // 返回session_key
})) // 将用户信息拼上平台用户信息返回
} else that.printf("Login: " + res.msg, 1)
}, err => { console.log(err) })
}
// SDK支付接口
public payOrder(Params) {
const that = this
that.MidasPaymentParams.offerId = SDKConfig.offerid
that.LoadingOn();
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
that.sdkRequest(sdkPortLinks.order, that.deepCopy({}, that.sdkParams, Params)).then(res => {
console.log("订单返回---->", res)
if (res.code == 0) {
if (res.data.weixin_mini_program_app_id) { // 跳小程序支付
const postParams = that.deepCopy({}, that.sdkParams, Params, {
weixin_mini_program_app_id: res.data.weixin_mini_program_app_id, // 跳转小程序的appid,获取新openid用
sub_product_code: res.data.sub_product_code, // 跳转小程序的productcode
pay_channel: res.data.pay_channel, // 支付方式改变
productKey: SDKConfig.productKey
}) // 合并后附上签名参数
const params = { // 跳转参数
appId: res.data.weixin_mini_program_app_id, // 跳转的小程序appid
path: '', // 跳转到首页
envVersion: SDKConfig.navPayEnv, //跳转方式
extraData: postParams,
success: () => { console.log("跳转成功") },
fail: () => { console.log("跳转失败") }
}
that.LoadingOff();
that.navigateToMiniProgram(params)
} else {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
that.MidasPaymentParams.buyQuantity = <number>(Params.money / 100) * <number>res.data.weixin_proportion // 充值金额
this.printf("SDK -> 发起支付参数:", 0)
this.printf(that.MidasPaymentParams, 0);
// 调微信米大师支付接口
(wx as any).requestMidasPayment(that.deepCopy({}, that.MidasPaymentParams, {
success: function (data) {
that.printf("SDK -> 支付成功:", 0)
that.printf(data, 0)
that.getCoins(that.deepCopy({}, that.sdkParams, { order_num: res.data.order_num }))
},
fail: function (err) {
that.printf("SDK -> 支付失败:", 0)
that.printf(err, 0)
}
}));
that.LoadingOff();
} else { // 已有未完成订单,弹窗提示
that.LoadingOff();
const params = {
title: SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
that.showModal(params)
}
}
} else { // 输出订单失败消息
that.LoadingOff();
const errmsg = res.msg || '支付失败..'
that.printf(res.msg, 1)
that.sdkAlert(errmsg)
}
}, err => {
that.LoadingOff();
console.log(err)
})
}
private getCoins(orderParams) { // 通知服务端扣费
this.printf("SDK -> 通知扣费:", 0)
this.printf(orderParams, 0)
this.sdkRequest(sdkPortLinks.pay, orderParams).then(res => {
this.printf("SDK -> 扣费成功:", 0)
})
}
// 客服
public Customer() {
const pparams = {} // 暂时留空,为以后H5充值准备
this.customer(pparams)
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
// 分享
public ShareApp(params?: string) {
const that = this
// 参数,记录分享的用户openid
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + (params ? params : '')
}
return this.share(ShareParams)
}
// 退出小游戏
public exitApp() {
return this.exitWechatApp()
}
// SDK上报接口
private sdkRequest(link: string, portData) {
this.md5_sign(portData) // 附上签名参数
this.printf("SDK -> 接口上报参数:" + link, 0)
this.printf(portData, 0)
return this.request(link, portData)
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData(portData) {
const that = this
portData = that.deepCopy({}, that.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
this.printf("SDK -> 数据上报:", 0)
this.printf(portData, 0)
this.request(report, portData, 'POST')
}
// 调用微信请求接口
private request(URI: string, Params: any, Method = 'GET') {
return this.fetchUri(URI, Params, Method).then(res => res.data)
}
/**
* 输出
* @param str 输出的字符串
* @param level 0:直接输出对象 1:输出错误信息 3:交由微信弹窗输出
* 当level:3时,obj需要包含 title:标题,content:内容
*/
private printf(obj: any, level: number = 3) {
if (this.debug == 1) {
switch (level) {
case 0:
console.log(obj)
break
case 1:
console.log('%cSDK错误:' + obj, 'color:red')
break
case 3:
this.showModal(obj)
break
}
}
}
//接口签名,直接返回完整对象
private md5_sign(obj) {
obj.time = Date.parse(new Date().toString()) // 获取请求的时间戳秒
let keys = Object.keys(obj).sort();
let key_url = "";
for (let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
key_url = key_url + SDKConfig.productKey
obj.sign = md5(key_url)
return obj
}
private isArray(arr) {
var toStr = Object.prototype.toString;
if (typeof Array.isArray === 'function') {
return Array.isArray(arr);
}
return toStr.call(arr) === '[object Array]';
}
private isPlainObject(obj) {
var toStr = Object.prototype.toString;
var hasOwn = Object.prototype.hasOwnProperty;
if (!obj || toStr.call(obj) !== '[object Object]') {
return false;
}
var hasOwnConstructor = hasOwn.call(obj, 'constructor');
var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
var key;
for (key in obj) { /**/ }
return typeof key === 'undefined' || hasOwn.call(obj, key);
}
// 数据深拷贝
public deepCopy(a, b, c?, d?, e?) {
const that = this
let options, name, src, copy, copyIsArray, clone;
let target = arguments[0];
let i = 1;
let length = arguments.length;
let deep = false;
if (typeof target === 'boolean') {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
target = {};
}
for (; i < length; ++i) {
options = arguments[i];
if (options != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target !== copy) {
if (deep && copy && (that.isPlainObject(copy) || (copyIsArray = that.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && that.isArray(src) ? src : [];
} else {
clone = src && that.isPlainObject(src) ? src : {};
}
target[name] = that.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,微信openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
model: null, // 必填,手机型号,微信api获取
system: null, // 必填,操作系统,微信api获取
networkType: null, // 选填,网络类型,微信api获取
language: null, // 选填,微信设置的语言,微信api获取
version: null, // 选填,微信版本号,微信api获取
SDKVersion: null, // 选填,微信客户端基础库版本
appVersion: null, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度,微信api获取
screenHeight: null, // 选填,屏幕高度,微信api获取
time: null // 必填,请求的时间戳(秒)
}
// SDK上报参数
private sdkParams = {
product_code: null, // 产品code
appid: null, // 小游戏appid
time: null, // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: null, // 用户openid
password: '', // 登录密码(微信免密)
source: 'WEIXIN', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: null, // 系统版本
equipmentname: null, // 手机型号
version: null, // SDK版本
package_code: '', // 渠道标识
sign: null, // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'weixin_minigame', // 客户端类型
session_key: '' // 用户session_key
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: SDKConfig.midasPayEnv, // 米大师环境
offerId: null, // 在米大师侧申请的应用id
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10, // buyQuantity * 游戏币单价 = 限定的价格等级(1,3,6,8,12,18,25,30,40,45,50,60,68,73,78,88,98,108,118,128,148,168,188,198,328,648)
zoneId: '1', // 分区ID,默认1
}
// 定义wechat方法
private async getUserInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getUserInfo({
success: function (res) {
resolve(res);
},
fail: function (res) {
reject(res)
}
})
})
}
private async login(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).login({
success: (res) => {
resolve(res)
},
fail: (res) => {
reject(res)
}
})
})
}
private async getNetworkType(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getNetworkType({
success: (res) => {
resolve(res);
},
fail: (err) => {
reject(err)
}
})
})
}
private async getSystemInfo(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).getSystemInfo({
success: (res) => {
resolve(res);
}
})
})
}
private async fetchUri(URI, DATA, METHOD): Promise<any> {
return new Promise((resolve, reject) => {
try {
(wx as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
} catch (err) {
reject(err)
}
})
}
private showModal(DATA) {
(wx as any).showModal(this.deepCopy({}, DATA, {
cancelText: '取消',
confirmText: '确认'
}))
}
private async share(DATA): Promise<any> {
const that = this
return new Promise((resolve, reject) => {
try {
(wx as any).shareAppMessage(that.deepCopy(DATA, {
withShareTicket: true,
success: res => {
resolve(res)
},
fail: res => {
reject(res)
},
complete() { }
}))
} catch (err) {
reject(err)
}
})
}
private shareInit() {
(wx as any).showShareMenu({
withShareTicket: 'true',
success: () => { },
fail: () => { },
complete: () => { }
})
}
// 分享
public addShareEvent(CALLBACK, DATA?: string) {
const that = this;
const ShareParams = {
title: SDKConfig.shareTitle,
imageUrl: SDKConfig.shareImageUrl,
query: 'fromOpenId=' + that.ReportParams.openId + '&from=share&tag=0&' + DATA ? DATA : ''
};
(wx as any).onShareAppMessage(() => {
return that.deepCopy(ShareParams, CALLBACK)
})
that.shareInit()
}
private customer(params) {
try {
(wx as any).openCustomerServiceConversation(params)
} catch (err) {
console.log("访问客服异常-->", err)
}
}
private navigateToMiniProgram(params) {
if (this.ReportParams.SDKVersion < '2.2') {
this.sdkAlert('微信版本不兼容,请升级..')
} else {
(wx as any).navigateToMiniProgram(params)
}
}
private showMsg(str) {
(wx as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
private async exitWechatApp(): Promise<any> {
return new Promise((resolve, reject) => {
(wx as any).exitMiniProgram({
success: function (res) {
console.log('退出成功')
resolve(res)
},
fail: function (res) {
console.log('退出失败')
reject(res)
}
})
})
}
// 获取启动参数
public getOptionsInfo() {
const that = this
const options = (wx as any).getLaunchOptionsSync()
if (!options.query && !options.referrerInfo && Object.keys(options.query).length == 0 && Object.keys(options.referrerInfo).length == 0) {
return {}
} else {
if (options.query) {
console.log("From Query..")
return options.query
} else if (options.referrerInfo && options.referrerInfo.extraData) {
console.log("From ReferrerInfo..")
return options.referrerInfo.extraData
}
}
}
private createUserInfoButton(LoginCallBack) {
const that = this
const w = (wx as any).getSystemInfoSync().windowWidth
const h = (wx as any).getSystemInfoSync().windowHeight
if ((wx as any).createUserInfoButton) { // 做兼容
const UserInfoButton = (wx as any).createUserInfoButton({ // 按钮样式
type: 'text',
text: ' ',
style: {
left: 0,
top: 0,
width: w,
height: h,
backgroundColor: 'rgba(0, 0, 0, 0)',
color: '#ffffff'
}
})
UserInfoButton.onTap(res => {
if (res.userInfo) { // 根据返回数据判断用户是否授权
that.doLogin(res, LoginCallBack) // 用户重新授权
UserInfoButton.destroy()
}
})
} else {
that.sdkAlert('微信版本不兼容,请升级..')
}
}
private LoadingOn() {
(wx as any).showLoading({
title: '请稍候..',
mask: true
})
}
private LoadingOff() {
(wx as any).hideLoading()
}
}
// md5加密
const rotateLeft = (lValue, iShiftBits) => { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)) }; var addUnsigned = function (lX, lY) { var lX4, lY4, lX8, lY8, lResult; lX8 = (lX & 2147483648); lY8 = (lY & 2147483648); lX4 = (lX & 1073741824); lY4 = (lY & 1073741824); lResult = (lX & 1073741823) + (lY & 1073741823); if (lX4 & lY4) { return (lResult ^ 2147483648 ^ lX8 ^ lY8) } if (lX4 | lY4) { if (lResult & 1073741824) { return (lResult ^ 3221225472 ^ lX8 ^ lY8) } else { return (lResult ^ 1073741824 ^ lX8 ^ lY8) } } else { return (lResult ^ lX8 ^ lY8) } }; var F = function (x, y, z) { return (x & y) | ((~x) & z) }; var G = function (x, y, z) { return (x & z) | (y & (~z)) }; var H = function (x, y, z) { return (x ^ y ^ z) }; var I = function (x, y, z) { return (y ^ (x | (~z))) }; var FF = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var GG = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var HH = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var II = function (a, b, c, d, x, s, ac) { a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac)); return addUnsigned(rotateLeft(a, s), b) }; var convertToWordArray = function (string) { var lWordCount; var lMessageLength = string.length; var lNumberOfWordsTempOne = lMessageLength + 8; var lNumberOfWordsTempTwo = (lNumberOfWordsTempOne - (lNumberOfWordsTempOne % 64)) / 64; var lNumberOfWords = (lNumberOfWordsTempTwo + 1) * 16; var lWordArray = Array(lNumberOfWords - 1); var lBytePosition = 0; var lByteCount = 0; while (lByteCount < lMessageLength) { lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); lByteCount++ } lWordCount = (lByteCount - (lByteCount % 4)) / 4; lBytePosition = (lByteCount % 4) * 8; lWordArray[lWordCount] = lWordArray[lWordCount] | (128 << lBytePosition); lWordArray[lNumberOfWords - 2] = lMessageLength << 3; lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; return lWordArray }; var wordToHex = function (lValue) { var WordToHexValue = "", WordToHexValueTemp = "", lByte, lCount; for (lCount = 0; lCount <= 3; lCount++) { lByte = (lValue >>> (lCount * 8)) & 255; WordToHexValueTemp = "0" + lByte.toString(16); WordToHexValue = WordToHexValue + WordToHexValueTemp.substr(WordToHexValueTemp.length - 2, 2) } return WordToHexValue }; var uTF8Encode = function (string) { string = string.replace(/\x0d\x0a/g, "\x0a"); var output = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { output += String.fromCharCode(c) } else { if ((c > 127) && (c < 2048)) { output += String.fromCharCode((c >> 6) | 192); output += String.fromCharCode((c & 63) | 128) } else { output += String.fromCharCode((c >> 12) | 224); output += String.fromCharCode(((c >> 6) & 63) | 128); output += String.fromCharCode((c & 63) | 128) } } } return output }; function md5(string) { var x = Array(); var k, AA, BB, CC, DD, a, b, c, d; var S11 = 7, S12 = 12, S13 = 17, S14 = 22; var S21 = 5, S22 = 9, S23 = 14, S24 = 20; var S31 = 4, S32 = 11, S33 = 16, S34 = 23; var S41 = 6, S42 = 10, S43 = 15, S44 = 21; string = uTF8Encode(string); x = convertToWordArray(string); a = 1732584193; b = 4023233417; c = 2562383102; d = 271733878; for (k = 0; k < x.length; k += 16) { AA = a; BB = b; CC = c; DD = d; a = FF(a, b, c, d, x[k + 0], S11, 3614090360); d = FF(d, a, b, c, x[k + 1], S12, 3905402710); c = FF(c, d, a, b, x[k + 2], S13, 606105819); b = FF(b, c, d, a, x[k + 3], S14, 3250441966); a = FF(a, b, c, d, x[k + 4], S11, 4118548399); d = FF(d, a, b, c, x[k + 5], S12, 1200080426); c = FF(c, d, a, b, x[k + 6], S13, 2821735955); b = FF(b, c, d, a, x[k + 7], S14, 4249261313); a = FF(a, b, c, d, x[k + 8], S11, 1770035416); d = FF(d, a, b, c, x[k + 9], S12, 2336552879); c = FF(c, d, a, b, x[k + 10], S13, 4294925233); b = FF(b, c, d, a, x[k + 11], S14, 2304563134); a = FF(a, b, c, d, x[k + 12], S11, 1804603682); d = FF(d, a, b, c, x[k + 13], S12, 4254626195); c = FF(c, d, a, b, x[k + 14], S13, 2792965006); b = FF(b, c, d, a, x[k + 15], S14, 1236535329); a = GG(a, b, c, d, x[k + 1], S21, 4129170786); d = GG(d, a, b, c, x[k + 6], S22, 3225465664); c = GG(c, d, a, b, x[k + 11], S23, 643717713); b = GG(b, c, d, a, x[k + 0], S24, 3921069994); a = GG(a, b, c, d, x[k + 5], S21, 3593408605); d = GG(d, a, b, c, x[k + 10], S22, 38016083); c = GG(c, d, a, b, x[k + 15], S23, 3634488961); b = GG(b, c, d, a, x[k + 4], S24, 3889429448); a = GG(a, b, c, d, x[k + 9], S21, 568446438); d = GG(d, a, b, c, x[k + 14], S22, 3275163606); c = GG(c, d, a, b, x[k + 3], S23, 4107603335); b = GG(b, c, d, a, x[k + 8], S24, 1163531501); a = GG(a, b, c, d, x[k + 13], S21, 2850285829); d = GG(d, a, b, c, x[k + 2], S22, 4243563512); c = GG(c, d, a, b, x[k + 7], S23, 1735328473); b = GG(b, c, d, a, x[k + 12], S24, 2368359562); a = HH(a, b, c, d, x[k + 5], S31, 4294588738); d = HH(d, a, b, c, x[k + 8], S32, 2272392833); c = HH(c, d, a, b, x[k + 11], S33, 1839030562); b = HH(b, c, d, a, x[k + 14], S34, 4259657740); a = HH(a, b, c, d, x[k + 1], S31, 2763975236); d = HH(d, a, b, c, x[k + 4], S32, 1272893353); c = HH(c, d, a, b, x[k + 7], S33, 4139469664); b = HH(b, c, d, a, x[k + 10], S34, 3200236656); a = HH(a, b, c, d, x[k + 13], S31, 681279174); d = HH(d, a, b, c, x[k + 0], S32, 3936430074); c = HH(c, d, a, b, x[k + 3], S33, 3572445317); b = HH(b, c, d, a, x[k + 6], S34, 76029189); a = HH(a, b, c, d, x[k + 9], S31, 3654602809); d = HH(d, a, b, c, x[k + 12], S32, 3873151461); c = HH(c, d, a, b, x[k + 15], S33, 530742520); b = HH(b, c, d, a, x[k + 2], S34, 3299628645); a = II(a, b, c, d, x[k + 0], S41, 4096336452); d = II(d, a, b, c, x[k + 7], S42, 1126891415); c = II(c, d, a, b, x[k + 14], S43, 2878612391); b = II(b, c, d, a, x[k + 5], S44, 4237533241); a = II(a, b, c, d, x[k + 12], S41, 1700485571); d = II(d, a, b, c, x[k + 3], S42, 2399980690); c = II(c, d, a, b, x[k + 10], S43, 4293915773); b = II(b, c, d, a, x[k + 1], S44, 2240044497); a = II(a, b, c, d, x[k + 8], S41, 1873313359); d = II(d, a, b, c, x[k + 15], S42, 4264355552); c = II(c, d, a, b, x[k + 6], S43, 2734768916); b = II(b, c, d, a, x[k + 13], S44, 1309151649); a = II(a, b, c, d, x[k + 4], S41, 4149444226); d = II(d, a, b, c, x[k + 11], S42, 3174756917); c = II(c, d, a, b, x[k + 2], S43, 718787259); b = II(b, c, d, a, x[k + 9], S44, 3951481745); a = addUnsigned(a, AA); b = addUnsigned(b, BB); c = addUnsigned(c, CC); d = addUnsigned(d, DD) } var tempValue = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d); return tempValue.toLowerCase() };
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论