ttApi.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. // import gameConfig from "../../../config/gameConfig";
  2. // import {
  3. // authorizeParams,
  4. // getUserInfoParams,
  5. // loadParams,
  6. // loginParams,
  7. // MiniGameApiBase,
  8. // ModalParams,
  9. // recordedGameScreenParams,
  10. // toastParams
  11. // } from "../miniGameBase/miniGameApiBase";
  12. import { sys, Vec2, Node } from "cc";
  13. import { MiniGameApiBase, getUserInfoParams, toastParams, loadParams, ModalParams, authorizeParams, loginParams, recordedGameScreenParams } from "./MiniGameApiBase";
  14. import { GameCfg } from "../Config/GameCfg";
  15. export interface TtRewardedVideoAdParam {
  16. // 名称 数据类型 属性 默认值 描述
  17. adUnitId: string; //required 广告位 id
  18. }
  19. export interface TtVideoAd {
  20. // 通过 load 方法主动预加载广告内容。
  21. // 此外,在显示广告出现问题时也可以尝试主动 load 一次。
  22. // 该方法返回一个 Promise,如果广告已经自动拉取成功,调用该方法返回一个 resolved Promise;
  23. load: () => Promise<any>;
  24. // 广告创建后默认是隐藏的,可以通过该方法显示广告。 该方法返回一个 Promise 对象。当广告组件正常获取素材时,该 Promise 对象会是一个 resolved Promise。当广告组件发生错误时,会是一个 rejected Promise,参数与error事件监听器获得的参数相同。
  25. show: () => Promise<any>;
  26. //绑定 load 事件的监听器,用户在手动调用 load 方法后,广告组件会预先加载。 广告组件成功拉取广告素材时会触发load事件的监听器。
  27. //确保监听此事件时,开发者主动调用过 load 方法。
  28. onLoad: (listener: Function) => void;
  29. // 解除绑定 load 事件的监听器。
  30. offLoad: (listener: Function) => void;
  31. //绑定 error 事件的监听器。 广告组件拉取广告素材和其他情况下如果发生错误,会触发error事件的监听器。监听器会获得一个包含errCode和errMsg属性的对象参数。
  32. // errCode 详情
  33. onError: (listener: (error: any) => void) => void;
  34. // 解除绑定 error 事件的监听器。
  35. offError: (listener: Function) => void;
  36. // 绑定 close 事件的监听器。 当用户点击了 Video 广告上的关闭按钮时,会触发close事件的监听器。监听器会获得一个包含isEnded属性的对象参数,表征用户是否完整观看了视频。
  37. onClose: (listener: (res: { isEnded: boolean }) => void) => void;
  38. //解除绑定 close 事件的监听器。
  39. offClose: (listener: Function) => void;
  40. //
  41. destroy: () => Promise<any>;
  42. }
  43. const tt: any = window['tt'];
  44. export default class TtApi extends MiniGameApiBase {
  45. protected m_AppId: string = "tt20b55608bf84081c02";
  46. protected m_Secret: string = "";
  47. protected m_VideoAdIdIndex: number = 0;
  48. protected m_VideoAdIdList: string[] = ["23h6nffncfjm20ki5m"];
  49. protected m_BannerAdIdIndex: number = 0;
  50. protected m_BannerAdId: string[] = [];
  51. protected m_InsertAdIdIndex: number = 0;
  52. protected m_InsertAdId: string[] = ["5ch1ssjoa29pmbe0me"];
  53. protected m_videoAd: TtVideoAd = undefined;
  54. protected m_BannerAd: unknown = undefined;
  55. /** 录屏管理器 */
  56. protected m_gameRecorder: any = null;
  57. validAppId(): void {
  58. console.log("tt-api-validAppId");
  59. }
  60. ready(): void {
  61. if (GameCfg.SYSTEM_LOG) console.log("tt-api-ready");
  62. this.m_gameRecorder = tt.getGameRecorderManager();
  63. }
  64. getUserInfo(params: getUserInfoParams): void {
  65. tt.getUserInfo(params);
  66. }
  67. showToast(params: toastParams): void {
  68. tt.showToast(params);
  69. }
  70. showLoading(params: loadParams): void {
  71. tt.showLoading(params);
  72. }
  73. hideLoading(): void {
  74. tt.hideLoading();
  75. }
  76. showModal(params: ModalParams): void {
  77. tt.showModal(params);
  78. }
  79. authorize(params: authorizeParams): void {
  80. params.success && params.success();
  81. }
  82. login(params: loginParams): void {
  83. tt.login(params);
  84. }
  85. checkScene(successCB: Function, errorCB?: Function) {
  86. tt.checkScene({
  87. scene: "sidebar",
  88. success: (res) => {
  89. console.log("check scene success: ", res.isExist);
  90. successCB && successCB()
  91. //成功回调逻辑
  92. },
  93. fail: (res) => {
  94. console.log("check scene fail:", res);
  95. //失败回调逻辑
  96. errorCB && errorCB()
  97. }
  98. });
  99. }
  100. navigateToScene(successCB: Function, errorCB?: Function) {
  101. tt.navigateToScene({
  102. scene: "sidebar",
  103. success: (res) => {
  104. console.log("navigate to scene success");
  105. // 跳转成功回调逻辑
  106. successCB && successCB()
  107. },
  108. fail: (res) => {
  109. console.log("navigate to scene fail: ", res);
  110. // 跳转失败回调逻辑
  111. errorCB && errorCB()
  112. },
  113. });
  114. }
  115. getVideoAdId(): string {
  116. const id: string = this.m_VideoAdIdList[this.m_VideoAdIdIndex];
  117. this.m_VideoAdIdIndex++;
  118. if (this.m_VideoAdIdIndex >= this.m_VideoAdIdList.length) {
  119. this.m_VideoAdIdIndex = 0;
  120. }
  121. return id;
  122. }
  123. loadAndShowVideoAd(successCB: () => void, errorCB?: (error: any) => void, completeCB?: () => void, reportAnalyticsExplain?: string): void {
  124. this.showLoading({ title: '请求中', mask: true });
  125. const videoAdId = this.getVideoAdId();
  126. console.log('tt 视频广告', videoAdId, reportAnalyticsExplain);
  127. //创建 视频
  128. const videoAd: TtVideoAd = tt.createRewardedVideoAd({
  129. adUnitId: videoAdId,
  130. });
  131. //监听 视频关闭
  132. let onCloseVideoAd = (res) => {
  133. //
  134. videoAd.offClose(onCloseVideoAd);
  135. console.log('tt 视频广告关闭', res);
  136. if (res && res.isEnded) {
  137. // 给予奖励
  138. successCB();
  139. // HttpRequest.post("https://game.renyouwangluo.cn/prod-api/ruoyi-ticktok/ticktok/Video_Message", { "openid": User.userData.openid, "mp_id": "tt833cf5811c08369602" })
  140. // .then(() => {
  141. // console.log("上报一次!!!!")
  142. // })
  143. // .catch(() => {
  144. // console.log("上报异常!!!!")
  145. // });
  146. } else {
  147. errorCB('视频中途退出');
  148. }
  149. completeCB && completeCB();
  150. };
  151. //重试
  152. let onTryAgain = (e: any) => {
  153. videoAd.load().then(() => {
  154. videoAd.show().then(() => {
  155. this.hideLoading();
  156. videoAd.onClose(onCloseVideoAd);
  157. }).catch((e) => {//展示异常
  158. errorCB && errorCB('视频展示异常');
  159. completeCB && completeCB();
  160. });
  161. }).catch((e) => {//加载异常
  162. errorCB && errorCB('视频拉取异常02');
  163. completeCB && completeCB();
  164. });
  165. }
  166. console.log('展示一次');
  167. videoAd.load().then(() => {
  168. videoAd.show().then(() => {
  169. this.hideLoading();
  170. videoAd.onClose(onCloseVideoAd);
  171. //展示异常
  172. }).catch((e) => {
  173. console.log('重试一次');
  174. onTryAgain(e);
  175. })
  176. }).catch((e) => {//加载异常
  177. errorCB && errorCB('视频拉取异常01');
  178. completeCB && completeCB();
  179. });
  180. }
  181. getInsertAdId(): string {
  182. const id: string = this.m_InsertAdId[this.m_InsertAdIdIndex];
  183. this.m_InsertAdIdIndex++;
  184. if (this.m_InsertAdIdIndex >= this.m_InsertAdId.length) {
  185. this.m_InsertAdIdIndex = 0;
  186. }
  187. return id;
  188. }
  189. showInsertAd(onAdClose: () => void, onFailed: () => void): void {
  190. console.log("加抖音 插屏 广告");
  191. const adId = this.getInsertAdId();
  192. let insertAd = tt.createInterstitialAd({
  193. adUnitId: adId,
  194. });
  195. insertAd.load();
  196. insertAd.onLoad(() => {
  197. console.warn('插屏广告 加载完成');
  198. insertAd.show().catch((err) => {
  199. console.warn('插屏广告 显示失败 :' + JSON.stringify(err));
  200. insertAd.destroy();
  201. insertAd = null;
  202. if (onFailed) {
  203. onFailed();
  204. }
  205. });
  206. });
  207. insertAd.onError((err) => {
  208. console.warn('插屏广告 加载失败' + JSON.stringify(err));
  209. insertAd.destroy();
  210. insertAd = null;
  211. if (onFailed) {
  212. onFailed();
  213. }
  214. });
  215. insertAd.onClose(() => {
  216. console.warn('插屏广告 关闭');
  217. if (insertAd != null) {
  218. insertAd.destroy();
  219. insertAd = null;
  220. }
  221. if (onAdClose) {
  222. onAdClose();
  223. }
  224. });
  225. }
  226. getBannerAdId(): string {
  227. const id: string = this.m_BannerAdId[this.m_BannerAdIdIndex];
  228. this.m_BannerAdIdIndex++;
  229. if (this.m_BannerAdIdIndex >= this.m_BannerAdId.length) {
  230. this.m_BannerAdIdIndex = 0;
  231. }
  232. return id;
  233. }
  234. showBannerAD(node: Node, successCB?: () => void, errorCB?: (error: any) => void, onCloseCB?: () => void,
  235. setBannerPos?: ({ screenWidth, screenHeight }: { screenWidth: any; screenHeight: any; }) => Vec2): void {
  236. }
  237. hideBanner() {
  238. // if (this.m_BannerAd != null) {
  239. // this.m_BannerAd.hide();
  240. // }
  241. }
  242. protected m_gameRecordDate: number = 0;
  243. protected m_gameRecordUrl: string = undefined;
  244. recordedGameScreenStart(params: recordedGameScreenParams, onStart?: (res: any) => void): void {
  245. this.m_gameRecordDate = Date.now();
  246. this.m_gameRecordUrl = null;
  247. this.m_gameRecorder.onStart((res) => {
  248. console.log('tt 录屏开始', res);
  249. onStart && onStart(res);
  250. });
  251. this.m_gameRecorder.onStop((res: any) => {
  252. console.log('tt 录屏结束', res.videoPath);
  253. this.m_gameRecordUrl = res.videoPath;
  254. });
  255. this.m_gameRecorder.start(params);
  256. }
  257. recordedGameScreenStop() {
  258. if (Date.now() - this.m_gameRecordDate < 3500) {
  259. return false;
  260. }
  261. this.m_gameRecorder.stop();
  262. return true;
  263. }
  264. shareRecordedGameScreen(successCb?: () => void, failCb?: (e?: any) => void): void {
  265. if (this.m_gameRecordUrl) {
  266. tt.shareAppMessage({
  267. channel: "video", // 转发内容类型
  268. title: GameCfg.appName,
  269. desc: GameCfg.GAME_VIDEO_SHARE_DESC,
  270. extra: {
  271. hashtag_list: [GameCfg.appName],
  272. videoPath: this.m_gameRecordUrl, // 可替换成录屏得到的视频地址
  273. videoTopics: [GameCfg.appName],
  274. video_title: GameCfg.GAME_VIDEO_SHARE_TITLE,
  275. withVideoId: true,
  276. defaultBgm: '',
  277. },
  278. success: (res) => {
  279. // let shareGameRecord = getShareGameRecordReportData('分享成功');
  280. // this.reportAnalytics(shareGameRecord.key, shareGameRecord.obj);
  281. console.log("tt 分享视频成功");
  282. //
  283. console.log(res.videoId);
  284. console.log(res.shareWithShareBgmStatus); //回调参数
  285. console.log("分享视频成功 4");
  286. successCb && successCb();
  287. },
  288. fail: (e) => {
  289. // let shareGameRecord = getShareGameRecordReportData('分享失败');
  290. // this.reportAnalytics(shareGameRecord.key, shareGameRecord.obj);
  291. console.log("tt 分享视频失败", e);
  292. failCb && failCb(e)
  293. }
  294. });
  295. } else {
  296. failCb && failCb(null);
  297. console.log("tt 分享视频为空");
  298. }
  299. }
  300. isHaveRecordedGameScreen(): boolean {
  301. return true;
  302. }
  303. getStorageSync(key: string) {
  304. let data = null;
  305. if (sys.isMobile) {
  306. if (window["tt"]) {
  307. try {
  308. data = window["tt"].getStorageSync(key)
  309. data = data == "" ? null : data
  310. } catch (error) {
  311. console.log(`get Storage ${key} fail`)
  312. }
  313. }
  314. } else {
  315. data = sys.localStorage.getItem(key)
  316. }
  317. return data
  318. }
  319. removeStorage (key?: string) {
  320. if (!key) {
  321. if (sys.isMobile) {
  322. if (window["tt"]) {
  323. window["tt"].clearStorage()
  324. }
  325. } else {
  326. sys.localStorage.clear()
  327. }
  328. } else {
  329. if (sys.isMobile) {
  330. if (window["tt"]) {
  331. window["tt"].removeStorage({ key: key })
  332. }
  333. } else {
  334. sys.localStorage.removeItem(key);
  335. }
  336. }
  337. }
  338. getDeviceInfo(): any {
  339. if (window["tt"]) {
  340. let obj: any = window["tt"].getSystemInfoSync()
  341. return obj.model
  342. }
  343. let str: string = navigator.userAgent
  344. let res: RegExpMatchArray = str.match(/ipad/i)
  345. console.log("userAgent: ", str)
  346. if (res) return "ipad"
  347. if (sys.isBrowser && sys.os == sys.OS.IOS) {
  348. res = str.match(/iphone/i)
  349. if (res) return "iphone"
  350. if (window.screen.height > window.screen.width) return "ipad"
  351. return "mac"
  352. }
  353. return ""
  354. }
  355. setUnlockAllTime(time: number) {
  356. if (sys.isMobile) {
  357. if (window["tt"]) {
  358. window["tt"].setStorage({
  359. key: "unit_unlock_all", data: time,
  360. success(res) {
  361. console.log("set unit_unlock_all success: ", res.data)
  362. }, fail(res) {
  363. console.log("set unit_unlock_all fail", res);
  364. }
  365. })
  366. }
  367. } else {
  368. sys.localStorage.setItem("unit_unlock_all", time)
  369. }
  370. }
  371. getUnlockAllTime(call: Function) {
  372. if (sys.isMobile) {
  373. if (window["tt"]) {
  374. window["tt"].getStorage({
  375. key: "unit_unlock_all", success(res) {
  376. console.log("get unit_unlock_all success: ", res)
  377. if (call)
  378. call(res.data);
  379. }, fail(res) {
  380. console.log("get unit_unlock_all fail: ", res)
  381. if (call) call();
  382. }
  383. })
  384. } else {
  385. if (call) call();
  386. }
  387. } else {
  388. if (call)
  389. call(sys.localStorage.getItem("unit_unlock_all"))
  390. }
  391. }
  392. setUnitState(state?: string) {
  393. if (sys.isMobile) {
  394. if (window["tt"]) {
  395. window["tt"].setStorage({
  396. key: "unit_state", data: state,
  397. success(res) {
  398. console.log("set unit_state success: ", res.data)
  399. }, fail(res) {
  400. console.log("set unit_state fail", res);
  401. }
  402. })
  403. }
  404. } else {
  405. sys.localStorage.setItem("unit_state", state)
  406. }
  407. }
  408. /**
  409. * 打点
  410. * @param eventName 事件名,注意不能超过 110 字符
  411. * @param data 上报的数据 可选 {}
  412. */
  413. reportAnalytics(eventName: string, data: { [key: string]: number | string | boolean } = {}) {
  414. if (window["tt"]) {
  415. window["tt"].reportAnalytics(eventName, data || {});
  416. }
  417. }
  418. setSoundInfo(sound?: boolean, music?: boolean) {
  419. if (sys.isMobile) {
  420. if (window["tt"]) {
  421. window["tt"].setStorage({
  422. key: "sound", data: JSON.stringify({ sound: sound, music: music }),
  423. success(res) {
  424. console.log("set sound success: ", res)
  425. }, fail(res) {
  426. console.log("set sound fail", res);
  427. }
  428. })
  429. }
  430. } else {
  431. sys.localStorage.setItem("sound", JSON.stringify({ sound: sound, music: music }))
  432. }
  433. }
  434. async getLaunchOptionsSync(): Promise<any> {
  435. return new Promise((resolve) => {
  436. const options = tt.getLaunchOptionsSync();
  437. resolve(options);
  438. });
  439. }
  440. }