apk反编译修改教程系列---简单给app添加启动弹窗 添加对话框 跳转指定网页等【七】

往期教程:

apk反编译修改教程系列-----修改apk应用名称 任意修改名称 签名【一】

apk反编译修改教程系列-----任意修改apk版本号 版本名 防止自动更新【二】

apk反编译修改教程系列-----修改apk中的图片 任意更换apk桌面图片【三】

apk反编译修改教程系列---简单去除apk联网权限 其他权限 无法自动更新等【四】

apk反编译修改教程系列---简单去除apk开屏广告【五】

apk反编译修改教程系列---修改apk设置菜单选项名称 修改默认设置 增加减少选项【六】

今天的教程简单演示一下如何给一款apk加启动弹窗 对话框等。

演示apk华硕手机计算器4.0.0.52

工具:MT或者电脑端反编译工具

操作步骤:

首先正常安装打开这款软件是这样的。工具打开很简洁,没有任何权限提示

按常规操作。首先找到这个apk,使用MT的ACTIVITY记录,点击开启。我们要先查看这个工具启动的主界面Activity 的代码名字。

然后打开这个计算器工具,在上方的Activity就可以看到工具主界面

点击查看,选择classes.dex文件。关于apk资源内各个文件夹的具体作用可以查看以前的博文都有说明。点击classes.dex文件。出来菜单选择Dex编辑器++

现在我们需要工具刚才查看到计算器的Activity记录来找到这个完整路径文件

完整的路径com.asus.calculator.Calc

.class public Lcom/asus/calculator/Calculator;
.super Lcom/asus/calculator/aa;

# interfaces
.implements Landroid/view/View$OnClickListener;
.implements Lcom/asus/calculator/z;


# static fields
.field private static i:Ljava/lang/String;

.field private static j:Ljava/lang/String;

.field private static k:Ljava/lang/String;


# instance fields
.field private A:I

.field private B:Landroid/view/ViewTreeObserver$OnGlobalLayoutListener;

.field private C:Ljava/lang/Runnable;

.field public a:Lcom/asus/calculator/history/a;

.field protected b:Lcom/asus/calculator/w;

.field c:Z

.field d:Z

.field private e:Landroid/content/Context;

.field private final f:Ljava/lang/String;

.field private final g:Ljava/lang/String;

.field private h:Landroid/os/Bundle;

.field private l:Lcom/asus/calculator/af;

.field private m:Lcom/asus/calculator/y;

.field private n:Lcom/asus/calculator/MyViewPager;

.field private o:Landroid/view/View;

.field private p:Landroid/view/View;

.field private q:Landroid/view/View;

.field private r:Landroid/view/View;

.field private s:Landroid/view/View;

.field private t:Landroid/content/BroadcastReceiver;

.field private u:Lcom/asus/calculator/ad;

.field private v:Ljava/util/List;
    .annotation system Ldalvik/annotation/Signature;
        value = {
            "Ljava/util/List",
            "<",
            "Landroid/view/View;",
            ">;"
        }
    .end annotation
.end field

.field private w:Landroid/view/View;

.field private x:Ljava/util/List;
    .annotation system Ldalvik/annotation/Signature;
        value = {
            "Ljava/util/List",
            "<",
            "Ljava/lang/Integer;",
            ">;"
        }
    .end annotation
.end field

.field private y:Landroid/os/Handler;

.field private z:Z


# direct methods
.method static constructor <clinit>()V
    .registers 1

    const-string v0, "asus.intent.action.INSTALL_DEMOAPK"

    sput-object v0, Lcom/asus/calculator/Calculator;->i:Ljava/lang/String;

    const-string v0, "com.asus.livedemo"

    sput-object v0, Lcom/asus/calculator/Calculator;->j:Ljava/lang/String;

    const-string v0, "com.asus.livedemoservice"

    sput-object v0, Lcom/asus/calculator/Calculator;->k:Ljava/lang/String;

    return-void
.end method

.method public constructor <init>()V
    .registers 5

    const/4 v3, 0x1

    const/4 v2, 0x0

    const/4 v1, 0x0

    invoke-direct {p0}, Lcom/asus/calculator/aa;-><init>()V

    new-instance v0, Lcom/asus/calculator/w;

    invoke-direct {v0, p0}, Lcom/asus/calculator/w;-><init>(Landroid/content/Context;)V

    iput-object v0, p0, Lcom/asus/calculator/Calculator;->b:Lcom/asus/calculator/w;

    const-string v0, "isLockedScreen"

    iput-object v0, p0, Lcom/asus/calculator/Calculator;->f:Ljava/lang/String;

    const-string v0, "isScreenOn"

    iput-object v0, p0, Lcom/asus/calculator/Calculator;->g:Ljava/lang/String;

    iput-object v1, p0, Lcom/asus/calculator/Calculator;->o:Landroid/view/View;

    iput-object v1, p0, Lcom/asus/calculator/Calculator;->p:Landroid/view/View;

    iput-object v1, p0, Lcom/asus/calculator/Calculator;->q:Landroid/view/View;

    iput-object v1, p0, Lcom/asus/calculator/Calculator;->r:Landroid/view/View;

    iput-object v1, p0, Lcom/asus/calculator/Calculator;->s:Landroid/view/View;

    iput-object v1, p0, Lcom/asus/calculator/Calculator;->t:Landroid/content/BroadcastReceiver;

    iput-object v1, p0, Lcom/asus/calculator/Calculator;->u:Lcom/asus/calculator/ad;

    iput-object v1, p0, Lcom/asus/calculator/Calculator;->v:Ljava/util/List;

    iput-object v1, p0, Lcom/asus/calculator/Calculator;->w:Landroid/view/View;

    new-array v0, v3, [Ljava/lang/Integer;

    const v1, 0x7f0f00db

    invoke-static {v1}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;

    move-result-object v1

    aput-object v1, v0, v2

    invoke-static {v0}, Ljava/util/Arrays;->asList([Ljava/lang/Object;)Ljava/util/List;

    move-result-object v0

    iput-object v0, p0, Lcom/asus/calculator/Calculator;->x:Ljava/util/List;

    new-instance v0, Landroid/os/Handler;

    invoke-direct {v0}, Landroid/os/Handler;-><init>()V

    iput-object v0, p0, Lcom/asus/calculator/Calculator;->y:Landroid/os/Handler;

    iput-boolean v2, p0, Lcom/asus/calculator/Calculator;->z:Z

    iput v2, p0, Lcom/asus/calculator/Calculator;->A:I

    new-instance v0, Lcom/asus/calculator/g;

    invoke-direct {v0, p0}, Lcom/asus/calculator/g;-><init>(Lcom/asus/calculator/Calculator;)V

    iput-object v0, p0, Lcom/asus/calculator/Calculator;->B:Landroid/view/ViewTreeObserver$OnGlobalLayoutListener;

    new-instance v0, Lcom/asus/calculator/h;

    invoke-direct {v0, p0}, Lcom/asus/calculator/h;-><init>(Lcom/asus/calculator/Calculator;)V

    iput-object v0, p0, Lcom/asus/calculator/Calculator;->C:Ljava/lang/Runnable;

    iput-boolean v2, p0, Lcom/asus/calculator/Calculator;->c:Z

    iput-boolean v3, p0, Lcom/asus/calculator/Calculator;->d:Z

    return-void
.end method

.method private c()V
    .registers 6

    const/4 v0, 0x0

    iget-object v1, p0, Lcom/asus/calculator/Calculator;->TAG:Ljava/lang/String;

    const/4 v2, 0x1

    new-array v2, v2, [Ljava/lang/Object;

    const-string v3, "updateTheme"

    aput-object v3, v2, v0

    invoke-static {v1, v2}, Lcom/asus/calculator/x;->a(Ljava/lang/String;[Ljava/lang/Object;)V

    iget-object v1, p0, Lcom/asus/calculator/Calculator;->mThemeManager:Lcom/asus/calculator/theme/g;

    iget-object v2, p0, Lcom/asus/calculator/Calculator;->mLayoutRoot:Landroid/widget/LinearLayout;

    invoke-virtual {v1, p0, v2}, Lcom/asus/calculator/theme/g;->a(Landroid/support/v7/a/ac;Landroid/view/View;)V

    iget-object v1, p0, Lcom/asus/calculator/Calculator;->u:Lcom/asus/calculator/ad;

    if-eqz v1, :cond_1d

    iget-object v1, p0, Lcom/asus/calculator/Calculator;->u:Lcom/asus/calculator/ad;

    invoke-virtual {v1}, Lcom/asus/calculator/ad;->a()V

    :cond_1d
    iget-object v1, p0, Lcom/asus/calculator/Calculator;->v:Ljava/util/List;

    if-eqz v1, :cond_44

    iget-object v1, p0, Lcom/asus/calculator/Calculator;->v:Ljava/util/List;

    invoke-interface {v1}, Ljava/util/List;->size()I

    move-result v1

    if-lez v1, :cond_44

    iget-object v1, p0, Lcom/asus/calculator/Calculator;->v:Ljava/util/List;

    invoke-interface {v1}, Ljava/util/List;->size()I

    move-result v2

    move v1, v0

    :goto_30
    if-ge v1, v2, :cond_44

    iget-object v3, p0, Lcom/asus/calculator/Calculator;->mThemeManager:Lcom/asus/calculator/theme/g;

    const/4 v4, 0x0

    iget-object v0, p0, Lcom/asus/calculator/Calculator;->v:Ljava/util/List;

    invoke-interface {v0, v1}, Ljava/util/List;->get(I)Ljava/lang/Object;

    move-result-object v0

    check-cast v0, Landroid/view/View;

    invoke-virtual {v3, v4, v0}, Lcom/asus/calculator/theme/g;->a(Landroid/support/v7/a/ac;Landroid/view/View;)V

    add-int/lit8 v0, v1, 0x1

    move v1, v0

    goto :goto_30

    :cond_44
    return-void
.end method

.method private d()V
    .registers 9

    const/4 v7, 0x2

    const/4 v6, 0x0

    const/4 v5, 0x1

    invoke-direct {p0}, Lcom/asus/calculator/Calculator;->e()Z

    move-result v0

    iput-boolean v0, p0, Lcom/asus/calculator/Calculator;->c:Z

    invoke-direct {p0}, Lcom/asus/calculator/Calculator;->f()Z

    move-result v0

    iput-boolean v0, p0, Lcom/asus/calculator/Calculator;->d:Z

    iget-object v0, p0, Lcom/asus/calculator/Calculator;->h:Landroid/os/Bundle;

    if-eqz v0, :cond_5c

    iget-object v0, p0, Lcom/asus/calculator/Calculator;->h:Landroid/os/Bundle;

    const-string v1, "isLockedScreen"

    invoke-virtual {v0, v1}, Landroid/os/Bundle;->getBoolean(Ljava/lang/String;)Z

    move-result v0

    iget-object v1, p0, Lcom/asus/calculator/Calculator;->h:Landroid/os/Bundle;

    const-string v2, "isScreenOn"

    invoke-virtual {v1, v2}, Landroid/os/Bundle;->getBoolean(Ljava/lang/String;)Z

    move-result v1

    iget-object v2, p0, Lcom/asus/calculator/Calculator;->TAG:Ljava/lang/String;

    new-array v3, v7, [Ljava/lang/Object;

    const-string v4, "wasLockedScreen"

    aput-object v4, v3, v6

    invoke-static {v0}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;

    move-result-object v4

    aput-object v4, v3, v5

    invoke-static {v2, v3}, Lcom/asus/calculator/x;->a(Ljava/lang/String;[Ljava/lang/Object;)V

    iget-object v2, p0, Lcom/asus/calculator/Calculator;->TAG:Ljava/lang/String;

    new-array v3, v7, [Ljava/lang/Object;

    const-string v4, "wasScreenOn"

    aput-object v4, v3, v6

    invoke-static {v1}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;

    move-result-object v4

    aput-object v4, v3, v5

    invoke-static {v2, v3}, Lcom/asus/calculator/x;->a(Ljava/lang/String;[Ljava/lang/Object;)V

    const/4 v2, 0x0

    iput-object v2, p0, Lcom/asus/calculator/Calculator;->h:Landroid/os/Bundle;

    iget-boolean v2, p0, Lcom/asus/calculator/Calculator;->c:Z

    if-ne v0, v2, :cond_50

    iget-boolean v0, p0, Lcom/asus/calculator/Calculator;->d:Z

    if-eq v1, v0, :cond_5c

    :cond_50
    iget-object v0, p0, Lcom/asus/calculator/Calculator;->TAG:Ljava/lang/String;

    new-array v1, v5, [Ljava/lang/Object;

    const-string v2, "different states"

    aput-object v2, v1, v6

    invoke-static {v0, v1}, Lcom/asus/calculator/x;->a(Ljava/lang/String;[Ljava/lang/Object;)V

    :cond_5b
    :goto_5b
    return-void

    :cond_5c
    iget-boolean v0, p0, Lcom/asus/calculator/Calculator;->d:Z

    if-eqz v0, :cond_5b

    iget-boolean v0, p0, Lcom/asus/calculator/Calculator;->c:Z

    if-eqz v0, :cond_5b

    iget-object v0, p0, Lcom/asus/calculator/Calculator;->TAG:Ljava/lang/String;

    new-array v1, v5, [Ljava/lang/Object;

    const-string v2, "enableShowWhenLocked"

    aput-object v2, v1, v6

    invoke-static {v0, v1}, Lcom/asus/calculator/x;->a(Ljava/lang/String;[Ljava/lang/Object;)V

    if-eqz p0, :cond_7f

    invoke-virtual {p0}, Landroid/app/Activity;->getWindow()Landroid/view/Window;

    move-result-object v0

    const/high16 v1, 0x80000

    invoke-virtual {v0, v1}, Landroid/view/Window;->addFlags(I)V

    const/high16 v1, 0x400000

    invoke-virtual {v0, v1}, Landroid/view/Window;->addFlags(I)V

    :cond_7f
    iput-boolean v5, p0, Lcom/asus/calculator/Calculator;->z:Z

    goto :goto_5b
.end method

.method private e()Z
    .registers 6

    const-string v0, "keyguard"

    invoke-virtual {p0, v0}, Lcom/asus/calculator/Calculator;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;

    move-result-object v0

    check-cast v0, Landroid/app/KeyguardManager;

    invoke-virtual {v0}, Landroid/app/KeyguardManager;->isKeyguardLocked()Z

    move-result v0

    iget-object v1, p0, Lcom/asus/calculator/Calculator;->TAG:Ljava/lang/String;

    const/4 v2, 0x2

    new-array v2, v2, [Ljava/lang/Object;

    const/4 v3, 0x0

    const-string v4, "isLockedScreen"

    aput-object v4, v2, v3

    const/4 v3, 0x1

    invoke-static {v0}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;

    move-result-object v4

    aput-object v4, v2, v3

    invoke-static {v1, v2}, Lcom/asus/calculator/x;->a(Ljava/lang/String;[Ljava/lang/Object;)V

    return v0
.end method

.method private f()Z
    .registers 6

    const-string v0, "power"

    invoke-virtual {p0, v0}, Lcom/asus/calculator/Calculator;->getSystemService(Ljava/lang/String;)Ljava/lang/Object;

    move-result-object v0

    check-cast v0, Landroid/os/PowerManager;

    sget v1, Landroid/os/Build$VERSION;->SDK_INT:I

    const/16 v2, 0x14

    if-lt v1, v2, :cond_27

    invoke-virtual {v0}, Landroid/os/PowerManager;->isInteractive()Z

    move-result v0

    :goto_12
    iget-object v1, p0, Lcom/asus/calculator/Calculator;->TAG:Ljava/lang/String;

    const/4 v2, 0x2

    new-array v2, v2, [Ljava/lang/Object;

    const/4 v3, 0x0

    const-string v4, "isScreenOn"

    aput-object v4, v2, v3

    const/4 v3, 0x1

    invoke-static {v0}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;

    move-result-object v4

    aput-object v4, v2, v3

    invoke-static {v1, v2}, Lcom/asus/calculator/x;->a(Ljava/lang/String;[Ljava/lang/Object;)V

    return v0

    :cond_27
    invoke-virtual {v0}, Landroid/os/PowerManager;->isScreenOn()Z

我们需要定位到工具主界面Activity。加入弹窗内容

内容可以任意修改。原路返回保存可以直接签名或者编译后在签名都可以。此时卸载原软件,安装编译签名后的软件,打开是这样的

效果:

这些步骤都是反编译apk起始的初步常识操作。当然也可以添加对话框等等。类似

或者点击对话框后跳转设定的网页  类似

做这个教程的目的是让初学者了解最简单的反编译操作,尽量每一步都详细说明。其实很多工具都有些类似的功能。例如查看活动Activity记录。很多软件Activity有很多。主界面 辅界面等等。当然加启动弹窗的方式有很多种。其中的一种方法不一定都可以通用所有apk。但要明白原理.

**系列教程将详细的由浅入深解析apk的各种反编译操作。有兴趣的友友可以关注

下期预解析:如何简单的汉化apk

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/246628.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FolkMQ 国产消息中间件,v1.0.21 发布

简介 采用 “多路复用” “内存运行” “快照持久化” “Broker 集群模式”&#xff08;可选&#xff09;基于 Socket.D 网络应用协议 开发。全新设计&#xff0c;自主架构&#xff01; 角色功能生产端发布消息&#xff08;Qos0、Qos1&#xff09;、发布定时消息&#xff…

jenkins-Generic Webhook Trigger指定分支构建

文章目录 1 需求分析1.1 关键词 : 2、webhooks 是什么&#xff1f;3、配置步骤3.1 github 里需要的仓库配置&#xff1a;3.2 jenkins 的主要配置3.3 option filter配置用于匹配目标分支 实现指定分支构建 1 需求分析 一个项目一般会开多个分支进行开发&#xff0c;测试&#x…

STM32--Wi-Fi插座_风扇_灯

项目需求 两个互相通信的双方&#xff0c;波特率必须相同!!!!!! 通过 ESP8266 模块&#xff0c;实现手机控制 wifi 插座 / 风扇 / 灯。 项目设计 串口 1 用于与 ESP8266 通讯&#xff0c;串口 2 连接 PC &#xff0c;用于打印 log &#xff0c;查看系统状态。 项目实现 注意&a…

ShenYu网关注册中心之HTTP注册原理

文章目录 1、客户端注册流程1.1、读取配置1.1.1、用于注册的 HttpClientRegisterRepository1.1.2、用于扫描构建 元数据 和 URI 的 SpringMvcClientEventListener 1.2、扫描注解&#xff0c;注册元数据和URI1.2.1、构建URI并写入Disruptor1.2.2、构建元数据并写入Disruptor1.2.…

GDPU 数据结构 天码行空14

实验十四 查找算法的实现 一、【实验目的】 1、掌握顺序排序&#xff0c;二叉排序树的基本概念 2、掌握顺序排序&#xff0c;二叉排序树的基本算法&#xff08;查找算法、插入算法、删除算法&#xff09; 3、理解并掌握二叉排序数查找的平均查找长度。 二、【实验内容】 …

GO的sql注入盲注脚本

之间学习了go的语法 这里就开始go的爬虫 与其说是爬虫 其实就是网站的访问如何实现 因为之前想通过go写sql注入盲注脚本 发现不是那么简单 这里开始研究一下 首先是请求网站 这里貌似很简单 package mainimport ("fmt""net/http" )func main() {res, …

【算法与数据结构】332、LeetCode重新安排行程

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题比较属于困难题目&#xff0c;难点在于完成机票、出发机场和到达机场之间的映射关系&#xff0c;再…

零信任 SASE 办公安全解决方案:提升企业网络安全与灵活性

​零信任 SASE&#xff08;Secure Access Service Edge&#xff09;办公安全解决方案为企业带来了许多好处&#xff0c;相较于以前的解决方案有明显差异。这个方案的出现是为了应对企业面临的新的网络安全挑战和远程办公的需求。 1、统一的网络安全管理&#xff1a;SASE 将网络…

【MySQL学习之基础篇】SQL

文章目录 1. SQL的通用语法2. SQL 分类3. 数据定义语言&#xff08;DDL&#xff09;3.1. 数据库操作3.2. 表操作3.2.1. 数据类型3.2.2. 表的创建和查询操作3.2.3. 应用案例3.2.3. 表的修改操作3.2.4. 表的删除操作 4. 数据操作语言(DML)4.1. 添加数据4.2. 修改数据4.3. 删除数据…

基于python实现原神那维莱特开转脚本

相信不少原友都抽取了枫丹大C那维莱特&#xff0c;其强力的输出让不少玩家爱不释手。由于其转的越快&#xff0c;越不容易丢伤害的特点&#xff0c;很多原友在开转时容易汗流浃背&#xff0c;所以特意用python写了一个自动转圈脚本&#xff0c;当按住鼠标侧键时&#xff0c;即可…

每天一点python——day94

#每天一点Python——94 #面向对象的三大特征——封装 封装&#xff1a;隐藏内部细节&#xff0c;对外提供操作方式。【提高程序的安全性】 继承&#xff1a;在函数调用时&#xff0c;使用’形参名称值‘的方式进行传参&#xff0c;传递参数的顺序可以与定义时参数顺序不同【提高…

搭配环境—Python解释器

对于一些库&#xff0c;需要创建虚拟环境&#xff08;就是给你电脑创建一个虚拟的地方来存&#xff0c;这个虚拟的地方有很多&#xff0c;需要自己找&#xff09; 对于人脸识别项目存在 使用的这个解释器&#xff0c;其他解释器可以去envs找找

JVM调优:参数(学习笔记)

一、jvm的运行参数 标准参数 -help、-version、-D参数 jvm的标准参数&#xff0c;一般都是很稳定的&#xff0c;在未来的JVM版本中不会改变&#xff0c;可以使用java -help 检索出所有的标准参数。 通过以下命令查看&#xff1a; 命令&#xff1a;java -help 可以看到我们经常…

亚马逊云科技AI应用 SageMaker 新突破,机器学习优势显著

&#xff08;声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区、知乎、自媒体平台、第三方开发者媒体等亚马逊云科技官方渠道&#xff09; Amazon SageMaker是一种机器学习服务&#xff0c;帮助开发人员快速…

数据结构之树

1. 遍历 b站收藏夹 2. 二叉树的存储 2.1 顺序存储 Linear_Tree.c 不推荐使用&#xff0c;因为会造成空间浪费 #include "stdio.h" #include "stdlib.h" #include "string.h" #include<stdbool.h> typedef bool status;#define MAXSIZE 3/…

【NSX-T】7. 搭建NSX-T环境 —— 部署和配置 Edge Cluster

目录 7. 部署和配置 Edge Cluster7.1 配置 Edge 节点&#xff08;1&#xff09;Name and Description&#xff08;2&#xff09;Credentials&#xff08;3&#xff09;Configure Deployment&#xff08;4&#xff09;Configure Node Settings&#xff08;5&#xff09;Configur…

RS485数据采集网关如何采集传感器、仪器仪表数据?

在工业自动化和数据采集领域&#xff0c;RS485作为一种常见的通信接口&#xff0c;被广泛应用于连接传感器、仪器仪表等设备。为了满足对这些设备数据的采集和处理需求&#xff0c;RS485数据采集网关应运而生。本文将围绕“RS485数据采集网关如何采集传感器、仪器仪表数据&…

说说对React高阶组件的理解?应用场景?

面试官&#xff1a;说说对高阶组件的理解&#xff1f;应用场景? 一、是什么 高阶函数&#xff08;Higher-order function&#xff09;&#xff0c;至少满足下列一个条件的函数 接受一个或多个函数作为输入输出一个函数 在React中&#xff0c;高阶组件即接受一个或多个组件作…

C# WPF上位机开发(键盘绘图控制)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在软件开发中&#xff0c;如果存在canvas图像的话&#xff0c;一般有几种控制方法。一种是鼠标控制&#xff1b;一种是键盘控制&#xff1b;还有一…

玄关柜和鞋柜是一回事吗?福州中宅装饰,福州装修

玄关柜和鞋柜虽然都用于存放鞋子&#xff0c;但它们在概念上有所不同。玄关柜是一个更大的概念&#xff0c;它包括鞋柜和其他功能区域&#xff0c;可以说鞋柜是玄关柜的一部分。 1️⃣概念上的不同 玄关柜是一种集成了鞋柜、挂衣架、换鞋凳等多种功能于一体的家居家具&#xf…