yoyoawb
Version:
awb交互式应用框架
829 lines (764 loc) • 40 kB
JavaScript
((Scratch) => {
/**
* 是Turbowarp扩展
* https://turbowarp.org/editor 在线编辑器
*/
const { app, eventEmitter } = (()=>{const __mutual_cache=new Map();const __mutual_event=new Map();class Mutual{App;constructor(){this.#initAsyncJsPrompt();this.#appInit()}isJSON(str){try{JSON.parse(str);return true}catch(e){return false}}#appInit(){this.App=new Proxy({},{get:(target,key)=>new Proxy(target,{get:(target1,key1)=>(args,configJson)=>{args??={};configJson??={};configJson._time??=5000;configJson._time=Number(configJson._time);if(isNaN(Number(configJson._time)))configJson._time=5000;configJson._time=Math.abs(configJson._time);const ID=this.#generateUniqueID();const isSuccessful=this.#invoke(ID,key,key1,args,configJson);let isAppResult=this.isJSON(isSuccessful);let AppResultObj={};if(isAppResult){AppResultObj=JSON.parse(isSuccessful);if(AppResultObj.status){const binaryData=atob(String(AppResultObj.value));const utf8DecodedString=new TextDecoder('utf-8').decode(new Uint8Array([...binaryData].map(c=>c.charCodeAt(0))));AppResultObj.value=this.isJSON(utf8DecodedString)?JSON.parse(utf8DecodedString):utf8DecodedString}}if(typeof args?.success=='function'||typeof args?.fail=='function'||typeof args?.complete=='function'){const PrObj={};const resultObj=new Proxy(PrObj,{get:(t,k)=>{return(args)=>{window.Android?.asyncTaskPrompt(ID,k,JSON.stringify(args))}},set:(t,p,newValue,rec)=>{return t[p]=newValue}});if(!isSuccessful||!isAppResult){typeof args.fail=='function'&&args.fail({id:ID,message:'Interaction failure !'});typeof args.complete=='function'&&args.complete();return null}if(!AppResultObj.status){typeof args.fail=='function'&&args.fail({id:ID,message:AppResultObj.value??AppResultObj.message});typeof args.complete=='function'&&args.complete();return null}const cacheObj={base:{},result:PrObj,timeoutId:undefined};if(typeof args?.success=='function')cacheObj.base.success=args?.success;if(typeof args?.fail=='function')cacheObj.base.fail=args?.fail;if(typeof args?.complete=='function')cacheObj.base.complete=args?.complete;if(AppResultObj.exportType==1){typeof args.success=='function'&&args.success(AppResultObj.value);typeof args.complete=='function'&&args.complete();return null}if(configJson._time!==0){cacheObj.timeoutId=setTimeout(()=>{__mutual_cache.delete(ID);typeof args?.fail=='function'&&args?.fail({id:ID,message:'request timeout !'});typeof args?.complete=='function'&&args?.complete()},configJson._time)}__mutual_cache.set(ID,cacheObj);return resultObj}return new Promise((resolve,reject)=>{if(!isSuccessful||!isAppResult)return reject({id:ID,message:'Interaction failure !'});if(!AppResultObj.status)return reject({id:ID,message:AppResultObj.value??AppResultObj.message});if(AppResultObj.exportType==1){resolve(AppResultObj.value);return null}let timeoutId=undefined;if(configJson._time!==0){timeoutId=setTimeout(()=>{__mutual_cache.delete(ID);reject({id:ID,message:'request timeout !'})},configJson._time)}__mutual_cache.set(ID,[resolve,reject,timeoutId])})}})})}#invoke(ID,className,functionName,data,configJson){const isInvokeSucceed=window.Android?.asyncJavaPrompt(ID,JSON.stringify({...configJson,class:className,function:functionName}),JSON.stringify(data));return isInvokeSucceed}#initAsyncJsPrompt(){Object.defineProperty(window,'asyncJsPrompt',{value:(ID,data,plan)=>{ID??='';data??='';plan??=100;if(!__mutual_cache.has(ID))return false;const binaryData=atob(data);const utf8DecodedString=new TextDecoder('utf-8').decode(new Uint8Array([...binaryData].map(c=>c.charCodeAt(0))));try{const jsonData=JSON.parse(utf8DecodedString);const eventCallBack=__mutual_cache.get(ID);if(Array.isArray(eventCallBack)){if(plan>=100){if(jsonData.status){eventCallBack[0](jsonData.data)}else{eventCallBack[1](jsonData)}if(eventCallBack[2])clearTimeout(eventCallBack[2]);__mutual_cache.delete(ID)}}else{const{base,result,timeoutId}=eventCallBack;if(jsonData.event){const callbackFun=result[jsonData.event];typeof callbackFun=='function'&&callbackFun(jsonData.data)}if(plan>=100){if(jsonData.status){typeof base.success=='function'&&base.success(jsonData.data)}else{typeof base.fail=='function'&&base.fail(jsonData)}typeof base.complete=='function'&&base.complete();if(timeoutId)clearTimeout(timeoutId);__mutual_cache.delete(ID)}}}catch(e){console.error('应用调用数据格式错误:',e.message);return false}return true}})}#generateUniqueID(){const characters={str1:'abcdefghij',str2:'klmnopqrst',str3:'uvwxyztsrq',str4:'jihgfedcba',str5:'a1b2c3d4e5',str6:'f6g7h8i9j0',};let charactersStr='';const randtf=Math.floor(Math.random()*6)+1;charactersStr=characters[`str${randtf}`];let timestamp=new Date().getTime().toString();timestamp=timestamp.split('').reverse().join('');const snRand=Math.floor(Math.random()*9999)+1000;const snRand2=Math.floor(Math.random()*9999)+1000;timestamp+=snRand.toString().padStart(4,'0')+snRand2.toString().padStart(4,'0');let id='';for(let i=0;i<timestamp.length;i++){const digit=parseInt(timestamp[i],10);let character;if(digit%3===0){character=charactersStr[digit%10]}else if(digit%3===1){character=digit%10}else{character=charactersStr[digit%10].toUpperCase()}id+=character}return id}}class EventEmitter{constructor(){this.#initAsyncJsEventEmit()}#initAsyncJsEventEmit(){Object.defineProperty(window,'asyncJsEventEmit',{value:(eventName,data)=>{if(!__mutual_event.has(eventName))return false;const binaryData=atob(data);const utf8DecodedString=new TextDecoder('utf-8').decode(new Uint8Array([...binaryData].map(c=>c.charCodeAt(0))));try{const jsonData=JSON.parse(utf8DecodedString);for(const listener of __mutual_event.get(eventName)){listener.call(this,jsonData)}}catch(e){console.error('应用调用数据格式错误:',e.message);return false}return true}})}on(eventName,listener){if(!__mutual_event.has(eventName)){__mutual_event.set(eventName,new Set())}__mutual_event.get(eventName).add(listener)}once(eventName,listener){const wrapper=(...args)=>{listener.apply(this,args);this.off(eventName,wrapper)};this.on(eventName,wrapper)}off(eventName,listener){if(__mutual_event.has(eventName)){const listeners=__mutual_event.get(eventName);const matchingListeners=Array.from(listeners).filter(fn=>fn===listener);for(const matchingListener of matchingListeners){listeners.delete(matchingListener)}}}emit(eventName,...args){if(__mutual_event.has(eventName)){for(const listener of __mutual_event.get(eventName)){listener.apply(this,args)}}}}const mutualClass=new Mutual();return{app:mutualClass.App,eventEmitter:new EventEmitter()}})();
window.$awb = { app, event: eventEmitter };
window.$isAwb = (() => typeof window.Android != 'undefined')();
window.$noAwbHint = ['%c当前不是AWB交互环境,你可以前往 https://docs.wyouw.cn/#/awb/ 找到程序、并打包!', 'background-color: red; color: white; padding: 10px;'];
const blockIconURI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAABJtJREFUeF7tW71O40AQ3hWp4QnQhRqeABooeQLo7mh4A69EdVyFtH4Dmst14QkoL1fAE0B9CJ6AB7B8jOWJRsbOzK49tnNgKQIl9mbmm29+d2PNB7/sB9fffALwyYCRIOC9/2at/ZLn+dQYgy+QblGK+CfLssXFxcVTlyIP6gJXV1fTyWTyNc/zS6FST1mWHXUJwiAAgOIbGxs/36x7SBXf2toym5ubBv7CC67X11fz8PCAtz0553aEYIlu6x0AoLoxBpQvLlB0b2/P7O7uLpWmks/nc/Py8lK8Za09SpIEXUKkIHdTrwB4739Tqx8cHJj9/f1GGUFxAKC8Zs65M06h0M97A8B7D1YH6xeWPjk5qbU4KgDUv76+VqM+LtwLAJT229vb5vT0lDVUDPUhtoQGSHUA0jQ9zPMcqG+kykPQu729Rb+/TJLkB4cYATkoUKoDgH4PtD8/P+f0KKI+of7COXfEPURBDg2WqgBQwY6Pj4toz10x1K8G17dYI2aBKgCh1r+/vzd3d3dBKY8qDyAT1xGlTDUAQq1fSXnB1Ad2AQCEQSIWqAFA016SJBzzqeDGOSeSy3ufY1rF+EIDaJZlO1xWEH0RK33NDQgAWmbVGkBbLHel1R6lPqRVyDBw0SAqWUsTgL/Q1XHVHghNAYAAZq09W1Xy0rqibn3IIgCEtZZNoZoAFPSURH8Q9vHxcRkASxBmdfm/bKQA3Ma6AuPAYADQAAi+iZ0d50oQCIENAEh5vWt/m6hP1yaBkA2mKgygVqL+yQGAPtzEhjRNv+PsYBWziEutHwAIEq0JyvegDS7mB1xJTQBgO0gVBoCQ3ntxEGxiBrgCKIPzALyPS6sYBI0xZ8652SrmaQJQ9P6ctTi3qAZIiUulaYrLrj8AqAkGRi6gjqYQoplAYjWOCdLPR1MKl3GgEzeQKl/pJ1j6w7pqMaAEYDkA7YMFtJWW9hOqAJT1ALBg2jYYciyIsb46A6gbwP9c+uKUXJUuyRRJ3E2qA0ADoaQpigGgWitIOkD6PaouUNevxyi5yvI3NzfL3iFUeVUGSJqWNmDUlMqiqF/9ThUGaFEfq0IodmjHyM0Pei+FQ6mPiqFSkDGw4sM+4Pn5+V1PAFvnkrF5rwDEUJ80L1KvmFlrf3WxUdqpC8RQnxYv5WEIejgCAMEDETAqW0h2iaQodhoEJaOqqmCVfYDl/A7Wgnu5iW6Iok33dsaAUOrH7AN0obBKFuCmtHWCU7+XzO81lO/EBWKoH7P/N1oAQqkfs/WtpXxrBoRSP2brW1P5VgC0pf6Qft9JMxRK/TH5fWsAQqnfx2mvWFcJrgNCqd/Xaa/eAPhfqI+ABTEglPoxR15iLRn7nBiAUOqPpdTlgBEDQKnPbXmP3e+Ds4B0WxoXHmvKq2ODiAG40wsLcNPdphaXo+JQn0sBeHfEve6w87r4fbALwAPVHzngOX963J20uKIzekNZPQoAfIjGA3gPj77Tgwwx8/mhwBC5QFW4pp+8FN2V4GjaUMpGB8Emgats6GJM3Tc4UQygQhI2TLv+RVcfYLQGoA8hNb/jEwBNdNdh7Q/PgH/s80Fud3ttIAAAAABJRU5ErkJggg==";
/* ------- BLOCKS -------- */
const { BlockType, Cast, ArgumentType, vm } = Scratch;
class awbExtend {
#tapUser = {
userInfo: {
nickName: '',//用户名
avatar: '',//用户头像图片地址
openid: '',//授权用户唯一标识,每个玩家在每个游戏中的 openid 都是不一样的,同一游戏获取同一玩家的 openid 总是相同
unionid: ''//授权用户唯一标识,一个玩家在一个厂商的所有游戏中 unionid 都是一样的,不同厂商 unionid 不同
},
isInit: false,//是否初始化
isLogin: false,//是否登录成功
};
// 系统相关
#sys = {
isVpnConnected: false
};
#tapAd = {
isInit: false,//是否初始化
};
getInfo() {
return {
// id是扩展的id,随便写,不重复
id: 'awbExtend',
// name 是扩展名字
name: 'AWB交互v1.0.97',
// 积木颜色
color: '#003666',
// menuIconURI 图标地址可以不用
// blockIconURI 积木图标
blockIconURI,
// 积木列表
blocks: [
{
blockType: BlockType.LABEL,
text: '只能打包调试目前!!!希望将来可以解决。'
},
{
func: 'openDocs',
blockType: BlockType.BUTTON,
text: '打开文档'
},
'---',
{
blockType: BlockType.LABEL,
text: '系统操作'
},
{
blockType: BlockType.COMMAND,
opcode: 'vibrate',
text: '手机震动[matrix]',
arguments: {
matrix: {
type: ArgumentType.STRING,
defaultValue: '50 100 50 200 50 200 50'
}
}
},
{
blockType: BlockType.COMMAND,
opcode: 'stopVibrate',
text: '停止震动'
},
{
blockType: BlockType.COMMAND,
opcode: 'showToast',
text: '提示[msg]',
arguments: {
msg: {
type: ArgumentType.STRING,
defaultValue: '我是Scratch'
}
}
},
{
blockType: BlockType.COMMAND,
opcode: 'disableScreenCapture',
text: '禁止截图和录屏'
},
{
blockType: BlockType.COMMAND,
opcode: 'enableScreenCapture',
text: '允许截图和录屏'
},
{
blockType: BlockType.COMMAND,
opcode: 'setVolume',
text: '设置当前 音量[value] 音量通道[type] 输出设备[outputDevice]',
arguments: {
value: {
type: ArgumentType.NUMBER,
defaultValue: 8
},
type: {
type: ArgumentType.NUMBER,
defaultValue: 3
},
outputDevice: {
type: ArgumentType.NUMBER,
defaultValue: 3
}
}
},
{
blockType: BlockType.REPORTER,
opcode: 'getCurrentVolume',
text: '获取当前音量'
},
'---',
{
blockType: BlockType.LABEL,
text: '窗口操作'
},
{
blockType: BlockType.COMMAND,
opcode: 'setStatusBarColor',
text: '设置状态栏背景颜色[color]',
arguments: {
color: {
type: ArgumentType.COLOR,
defaultValue: '#515151'
}
}
},
{
blockType: BlockType.COMMAND,
opcode: 'setStatusBarTextColor',
text: '设置状态栏文字颜色[colorList]',
arguments: {
colorList: {
type: ArgumentType.STRING,
menu: 'monocHrome'
}
}
},
{
blockType: BlockType.COMMAND,
opcode: 'setStatusBarTransparency',
text: '隐藏状态栏'
},
{
blockType: BlockType.COMMAND,
opcode: 'setLandscape',
text: '设置横屏'
},
{
blockType: BlockType.COMMAND,
opcode: 'setPortrait',
text: '设置竖屏'
},
{
blockType: BlockType.COMMAND,
opcode: 'setFullScreen',
text: '设置全屏'
},
{
blockType: BlockType.COMMAND,
opcode: 'exitFullScreen',
text: '取消全屏'
},
{
blockType: BlockType.COMMAND,
opcode: 'home',
text: '返回桌面'
},
{
blockType: BlockType.COMMAND,
opcode: 'exit',
text: '结束应用',
isTerminal: true
},
{
blockType: BlockType.BOOLEAN,
opcode: 'isVPN',
text: '当前是否开启VPN'
},
'---',
{
blockType: BlockType.LABEL,
text: 'TapTap用户操作'
},
{
blockType: BlockType.COMMAND,
opcode: 'tapUserInit',
text: '初始化登录 Id[clientId] Token[clientToken] Url[serverUrl]',
arguments: {
clientId: {
type: ArgumentType.STRING,
defaultValue: '应用的ClientID'
},
clientToken: {
type: ArgumentType.STRING,
defaultValue: '应用的clientToken'
},
serverUrl: {
type: ArgumentType.STRING,
defaultValue: '绑定的服务器域名'
}
}
},
{
blockType: BlockType.BOOLEAN,
opcode: 'tapUserIsLogin',
text: '当前是否登录'
},
{
blockType: BlockType.COMMAND,
opcode: 'tapUserLogin',
text: '调用TapTap登录'
},
{
blockType: BlockType.EVENT,
opcode: 'tapUserisLoginStatus',
text: 'tapTap登录响应',
isEdgeActivated: false,//不是一直响应触发的
},
{
blockType: BlockType.REPORTER,
opcode: 'tapUserGetUserInfo',
text: '获取当前登录的信息'
},
{
blockType: BlockType.COMMAND,
opcode: 'tapUserLogout',
text: '退出登录'
},
'---',
{
blockType: BlockType.LABEL,
text: 'TapTap广告操作'
},
{
blockType: BlockType.COMMAND,
opcode: 'tapAdInit',
text: '初始化广告 [mediaId] 媒体名称[mediaName] 密钥[mediaKey] 游戏Id[clientId]',
arguments: {
mediaId: {
type: ArgumentType.STRING,
defaultValue: 'TapADN Id'
},
mediaName: {
type: ArgumentType.STRING,
defaultValue: 'TapADN注册的媒体名称'
},
mediaKey: {
type: ArgumentType.STRING,
defaultValue: '媒体密钥'
},
clientId: {
type: ArgumentType.STRING,
defaultValue: 'clientId'
}
}
},
{
blockType: BlockType.EVENT,
opcode: 'onRewardVideoAdLoadError',
text: '激励视频获取失败',
isEdgeActivated: false,//不是一直响应触发的
},
{
blockType: BlockType.EVENT,
opcode: 'onRewardVideoAdFinish',
text: '看完激励视频',
isEdgeActivated: false,//不是一直响应触发的
},
{
blockType: BlockType.EVENT,
opcode: 'onRewardVideoAdClose',
text: '关闭激励视频',
isEdgeActivated: false,//不是一直响应触发的
},
{
blockType: BlockType.COMMAND,
opcode: 'showRewardVideoAd',
text: '打开激励视频广告ID[spaceId] 奖品名称[rewordName]',
arguments: {
spaceId: {
type: ArgumentType.STRING,
defaultValue: '广告位id'
},
rewordName: {
type: ArgumentType.STRING,
defaultValue: '奖品名称'
},
}
},
{
blockType: BlockType.EVENT,
opcode: 'onSplashAdLoadError',
text: '开屏广告获取失败',
isEdgeActivated: false,//不是一直响应触发的
},
{
blockType: BlockType.EVENT,
opcode: 'onSplashAdFinish',
text: '开屏广告结束',
isEdgeActivated: false,//不是一直响应触发的
},
{
blockType: BlockType.COMMAND,
opcode: 'showSplashAd',
text: '打开开屏广告ID[spaceId]',
arguments: {
spaceId: {
type: ArgumentType.STRING,
defaultValue: '广告位id'
}
}
},
],
menus: {
SPRITES: {
acceptReporters: true,
items: 'getSprites'
},
variablesMenu: {
acceptReporters: false,
items: "getVariables",
},
monocHrome: {
acceptReporters: true,
items: ['black', 'white']
}
}
}
}
/**
* 打开AWB文档
*/
openDocs() {
window.open('https://docs.wyouw.cn/#/awb/', '_blank');
}
/* 系统操作 */
/**
* 手机震动
*/
vibrate(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
const matrix = String(args.matrix);
if (matrix.length <= 0) return;
const matrixArr = matrix.match(/[\S]+/g).map(Number).filter(v => !isNaN(v));//将字符串转成数组矩阵
$awb.app.sys.vibrate({ array: matrixArr }).catch(e => {
console.error(e);
});
}
/**
* 停止震动
*/
stopVibrate(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.sys.stopVibrate().catch(e => {
console.error(e);
});
}
/**
* Toast提示
*/
showToast(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
const msg = String(args.msg);
if (msg.length <= 0) return;
$awb.app.fun.showToast({ message: msg }).catch(e => {
console.error(e);
});
}
// 禁止截图和录屏
disableScreenCapture(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.sys.disableScreenCapture().catch(e => {
console.error(e);
});
}
// 允许截图和录屏
enableScreenCapture(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.sys.enableScreenCapture().catch(e => {
console.error(e);
});
}
// 设置当前音量
setVolume(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
const { value, type, outputDevice } = args;
$awb.app.audio.setVolume({ value, type, outputDevice }).catch(e => {
console.error(e);
});
}
// 获取当前音量
async getCurrentVolume(args, util) {
if (!$isAwb) {
console.log(...$noAwbHint);
return 0;
}
const result = await $awb.app.audio.getCurrentVolume().catch(e => {
console.error(e);
});
return Cast.toNumber(result || 0);
}
/* 窗口操作类 */
async isVPN(args, util) {
if (!$isAwb) {
console.log(...$noAwbHint);
return false;
}
const result = await $awb.app.fun.isVpn().catch(e => {
console.error(e);
this.#sys.isVpnConnected = false;
});
this.#sys.isVpnConnected = result || false;
return Cast.toBoolean(result || false);
}
// 结束应用
exit(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.win.exit().catch(e => {
console.error(e);
});
}
// 返回桌面
home(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.win.home().catch(e => {
console.error(e);
});
}
// 设置状态栏背景颜色
setStatusBarColor(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
const color = String(args.color);
if (color.length <= 0) return;
$awb.app.win.setStatusBarColor({ color }).catch(e => {
console.error(e);
});
}
// 设置状态栏文字颜色
setStatusBarTextColor(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
const monochrome = args.colorList;
$awb.app.win.setStatusBarTextColor({ isDark: Boolean(monochrome == 'black' || false) }).catch(e => {
console.error(e);
});
}
// 隐藏状态栏
setStatusBarTransparency(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.win.setStatusBarTransparency().catch(e => {
console.error(e);
});
}
// 设置横屏
setLandscape(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.win.setLandscape({
status: true
}).catch(e => {
console.error(e);
});
}
// 设置竖屏
setPortrait(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.win.setPortrait({
status: false
}).catch(e => {
console.error(e);
});
}
// 设置全屏
setFullScreen(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.win.setFullscreen({
status: true
}).catch(e => {
console.error(e);
});
}
// 取消全屏
exitFullScreen(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.win.setFullscreen({
status: false
}).catch(e => {
console.error(e);
});
}
/* TapTap用户 */
// 初始化登录SDK
tapUserInit(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
const { clientId, clientToken, serverUrl } = args;
$awb.app.tapUser.init({ clientId, clientToken, serverUrl })
.then(() => {
this.#tapUser.isInit = true;
}).catch(e => {
this.#tapUser.isInit = false;
console.error(e);
});
}
// 当前是否登录
async tapUserIsLogin(args, util) {
if (!$isAwb) {
console.log(...$noAwbHint);
return false;
}
const result = await $awb.app.taptap.isLogin().catch(e => {
console.error(e);
this.#tapUser.isLogin = false;
});
this.#tapUser.isLogin = result || false;
return Cast.toBoolean(result || false);
}
// 调用TapTap登录
tapUserLogin(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.taptap.login(null, { _time: 0 }).then(res => {
this.#tapUser.isLogin = true;
this.#tapUser.userInfo = res;
vm.runtime.startHats('awbExtend_tapUserisLoginStatus');//登录反馈
}).catch(e => {
this.#tapUser.isLogin = false;
const object = Object.key(this.#tapUser.userInfo).reduce((acc, key) => ({
...acc,
[key]: '',
}), {});
this.#tapUser.userInfo = object;//清空数据
vm.runtime.startHats('awbExtend_tapUserisLoginStatus');//登录反馈
console.error(e);
});
}
// 获取当前登录的信息
async tapUserGetUserInfo(args, util) {
if (!$isAwb) {
console.log(...$noAwbHint);
return this.#tapUser.userInfo;
}
const result = await $awb.app.taptap.userInfo().catch(e => {
console.error(e);
const object = Object.key(this.#tapUser.userInfo).reduce((acc, key) => ({
...acc,
[key]: '',
}), {});
this.#tapUser.userInfo = object;//清空数据
});
return result || this.#tapUser.userInfo;
}
// 退出登录
tapUserLogout(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
$awb.app.taptap.logout().catch(e => {
console.error(e);
});
}
/* TapTap广告 */
// 初始化广告SDK
tapAdInit(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
const { mediaId, mediaName, mediaKey, clientId } = args;
$awb.app.taptap.initAd({
mediaId,
mediaName,
mediaKey,
clientId,
clientToken,
serverUrl,
mediaVersion: 1,
// 是否打开 debug 调试信息输出:true 打开、false 关闭。默认 false 关闭
debuggable: false,
// 渠道
channel: "tapTap",
// 是否开启摇一摇: true 打开、false 关闭
shakeEnable: true,
// 是否允许 SDK 主动使用地理位置信息
isCanUseLocations: true,
// 当 isCanUseLocation=false 时,可传入地理位置信息,TapAd 使用您传入的地理位置信息
latitude: 0.0,//经度
longitude: 0.0,//纬度
accuracy: 0.0,//精度
// 是否允许 SDK 主动使用手机硬件参数,如 imei
isCanUsePhoneState: true,
// 当 isCanUsePhoneState=false 时,可传入 imei 信息,TapAd 使用您传入的 imei 信息
imei: "ozVtU3CR2lglUrbZ9wE4FulcEE4dOd7TnKGsji0E",
// 是否允许 SDK 主动使用 ACCESS_WIFI_STATE 权限
isCanUseWifiState: true,
// 是否允许 SDK 主动使用 WRITE_EXTERNAL_STORAGE 权限
isCanUseWriteExternal: true,
// 是否允许 SDK 主动获取设备上应用安装列表的采集权限
isAlist: true,
// 是否允许 SDK 主动获取 ANDROID_ID
isCanUseAndroidId: true,
/* 用户信息(针对用户推荐广告)*/
age: 1,//年龄
sex: 1,//性别 0:男 1:女
avatarSex: 1,//角色性别 0:男 1:女
avatarLevel: 1,//角色等级
isNewUserStatus: 0,//是否新玩家 0:否;1:是
isPayedUserStatus: 0,//是否付费用户 0:否;1:是
finished: 0,//是否通过新手教程 0:否 1:是
cnt: 0,//角色当前付费道具数量
})
.then(() => {
this.#tapAd.isInit = true;
}).catch(e => {
this.#tapAd.isInit = false;
console.error(e);
});
}
// 打开激励视频广告
showRewardVideoAd(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
const { spaceId, rewordName } = args;
const tapadObj = $awb.app.taptap.showRewardVideoAd({
// 广告后台获取广告位id
spaceId,
// 奖品名称
rewordName,
// 游戏如果要通过 s2s 验证激励广告有效性的时候需要传入一些辅助信息来验证本次激励活动是否有效
extra1: "your_extra_info",
// 游戏如果要通过 s2s 验证激励广告有效性的时候需要传入游戏中的玩家 id,来验证是否可以对当前用户发放奖励
userId: "game_user_id",
complete: () => { }
}, {
_time: 0//等待超时时间 单位毫秒 0是无限
});
tapadObj.onError = () => {
vm.runtime.startHats('awbExtend_onRewardVideoAdLoadError');//拉取失败
};
tapadObj.onAdClose = () => {
vm.runtime.startHats('awbExtend_onRewardVideoAdClose');//视频被关闭
};
tapadObj.onVideoComplete = () => {
vm.runtime.startHats('awbExtend_onRewardVideoAdFinish');//视频看完
};
}
// 打开开屏广告
showSplashAd(args, util) {
if (!$isAwb) return console.log(...$noAwbHint);
const { spaceId } = args;
const tapadObj = $awb.app.taptap.showSplashAd({
// 广告后台获取广告位id
spaceId,
complete: () => { }
}, {
_time: 0//等待超时时间 单位毫秒 0是无限
});
tapadObj.onError = () => {
vm.runtime.startHats('awbExtend_onSplashAdLoadError');//拉取失败
};
tapadObj.onAdSkip = () => {
vm.runtime.startHats('awbExtend_onSplashAdFinish');//点击了跳过,可以进入游戏
};
tapadObj.onAdTimeOver = () => {
vm.runtime.startHats('awbExtend_onSplashAdFinish');//开屏时间到(开屏页已关闭),可以进入游戏
};
}
/** (额外封装) */
// 获取所有角色
getSprites() {
const sprites = [];
for (const target of vm.runtime.targets) {
if (target.isOriginal && !target.isStage) {
sprites.push({
text: target.getName(),
value: target.id,
});
}
}
if (sprites.length === 0) {
return [
{
text: Scratch.translate("没有角色"),
value: " ",
},
];
}
return sprites;
}
/**
* 通过名称找到角色
* @param {VM.BlockUtility} util
* @param {unknown} SpriteName
*/
getSpriteTargetByName(util, SpriteName) {
const nameString = Scratch.Cast.toString(SpriteName);
const target = util.target;
if (target.getName() === nameString) {
return target;
}
return util.runtime.getSpriteTargetByName(nameString);
}
/**
* 通过ID找到角色
* @param {VM.BlockUtility} util
* @param {unknown} SpriteId
*/
getSpriteTargetById(util, SpriteId) {
const idString = Scratch.Cast.toString(SpriteId);
const target = util.target;
if (target.id === idString) {
return target;
}
return util.runtime.getTargetById(idString);
}
//获取所有列表
getVariablesList() {
return this.getVariables(2);
}
//获取所有变量 1 是全部变量 2是全部列表 3是列表和变量
getVariables(type = 1) {
// 获取指定目标的私有变量值(舞台,属于公共的呀)
const getMyvariables = (target) => {
return Object.values(target.variables).filter((variable) => {
if (type == 1 && variable.type != 'list') return true;
if (type == 2 && variable.type == 'list') return true;
if (type == 3) return true;
return false;
});
};
const editingTarget = vm.editingTarget;
const isStage = editingTarget.isStage;//当前是否选中舞台
let variables = [];
if (isStage) {
//选中的舞台 只需要获取舞台的值
variables = getMyvariables(editingTarget);
} else {
//选中的其他角色 除了角色本身的变量之外,还需要获取所有目标中的第一个舞台角色
//获取自身的
variables = getMyvariables(editingTarget);
// 获取舞台角色的变量
const targets = vm.runtime.targets;
const stage = targets.find((t) => t.isStage);
variables = [...variables, ...getMyvariables(stage)]
}
const newResult = variables.map((model) => ({
text: model.name,
value: model.id,
}));
if (newResult.length > 0) {
return newResult;
} else {
return [{ text: "", value: "" }];
}
}
//获取原有变量的值
getVariablesValue(id) {
const targets = vm.runtime.targets;
const target = targets.find((t) => Object.values(t.variables).find((v) => v.id == id));
if (!target) return null;
const variable = target.variables[id];
return variable.value;
}
}
Scratch.extensions.register(new awbExtend());
})(Scratch);