Android学习之路(27) ProGuard,混淆,R8优化

前言

使用java编写的源代码编译后生成了对于的class文件,但是class文件是一个非常标准的文件,市面上很多软件都可以对class文件进行反编译,为了我们app的安全性,就需要使用到Android代码混淆这一功能。

针对 Java 的混淆,ProGuard 就是常用的混淆工具,且他不仅仅是混淆工具,它同时可以对代码进行 压缩优化混淆

下面我们来简单介绍下ProGuard工作流程。

ProGuard 工作流程

ProGuard工作过程包括四个步骤:shrinkoptimizeobfuscatepreverigy。这四个步骤都是可选,但是顺序都是不变的

46abad1b3fbc2c28db008ecb949676b2.png

  • shrink:检测并删除项目中未使用到的类,字段,方法以及属性
  • optimize:优化字节码,移除无用指令,或者进行指令优化。
  • obfuscate:代码混淆,将代码中的类,字段,方法和属性等名称使用无意义的名称进行表示,减少代码反编译后的可读性。
  • preverify:针对 Java 1.6 及以上版本进行预校验, 校验 StackMap /StackMapTable 属性.在编译时可以关闭,加快编译速度

Android中的代码优化以及混淆

Android构建中,在AGP3.4.0之前也是使用的ProGuard 进行代码优化混淆,但是在3.4.0之后,谷歌将这一工作赋予给了性能更佳的R8编译器

虽然摒弃了ProGuard,但是R8编译器还是兼容ProGuard的配置规则

使用R8编译器可以做以下优化:

  • 1.代码缩减
  • 2.资源缩减
  • 3.代码混淆
  • 4.代码优化
1.代码缩减

代码缩减指的是:R8编译期智能检测代码中未使用到的类、字段、方法和属性等,并移除

比如你项目中依赖了很多库,但是只使用了库里面少部分代码,为了移除这部分代码,R8会根据配置文件确定应用代码的所有入口点:包括应用启动的第一个Activity或者服务等,R8会根据入口,检测应用代码,并构建出一张图表,列出应用运行过程中可能访问的方法,成员变量和类等,并对图中没有关联到的代码,视为可移除代码。

如下图:

图中入口位置:MainActivity,整个调用链路中,使用到了foo,bar函数以及AwesomeApi类中的faz函数,所以这部分代码会被构建到依赖图中,而OkayApi类以及其baz函数都未访问到,则这部分代码就可以被优化。

使用方式:

arduino
复制代码
android {buildTypes {release {...minifyEnabled true}}...
}

minifyEnabled 设置为true,会默认启用R8代码缩减功能。

代码优化需要注意的两种情况:

1.反射调用的情况

2.JNI调用的情况

R8并未对反射以及JNI等情况进行检测,如果配置文件中未处理,则这部分代码就会被丢弃,会出现NoClassFindException的异常,如何解决呢?

  • 1.1:在配置文件中使用-keep对这部分类进行说明:
kotlin
复制代码
-keep public class MyClass
  • 1.2:给需要保留的代码添加@keep注解

前提条件:1.声明了使用AndroidX 2.使用AGP默认的ProGuard文件

R8配置文件

R8使用ProGuard 规则文件来决定哪部分代码需要保留,配置文件来源分为下面几个:

  • 1.AndroidStudio:

位置:/proguard-rules.pro

说明

创建新的模块时,会在当前模块目录下创建一个默认的:proguard-rules.pro 文件

  • 2.AGP插件

位置:由AGP在编译时生成的proguard-android-optimize.txt

说明

Android Gradle 插件会生成 proguard-android-optimize.txt(其中包含了对大多数 Android 项目都有用的规则),并启用 @Keep* 注解。

编译后在\build\intermediates\proguard-files\目录下会生成3个文件:

image-20230424141102942

其中proguard-android-optimize.txt-4.1.1是需要进行optimize代码优化的ProGuard配置文件,而proguard-android.txt-4.1.1表示不需要进行optimize代码优化的ProGuard文件。

4.1.1表示当前模块的AGP插件版本

  • 3.库依赖项

位置

AAR 库:<library-dir>/proguard.txt

JAR 库:<library-dir>/META-INF/proguard/

说明

引入的aar或者jar包的库中,默认包含proguard优化规则,则在编译过程中也会被纳入R8配置项中,所以特别注意aar中引入的proguad和原项目规则冲突的情况。

  • 4.AAPT2(Android资源打包工具)

位置:使用 minifyEnabled true 构建项目后:<module-dir>/build/intermediates/proguard-rules/debug/aapt_rules.txt

说明

AAPT2 会根据对应用清单中的类、布局及其他应用资源的引用,生成保留规则。例如,AAPT2 会为您在应用清单中注册为入口点的每个 activity 添加一个保留规则。

  • 5.自定义配置文件

位置:默认情况下,当您使用 Android Studio 创建新模块时,IDE 会创建 <module-dir>/proguard-rules.pro,以便您添加自己的规则。

说明

您可以添加其他配置,R8 会在编译时应用这些配置。如果您将 minifyEnabled 属性设为 true,R8 会将来自上述所有可用来源的规则组合在一起,但是需要注意依赖库引入导致的规则冲突问题

如果需要输出 R8 在构建项目时应用的所有规则的完整报告:可以添加下面语句到proguard-rules.pro中

javascript
复制代码
// You can specify any path and filename.
-printconfiguration ~/tmp/full-r8-config.txt

如果需要添加额外的proguad文件:可以通过将相应文件添加到模块的 build.gradle 文件的 proguardFiles 属性中:

如分别给每个productflavor添加规则可以使用下面这种方式:

java
复制代码
android {...buildTypes {release {minifyEnabled trueproguardFilesgetDefaultProguardFile('proguard-android-optimize.txt'),// List additional ProGuard rules for the given build type here. By default,// Android Studio creates and includes an empty rules file for you (located// at the root directory of each module).'proguard-rules.pro'}}flavorDimensions "version"productFlavors {flavor1 {...}flavor2 {proguardFile 'flavor2-rules.pro'}}
}
2.资源缩减

资源缩减是在代码缩减之后进行的,只有去除了不需要的代码后, 才可以知道哪些代码里面的资源也是不被引入,可以移除的。

资源缩减只要在模块gradle下面添加shrinkResources属性即可:

arduino
复制代码
android {...buildTypes {release {shrinkResources trueminifyEnabled true...}}
}

注意:资源缩减需要提前开启代码缩减minifyEnabled

当然你也可以对资源文件添加白名单

xml
复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"tools:discard="@layout/unused2" />

使用tools:keep指定需要保留的资源文件,使用tools:discard指定可以舍弃的资源文件

3.代码混淆

混淆指的是将类名,方法名,属性名使用无意义的字符来表示:看下图:

image-20230424134309753

如何进行混淆?

混淆的一些基本规则

  • 一颗星:表示保留当前包下的类名,如果有子包,子包中的类会被混淆
kotlin
复制代码
-keep class cn.hadcn.test.*
  • 两颗星:表示保留当前包下的类名,如果有子包,子包中的类名也会被保留。
kotlin
复制代码
-keep class cn.hadcn.test.**
  • 上面的方式虽然保留了类名,但是内容还是会被混淆,使用下面方式保留内容
kotlin
复制代码
-keep class cn.hadcn.test.* {*;}
  • 在此基础上,我们也可以使用Java的基本规则来保护特定类不被混淆,比如我们可以用extends,implements等这些Java规则。如下例子就避免所有继承Activity的类被混淆:
scala
复制代码
-keep public class * extends android.app.Activity
  • 如果我们要保留一个类中的内部类不被混淆则需要用$符号,如下例子表示保持ScriptFragment内部类JavaScriptInterface中的所有public内容不被混淆。
kotlin
复制代码
-keepclassmembers class cc.ninty.chat.ui.fragment.ScriptFragment$JavaScriptInterface {public *;
}
  • 再者,如果一个类中你不希望保持全部内容不被混淆,而只是希望保护类下的特定内容,就可以使用:
csharp
复制代码
<init>;     //匹配所有构造器
<fields>;   //匹配所有域
<methods>;  //匹配所有方法方法
  • 你还可以在或前面加上private 、public、native等来进一步指定不被混淆的内容,如
kotlin
复制代码
-keep class cn.hadcn.test.One {public <methods>;
}
  • 当然你还可以加入参数,比如以下表示用JSONObject作为入参的构造函数不会被混淆:
kotlin
复制代码
-keep class cn.hadcn.test.One {public <init>(org.json.JSONObject);
}
  • 有时候你是不是还想着:我不需要保持类名,我只需要把该类下的特定方法保持不被混淆就好,那你就不能用keep方法了,keep方法会保持类名,而需要用keepclassmembers ,如此类名就不会被保持,为了便于对这些规则进行理解,官网给出了以下表格:

android打包混淆及语法规则详解_android

bash
复制代码
# -keep关键字
# keep:包留类和类中的成员,防止他们被混淆
# keepnames:保留类和类中的成员防止被混淆,但成员如果没有被引用将被删除
# keepclassmembers :只保留类中的成员,防止被混淆和移除。
# keepclassmembernames:只保留类中的成员,但如果成员没有被引用将被删除。
# keepclasseswithmembers:如果当前类中包含指定的方法,则保留类和类成员,否则将被混淆。
# keepclasseswithmembernames:如果当前类中包含指定的方法,则保留类和类成员,如果类成员没有被引用,则会被移除。
注意事项
  • 1.使用AS4.1.1版本进行混淆编译后,在 /build/outputs/mapping/release/下面会生成以下四个文件:

    • configuration:所有ProGuard文件整合后的规则文件:
    • mapping:混淆前后的映射文件,这个文件在使用反混淆的时候有用。
    • seeds:未进行混淆的类和成员。
    • usage:未使用的文件,也就是移除后的文件。

      image-20230424143702751

  • 2.有使用jni的情况下,jni方法不可混淆
arduino
复制代码
-keepclasseswithmembernames class * {    native <methods>;
}
  • 3.反射用到的类不混淆。
  • 4.AndroidMainfest中的类不混淆,所有四大组件和Application的子类和Framework层下所有的类默认不会进行混淆,自定义的View默认也不会被混淆。所以像网上贴的很多排除自定义View,或四大组件被混淆的规则在Android Studio中是无需加入的。
  • 5.与服务端交互时,使用GSON、fastjson等框架解析服务端数据时,所写的JSON对象类不混淆,否则无法将JSON解析成对应的对象;
  • 6.使用第三方开源库或者引用其他第三方的SDK包时,如果有特别要求,也需要在混淆文件中加入对应的混淆规则;
  • 7.有用到WebView的JS调用也需要保证写的接口方法不混淆,原因和第一条一样;
  • 8.Parcelable的子类和Creator静态成员变量不混淆,否则会产生Android.os.BadParcelableException异常;
php
复制代码
# 保持Parcelable不被混淆    
-keep class * implements Android.os.Parcelable {         public static final Android.os.Parcelable$Creator *;
}
  • 9.使用enum类型时需要注意避免以下两个方法混淆,因为enum类的特殊性,以下两个方法会被反射调用,见第二条规则。
arduino
复制代码
-keepclassmembers enum * {  public static **[] values();  public static ** valueOf(java.lang.String);  
}
混淆模板

下面是一个混淆模板:可根据自身需要进行添加和删除

scala
复制代码
#--------------------------1.实体类---------------------------------
# 如果使用了Gson之类的工具要使被它解析的JavaBean类即实体类不被混淆。(这里填写自己项目中存放bean对象的具体路径)
-keep class com.php.soldout.bean.**{*;}
​
#--------------------------2.第三方包-------------------------------
​
#Gson
-keepattributes Signature
-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
-keep class com.google.gson.* { *;}
-dontwarn com.google.gson.**
​
#butterknife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
​
#-------------------------3.与js互相调用的类------------------------
​
​
#-------------------------4.反射相关的类和方法----------------------
​
​
#-------------------------5.基本不用动区域--------------------------
#指定代码的压缩级别
-optimizationpasses 5
​
#包明不混合大小写
-dontusemixedcaseclassnames
​
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
​
#混淆时是否记录日志
-verbose
​
#优化  不优化输入的类文件
-dontoptimize
​
#预校验
-dontpreverify
​
# 保留sdk系统自带的一些内容 【例如:-keepattributes *Annotation* 会保留Activity的被@override注释的onCreate、onDestroy方法等】
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
​
# 记录生成的日志数据,gradle build时在本项根目录输出
# apk 包内所有 class 的内部结构
-dump proguard/class_files.txt
# 未混淆的类和成员
-printseeds proguard/seeds.txt
# 列出从 apk 中删除的代码
-printusage proguard/unused.txt
# 混淆前后的映射
-printmapping proguard/mapping.txt
​
​
# 避免混淆泛型
-keepattributes Signature
# 抛出异常时保留代码行号,保持源文件以及行号
-keepattributes SourceFile,LineNumberTable
​
#-----------------------------6.默认保留区-----------------------
# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {native <methods>;
}
​
-keepclassmembers public class * extends android.view.View {public <init>(android.content.Context);public <init>(android.content.Context, android.util.AttributeSet);public <init>(android.content.Context, android.util.AttributeSet, int);public void set*(***);
}
​
#保持 Serializable 不被混淆
-keepclassmembers class * implements java.io.Serializable {static final long serialVersionUID;private static final java.io.ObjectStreamField[] serialPersistentFields;!static !transient <fields>;!private <fields>;!private <methods>;private void writeObject(java.io.ObjectOutputStream);private void readObject(java.io.ObjectInputStream);java.lang.Object writeReplace();java.lang.Object readResolve();
}
​
# 保持自定义控件类不被混淆
-keepclasseswithmembers class * {public <init>(android.content.Context,android.util.AttributeSet);
}
# 保持自定义控件类不被混淆
-keepclasseswithmembers class * {public <init>(android.content.Context,android.util.AttributeSet,int);
}
# 保持自定义控件类不被混淆
-keepclassmembers class * extends android.app.Activity {public void *(android.view.View);
}
​
# 保持枚举 enum 类不被混淆
-keepclassmembers enum * {public static **[] values();public static ** valueOf(java.lang.String);
}
​
# 保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator *;
}
​
# 不混淆R文件中的所有静态字段,我们都知道R文件是通过字段来记录每个资源的id的,字段名要是被混淆了,id也就找不着了。
-keepclassmembers class **.R$* {public static <fields>;
}
​
#如果引用了v4或者v7包
-dontwarn android.support.**
​
# 保持哪些类不被混淆
-keep public class * extends android.app.Appliction
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.preference.Preference
​
-keep class com.zhy.http.okhttp.**{*;}
-keep class com.wiwide.util.** {*;}
​
# ============忽略警告,否则打包可能会不成功=============
-ignorewarnings
4.代码优化

为了进一步缩减应用,R8 会在更深的层次上检查代码,以移除更多不使用的代码,或者在可能的情况下重写代码,以使其更简洁。下面是此类优化的几个示例:

  • 如果您的代码从未采用过给定 if/else 语句的 else {} 分支,R8 可能会移除 else {} 分支的代码
  • 如果您的代码只在一个位置调用某个方法,R8 可能会移除该方法并将其内嵌在这一个调用点
  • 如果 R8 确定某个类只有一个唯一子类且该类本身未实例化(例如,一个仅由一个具体实现类使用的抽象基类),它就可以将这两个类组合在一起并从应用中移除一个类。

更多优化点可以查看:Jake Wharton 写的关于 R8 优化的博文。

总结

本篇文章主要讲解了关于R8编译器在整个编译过程中对apk代码以及资源的一些优化操作,主要集中在代码缩减,资源缩减,代码混淆,代码优化这几部分,其中对代码混淆做了一个比较全面的分析,后期还会讲解一些关于代码反混淆的知识,这篇文章就讲到这里了,我是小余,我们下期见。

作者:小余的自习室
链接:https://juejin.cn/post/7225511164120891453
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Docker】Docker Registry(镜像仓库)

文章目录 一、什么是 Docker Registry二、镜像仓库分类三、镜像仓库工作机制四、常用的镜像仓库五、常用命令镜像仓库命令镜像命令(部分)容器命令(部分) 六、docker镜像仓库实战综合实战一&#xff1a;搭建一个 nginx 服务综合实战二&#xff1a;Docker hub上创建自己私有仓库综…

B站课程评分

Spring6 https://www.bilibili.com/video/BV1Ft4y1g7Fb/ 评价: 推荐一看 配套文档优秀, 老师口齿清晰, 条理不错. mybatis https://www.bilibili.com/video/BV1JP4y1Z73S/?spm_id_from333.337.search-card.all.click 评价: 推荐一看 配套文档优秀, 老师口齿清晰, 条理不错…

等变和不变 、向量神经元(vector neurons)是什么?

等变和不变 等变&#xff1a;如果输入是一个旋转后的椅子&#xff0c;那么输出也应该是一个旋转后的椅子 不变&#xff1a;如果输入是一个旋转后的椅子&#xff0c;那么输出应该是一个椅子&#xff0c;而不是一只狗。 向量神经元&#xff08;vector neurons&#xff09; 向量…

如何监控摄像头是否在线?有什么工具推荐

WGCLOUD监控系统 我们项目中&#xff0c;摄像头用的WGCLOUD监控系统来监控的&#xff0c;主要两种方式来监控 一种是监控摄像头的端口&#xff0c;使用WGCLOUD的端口监控模块 一种是PING摄像头的IP&#xff0c;使用WGCLOUD的ping监测模块 这两种方式比较简单&#xff0c;也…

1997-2022年中央对各省份一般公共预算转移支付数据

1997-2022年中央对各省份一般公共预算转移支付数据 1、时间&#xff1a;1997-2022年 2、范围&#xff1a;31省 3、指标&#xff1a;一般公共预算转移支付 4、来源&#xff1a;wind 财政部 5、指标解释&#xff1a;一般性转移支付又称体制性转移支付&#xff0c;是指上级政…

【2024.2.4练习】国王游戏

题目描述 题目思路 涉及排列组合求最优解问题&#xff0c;数据大考虑是否满足某种贪心策略。 假设不除以右手的数字&#xff0c;那么获得金币数量最多的显然为最后一个人。左手数字最大的应排在最后一位。在右手有数字的情况下&#xff0c;不妨也尝试从最后一个人开始排。 假…

Element UI+Spring Boot进行CRUD的实例

ElementUI安装与使用指南 前端代码&#xff1a;点击查看learnelementuispringboot项目源码 后端代码&#xff1a;点击查看 LearnElementUiAndSpringBoot 一、前端配置 安装axios axios官网axios中文文档安装指令&#xff1a;npm install axios 二、后端配置 springboot3m…

BLIP2——采用Q-Former融合视觉语义与LLM能力的方法

BLIP2——采用Q-Former融合视觉语义与LLM能力的方法 FesianXu 20240202 at Baidu Search Team 前言 大规模语言模型&#xff08;Large Language Model,LLM&#xff09;是当前的当红炸子鸡&#xff0c;展现出了强大的逻辑推理&#xff0c;语义理解能力&#xff0c;而视觉作为人…

YOLOv8进阶 | 如何用yolov8训练自己的数据集(以安全帽佩戴检测举例)

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。YOLOv8是一种目标检测算法&#xff0c;它是YOLO&#xff08;You Only Look Once&#xff09;系列算法的最新版本。本节课就带领大家如何基于YOLOv8来训练自己的目标检测模型&#xff0c;本次作者就以安全帽佩戴检测为案例进…

华为机考入门python3--(7)牛客7-取近似值

分类&#xff1a;数字 知识点&#xff1a; str转float float(str) 向上取整 math.ceil(float_num) 向下取整 math.floor(float_num) 题目来自【牛客】 import math def round_to_int(float_num): # 如果小数点后的数值大于等于0.5&#xff0c;则向上取整&#xf…

Fink CDC数据同步(一)环境部署

1 背景介绍 Apache Flink 是一个框架和分布式处理引擎&#xff0c;用于在无边界和有边界数据流上进行有状态的计算。Flink 能在所有常见集群环境中运行&#xff0c;并能以内存速度和任意规模进行计算。 Flink CDC 是 Apache Flink 的一组源连接器&#xff0c;基于数据库日志的…

【SpringBoot】RBAC权限控制

&#x1f4dd;个页人主&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;SpringBoot⛺️稳重求进&#xff0c;晒太阳 权限系统与RBAC模型 权限 为了解决用户和资源的操作关系&#xff0c; 让指定的用户&#xff0c;只能操作指定的资源。 权限功能 菜单权限&a…

windows下安装go

下载golang Go 官网下载地址&#xff1a; https://golang.org/dl/ Go 官方镜像站&#xff08;推荐&#xff09;&#xff1a; https://golang.google.cn/dl/ 选择安装包 验证有没有安装成功 查看 go 环境 说明 &#xff1a; Go1.11 版本之后无需手动配置环境变量&#xff0c…

29 python快速上手

Python操作MySQL和实战 1. 事务1.1 MySQL客户端1.2 Python代码 2. 锁2.1 排它锁2.2 共享锁 3. 数据库连接池4. SQL工具类4.1 单例和方法4.2 上下文管理 5.其他总结 目标&#xff1a;掌握事务和锁以及Python操作MySQL的各种开发必备知识。 概要&#xff1a; 事务锁数据库连接池…

Weblogic反序列化漏洞分析之CVE-2021-2394

目录 简介 前置知识 Serializable示例 Externalizable示例 联系weblogic ExternalizableLite接口 ExternalizableHelperl类 JdbcRowSetImpl类 MethodAttributeAccessor类 AbstractExtractor类 FilterExtractor类 TopNAggregator$PartialResult类 SortedBag$Wrappe…

【测试运维】web自动化全知识点笔记第1篇:什么是Web自动化测试(已分享,附代码)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论Web自动化测试相关知识。了解什么是自动化&#xff0c;理解什么是自动化测试以及为什么要使用自动化测试。具体包含&#xff1a;WebDriver的基本操作&#xff0c;WebDriver的鼠标、键盘操作&#xff0c;下拉选择框、警告…

【教学类-46-01】吉祥字门贴1.0(华光通心圆_CNKI 文本框 空心字涂色,最好繁体字)

作品展示 背景需求&#xff1a; 马上就要过年了&#xff0c;家家户户大门上贴上对联和福字 我想用正方形红色手工纸&#xff08;15CM&#xff09;也做一个幼儿描线版的福字 问题一&#xff1a;福字顺时针旋转45度 打印纸上制作福字&#xff0c;需要让这个字顺时针旋转45度&am…

【C++栈和队列:数据结构中的经典组合,高效处理先进先出与后进先出问题的最佳方案】

[本节目标] 1. stack的介绍和使用 2. queue的介绍和使用 3. priority_queue的介绍和使用 4. 容器适配器 1. stack的介绍和使用 1.1 stack的介绍 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的…

【DC渗透系列】DC-2靶场

arp先扫 ┌──(root㉿kali)-[~] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:6b:ed:27, IPv4: 192.168.100.251 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.100.1 00:50:56:c0:00:08 VMware, In…

DolphinScheduler实现隔几天调度

1.场景分析 dolphinscheduler&#xff08;海豚&#xff09;定时器模块-定时调度时每3秒|每3分钟|每3天这种定时&#xff0c;不能够跨分钟&#xff0c;跨小时&#xff0c;跨月&#xff0c;每次跨月等都会从每个月的第1天&#xff08;第几天开始可以设定&#xff09;开始重新计时…