提交 b67bbbc4 作者: wj

更新抖音SDK

上级 aa2b803b
/**
* 鲸鱼游戏头条小游戏接入库
* @author 推广技术部
* @time: 2019-09-25
*/
class TTSDK {
private sdkVersion: string = '1.2';
private isBind = 0; // 是否已经绑定过其他角色
public constructor() {
this.sdkInit();
this.timerInit();
}
private onlineTime: number = 0; // 在线时长(单位:分钟)
private timerInit() { // 用户在线时间
const _selt = this;
let loginTime = new Date().getTime(); // 登录时间
let offTime = (tt as any).getStorageSync('offlineTime'); // 离线前记录的时间点
let offlineTime = offTime ? ((loginTime - offTime) / (1000 * 60)).toFixed(2) : 0; // 离线时长(分钟)
if (offlineTime > 299) {
_selt.onlineTime = 0;
} else {
_selt.onlineTime = (tt as any).getStorageSync('onlineMinute') || 0;
}
setInterval(function () { // 每分钟记录一次
_selt.onlineTime++;
let curTime = new Date().getTime();
(tt as any).setStorageSync("onlineMinute", _selt.onlineTime);
(tt as any).setStorageSync("offlineTime", curTime);
}, 60000);
}
private async sdkInit() {
const _selt = this;
_selt.ReportParams.productCode = _selt.sdkParams.product_code = tt_SDKConfig.productCode;
_selt.sdkParams.appid = tt_SDKConfig.appid;
_selt.sdkParams.version = _selt.sdkVersion;
const options = _selt.getOptionsInfo(); // 返回参数对象
_selt.ReportParams.query = encodeURIComponent(JSON.stringify(options)) || '';
_selt.ReportParams.from = options.from || 0;
_selt.ReportParams.tag = options.tag || 0;
_selt.ReportParams.fromOpenId = options.fromOpenId || '';
_selt.ReportParams.adid = options.adid || '';
_selt.ReportParams.creativeid = options.creativeid || '';
_selt.ReportParams.creativetype = options.creativetype || '';
_selt.ReportParams.clickid = options.clickid || '';
await _selt.getNetworkType();
await _selt.getSystemInfo();
console.log("$$SDK初始化结束", _selt.ReportParams);
}
public async Login() {
const _selt = this;
const loginPromise = await _selt._login(false).catch(err => {
console.log("$$SDK登录异常::Login", err);
});
_selt.sdkParams.source = 'TOUTIAO';
let loginPostData = _selt.deepCopy({}, _selt.sdkParams, { // 拼上appid和code
anonymous_code: loginPromise.anonymousCode || '',
appid: tt_SDKConfig.appid,
code: loginPromise.code || ''
});
let sdkLoginData = await _selt.sdkRequest(ttLinks.init, loginPostData).catch(err => {
_selt.Login();
});
if (sdkLoginData.code == 0) {
_selt.sdkParams.open_id = sdkLoginData.data.openid || '';
_selt.ReportParams.openId = _selt.sdkParams.anonymous_openid = _selt.heartParams.uuid = sdkLoginData.data.anonymous_openid || ''; // 游客openid
_selt.sdkParams.session_key = sdkLoginData.data.session_key || '';
_selt.sdkParams.uniqueid = sdkLoginData.data.anonymous_openid;
}
return _selt.sdkActive();
}
// SDK激活
private async sdkActive() {
const _selt = this;
let sdkActData = await _selt.sdkRequest(ttLinks.active, this.sdkParams).catch(err => {
console.log("$$SDK激活异常:", err);
_selt.sdkAlert("$$SDK激活异常:" + err);
});
_selt.sdkParams.pay_channel = sdkActData.data.default_pay_channel;
_selt.ActiReport(); // 上报激活
return _selt.sdkLogin();
}
private async sdkLogin() {
const _selt = this
// 获取用户信息
_selt.sdkParams.token = '' // 强制清空登录token
let sdkLoginData = await _selt.sdkRequest(ttLinks.login, _selt.sdkParams).catch(err => {
console.log("$$SDK登陆异常:", err);
_selt.sdkAlert("$$SDK登陆异常:" + err);
});
if (sdkLoginData.code == 0) {
// 根据SDK返回用户状态来判断用户是否注册
_selt.sdkParams.token = sdkLoginData.data.token // 记录用户toekn
_selt.ReportParams.userId = _selt.heartParams.userid = sdkLoginData.data.uid // 记录用户ID
let LoginCallBack = _selt.deepCopy({}, sdkLoginData.data, {
os: _selt.sdkParams.os, // 返回系统类型IOS或者android
session_key: _selt.sdkParams.session_key, // 返回session_key
appName: _selt.ReportParams.appName
});
// _selt.createGameRecorder();
return LoginCallBack;
} else if (sdkLoginData.code == 182) { // 帐号下已经绑定其他角色
_selt.isBind = 1;
return sdkLoginData.msg;
}
}
public async payOrderStatus(Params) {
let payResult = await this.payOrder(Params, false);
return payResult;
}
private async checkUserLogin() {
return new Promise((resolve, reject) => {
(tt as any).checkSession({
success(res) {
resolve(0)
},
fail(res) {
resolve(-1);
}
});
});
}
// SDK支付接口
public async payOrder(Params, showSDKAlert = true) {
const _selt = this;
console.log("#_selt.isBind", _selt.isBind);
if (_selt.isBind == 1) {
const msg = {
title: '提示',
content: '所绑定账号在本服已存在角色,请重新绑定新账号',
showCancel: false
}
_selt.showModal(msg);
return false;
}
// 支付前先判断用户是否登录
const isLogin = await _selt.checkUserLogin();
if (isLogin == -1) {
const isGuest = await _selt.reLogin();
if (isGuest == 0) return false;
}
_selt.LoadingOn();
// 支付前先获取用户订单状态,如果没有未完成订单则继续支付
let res = await _selt.sdkRequest(ttLinks.order, _selt.deepCopy({}, _selt.sdkParams, Params)).catch(err => {
_selt.LoadingOff();
console.log("$$SDK异常::payOrder", err);
});
console.log("$$订单返回---->", res);
_selt.LoadingOff();
if (res.code == 0) {
// 根据返回的用户订单状态判断是新订单还是未完成订单
if (res.data.order_type == 1) { // 新订单
_selt.MidasPaymentParams.buyQuantity = <number>(Params.money / 100) * <number>res.data.platform_payment_proportion // 充值金额
console.log("$$SDK -> 发起支付参数:", _selt.MidasPaymentParams);
return new Promise((resolve, reject) => {
(tt as any).requestGamePayment(_selt.deepCopy({}, _selt.MidasPaymentParams, {
success: async function (data) {
console.log("$$SDK -> 支付成功:", data);
let coinsResult = await _selt.getCoins(_selt.deepCopy({}, _selt.sdkParams, { order_num: res.data.order_num }));
if (coinsResult.code == 0 || coinsResult.code == 3012) {
resolve(200);
}
else {
resolve(0);
}
},
fail: function (err) {
var msg = '';
switch (err.errCode) {
case -1:
msg = '支付失败';
break;
case -2:
msg = '支付取消';
break;
case -15001:
msg = '缺少参数';
break;
case -15002:
msg = '请求参数不合法';
break;
case -15006:
msg = 'app没有支付权限';
break;
case -15009:
msg = ' 财经方失败';
break;
case -16000:
msg = '用户未登录';
break;
case 2:
msg = '重复发起支付请求';
break;
case 3:
msg = '调起收银台失败';
break;
case 4:
msg = '网络异常';
break;
case 6:
msg = '其他错误';
break;
}
if (showSDKAlert && msg != '') _selt.sdkAlert(msg);
resolve(err.errCode);
}
}));
});
} else { // 已有未完成订单,弹窗提示
const params = {
title: tt_SDKConfig.shareTitle,
content: '订单发货中,请稍候下单..'
}
_selt.showModal(params);
}
} else if (res.code == 3023) {
const params = {
title: '支付提示',
content: res.msg
}
_selt.showModal(params);
return 3023;
} else { // 输出订单失败消息
const errmsg = res.msg || '支付失败..'
if (showSDKAlert) _selt.sdkAlert(errmsg);
return 0;
}
}
private async getCoins(orderParams) { // 通知服务端扣费
console.log("$$SDK通知扣费", orderParams);
let coinsResult = await this.sdkRequest(ttLinks.pay, orderParams).catch(err => {
console.log("$$SDK异常::getCoins", err);
});
return coinsResult;
}
public async checkUserPhoneBind() { // 查询用户绑定状态
const _selt = this;
let postData = _selt.deepCopy({}, _selt.sdkParams, { uid: _selt.ReportParams.userId });
let bindType = await _selt.sdkRequest(ttLinks.bindPhone, postData);
return (bindType.code == 0);
}
public async phoneCode(phoneInfo, callback) {
const _selt = this;
let postData = this.deepCopy({}, _selt.sdkParams, phoneInfo);
postData.type = 'SDK.BIND_MOBILE'; // 小程序专属短信类型
// 发送验证码接口
let res = await this.sdkRequest(ttLinks.sendCode, postData).catch(err => {
console.log("$$SDK::验证码发送失败", err);
_selt.sdkAlert("发送失败,请重试..");
});
if (res.code == 0) {
callback(true);
} else {
callback(false);
}
}
public async userPhone(phoneInfo, callback) {
const _selt = this;
let postData = this.deepCopy({}, _selt.sdkParams, phoneInfo);
postData.source = 'TOUTIAO'; // 用户平台来源
//保存用户手机信息
let res = await this.sdkRequest(ttLinks.saveNum, postData).catch(err => {
console.log("$$SDK::保存手机失败", err);
});
if (res.code == 0) {
callback(true);
} else {
console.log("$$绑定失败::", res.msg);
callback(false);
}
}
public async checkUserAdvised() { // 防沉迷验证
const _selt = this;
let time = _selt.onlineTime * 60; // 转成成秒
return time;
}
// 米大师支付参数
private MidasPaymentParams = {
mode: 'game', // 支付的类型
env: tt_SDKConfig.payEnv, // 米大师环境
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)
}
//把字符串转换成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 + tt_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 _self = 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 && (_self.isPlainObject(copy) || (copyIsArray = _self.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && _self.isArray(src) ? src : [];
} else {
clone = src && _self.isPlainObject(src) ? src : {};
}
target[name] = _self.deepCopy(deep, clone, copy);
} else if (typeof copy !== 'undefined') {
target[name] = copy;
}
}
}
}
}
return target
}
// 获取启动参数
public getOptionsInfo() {
const _selt = this
const options = (tt as any).getLaunchOptionsSync();
let obj;
if (options.query && Object.keys(options.query).length > 0) {
if (options.query.scene && options.query.scene != '') { // 扫码参数
obj = _selt.toJson(decodeURIComponent(options.query.scene));
} else obj = options.query // 普通url参数
} else if (options.referrerInfo && Object.keys(options.referrerInfo).length > 0 && options.referrerInfo.extraData && Object.keys(options.referrerInfo.extraData).length > 0) {
obj = options.referrerInfo.extraData // 小程序跳转附带参数
} else {
obj = {}
}
const a = obj.adid || '';
const b = obj.creativeid || '';
if (a != '' && a != '__AID__' && b != '' && b != '__CID__') {
obj.from = 'toutiaoxyx001';
}
console.log("$$启动参数--->", obj);
return obj;
}
public getLaunchOptions() {
return (tt as any).getLaunchOptionsSync();
}
private async getNetworkType() {
const _selt = this;
await (tt as any).getNetworkType({
success: (res) => {
_selt.ReportParams.networkType = _selt.heartParams.info.network = res.networkType
},
fail: (err) => {
console.log("$$SDK错误->getNetworkType", err)
}
})
}
private async getSystemInfo() {
const _selt = this;
await (tt as any).getSystemInfo({
success: (res) => {
_selt.ReportParams.model = _selt.sdkParams.equipmentname = _selt.heartParams.info.model = res.model
_selt.ReportParams.screenWidth = res.screenWidth
_selt.ReportParams.screenHeight = res.screenHeight
_selt.heartParams.resolution = res.screenWidth + '*' + res.screenHeight
_selt.ReportParams.language = _selt.heartParams.language = res.language
_selt.ReportParams.system = _selt.sdkParams.equipmentos = res.system
_selt.ReportParams.version = res.version
_selt.ReportParams.SDKVersion = res.SDKVersion
_selt.ReportParams.appName = res.appName
_selt.sdkParams.os = _selt.heartParams.osname = (res.system).split(' ')[0].toLowerCase()
}
})
}
private async reLogin() {
const _selt = this;
const loginPromise = await _selt._login(true).catch(err => {
console.log("$$SDK登录异常::Login", err);
});
if (loginPromise == -1) return false; // 用户取消登录
let loginPostData = _selt.deepCopy({}, _selt.sdkParams, { // 拼上appid和code
anonymous_code: loginPromise.anonymousCode || '',
appid: tt_SDKConfig.appid,
code: loginPromise.code || ''
});
let sdkLoginData = await _selt.sdkRequest(ttLinks.init, loginPostData).catch(err => {
_selt.reLogin();
});
if (sdkLoginData.code == 0) {
_selt.sdkParams.open_id = sdkLoginData.data.openid || '';
_selt.ReportParams.openId = _selt.sdkParams.anonymous_openid = sdkLoginData.data.anonymous_openid || ''; // 游客openid
_selt.sdkParams.session_key = sdkLoginData.data.session_key || '';
_selt.sdkParams.uniqueid = sdkLoginData.data.anonymous_openid;
_selt.sdkParams.type = 'bind'
}
const res = await _selt.sdkLogin();
console.log("#res", res);
if (res && res != '') {
_selt.sdkAlert(res);
return 0;
} else {
return -1;
}
}
private _login(showLoginView: boolean): Promise<any> {
return new Promise((resolve, reject) => {
try {
(tt as any).login({
success: (res) => {
resolve(res);
},
fail: (res) => {
resolve(-1);
},
force: showLoginView // 不强制调起登录框
});
} catch (err) { }
});
}
// 退出小游戏
public async exitApp(): Promise<any> {
return new Promise((resolve, reject) => {
(tt as any).exitMiniProgram({
success: (res) => {
console.log('退出成功')
resolve(res)
},
fail: (res) => {
console.log('退出失败')
reject(res)
}
})
})
}
// SDK上报接口
private sdkRequest(link: string, portData, method?) {
this.md5_sign(portData) // 附上签名参数
console.log("##SDK激活上报参数", portData)
return this.request(link, portData, method).catch(err => {
console.log(err);
});
}
// 上报心跳
private heartBeat() {
const _selt = this;
const obj = this.heartParams;
const tmp = Date.parse(new Date().toString()).toString() // 获取请求的时间戳秒
obj.time = obj.gentime = tmp.substr(0, 10);
let keys = Object.keys(obj).sort();
let key_url = "";
for (let i = 0; i < keys.length; i++) {
if (keys[i] != 'sign' && keys[i] != 'info' && keys[i] != 'content') key_url += keys[i] + '=' + obj[keys[i]] + '&'
}
obj.sign = md5(key_url + 'BA886FF52827126DCD18E73E0E16420C')
this.request(ttLinks.heartReport, obj, 'POST');
setTimeout(function () {
_selt.heartBeat();
}, 60000);
}
// 上报激活
public ActiReport() {
this.ReportData({ action: 'activation' });
this.heartBeat();
}
// 上报注册
public RegisterReport() {
this.ReportData({ action: 'register' });
}
// 上报登录
public LoginReport() {
this.ReportData({ action: 'login' })
}
// 上报等级
public RoleLevelReport(roleInfo) {
var reportData = this.deepCopy(roleInfo, { action: 'roleUpgrade' });
this.ReportData(reportData);
}
// 自定义上报
public CustomReport(custInfo) {
var reportData = this.deepCopy(custInfo, { action: 'customevent' });
this.ReportData(reportData);
}
// 数据上报接口,外部调用,参数中必须含有action值
public ReportData(portData) {
const _self = this
portData = _self.deepCopy({}, _self.ReportParams, portData)
portData.time = Date.parse(new Date().toString()) // 获取当前时间戳秒
console.log("##SDK统计上报参数", portData)
this.request(tt_SDKConfig.report, portData, 'POST').catch(err => {
console.log("$$SDK上报数据异常", err);
});
}
// 通用请求接口
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 {
(tt as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
'Content-Type': 'json'
},
success: resolve,
fail: reject
})
} catch (err) {
reject(err)
}
})
}
// 头条必接录屏功能
private GameRecorder: any
private videoPath: string
// 创建录屏对象
public createGameRecorder(startEventCallBack?, stopEventCallBack?) {
const _self = this;
try {
this.GameRecorder = (tt as any).getGameRecorderManager();
this.GameRecorder.onStart(res => {
console.log("$$开始录屏::麦克风状态", res);
if (startEventCallBack) startEventCallBack();
});
this.GameRecorder.onStop(res => {
console.log("$$结束录屏::视频路径", res);
if (res) _self.videoPath = res.videoPath;
if (stopEventCallBack) stopEventCallBack();
})
} catch (err) {
console.log("$$SDK录屏异常::gameRecorder", err);
}
}
public startGameRecorder(recorderInfo: ttRecorderInfo) {
try {
this.GameRecorder.start({
duration: recorderInfo.time,
microphoneEnabled: recorderInfo.useMic
});
} catch (err) {
console.log("$$SDK录屏异常::gameRecorder", err);
}
}
public stopGameRecorder() {
try {
this.GameRecorder.stop();
} catch (err) {
console.log("$$SDK录屏异常::gameRecorder", err);
}
}
public async shareVideo(videoInfo) {
const _self = this;
try {
return new Promise((resolve, reject) => {
console.log('@@视频本地地址', _self.videoPath);
(tt as any).shareAppMessage({
channel: 'video',
query: 'fromOpenId=' + _self.ReportParams.openId + '&from=sharetoutiao&tag=0&' + (videoInfo.query ? videoInfo.query : ''),
title: videoInfo.title,
extra: {
videoPath: _self.videoPath
},
success: function () {
console.log("分享视频成功...");
resolve(1);
},
fail: function () {
console.log("分享视频失败...");
resolve(-1);
}
});
});
} catch (err) {
console.log("$$SDK录屏异常::shareVideo", err);
}
}
// 消息提示框
public sdkAlert(str) {
this.showMsg(str)
}
private showMsg(str) {
(tt as any).showToast({
title: str,
icon: 'none',
duration: 3000
})
}
private LoadingOn() {
(tt as any).showLoading({
title: '请稍候..',
mask: true
})
}
private LoadingOff() {
(tt as any).hideLoading();
}
private showModal(DATA) {
(tt 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();
if (status == 0) {
tt.authorize({ // 拉起授权
scope: 'scope.userInfo',
success: async function (res) {
let userInfo = await _selt._getUserInfo();
// 上报用户授权
_selt.ReportData(_selt.deepCopy({}, userInfo, {
action: 'authorize',
nickName: encodeURI(userInfo.nickName)
}));
resolve(userInfo);
},
fail: function (err) {
resolve(0); // 用户取消授权
}
});
} else {
// 用户已授权,可以直接调用相关 API
let userInfo = await _selt._getUserInfo();
// 上报用户授权
_selt.ReportData(_selt.deepCopy({}, userInfo, {
action: 'authorize',
nickName: encodeURI(userInfo.nickName)
}));
resolve(userInfo);
}
});
}
private async _getUserInfo(): Promise<any> {
return new Promise(async function (resolve, reject) {
(tt as any).getUserInfo({
withCredentials: false, //获取用户信息,withCredentials 为 true 时需要先调用 tt.login 接口。需要用户授权 scope.userInfo。
success: (res) => {
var userInfo = res["userInfo"];
resolve(userInfo);
},
fail: (res) => {
resolve(0);
}
});
});
}
/**
* 检查授权配置
*/
private async _getSetting(): Promise<any> {
return new Promise(async function (resolve, reject) {
(tt as any).getSetting({
success: function (res) {
var authSetting = res.authSetting;
if (authSetting['scope.userInfo'] === true) {
resolve(1);
}
else {
resolve(0);
}
},
fail: function () {
reject();
},
complete: function () { }
});
});
}
private async share(DATA): Promise<any> {
const _selt = this;
return new Promise(async (resolve, reject) => {
try {
let sharePromise = await _selt._share(DATA);
if (sharePromise > 0) {
resolve(sharePromise);
}
else {
reject(sharePromise);
console.log("$$SDK分享错误", sharePromise);
}
} catch (err) {
reject(err);
}
})
}
private _share(DATA) {
const _selt = this;
return new Promise((resolve, reject) => {
try {
let opt = _selt.deepCopy(DATA, {
success: res => {
resolve(1);
},
fail: res => {
resolve(-1);
}
});
console.log("Share::", opt);
(tt as any).shareAppMessage(opt);
setTimeout(function () { // 两秒后直接当分享成功返回,避免回调取消引起await问题
resolve(2);
}, 3000);
} catch (err) {
resolve(err)
}
})
}
private shareInit() {
(tt as any).showShareMenu({
withShareTicket: 'true',
success: () => { },
fail: () => { },
complete: () => { }
})
}
// 监听右上角菜单分享
public addShareEvent(shareInfo: ttshareInfo, callback?) {
const _self = this;
(tt as any).onShareAppMessage(() => {
if (callback) callback();
const ShareParams = {
article: 'article',
title: shareInfo.title ? shareInfo.title : tt_SDKConfig.shareTitle,
imageUrl: shareInfo.image ? shareInfo.image : tt_SDKConfig.shareImageUrl,
query: 'fromOpenId=' + _self.ReportParams.openId + '&from=sharetoutiao&tag=0&' + (shareInfo.query ? shareInfo.query : ''),
withShareTicket: true,
success: shareInfo.success,
fail: shareInfo.fail,
complete: shareInfo.complete
};
return ShareParams;
});
_self.shareInit();
}
public ShareApp(params?: string) {
const _self = this
// 参数,记录分享的用户openid
const ShareParams = {
article: 'article',
title: tt_SDKConfig.shareTitle,
imageUrl: tt_SDKConfig.shareImageUrl,
query: 'fromOpenId=' + _self.ReportParams.openId + '&from=sharetoutiao&tag=0&' + (params ? params : '')
}
return this.share(ShareParams);
}
private heartParams = {
action: "heartbeat",
appid: tt_SDKConfig.productCode,
time: null, // 【发送请求时间】 unix时间戳,要求是10位数字
gentime: null, // 【数据生成时间】 unix时间戳,要求是10位数字
advid: "", // 广告活动ID
osname: "", // 操作系统名字
userid: "", // 玩家ID
osversion: "", // 操作系统版本号
sdkversion: this.sdkVersion, // sdk 版本号
appname: tt_SDKConfig.appName, // 当前应用的app名字
packagename: "", // 当前应用的包名
appversion: tt_SDKConfig.appVersion, // 当前应用的版本号
resolution: "", // 屏幕分辨率
language: "", // 语言CODE
country: "", // 国家
timezone: "", // 时区
uuid: "", // openid
testid: "", // 测试序列号
sign: "",
info: {
idfa: "",
imei: "",
imsi: "",
mac: "",
model: "", // 手机型号
buildid: "",
manufacturer: "",
memory_free: "",
memory_total: "",
network: "", // 网络状态
battery: "", // 电量
androidid: "",
advertisingid: "",
deeplink: "",
wifiname: ""
},
source: "toutiaoxyx",
content: ""
}
// 统计上报参数
private ReportParams = {
action: null, // 必填,事件类型
openId: null, // 必填,openid,通过code去SDK接口换取
userId: '', // 必传,用户ID
productCode: null, // 必填,产品代号,配置文件配置
from: null, // 必填,广告标识,附带在url上
tag: null, // 必填,创意标识,附带在url上
fromOpenId: null, // 选填,分享来源的用户openid
adid: null, // 头条广告来源
creativeid: null,
creativetype: null,
clickid: null,
model: null, // 必填,手机型号
system: null, // 必填,操作系统
appName: null, // 宿主APP名称
networkType: null, // 选填,网络类型
language: null, // 选填,设置的语言
version: null, // 选填,版本号
SDKVersion: null, // 选填,客户端基础库版本
appVersion: tt_SDKConfig.appVersion, // 选填,产品版本号,配置文件配置
screenWidth: null, // 选填,屏幕宽度
screenHeight: null, // 选填,屏幕高度
time: null, // 必填,请求的时间戳(秒)
query: null
}
// SDK上报参数
private sdkParams = {
product_code: "", // 产品code
appid: "", // 小游戏appid
time: "", // 当前时间戳秒
uniqueid: '', // 设备唯一号
mac: '', // 网卡mac地址
idfa: '', // 苹果设备IDFA
open_id: "", // 用户openid
anonymous_openid: "", // 游客openid
password: '', // 登录密码(小程序免密)
source: 'TOUTIAO', // 用户来源
token: '', // 登录成功返回
os: 'H5', // 系统类型
equipmentos: "", // 系统版本
equipmentname: "", // 手机型号
version: "", // SDK版本
package_code: '', // 渠道标识
sign: "", // 签名
unionid: '', // 用户Unionid,用于切支付
pay_channel: '', // 支付方式,初始化接口返回
client_type: 'toutiao_minigame', // 客户端类型
session_key: '', // 用户session_key
type: '' // 登录类型
}
}
// SDK后端接口(勿改)
const ttLinks = {
init: tt_SDKConfig.sdk_domain + '/v2/toutiao/code2SessionKey', // 获取openid
active: tt_SDKConfig.sdk_domain + '/appInit.php', // SDK初始化接口
login: tt_SDKConfig.sdk_domain + '/v2/toutiao/login', // SDK登录接口,获取用户平台信息
order: tt_SDKConfig.pay_domain + '/pay.php', //订单接口
pay: tt_SDKConfig.pay_domain + '/callback/toutiao', //扣费接口
payType: tt_SDKConfig.pay_domain + '/pay_channel/status.php', // 查询支付状态
sendCode: tt_SDKConfig.sdk_domain + '/sms/send.php', // 发送验证码
saveNum: tt_SDKConfig.sdk_domain + '/bind/mobile.php', // 保存手机号码
bindPhone: tt_SDKConfig.sdk_domain + '/bind/is_bind_mobile.php', // 用户手机绑定状态
heartReport: 'https://s.pthzwl.net/sdkapi.php', // 心跳上报接口
}
class ttshareInfo {
title?: string
image?: string
query?: string
success: any
fail: any
complete?: any
}
class ttRecorderInfo {
time: number
useMic: boolean
}
// md5加密
const ttrotateLeft = (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(ttrotateLeft(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(ttrotateLeft(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(ttrotateLeft(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(ttrotateLeft(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 tt_SDKConfig = {
// 配置项目参数
sdk_domain: 'https://account.pthc8.com', // SDK上报的接口域名
pay_domain: 'https://pay.pthc8.com', // 支付接口域名
report: 'https://s.pthc8.com/xyx/toutiao/api.php', // 数据上报接口域名
appid: "tt3de14b5ca2cb8ca2", // 换openid
appName: "推广部测试应用", // 应用名称
productCode: "3390830be644dfb22f7022df12c6fa37", // 产品code
productKey: "1e2cf47f40d7fcf9aef6e5d5c0990450", // 产品key,用于生成签名
appVersion: "产品版本号(cp)", // 产品版本号
payEnv: 0, // 米大师支付环境 0:正式环境, 1:沙盒模式
shareTitle: "鲸鱼推广部", // 分享标题
shareImageUrl: "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3903587193,374462562&fm=27&gp=0.jpg" //分享图片链接
// 结束
}
\ No newline at end of file
/**
* 鲸鱼游戏头条/抖音小游戏接入库
* @author 推广技术部
* @time: 2023-05-11
*/
export class TTSDK {
private static sdkVersion: string = '2.0.0';
private static appInfo: AppInfo;
private static isBind = 0; // 是否已经绑定过其他角色
public static LaunchOptions: any; // 启动参数对象
public static SystemInfo: any; // 设备信息
public static LoginData: any; // 登录信息
private static clickCounter = 0; // 当前用户点击次数
private static contrlShareMenu: number = 0; // 右上角分享开关
/**
* SDK初始化接口
* @param appInfo 必传产品参数
* @param retry 重连次数
* @returns { code:number, message:string }
*/
public static SDKInit = async (appInfo: AppInfo, retry = 0): Promise<any> => {
this.appInfo = appInfo;
this.SDKCOMMDATA["product_code"] = appInfo.productCode;
if (retry == 0) {
console.info("当前加载SDK版本号为:", TTSDK.sdkVersion);
this.LaunchOptions = await this.getOptionsInfo();
this.SystemInfo = await this.getSystemInfo();
this.SystemInfo["networkType"] = await this.getNetworkType();
this.SDKCOMMDATA["os"] = this.SystemInfo["system"].split(" ")[0].toLowerCase();
}
if (retry > 2) {
this.showMsg("登录异常,请联系客服.");
return { error: "登录超时.." };
}
const ttUser = await this.ttLogin(false);
let { code, data, msg } = await this.sdkRequest(ttLinks.init, {
...this.SDKCOMMDATA,
appid: appInfo.appid,
anonymous_code: ttUser.anonymousCode || '',
code: ttUser.code,
});
if (!code) {
this.LoginData = { ...data };
this.SDKCOMMDATA["uuid"] = data.openid == "" ? data.anonymous_openid : data.openid;
this.LoginData["open_id"] = data.openid;
return this.SDKActive();
} else
console.error("SDK初始化异常:", msg);
// 登录失败发起重连
retry += 1;
this.SDKInit(appInfo, retry);
}
private static SDKActive = async (): Promise<any> => {
const { code, data, msg } = await this.sdkRequest(ttLinks.active, { ...this.SDKCOMMDATA, ...this.LoginData });
if (!code) {
this.LoginData["pay_channel"] = data.default_pay_channel;
this.LoginData["ad_unit_id"] = data.ad_unit_id;
this.LoginData["game_club"] = data.game_club;
this.contrlShareMenu = data.share;
this.ActiReport(); // 上报激活
return { code: 0, message: 'SDK激活完成.' };
} else
return { code: code, message: msg };
}
/**
* SDK登录接口
* @returns SDK登录信息
*/
public static SDKLogin = async (): Promise<any> => {
delete this.LoginData["token"]; // 强制清空登录toekn
const { data, msg, code } = await this.sdkRequest(ttLinks.login, { ...this.SDKCOMMDATA, ...this.LoginData });
if (Object.keys(data).length == 0) {
this.showMsg(msg);
return { code: code, message: msg };
}
// 游客帐号下已经绑定其他角色
if (code == 182) {
this.isBind = 1;
return { code: code, message: msg }
}
this.LoginData = { ...this.LoginData, ...data };
const filters = (({ create_time, nickname, openid, uid, enter_game, origin_uid, origin_open_id }) => ({
create_time,
nickname,
openid,
uid,
enter_game,
origin_uid,
origin_open_id,
}))(this.LoginData);
return {
code: 0,
data: {
...filters,
os: this.SDKCOMMDATA["os"], // 返回系统类型IOS或者android
scene: this.LaunchOptions["scene"], // 用户来源场景值
from_appid: this.LaunchOptions["appId"] || this.LaunchOptions["appid"],
launchOptions: this.LaunchOptions,
user_status: data.user_status || 0,
game_club: this.LoginData["game_club"] || 0 // 游戏圈开关
}
};
}
/**
* SDK支付接口
* @returns { code: number, message: string }
*/
public static payOrder = async (Params: PaymentData): Promise<any> => {
if (this.isBind == 1) {
const msg = {
title: '提示',
content: '所绑定账号在本服已存在角色,请重新绑定新账号',
showCancel: false
}
this.showModal(msg);
return false;
}
// 支付前先判断用户是否登录
const isLogin = await this.checkUserLogin();
if (isLogin == -1) {
const isGuest = await this.SDKQuickLogin();
if (isGuest == -1) return { code: -1, message: '游客无法充值.' };
}
this.loadingView(true);
const { code, data, msg } = await this.fetchUri(
ttLinks.order,
this.md5_sign({
...this.SDKCOMMDATA,
...Params,
token: this.LoginData["token"],
equipmentname: this.SystemInfo["model"] || '',
equipmentos: this.SystemInfo["system"] || '',
pay_channel: this.LoginData["pay_channel"]
}),
"GET"
);
this.loadingView(false);
if (!code) {
this.paymentData["buyQuantity"] = <number>(Params.money / 100) * <number>data.platform_payment_proportion; // 充值金额
this.paymentData["customId"] = <string>data.order_num;
this.paymentData["extraInfo"] = <string>data.extra;
console.log("支付参数:", this.paymentData);
// 调微信米大师支付接口
return new Promise((resolve, reject) => {
(tt as any).requestGamePayment({
...this.paymentData,
success: async () => {
let { code, msg } = await this.getCoins({ ...this.SDKCOMMDATA, token: this.LoginData["token"], order_num: data.order_num });
if (code == 0 || code == 3012) {
resolve({ code: 0, message: "" });
} else {
resolve({ code: <number>code, message: msg });
}
},
fail: (err: any) => {
let msg = this.PaymentErrorCode[err.errCode];
const params = {
title: "支付提示",
content: msg || "支付异常",
showCancel: false,
};
this.showModal(params);
resolve({ code: err.errCode, message: msg });
this.reportPaymentError({ code: <number>err.errCode, message: msg, order_num: data.order_num });
},
});
});
} else {
const err = {
title: '提示',
content: msg,
showCancel: false
}
this.showModal(err);
return { code: <number>code, message: msg }
}
}
// 通知服务端扣费
private static getCoins = async (orderParams: any) => {
console.log("通知扣费:", orderParams);
return await this.sdkRequest(ttLinks.pay, orderParams);
};
private static SDKQuickLogin = async (): Promise<any> => {
let ttLoginData = await this.ttLogin(true);
if (ttLoginData.status == -1) {
this.showMsg("用户取消登录.");
return { code: -1, message: '用户取消登录' };
}
let { code, data, msg } = await this.sdkRequest(ttLinks.init, {
...this.SDKCOMMDATA,
anonymous_code: ttLoginData.anonymousCode || '',
appid: this.appInfo.appid,
code: ttLoginData.code || ''
});
if (!code) {
this.LoginData = { ...data };
this.SDKCOMMDATA["uuid"] = data.openid;
this.SDKCOMMDATA["uniqueid"] = data.anonymous_openid;
this.SDKCOMMDATA["type"] = 'bind';
let { code } = await this.SDKLogin();
return code;
}
}
private static checkUserLogin = async (): Promise<any> => {
return new Promise((resolve, reject) => {
(tt as any).checkSession({
success(res: any) {
resolve(0)
},
fail(res: any) {
resolve(-1);
}
});
});
}
// 头条登录逻辑
private static ttLogin = (showLoginView: boolean): Promise<any> => {
return new Promise<any>((resolve, reject) => {
(tt as any).login({
success: (res: any) => {
resolve({ ...res, status: 0 });
},
fail: (res: any) => {
resolve({ ...res, status: -1 }); // 用户取消登录
},
force: showLoginView // 是否唤醒登录框
});
});
}
public static getOptionsInfo = async (): Promise<any> => {
const options: any = (tt as any).getLaunchOptionsSync();
console.log("游戏启动参数--->", options);
if (options.query && Object.keys(options.query).length > 0) {
if (options.query["scene"]) {
// 扫码参数
const scene = this.toJson(decodeURIComponent(options.query["scene"]));
return scene;
} else return { ...options.query, scene: options["scene"] || "" }; // 普通url参数
} else if (options.referrerInfo && options.referrerInfo.appId) {
return { ...options.referrerInfo.extraData, scene: options["scene"] || "", appId: options.referrerInfo.appId }; // 小程序跳转附带参数
} else return {};
}
public static getSystemInfo = (): Promise<any> => {
return new Promise((resolve, reject) => {
(tt as any).getSystemInfo({
success: (res: any) => {
resolve(res);
},
});
});
};
public static getNetworkType = (): Promise<any> => {
return new Promise((resolve, reject) => {
(tt as any).getNetworkType({
success: (res: any) => {
resolve(res.networkType);
},
});
});
};
private static sdkRequest = async (link: string, portData: any, method?: any): Promise<any> => {
portData = this.md5_sign(portData); // 附上签名参数
// console.log("SDK接口:", portData);
return await this.request(link, portData, method);
};
// SDK接口签名方法
private static md5_sign(obj: any) {
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 + this.appInfo.productKey
obj.sign = md5(key_url)
return obj
}
private static request = async (URI: string, Params: any, Method = "GET") => {
const { code, data, msg } = await this.fetchUri(URI, Params, Method);
return { code, data: !data ? {} : data, msg };
};
private static fetchUri = (URI: string, DATA: any, METHOD: string): Promise<any> => {
return new Promise((resolve, reject) => {
try {
(tt as any).request({
url: URI,
method: METHOD,
data: DATA,
header: {
"Content-Type": "json",
},
success: (response: any) => {
resolve(response.data);
},
fail: resolve,
});
} catch (err) {
reject(err);
}
});
};
//把字符串转换成json
private static toJson = (str: string) => {
let json: any = {};
const jsonArr = str.split("&");
for (let i = 0; i < jsonArr.length; i++) {
const keyArr = jsonArr[i].split("=");
json[keyArr[0]] = keyArr[1] || "";
}
return json;
};
private static showModal(DATA: any) {
(tt as any).showModal({
...DATA,
cancelText: "取消",
confirmText: "确认",
});
}
public static showMsg = (str: string, duration = 3000) => {
(tt as any).showToast({
title: str,
icon: "none",
duration: duration,
});
};
private static loadingView(show: boolean) {
if (show) {
(tt as any).showLoading({
title: '请稍候..',
mask: true
})
} else {
(tt as any).hideLoading();
}
}
// 上报激活
public static ActiReport() {
this.ReportData({ action: "activation" });
this.heartBeatReport();
}
// 上报注册
public static RegisterReport() {
this.ReportData({ action: 'register' });
}
// 上报登录
public static LoginReport() {
this.ReportData({ action: 'login' })
}
// 上报等级
public static RoleLevelReport(roleInfo: any) {
this.ReportData({ ...roleInfo, action: "roleUpgrade" });
}
// 自定义上报
public static CustomReport(custInfo: any) {
this.ReportData({ ...custInfo, action: "customevent" });
}
public static userClickEvent() {
this.clickCounter++;
}
private static heartBeatReport() {
setTimeout(() => {
this.clickReport();
this.heartBeatReport();
}, 60 * 1000);
}
private static clickReport = async () => {
this.ReportData({ action: "heartBeat" });
this.clickCounter > 0 && this.ReportData({ action: "userappclick", click_times: this.clickCounter });
this.clickCounter = 0; // 上报后归零
};
// 上报支付异常
private static reportPaymentError(err: Object) {
let portData = {
...this.SDKCOMMDATA,
uid: this.LoginData["uid"],
event_code: "PaymentError",
event_data: JSON.stringify(err),
};
this.sdkRequest(ttLinks.paymentErrorReport, portData, "POST");
}
// 数据上报接口,外部调用,参数中必须含有action值
public static ReportData(portData: any) {
portData["launchOptions"] = this.LaunchOptions;
portData["userInfo"] = { ...portData["userInfo"], ...{ userId: this.LoginData["uid"] || "", open_id: this.LoginData["openid"] || "", anonymous_openid: this.LoginData["anonymous_openid"] } };
portData["systemInfo"] = this.SystemInfo;
portData["product_code"] = this.appInfo.productCode;
portData["time"] = Date.parse(new Date().toString()); // 获取当前时间戳秒
console.log("--SDK上报:", portData);
this.request(reportDomain, portData, "POST");
}
public static sendPhoneCode = async (phoneInfo: any): Promise<any> => {
// 发送验证码接口
const { code } = await this.sdkRequest(ttLinks.sendCode, { ...this.SDKCOMMDATA, ...phoneInfo, type: "SDK.BIND_MOBILE" });
return { code: code };
}
public static bindPhone = async (phoneInfo: any): Promise<any> => {
// 绑定手机
const { code } = await this.sdkRequest(ttLinks.saveNum, { ...this.SDKCOMMDATA, open_id: this.LoginData["openid"], ...phoneInfo, source: "WEIXIN" });
return { code: code };
}
public static checkUserPhoneBind = async (): Promise<any> => {
// 查询用户绑定状态
const { code } = await this.sdkRequest(ttLinks.bindPhone, { ...this.SDKCOMMDATA, uid: this.LoginData["uid"] });
return { code: code };
}
// 获取用户信息
public static getUserInfo = (): Promise<any> => {
return new Promise(async (resolve, reject) => {
const userInfo = await this._getUserInfo();
if (userInfo.nickname) {
// 上报用户授权
this.ReportData({
userInfo: { ...userInfo, nickName: encodeURI(userInfo.nickName) },
action: "authorize",
});
}
resolve(userInfo);
});
};
private static async _getUserInfo(): Promise<any> {
return new Promise(async function (resolve, reject) {
(tt as any).getUserInfo({
withCredentials: false, //获取用户信息,withCredentials 为 true 时需要先调用 wx.login 接口。需要用户授权 scope.userInfo。
success: (res: any) => {
let userInfo = res["userInfo"];
resolve(userInfo);
},
fail: (res: any) => {
console.log("--SDK:玩家头像等数据失败,用户未授权");
resolve({});
},
});
});
}
public static addShareEvent = (shareInfo: ShareInfo) => {
if (!this.contrlShareMenu) return;
(tt as any).onShareAppMessage(() => {
const ShareParams = {
title: shareInfo.title,
imageUrl: shareInfo.image,
imageUrlId: shareInfo.imageId,
query: "fromOpenId=" + this.LoginData["openid"] + "&from=share&tag=0&" + (shareInfo.query ? shareInfo.query : ""),
withShareTicket: true,
};
return ShareParams;
});
(tt as any).showShareMenu({ withShareTicket: true });
};
public static ShareGame = (shareInfo: ShareInfo) => {
// 参数,记录分享的用户openid
const ShareParams = {
title: shareInfo.title,
imageUrl: shareInfo.image,
imageUrlId: shareInfo.imageId,
query: "fromOpenId=" + this.LoginData["openid"] + "&from=share&tag=0&" + (shareInfo.query ? shareInfo.query : ""),
};
return this._share(ShareParams);
};
private static _share = (DATA: any): Promise<any> => {
return new Promise((resolve, reject) => {
(tt as any).shareAppMessage({
...DATA,
withShareTicket: true,
success: (res: any) => {
resolve(1);
},
fail: (res: any) => {
resolve(-1);
},
});
setTimeout(function () {
// 两秒后直接当分享成功返回
resolve(2);
}, 3000);
});
};
// 客服
public static Customer = (_orderInfo?: any) => {
try {
(tt as any).openCustomerServiceConversation(_orderInfo);
} catch (err) {
console.log("访问客服异常:", err);
this.showMsg("这傻鸟走开了.");
}
};
// SDK接口通用参数
private static SDKCOMMDATA: any = {
source: "TOUTIAO",
product_code: "",
uuid: "",
equipmentos: "",
package_code: "",
time: "",
sign: "",
os: "",
version: this.sdkVersion,
};
// 米大师支付参数
private static paymentData = {
mode: 'game', // 支付的类型
env: 0, // 米大师支付环境 0:正式环境, 1:沙盒模式
currencyType: 'CNY', // 币种
platform: 'android',
buyQuantity: 10,
customId: '',
extraInfo: ''
}
private static PaymentErrorCode: any = {
"-1": "系统失败",
"-2": "支付取消",
"-15001": "缺少参数",
"-15002": "请求参数不合法",
"-15003": "app 不支持小游戏支付",
"-15006": "app 没有支付权限",
"-15009": "内部错误,支付失败",
"-15098": "当前用户未通过实名认证",
"-15099": "当前用户累计支付金额超过限制",
"-15101": "customId 为空或者不唯一",
"-16000": "用户未登录",
"2": "正在支付一起订单时,又发起了一笔支付请求",
"3": "调起收银台失败",
"4": "网络异常",
"5": "IOS 平台错误,当前平台不支持支付",
"6": "其他错误",
}
}
// SDK后端接口(勿改)
const sdkDomain = 'https://account.shdxw.net';
const sdkPaymentDomain = 'https://pay.shdxw.net';
const reportDomain = 'https://s.shdxw.net/v2/sdkapi.php?jy_platform=toutiao_min_game';
const ttLinks = {
init: sdkDomain + '/v2/toutiao/code2SessionKey', // 获取openid
active: sdkDomain + '/appInit.php', // SDK初始化接口
login: sdkDomain + '/v2/toutiao/login', // SDK登录接口,获取用户平台信息
order: sdkPaymentDomain + '/pay.php', //订单接口
pay: sdkPaymentDomain + '/notify/douyin/callback.php', //扣费接口
payType: sdkPaymentDomain + '/pay_channel/status.php', // 查询支付状态
sendCode: sdkDomain + '/sms/send.php', // 发送验证码
saveNum: sdkDomain + '/bind/mobile.php', // 保存手机号码
bindPhone: sdkDomain + '/bind/is_bind_mobile.php', // 用户手机绑定状态
paymentErrorReport: sdkDomain + "/v2/analytics/event", // 上报支付错误信息
}
class ShareInfo {
title?: string
image?: string
query?: string
imageId?: string
success?: any
fail?: any
complete?: any
}
class RecorderInfo {
time: number
useMic: boolean
}
declare interface ProductInfo {
money: number
product_id: string
product_name: string
product_num: number
app_server: string
role_level: number
role_name: string
}
declare interface AppInfo {
appid: string
productCode: string // SDK后台生成的产品code
productKey: string // SDK后台生成的产品key
appVersion?: string // 产品版本号
}
declare interface PaymentData {
money: number
product_id: string
product_name: string
product_num: number
cp_order_num: string
app_server: string
role_level: number
role_name: string
passthrough_params?: string
}
declare interface NavOptions {
appId: string
}
// md5加密
const ttrotateLeft = (lValue: any, iShiftBits: any) => { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)) }; var addUnsigned = function (lX: any, lY: any) { 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: any, y: any, z: any) { return (x & y) | ((~x) & z) }; var G = function (x: any, y: any, z: any) { return (x & z) | (y & (~z)) }; var H = function (x: any, y: any, z: any) { return (x ^ y ^ z) }; var I = function (x: any, y: any, z: any) { return (y ^ (x | (~z))) }; var FF = function (a: any, b: any, c: any, d: any, x: any, s: any, ac: any) { a = addUnsigned(a, addUnsigned(addUnsigned(F(b, c, d), x), ac)); return addUnsigned(ttrotateLeft(a, s), b) }; var GG = function (a: any, b: any, c: any, d: any, x: any, s: any, ac: any) { a = addUnsigned(a, addUnsigned(addUnsigned(G(b, c, d), x), ac)); return addUnsigned(ttrotateLeft(a, s), b) }; var HH = function (a: any, b: any, c: any, d: any, x: any, s: any, ac: any) { a = addUnsigned(a, addUnsigned(addUnsigned(H(b, c, d), x), ac)); return addUnsigned(ttrotateLeft(a, s), b) }; var II = function (a: any, b: any, c: any, d: any, x: any, s: any, ac: any) { a = addUnsigned(a, addUnsigned(addUnsigned(I(b, c, d), x), ac)); return addUnsigned(ttrotateLeft(a, s), b) }; var convertToWordArray = function (string: any) { 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: any) { 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: any) { 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: any) { 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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论