import { isValid, randomRange, view } from "cc"; import GlobalValue, { VideoRoleType } from "../Common/GlobalValue"; import SubManager from "../../Sub/SubManager"; import { I_SDK_UserInfo_Callback, SDKManager } from "./SDKManager"; import Utils from "../Common/Utils"; import { InnerMsgCode } from "../Config/InnerMsgCode"; import { BgVideo } from "./BgVideo"; import { SceneBgVideoLayer } from "../../Sub/UI/SceneBgVideoLayer"; import { logger } from "db://assets/Scripts/Main/Common/Logger"; //广告ID const wx_banner_ad_unit_id = 'test' const wx_splash_ad_unit_id = 'test' const wx_video_ad_unit_id = 'test' export class KSSDK{ static g_InGameScene = null; //游戏场景值 private wx_video:any = null; private wx_splash:any = null; private wx_banner:any = null; private wx_video_callback:Function = null; private wx_video_tag:number = null; private wx_gameClub:any = null; //游戏圈按钮 private ShareSTime: any; private ShareCb: any; //分享回调 private shareTxt = ["分享失败", "请分享到一个群", "请分享给一位好友", "分享过于频繁"] //初始化 init(cb: Function = null) { // 保持屏幕常亮 // window['ks'].setKeepScreenOn({ keepScreenOn: true }); //获取小游戏冷启动时的参数 热启动参数通过 ks.onShow 接口获取。 let launchOption = window['ks'].getLaunchOptionsSync(); KSSDK.g_InGameScene = launchOption.from; logger.log('init 快手 - 进入游戏的场景值', launchOption); // //显示分享按钮 // window['ks'].showShareMenu({ // withShareTicket: true, // menus: ["shareAppMessage", "shareTimeline"], // }); // window['ks'].onShareAppMessage(() => { // return this.shareInfo(); // }); // window['ks'].onShareTimeline(() => { // return this.shareInfo(); // }) //小游戏回到前台 window['ks'].onShow(this.onWxShow.bind(this)); //小游戏被隐藏 记个时间 window['ks'].onHide(() => { logger.log("快手 onHide回调:") if (this.ShareCb) { this.ShareSTime = new Date().getTime(); logger.log("分享时间差 记录:", this.ShareSTime); } }); this.init_video(); //初始化视频广告 this.init_splash(); //初始化插屏广告 this.init_banner(); //初始化Banner广告 弹窗广告 this.qiangzhiUpdata(); //强制更新 cb && cb(); } //小游戏回到前台 onWxShow(data: any) { logger.log("快手 onShow回调:", data) if (data) { //启动小游戏时传入的参数 object if (data.query) { GlobalValue.ShareTocusid = data.query.ShareCode } //游戏启动场景 string if (data.from) { } } if (this.ShareCb) { if (this.ShareSTime) { let nT = new Date().getTime(); logger.log("分享时间差 计算:",nT, this.ShareSTime, nT - this.ShareSTime); if (nT - this.ShareSTime > 1) { //快手的onHide有问题,离onShow很近 let cb = this.ShareCb.succ cb && cb() } else { this.tostErr() } } this.ShareCb = null; } } //分享失败 tostErr() { let rint = Math.floor( randomRange(0, this.shareTxt.length - 1) ) SubManager.ShowPrompt(this.shareTxt[rint]) if (this.ShareCb) { let cb = this.ShareCb.fail cb && cb() } } /**获取用户授权状态 * @param autoKey string 授权类型 userInfo=用户信息,对应接口wx.getUserInfo */ checkAutoSetting(autoKey:string, cb:Function = null) { window['ks'].getSetting({ success(res:any) { logger.log("快手 - 检测权限状态 succ:", res) if (autoKey == "userInfo" && res.authSetting['scope.userInfo']) { cb && cb(true) } else { cb && cb(false) } }, fail(res:any) { logger.log("快手 - 检测权限状态 fail:", res) cb && cb(false) } }) } /** * 获取个人信息 */ getUserInfo(cb:I_SDK_UserInfo_Callback = null) { var self = this; window['ks'].getSetting({ success(res:any) { logger.log("快手 - 获取授权信息成功:", res); let isScope = res.authSetting['scope.userInfo'] if (isScope) { window['ks'].getUserInfo({ success: (res2) => { logger.log("快手 - 获取用户信息成功:", res2); cb && cb({avatarUrl:res2.userInfo.avatarUrl, nickName:res2.userInfo.nickName}) }, fail: (error) => { logger.log("快手 - 获取用户信息失败:", error); } }) } else { //向用户发起授权请求 window['ks'].authorize({ scope: 'scope.userInfo', success: (res) => { logger.log("快手 - 发起授权请求成功:", res); self.getUserInfo(cb) }, fail: (error) => { logger.log("快手 - 发起授权请求失败: ", error); } }) } }, fail: (error) => { logger.log("快手 - 获取授权信息失败: ", error); // cb && cb({avatarUrl:"", nickName:""}) } }) } //region 快手登录 login(cb: Function = null) { window['ks'].login({ success: (res) => { logger.log('快手 - 登录成功', res.code); cb && cb({ platform:3, code: res.code }); }, fail(res: any) { logger.log(`快手 login 调用失败`, res); cb && cb({ platform:3, code: null }); }, }); } //初始化视频广告 private init_video() { if (wx_video_ad_unit_id as any == "test") { logger.log("快手 激励广告id未配置,跳过此类型初始化") return } this.wx_video = window['ks'].createRewardedVideoAd({ adUnitId: wx_video_ad_unit_id }); this.wx_video.onError((err) => { logger.log('onError event emit', err); }); this.wx_video.onClose(res => { logger.log('onClose event emit',res); // 用户点击了【关闭广告】按钮 // 小于 2.1.0 的基础库版本,res 是一个 undefined if ((res && res.isEnded) || res === undefined) { // 正常播放结束,可以下发游戏奖励 if (this.wx_video_callback) { this.wx_video_callback(this.wx_video_tag); } } else { // 播放中途退出,不下发游戏奖励 //wx_video_callback(-1); } SDKManager.video_ad_back(); }); } //初始化插屏广告 private init_splash() { if (wx_splash_ad_unit_id as any == "test") { logger.log("快手 插屏广告id未配置,跳过此类型初始化") return } // 创建插屏广告实例,提前初始化 if (window['ks'].createInterstitialAd){ this.wx_splash = window['ks'].createInterstitialAd({ adUnitId: wx_splash_ad_unit_id }); this.wx_splash.onError((err) => { logger.log('splash onError event emit', err); }); this.wx_splash.onClose(res => { logger.log('splash onClose event emit', res); }); } } //初始化Banner private init_banner() { if (wx_banner_ad_unit_id as any == "test") { logger.log("快手 横幅广告id未配置,跳过此类型初始化") return } } //显示视频广告 show_video(callback:Function, tag:number) { if (wx_video_ad_unit_id == 'test') { logger.log('未接入广告ID,视频广告请求直接返回'); callback && callback(); SDKManager.video_ad_back(); return; } if (this.wx_video) { this.wx_video_callback = callback; this.wx_video_tag = tag; let p = this.wx_video.show() p.then(function(result){ // 激励视频展示成功 logger.log(`快手 show rewarded video ad success, result is ${result}`) }).catch(function(error){ // 激励视频展示失败 logger.log(`快手 show rewarded video ad failed, error is ${error}`) }) // this.wx_video.load() // .then(() => { // this.wx_video.show() // .catch(err => { // this.wx_video.load() // .then(() => this.wx_video.show()) // }) // }) } } //显示插屏 show_splash() { if (this.wx_splash) { let p = this.wx_splash.show() p.then(function(result){ // 插屏广告展示成功 logger.log(`快手 show interstitial ad success, result is ${result}`) }).catch(function(error){ // 插屏广告展示失败 logger.log(`快手 show interstitial ad failed, error is ${error}`) if (error.code === -10005) { // 表明当前app版本不支持插屏广告,可以提醒用户升级app版本 } }) } } //显示Banner show_banner() { if (this.wx_banner) { this.wx_banner.show(); //banner 默认隐藏(hide) 要打开 } } //隐藏Banner hide_banner() { if (this.wx_banner) { this.wx_banner.hide(); //banner 默认隐藏(hide) 要打开 } } //分享信息 shareInfo() { return { templateId: undefined, //分享模版id,不传走默认分享文案 //查询字符串,从这条转发消息进入后,可通过 ks.getLaunchOptionsSync() 或 ks.onShow() 获取启动参数中的 query。必须是 key1=val1&key2=val2 的格式。 query: "ShareCode=" + "user_default", //ModelPlayer.I.getPlayerId(), } } //主动拉起分享 show_share(rewardCB?:Function) { logger.log("主动拉起分享"); let info:any = this.shareInfo(); info.succ = rewardCB; info.success = null; info.fail = null; this.ShareCb = info; window['ks'].shareAppMessage(info); } //获取设备分辨率 getWindowSize() { let windowinfo = window['ks'].getSystemInfoSync(); return {width:windowinfo.screenWidth, height: windowinfo.screenHeight}; } //显示游戏圈 show_gameClub(leftRatio, topRatio, widthRatio, heightRatio) { if (true) { logger.log("显示游戏圈,快手暂不支持"); return } } //隐藏游戏圈 hide_gameClub() { logger.log("隐藏游戏圈"); if (this.wx_gameClub) { this.wx_gameClub.hide(); } } //检查是否支持base64音频播放 checkSupportBase64Audio() { return true; } //播放base64音频 private _innerAudioContext: any = null; private _iacIdx = 0 //音频播放索引 playBase64Audio(base64, loop) { if (!this.checkSupportBase64Audio()) { logger.log("当前平台不支持base64音频播放"); return; } let substring = base64; let qianzhui = "data:audio/x-wav;base64," if(base64.startsWith(qianzhui)) { substring = base64.substring(qianzhui.length, base64.length) } let self = this; const fs = window['ks'].getFileSystemManager(); //1.删除上一个音频 const lastPath = window['ks'].env.USER_DATA_PATH + `/ordernew${self._iacIdx}.mp3` logger.log("快手 正在删除上一个音频 ->", lastPath); fs.removeSavedFile({ filePath: lastPath, success(res) { logger.log("快手 删除上一个音频成功", res); }, fail(err) { logger.log("快手 删除上一个音频失败", err); }, complete(res) { logger.log("快手 删除上一个音频完成", res); //2.保存当前音频 //这里需要每次保存时换一下名字的原因是:innerAudioContext设置路径时如果路径相同,会认为还是同一个音频,不会重新加载,所以需要每次保存时换一下名字 self._iacIdx++; const audioPath = window['ks'].env.USER_DATA_PATH + `/ordernew${self._iacIdx}.mp3` logger.log("快手 正在保存本次音频 ->", audioPath); fs.writeFile({ filePath: audioPath, data: substring, encoding: 'base64', success(res) { if (self._innerAudioContext == null){ self._innerAudioContext = window['ks'].createInnerAudioContext(); // 添加播放结束的回调 self._innerAudioContext.onEnded(() => { logger.log("快手 AI语音播放结束") self._innerAudioContext.stop(); // 使用 stop 方法停止音频并重置播放状态 self._innerAudioContext.destroy(); // 销毁音频实例 self._innerAudioContext = null; }); } logger.log("快手 播放base64音频", audioPath) self._innerAudioContext.src = audioPath; self._innerAudioContext.play(); // 开始播放音频 }, fail(err) { logger.log("快手 保存本次音频失败", err); } }) } }) } //region版本更新检测 //微信开发者工具上可以通过「编译模式」下的「下次编译模拟更新」开关来调试 qiangzhiUpdata() { if (window['ks'].getUpdateManager == null) { logger.log("快手 没有更新管理器", window['ks'].getUpdateManager) return; } const updateManager = window['ks'].getUpdateManager(); //监听向微信后台请求检查更新结果事件。微信在小程序每次启动(包括热启动)时自动检查更新,不需由开发者主动触发。 updateManager.onCheckForUpdate((res) => { // 请求完新版本信息的回调 logger.log("快手 检查是否有新版本:", res.hasUpdate) }); //监听小程序有版本更新事件。客户端主动触发下载(无需开发者触发),下载成功后回调 updateManager.onUpdateReady(async () => { const { confirm } = await window['ks'].showModal({ title: '更新提示', content: '新版本已经准备好,是否重启应用?', }); if (confirm) { // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启 updateManager.applyUpdate(); } }); //监听小程序更新失败事件。小程序有新版本,客户端主动触发下载(无需开发者触发),下载失败(可能是网络原因等)时回调 updateManager.onUpdateFailed(function (err) { logger.log("快手 新版本下载失败", err) }) } //客服功能是否支持 kefuSupport() { logger.log("快手 不支持联系客服") return false; } //进入联系客服 openKefu() { logger.log("快手 进入联系客服") } //region 播放背景视频 private _bgVideo: any = null; //正式播放的视频组件 private _bgShow: boolean = false; private curPlayType: VideoRoleType = VideoRoleType.None //当前播放的视频的类型 playBgAudio(remoteUrl:string, vtype:VideoRoleType, loop:boolean = false, extra:any = {}) { if (!window['ks'].createVideo) { logger.log("快手 不支持播放视频") return } if (this._bgVideo && this._bgShow) { this.playBgAudioNext(remoteUrl, vtype, loop, extra); return } let self = this; logger.log("微信 播放背景视频组件1", remoteUrl); this.curPlayType = vtype if (!this._bgVideo) { this._bgVideo = this.createVideoHandle(); // this._bgVideo.onPlay(() => { // logger.log("微信 背景视频播放开始"); // }) this._bgVideo.onTimeUpdate((_tinfo:any) =>{ // logger.log("微信 背景视频播放进度", self._bgShow, _tinfo); if (!self._bgShow) { if (_tinfo && _tinfo.position > 0.01) { logger.log("微信 背景视频1进入视野"); self.videoMoveIn(self._bgVideo) self._bgShow = true; self.removeBgAudioNext() Utils.sendInnerMsg(InnerMsgCode.BgVideo_Ready, {}); } } }) this._bgVideo.onEnded(() => { if (self.doPlayEmoReadyAudio()) { self.setBgAudioPause(self._bgVideo) } Utils.sendInnerMsg(InnerMsgCode.BgVideo_End, {}); }) } this._bgVideo.src = remoteUrl; //视频的地址 this._bgVideo.loop = loop; //循环播放 this._bgVideo.play(); } removeBgAudio() { this._bgShow = false; if (this._bgVideo) { this._bgVideo.stop(); this.videoMoveOut(this._bgVideo) } } //播放下一个视频,先加载,播放后再转到正式组件上 private _bgTempVideo: any = null; //临时视频组件,等加载完成 private _bgTempShow: boolean = false; playBgAudioNext(remoteUrl:string, vtype:VideoRoleType, loop:boolean = false, extra:any = {}) { this.removeBgAudioNext(); logger.log("微信 创建背景视频组件2--->", remoteUrl); this.curPlayType = vtype let self = this; if (!this._bgTempVideo) { this._bgTempVideo = this.createVideoHandle(); // this._bgTempVideo.onPlay(() => { // logger.log("微信 临时背景视频播放开始"); // }) this._bgTempVideo.onTimeUpdate((_tinfo:any) =>{ // logger.log("微信 临时背景视频播放进度", self._bgTempShow, _tinfo); if (!self._bgTempShow) { if (_tinfo && _tinfo.position > 0.01) { logger.log("微信 背景视频2进入视野"); self._bgTempShow = true; self.videoMoveIn(self._bgTempVideo) self.removeBgAudio() Utils.sendInnerMsg(InnerMsgCode.BgVideo_Ready, {}); } } }) this._bgTempVideo.onEnded(() => { if (self.doPlayEmoReadyAudio()) { self.setBgAudioPause(self._bgTempVideo) } Utils.sendInnerMsg(InnerMsgCode.BgVideo_End, {}); }) } this._bgTempVideo.src = remoteUrl; //视频的地址 this._bgTempVideo.loop = loop; //循环播放 this._bgTempVideo.play(); } removeBgAudioNext() { this._bgTempShow = false; if (this._bgTempVideo) { this._bgTempVideo.stop(); this.videoMoveOut(this._bgTempVideo) } } //region 播放emo视频 private _emoVideo: any = null; //正式播放的视频组件 private _emoShow: boolean = false; addEmoAudio(remoteUrl:string, vtype:VideoRoleType, loop:boolean = false, extra:any = {}) { if (this._emoVideo && this._emoShow) { this.playEmoAudioNext(remoteUrl, vtype, loop, extra); return } let self = this; logger.log("微信 播放emo视频1", remoteUrl); this.curPlayType = vtype if (!this._emoVideo) { this._emoVideo = this.createVideoHandle(); // this._emoVideo.onPlay(() => { // logger.log("微信 背景视频播放开始"); // }) this._emoVideo.onTimeUpdate((_tinfo:any) =>{ // logger.log("微信 背景视频播放进度", self._emoShow, _tinfo); if (!self._emoShow) { if (_tinfo && _tinfo.position > 0.01) { logger.log("微信 emo视频1准备好了"); self._emoShow = true; self.removeEmoAudioNext() self.setEmoReadyAudio(self._emoVideo) if (self.curPlayType == VideoRoleType.emo) { self.doPlayEmoReadyAudio() } } } }) this._emoVideo.onEnded(() => { self.doEmoFinish() }) } this._emoVideo.src = remoteUrl; //视频的地址 this._emoVideo.loop = loop; //循环播放 this._emoVideo.play(); } removeEmoAudio() { this._emoShow = false; if (this._emoVideo) { this._emoVideo.stop(); this.videoMoveOut(this._emoVideo) } } //播放下一个视频,先加载,播放后再转到正式组件上 private _emoTempVideo: any = null; //临时视频组件,等加载完成 private _emoTempShow: boolean = false; playEmoAudioNext(remoteUrl:string, vtype:VideoRoleType, loop:boolean = false, extra:any = {}) { this.removeEmoAudioNext(); logger.log("微信 播放emo视频2--->", remoteUrl); this.curPlayType = vtype let self = this; if (!this._emoTempVideo) { this._emoTempVideo = this.createVideoHandle(); // this._emoTempVideo.onPlay(() => { // logger.log("微信 临时背景视频播放开始"); // }) this._emoTempVideo.onTimeUpdate((_tinfo:any) =>{ // logger.log("微信 临时背景视频播放进度", self._emoTempShow, _tinfo); if (!self._emoTempShow) { if (_tinfo && _tinfo.position > 0.01) { logger.log("微信 emo视频2已准备好"); self._emoTempShow = true; self.removeEmoAudio() self.setEmoReadyAudio(self._emoTempVideo) if (self.curPlayType == VideoRoleType.emo) { self.doPlayEmoReadyAudio() } } } }) this._emoTempVideo.onEnded(() => { self.doEmoFinish() }) } this._emoTempVideo.src = remoteUrl; //视频的地址 this._emoTempVideo.loop = loop; //循环播放 this._emoTempVideo.play(); } removeEmoAudioNext() { this._emoTempShow = false; if (this._emoTempVideo) { this._emoTempVideo.stop(); this.videoMoveOut(this._emoTempVideo) } } //视频移入屏幕 private videoMoveIn(video:any) { let adainfo = this.getVideoAdaInfo() video.x = adainfo.x video.y = adainfo.y } //视频移出屏幕 private videoMoveOut(video:any) { video.x = 10000 video.y = 10000 } /**创建一个视频播放器 */ private createVideoHandle() { let size = this.getWindowSize(); let adainfo = this.getVideoAdaInfo() let bgVideo = window['ks'].createVideo({ // src: remoteUrl, //视频的地址 x: size.width, //先在屏幕外创建,等加载完成后再移动到屏幕上 y: size.height, width: this.videoWidth*adainfo.scale, //视频的宽度 height: this.videoHeight*adainfo.scale, //视频的高度 autoplay: true, //自动播放 // loop: loop, //循环播放 controls: false, //是否显示控件 showProgress: false, //显示进度条 showProgressInControlMode: false, //在控制模式下显示进度条 enableProgressGesture: false, //是否启用进度手势 showCenterPlayBtn: false, //是否显示中间的播放按钮 underGameView: true, //视频是否显示在游戏画布之下。需要设置Camera的Clear Color为透明色 // backgroundColor: "#00000000", //视频背景颜色 objectFit: "fill" //视频的填充模式 }) return bgVideo } //获取视频适配信息 private videoWidth = 720 private videoHeight = 1280 private videoAdaInfo = null private getVideoAdaInfo() { if (this.videoAdaInfo) return this.videoAdaInfo this.videoAdaInfo = { x: 0, y: 0, scale: 1 } let size = this.getWindowSize(); let ratiow = size.width / this.videoWidth; //屏幕和视频的宽高比,谁大用谁 let ratioh = size.height / this.videoHeight; if (ratiow > ratioh) { this.videoAdaInfo.scale = ratiow this.videoAdaInfo.x = 0 this.videoAdaInfo.y = -(this.videoHeight * ratiow - size.height) / 2 } else { this.videoAdaInfo.scale = ratioh this.videoAdaInfo.x = -(this.videoWidth * ratioh - size.width) / 2 this.videoAdaInfo.y = 0 } logger.log("微信 视频适配信息", this.videoAdaInfo, size) return this.videoAdaInfo } //设置暂停播放的主视频 private vpWait: any = null; setBgAudioPause(wait:any) { logger.log("微信 主视频暂停播放") this.vpWait = wait this.vpWait.pause() } replayBgAudioPause() { logger.log("微信 主视频继续播放") if (this.vpWait) { this.vpWait.play() } } //设置准备好要播放的表情视频 private emoReady: any = null; setEmoReadyAudio(au: any) { logger.log("微信 设置emo ready视频") if (this.emoReady) { this.emoReady.stop() this.videoMoveOut(this.emoReady) } this.emoReady = au; this.emoReady.pause() } //移除准备好要播放的表情视频 removeEmoReadyAudio() { logger.log("微信 移除emo ready视频") if (this.emoReady) { this.emoReady.stop() this.videoMoveOut(this.emoReady) } this.emoReady = null } //播放准备好要播放的表情视频 doPlayEmoReadyAudio():boolean { if (this.emoReady) { logger.log("微信 播放emo ready视频") this.emoReady.play() this.videoMoveIn(this.emoReady) return true } return false } //表情视频播放结束 doEmoFinish() { logger.log("微信emo ready视频播放结束") this.removeEmoReadyAudio() this.replayBgAudioPause() } //region 复制到剪贴板 /**复制文本到剪贴板 */ copyToClipboard(text: string, cb?: Function) { logger.log("快手 复制到剪贴板:", text); window['ks'].setClipboardData({ data: text, success: () => { logger.log("快手 复制成功"); cb && cb(true); }, fail: (err) => { logger.log("快手 复制失败:", err); cb && cb(false); } }); } //region 友盟+ umaInit() { } //友盟统计是否开启 umaSwt() { return false; } //友盟事件统计 umaEvent(eventName: string, value: any = {}) { } }