--===================================================================== -- 白色液态玻璃 UI · RLGG 版(三页) -- 布局:左边一条竖排导航「主页 / 防封 / 功能」,右边是对应内容页 -- 主页 —— 2 个按钮:例子1、例子2 -- 防封 —— 4 个按钮:例子(两个一行,共两行) -- 功能 —— 2 个按钮 -- 实现:Lua 建悬浮窗 + WebView,CSS 画玻璃(本引擎没有绘制函数, -- UI 一律走 WebView;按钮点击用 rlgg.load 回调进 Lua) -- 操作:顶部细边可拖窗口 · 右上「—」收成小圆标,点圆标弹回来 · 「✕」退出 -- 动画:展开 / 收起 / 退出都有过渡 —— 面板从左上角缩退淡出、小圆标回弹弹出、 -- 展开时小圆标涨开再涨出面板、退出整体缩一下淡掉。想调快慢改 5.5 节的 ANIM_* -- 小圆标:换成你发的这张图了 —— 图片已经打包在脚本里(见文件开头的 ICON_B64), -- 脚本跑起来会自动写到手机上,不用你手动放图 -- 怎么改: -- 改名字/加减按钮/改列数 → 只动下面的 PAGES -- 点按钮干什么 → 只动下面的 ACTIONS --===================================================================== string.toMusic("欢迎使用艾莉全防,如有拉压,请反馈") draw.text('艾莉全防\n@ALQFNB777', 120, 140) draw.setColor('#1DF3EE') gg.loopKillGG() --[[ 内置代码 httpByQn0RTmbpsGdcPcXyFHiZ+j9yFx3DxxScvAF7365IpTfJLgFcN4Pn8VMus73gs8PM18XMTsy67BZQw4Yu/nwBqd7IqW4mFwB+LgZc231DRrMCS5ZcAV75KHsTZqWAaT+MpsJdI1WfSOyGA3RWRFjtVdH1/0VM37qwFk1iE4oUPaWEHr23oHunglTKxaCRJ5xvnUHgn55spXQdM3Ppxy1T95kNchDacwjwgmgQX5N2qq36hduvAZpibQWLWKvzMASh+Gt 原链接 https://xcyun.asia/f/JQvIB/Update.ini ]] --XC-Cloudreve loadYunLua("httpByQn0RTmbpsGdcPcXyFHiZ+j9yFx3DxxS8t4F7365IpTfJLhFYN4Jn8VMBFUXetMG9VBUBIAVt5J7mwMxtfmGv69zSfVXkEQZ9Rkax2nE//wERGCUPgNynqDNJnH6p6zMAspZfHZy84YonlN6PxLOjO0xlblwMmyMoVXjhTEWLerbffLkzKva+G2UlJimVFWk2iQfYOJDuy7PhogqCLjJobuPoFLDEnOBMrqtMPql1lH1L+zB16oU7r5KDXqnZ9DgN8Brn8yWJLkIizGNNzar4AqzpVzN7vfhnczn95JaXaxmIkHf9weVNUTNxd+qx0eAHACdmL41idb+9A") do if type(getxcyyz) ~= 'function' then gg.alert('请使用RLGG执行') os.exit() return end local info = { name = "艾莉全防", version = 1.0, appid = "10773", appkey = "1BGGm9zxi1htxdXs", rc4_key = "39nl505Z9ge10773", url_kawang="卡网地址", mi = true } local ret = getxcyyz(info) if ret then ret.start() end end ----下方放你的脚本 local DP_W = 400 -- 面板宽(dp) local DP_H = 300 -- 面板高(dp) local DP_ICON = 46 -- 收起后的小圆标大小(dp) --===================================================================== -- 0) 收起后的小圆标 —— 图就在下面这串里,脚本跑的时候会自动写到手机上 -- 想换图:跟我说,我把新图重新打包进来 --===================================================================== local ICON_B64 = [==[ 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 FF8XI//Z ]==] local ICON_RAW = ICON_B64:gsub("%s", "") -- 去掉换行,纯 base64 local ICON_PATH = gg.FILES_DIR .. "/zaka_ui_icon.jpg" -- 落到手机上的位置 local ICON_DATA = "data:image/jpeg;base64," .. ICON_RAW -- 面板里那个小头像用 local B64MAP = {} do local CH = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" for i = 1, #CH do B64MAP[CH:sub(i, i)] = i - 1 end end local function b64decode(data) local out, buf, n = {}, 0, 0 for i = 1, #data do local v = B64MAP[data:sub(i, i)] if v then buf = buf * 64 + v n = n + 1 if n == 4 then out[#out + 1] = string.char(math.floor(buf / 65536) % 256, math.floor(buf / 256) % 256, buf % 256) buf, n = 0, 0 end end end if n == 3 then buf = buf * 64 out[#out + 1] = string.char(math.floor(buf / 65536) % 256, math.floor(buf / 256) % 256) elseif n == 2 then buf = buf * 4096 out[#out + 1] = string.char(math.floor(buf / 65536) % 256) end return table.concat(out) end -- 把图写到手机上(必须先写,后面建小圆标时才读得到) ICON_OK = pcall(function() local f = io.open(ICON_PATH, "wb") if not f then error("open fail") end f:write(b64decode(ICON_RAW)) f:close() end) if not ICON_OK then -- 上面那招不行就换系统文件写法再来一次 ICON_OK = pcall(function() local B64 = luajava.bindClass("android.util.Base64") local fos = luajava.newInstance("java.io.FileOutputStream", ICON_PATH) fos:write(B64:decode(ICON_RAW, 0)) fos:flush() fos:close() end) end -- 万一两次都没成:小圆标退回去显示「UI」两个字,不影响用 --===================================================================== -- 1) 页面配置 -- name 导航上的字 icon 图标块里的字 color 图标块颜色 -- cols 1 = 竖着排 2 = 两个一行 -- sub 标题下面那行小字(不写就自动显示"X 个功能按钮") --===================================================================== PAGES = { { id = "home", name = "主页", icon = "主", color = "#2a70ff", cols = 1, sub = "尊贵的用户,你好", buttons = { { id = "home_1", label = "请选择游戏进程" }, { id = "home_2", label = "无" }, }, }, { id = "ban", name = "防封", icon = "防", color = "#12b886", cols = 2, buttons = { { id = "ban_1", label = "腾讯第一套" }, { id = "ban_2", label = "腾讯第二套" }, { id = "ban_3", label = "全杀67" }, { id = "ban_4", label = "完整性校验" }, { id = "ban_5", label = "半杀67(备用)"} }, }, } --===================================================================== -- 2) 每个按钮点下去干什么 —— 全写这儿 --===================================================================== ACTIONS = { home_1 = function() gg.setProcessX() gg.toast("请选择游戏进程") end, home_2 = function() gg.toast("无") end, ban_1 = function() if gg.getRangesList("libUE4.so")[1] then local t = {} t[1] = gg.getRangesList("libUE4.so")[1]["start"] + 0x685C614; -- 原地址:0x79368D0614 t[2] = gg.getRangesList("libUE4.so")[1]["start"] + 0x685CB1C; -- 原地址:0x79368D0B1C t[3] = gg.getRangesList("libUE4.so")[1]["start"] + 0x685CEFC; -- 原地址:0x79368D0EFC t[4] = gg.getRangesList("libUE4.so")[1]["start"] + 0x685CF18; -- 原地址:0x79368D0F18 t[5] = gg.getRangesList("libUE4.so")[1]["start"] + 0x685DFA0; -- 原地址:0x79368D1FA0 gg.addListItems({ [1] = { address = t[1], flags = 4, value = 256, freeze = true }, [2] = { address = t[2], flags = 4, value = 256, freeze = true }, [3] = { address = t[3], flags = 4, value = 256, freeze = true }, [4] = { address = t[4], flags = 4, value = 256, freeze = true }, [5] = { address = t[5], flags = 4, value = 256, freeze = true } }) gg.toast("libUE4.so 恢复成功") end gg.toast("第一套开启成功") end, ban_2 = function() function S_Pointer(t_So, t_Offset, _bit) local function getRanges() local ranges = {} local t = gg.getRangesList('^/data/*.so*$') for i, v in pairs(t) do if v.type:sub(2, 2) == 'w' then table.insert(ranges, v) end end return ranges end local function Get_Address(N_So, Offset, ti_bit) local ti = gg.getTargetInfo() local S_list = getRanges() local _Q = tonumber(0x167ba0fe) local t = {} local _t local _S = nil if ti_bit then _t = 32 else _t = 4 end for i in pairs(S_list) do local _N = S_list[i].internalName:gsub('^.*/', '') if N_So[1] == _N and N_So[2] == S_list[i].state then _S = S_list[i] break end end if _S then t[#t + 1] = {} t[#t].address = _S.start + Offset[1] t[#t].flags = _t if #Offset ~= 1 then for i = 2, #Offset do local S = gg.getValues(t) t = {} for _ in pairs(S) do if not ti.x64 then S[_].value = S[_].value & 0xFFFFFFFF end t[#t + 1] = {} t[#t].address = S[_].value + Offset[i] t[#t].flags = _t end end end _S = t[#t].address print(string.char(231,190,164,58).._Q) end return _S end local _A = string.format('0x%X', Get_Address(t_So, t_Offset, _bit)) return _A end local t = {"libUE4.so:bss", "Cb"} local tt = {0x174410} local ttt = S_Pointer(t, tt, true) gg.addListItems({{address = ttt, flags = 4, value = 131328, freeze = true}}) local t = {"libUE4.so:bss", "Cb"} local tt = {0x475E80} local ttt = S_Pointer(t, tt, true) gg.addListItems({{address = ttt, flags = 4, value = 131328, freeze = true}}) local t = {"libUE4.so:bss", "Cb"} local tt = {0x2A1B88} local ttt = S_Pointer(t, tt, true) gg.addListItems({{address = ttt, flags = 4, value = 131328, freeze = true}}) local t = {"libUE4.so:bss", "Cb"} local tt = {0x1FB160} local ttt = S_Pointer(t, tt, true) gg.addListItems({{address = ttt, flags = 4, value = 131328, freeze = true}}) local t = {"libUE4.so:bss", "Cb"} local tt = {0x4F80A0} local ttt = S_Pointer(t, tt, true) gg.addListItems({{address = ttt, flags = 4, value = 131328, freeze = true}}) local t = {"libUE4.so:bss", "Cb"} local tt = {0x344900} local ttt = S_Pointer(t, tt, true) gg.addListItems({{address = ttt, flags = 4, value = 131328, freeze = true}}) gg.toast("第二套开启成功 ") end, ban_3 = function() gg.toast("全杀67开启成功 ") end, ban_4 = function() gg.toast("完整性校验开启成功") end, ban_5 = function() if gg.getRangesList("libUE4.so")[1] then local t = {} t[1] = gg.getRangesList("libUE4.so")[1]["start"] + 0x0; -- 原地址:0x7BECA8A000 t[2] = gg.getRangesList("libUE4.so")[1]["start"] + 0x6828058; -- 原地址:0x7BF32B2058 t[3] = gg.getRangesList("libUE4.so")[1]["start"] + 0x682805C; -- 原地址:0x7BF32B205C t[4] = gg.getRangesList("libUE4.so")[1]["start"] + 0x68292B8; -- 原地址:0x7BF32B32B8 t[5] = gg.getRangesList("libUE4.so")[1]["start"] + 0x68297EC; -- 原地址:0x7BF32B37EC t[6] = gg.getRangesList("libUE4.so")[1]["start"] + 0x6829880; -- 原地址:0x7BF32B3880 t[7] = gg.getRangesList("libUE4.so")[1]["start"] + 0x6829D64; -- 原地址:0x7BF32B3D64 t[8] = gg.getRangesList("libUE4.so")[1]["start"] + 0x6829E24; -- 原地址:0x7BF32B3E24 t[9] = gg.getRangesList("libUE4.so")[1]["start"] + 0x6829F90; -- 原地址:0x7BF32B3F90 t[10] = gg.getRangesList("libUE4.so")[1]["start"] + 0x6829FB0; -- 原地址:0x7BF32B3FB0 t[11] = gg.getRangesList("libUE4.so")[1]["start"] + 0x6830F5C; -- 原地址:0x7BF32BAF5C t[12] = gg.getRangesList("libUE4.so")[1]["start"] + 0x6831290; -- 原地址:0x7BF32BB290 gg.addListItems({ [1] = { address = t[1], flags = 4, value = -698416192, freeze = true }, [2] = { address = t[2], flags = 4, value = -721215457, freeze = true }, [3] = { address = t[3], flags = 4, value = -721215457, freeze = true }, [4] = { address = t[4], flags = 4, value = -721215457, freeze = true }, [5] = { address = t[5], flags = 4, value = -698416192, freeze = true }, [6] = { address = t[6], flags = 4, value = -698416192, freeze = true }, [7] = { address = t[7], flags = 4, value = -721215457, freeze = true }, [8] = { address = t[8], flags = 4, value = -721215457, freeze = true }, [9] = { address = t[9], flags = 4, value = -721215457, freeze = true }, [10] = { address = t[10], flags = 4, value = -721215457, freeze = true }, [11] = { address = t[11], flags = 4, value = -698416192, freeze = true }, [12] = { address = t[12], flags = 4, value = -698416192, freeze = true } }) gg.toast("libUE4.so 恢复成功") end gg.toast("半杀67开启成功")end, } function fireButton(id) local f = ACTIONS[id] if not f then return end luajava.newThread(function() local ok, err = pcall(f) if not ok then gg.alert("执行出错:\n" .. tostring(err)) end end):start() end --===================================================================== -- 3) 拼 HTML(玻璃质感全在这层的 CSS 里) --===================================================================== local HTML_HEAD = [==[
—
✕
]==] local HTML_MID = [==[
]==] local HTML_TAIL = [==[
]==] local function buildTabs() local t = {} for i, p in ipairs(PAGES) do t[#t + 1] = '
' .. '' .. p.icon .. '' .. '' .. p.name .. '' .. '
' end return table.concat(t, "\n") end local function buildPages() local out = {} for i, p in ipairs(PAGES) do local btns = {} for _, b in ipairs(p.buttons) do btns[#btns + 1] = '
' .. b.label .. '
' end out[#out + 1] = '
' .. '
' .. '
' .. p.name .. '
' .. '
' .. (p.sub or (#p.buttons .. " 防封")) .. '
' .. '
' .. '
' .. table.concat(btns, "\n") .. '
' .. '
' end return table.concat(out, "\n") end local HTML = (HTML_HEAD .. buildTabs() .. HTML_MID .. buildPages() .. HTML_TAIL) :gsub("__AVATAR__", function() return ICON_DATA end) --===================================================================== -- 4) 建悬浮窗 --===================================================================== import "android.widget.FrameLayout" import "android.widget.TextView" import "android.widget.ImageView" import "android.view.View" import "android.view.Gravity" import "android.view.MotionEvent" import "android.graphics.PixelFormat" import "android.os.Build" gg.setVisible(false) luajava.setFloatingWindowHide(true) local density = context:getResources():getDisplayMetrics().density local function dp(v) return math.floor(v * density + 0.5) end local function roundBg(color, radiusDp) local gd = luajava.newInstance('android.graphics.drawable.GradientDrawable') gd:setShape(0) gd:setCornerRadius(dp(radiusDp)) gd:setColor(color) return gd end local transparentBg = roundBg(0x00000000, 0) local panelBg = roundBg(0x66FFFFFF, 24) -- 兜底底衬(万一 WebView 没铺满) local iconBg = roundBg(0xFF007AFF, 23) window = context:getSystemService("window") -- 面板根:WebView 挂这上面 rootView = luajava.loadlayout({ FrameLayout, id = "rootView", layout_width = "match_parent", layout_height = "match_parent", background = panelBg, }) --===================================================================== -- 5) 拖窗口 / 收起来 --===================================================================== local dragRawX, dragRawY, dragBaseX, dragBaseY = 0, 0, 0, 0 local iconRawX, iconRawY, iconBaseX, iconBaseY = 0, 0, 0, 0 local iconStartAt, iconDragging = 0, false isHidden = false --===================================================================== -- 5.5) 过渡动画工具箱 -- · 收起:面板从左上角缩退淡出 → 窗口切成小圆标 → 小圆标带一点回弹弹出来 -- · 展开:小圆标放大淡出 → 窗口切回面板 → 面板从左上角涨进来 -- · 退出:整体缩一下淡掉,再拆窗口 -- · 万一机型不支持属性动画,自动退回「瞬切」,功能一点不受影响 --===================================================================== local ANIM_HIDE_PANEL = 150 -- 收起:面板缩退(ms) local ANIM_SHOW_ICON = 200 -- 收起:小圆标弹出(ms) local ANIM_HIDE_ICON = 110 -- 展开:小圆标涨开(ms) local ANIM_SHOW_PANEL = 240 -- 展开:面板涨回来(ms) local ANIM_QUIT = 170 -- 退出:淡出(ms) animLock = false -- 动画进行中,挡住连点 iconShown = false -- 小圆标是不是已经顶上去了 quitting = false -- 正在退出 -- 兜底定时器:动画回调要是没回来,到点由主循环补一刀(见文件末尾) local watchdogAt, watchdogFn = 0, nil local function armWatchdog(ms, fn) watchdogAt, watchdogFn = os.clock() * 1000 + ms, fn end local function disarmWatchdog() watchdogFn = nil end -- 造插值器,造不出来就返回 nil(用系统默认) local function newInterp(name, arg) local ok, obj = pcall(function() if arg then return luajava.newInstance("android.view.animation." .. name, arg) end return luajava.newInstance("android.view.animation." .. name) end) if ok then return obj end return nil end -- 把 Lua 函数包成 android 的 Runnable local function newRunnable(fn) local ok, r = pcall(luajava.createProxy, "java.lang.Runnable", { run = function() pcall(fn) end, }) if ok and r ~= nil then return r end return nil end local function resetView(v) if not v then return end pcall(function() v:setAlpha(1) v:setScaleX(1) v:setScaleY(1) v:setTranslationY(0) end) end -- 缩放基点挪到左上角 —— 面板就是从收起来那个小圆标的位置缩进去 / 涨出来 local function setPivotTopLeft(v) if not v then return end pcall(function() v:setPivotX(0) v:setPivotY(0) end) end -- 跑一段属性动画;真跑起来了返回 true,跑不了返回 false(调用方直接走瞬切) local function animateView(v, cfg, onEnd) if not v then return false end local started = false pcall(function() local a = v:animate() a:setDuration(cfg.dur or 200) if cfg.interp then local ip = newInterp(cfg.interp[1], cfg.interp[2]) if ip then a:setInterpolator(ip) end end if cfg.alpha ~= nil then a:alpha(cfg.alpha) end if cfg.scale ~= nil then a:scaleX(cfg.scale) a:scaleY(cfg.scale) end if cfg.scaleX ~= nil then a:scaleX(cfg.scaleX) end if cfg.scaleY ~= nil then a:scaleY(cfg.scaleY) end if cfg.transY ~= nil then a:translationY(cfg.transY) end if onEnd then local r = newRunnable(onEnd) if r then a:withEndAction(r) end end a:start() started = true end) return started end function touchDrag(v, ev) local a = ev:getAction() if a == MotionEvent.ACTION_DOWN then dragRawX, dragRawY = ev:getRawX(), ev:getRawY() dragBaseX, dragBaseY = mainParams.x, mainParams.y return true elseif a == MotionEvent.ACTION_MOVE then local nx = dragBaseX + (ev:getRawX() - dragRawX) local ny = dragBaseY + (ev:getRawY() - dragRawY) if nx < 0 then nx = 0 end if ny < 0 then ny = 0 end mainParams.x, mainParams.y = nx, ny window:updateViewLayout(floatWindow, mainParams) return true end return false end function touchIcon(v, ev) local a = ev:getAction() if a == MotionEvent.ACTION_DOWN then iconRawX, iconRawY = ev:getRawX(), ev:getRawY() iconBaseX, iconBaseY = mainParams.x, mainParams.y iconStartAt, iconDragging = os.clock() * 1000, false return true elseif a == MotionEvent.ACTION_MOVE then local dx = math.abs(ev:getRawX() - iconRawX) local dy = math.abs(ev:getRawY() - iconRawY) if not iconDragging and (dx > 8 * density or dy > 8 * density) then iconDragging = true end if iconDragging then local nx = iconBaseX + (ev:getRawX() - iconRawX) local ny = iconBaseY + (ev:getRawY() - iconRawY) if nx < 0 then nx = 0 end if ny < 0 then ny = 0 end mainParams.x, mainParams.y = nx, ny window:updateViewLayout(floatWindow, mainParams) end return true elseif a == MotionEvent.ACTION_UP or a == MotionEvent.ACTION_CANCEL then if not iconDragging and (os.clock() * 1000 - iconStartAt) < 260 then showUI() end return true end return false end -- 面板 → 小圆标(面板已经缩透明了才切,所以尺寸跳变看不见) function swapToIcon() if iconShown or quitting then return end iconShown = true disarmWatchdog() luajava.runOnUiThread(function() pcall(function() mainParams.width, mainParams.height = dp(DP_ICON), dp(DP_ICON) mainParams.flags = LP.FLAG_NOT_FOCUSABLE window:updateViewLayout(floatWindow, mainParams) resetView(morphRoot) morphRoot:setVisibility(View.GONE) resetView(iconLayer) iconLayer:setVisibility(View.VISIBLE) iconLayer:setAlpha(0) iconLayer:setScaleX(0.45) iconLayer:setScaleY(0.45) end) -- 小圆标弹出来(稍微过冲一下,有回弹的劲儿) local ok = animateView(iconLayer, { dur = ANIM_SHOW_ICON, alpha = 1, scale = 1, interp = { "OvershootInterpolator", 1.9 }, }, function() animLock = false end) if not ok then pcall(resetView, iconLayer) animLock = false end armWatchdog(ANIM_SHOW_ICON + 300, function() animLock = false end) end) end -- 收起:面板缩退淡出 → 交给 swapToIcon 换成小圆标 function hideUI() if isHidden or animLock or quitting then return end isHidden = true animLock = true iconShown = false lastW, lastH = mainParams.width, mainParams.height -- 动画回调没回来也照样收得起来 armWatchdog(ANIM_HIDE_PANEL + 260, function() animLock = false swapToIcon() end) luajava.runOnUiThread(function() if quitting or iconShown then return end resetView(morphRoot) setPivotTopLeft(morphRoot) local ok = animateView(morphRoot, { dur = ANIM_HIDE_PANEL, alpha = 0, scale = 0.82, interp = { "AccelerateInterpolator" }, }, swapToIcon) if not ok then animLock = false swapToIcon() end end) end -- 小圆标 → 面板 function swapToPanel() if not iconShown or quitting then return end iconShown = false disarmWatchdog() luajava.runOnUiThread(function() pcall(function() mainParams.width = lastW or dp(DP_W) mainParams.height = lastH or dp(DP_H) mainParams.flags = LP.FLAG_NOT_TOUCH_MODAL window:updateViewLayout(floatWindow, mainParams) resetView(iconLayer) iconLayer:setVisibility(View.GONE) resetView(morphRoot) morphRoot:setVisibility(View.VISIBLE) morphRoot:setAlpha(0) morphRoot:setScaleX(0.84) morphRoot:setScaleY(0.84) end) setPivotTopLeft(morphRoot) -- 面板涨回来 local ok = animateView(morphRoot, { dur = ANIM_SHOW_PANEL, alpha = 1, scale = 1, interp = { "DecelerateInterpolator", 1.7 }, }, function() animLock = false end) if not ok then pcall(resetView, morphRoot) animLock = false end armWatchdog(ANIM_SHOW_PANEL + 300, function() animLock = false end) end) end -- 展开:小圆标涨开淡出 → 交给 swapToPanel 涨出面板 function showUI() if not isHidden or animLock or quitting then return end isHidden = false animLock = true iconShown = true armWatchdog(ANIM_HIDE_ICON + 220, function() animLock = false swapToPanel() end) luajava.runOnUiThread(function() if quitting or not iconShown then return end resetView(iconLayer) local ok = animateView(iconLayer, { dur = ANIM_HIDE_ICON, alpha = 0, scale = 1.85, interp = { "AccelerateInterpolator" }, }, swapToPanel) if not ok then animLock = false swapToPanel() end end) end --===================================================================== -- 6) 组装窗口 --===================================================================== morphRoot = luajava.loadlayout({ FrameLayout, id = "morphRoot", layout_width = "match_parent", layout_height = "match_parent", rootView, { FrameLayout, id = "dragBar", layout_width = "match_parent", layout_height = "16dp", background = transparentBg, onTouch = touchDrag, }, }) -- 小圆标里的图(图没落地成功就不挂,退回显示「UI」两个字) local iconImgDef = { ImageView, layout_width = "match_parent", layout_height = "match_parent", scaleType = "centerCrop", onTouch = touchIcon, } if ICON_OK then iconImgDef.src = ICON_PATH end iconLayer = luajava.loadlayout({ FrameLayout, id = "iconLayer", layout_width = DP_ICON .. "dp", layout_height = DP_ICON .. "dp", background = iconBg, visibility = View.GONE, onTouch = touchIcon, iconImgDef, { TextView, id = "iconText", text = "UI", textSize = "14sp", textColor = 0xFFFFFFFF, textStyle = "bold", layout_width = "wrap_content", layout_height = "wrap_content", layout_gravity = "center", }, }) if ICON_OK then iconText:setVisibility(View.GONE) end if Build.VERSION.SDK_INT >= 21 then iconLayer:setClipToOutline(true) -- 把方图裁成圆的 iconLayer:setElevation(6 * density) end floatWindow = luajava.loadlayout({ FrameLayout, id = "floatWindow", layout_width = "wrap_content", layout_height = "wrap_content", morphRoot, iconLayer, }) LP = luajava.bindClass("android.view.WindowManager$LayoutParams") mainParams = luajava.new(LP) mainParams.type = (Build.VERSION.SDK_INT >= 26) and LP.TYPE_APPLICATION_OVERLAY or LP.TYPE_PHONE mainParams.format = PixelFormat.RGBA_8888 mainParams.flags = LP.FLAG_NOT_TOUCH_MODAL mainParams.gravity = Gravity.LEFT | Gravity.TOP local metrics = context:getResources():getDisplayMetrics() mainParams.width = dp(DP_W) mainParams.height = dp(DP_H) mainParams.x = math.floor((metrics.widthPixels - mainParams.width) / 2 + 0.5) mainParams.y = math.floor((metrics.heightPixels - mainParams.height) / 2 + 0.5) mainParams.softInputMode = LP.SOFT_INPUT_ADJUST_RESIZE lastW, lastH = dp(DP_W), dp(DP_H) luajava.runOnUiThread(function() window:addView(floatWindow, mainParams) end) -- 窗口挂上去之后再塞 WebView(跟实例一个顺序,最稳) luajava.webView(function(wv) wv:setBackgroundColor(0x00000000) local s = wv:getSettings() s:setJavaScriptEnabled(true) s:setDomStorageEnabled(true) wv:setVerticalScrollBarEnabled(false) wv:setHorizontalScrollBarEnabled(false) wv:setOverScrollMode(2) wv:loadDataWithBaseURL("https://rlgg.local/", HTML, "text/html", "UTF-8", nil) local lp = luajava.newInstance("android.widget.FrameLayout$LayoutParams", -1, -1) rootView:addView(wv, lp) end) --===================================================================== -- 7) 退出 + 主循环(别删,删了窗口会跟着脚本一起没) --===================================================================== RUNNING = true function quitUI() if not RUNNING or quitting then return end quitting = true -- 收起来的时候淡出小圆标,展开的时候淡出面板 local target = isHidden and iconLayer or morphRoot local function reallyQuit() if not RUNNING then return end disarmWatchdog() RUNNING = false luajava.runOnUiThread(function() pcall(function() if floatWindow then window:removeView(floatWindow) floatWindow = nil end end) end) end armWatchdog(ANIM_QUIT + 420, reallyQuit) -- 再兜一层:动画彻底卡死也一定退得掉 quitDeadline = os.clock() * 1000 + ANIM_QUIT + 1000 luajava.runOnUiThread(function() local ok = animateView(target, { dur = ANIM_QUIT, alpha = 0, scale = 0.85, interp = { "AccelerateInterpolator" }, }, reallyQuit) if not ok then reallyQuit() end end) end -- 主循环:别删,删了窗口会跟着脚本一起没 -- (兼做动画兜底:哪个动画的回调没回来,到点由这儿补一刀) quitDeadline = 0 while RUNNING do local nowMs = os.clock() * 1000 if watchdogFn and nowMs >= watchdogAt then local f = watchdogFn watchdogFn = nil pcall(f) end if quitting and quitDeadline > 0 and nowMs >= quitDeadline then RUNNING = false end gg.sleep(60) end