Android打造专有Hook第三篇,实战全量代码规范检查

简介: 目前的规范检查,我分为了全量文件检查和增量文件检查,基本上和Git提交保持一致,在实际的业务中,开发者可以动态修改配置文件参数gitIncrement,来切换是增量还是全量,增量和全量有一些是共通的地方,接下来的代码中会陈述。

上篇文章,环境已经搭建,初始化程序已经完成,所需要的配置文件也均已创建,后面就是着手业务逻辑编写了,各位老铁,准备,开干!开干前,需要再次补充一下,虽是Android端的规范检查,但开发语言是Js,所以啊,各位铁子,不了解的话,抽个时间,看一看Js相关的语法,这么说吧,简单,毕竟我们都是掌握过高级编程语言的人,学起来,真的,没那么难,还是那句话,得得确确没时间学的话,也问题不大,跟着我的脚步,一步步执行,加上相关注释的理解,我相信,搞出来属于自己公司的规范,也只是时间的问题,况且,大部分的场景,我也基本上都会实现,最后也会开源给大家,大家完全可是使用我的,或者在我的基础之上更改即可。


目前的规范检查,我分为了全量文件检查和增量文件检查,基本上和Git提交保持一致,在实际的业务中,开发者可以动态修改配置文件参数gitIncrement,来切换是增量还是全量,增量和全量有一些是共通的地方,接下来的代码中会陈述。


最终的所有代码开源地址如下:


https://github.com/AbnerMing888/AndroidGitHook


今天的主要概述内容如下:


1、获取Git提交文件列表

2、判断提交文件类型

3、各中规范类型规范检测

4、补充说明


一、获取Git提交文件列表


在上篇中,我们定义了四个变量,临时存储了获取配置文件中的参数,下面我们就可以根据这些参数,来进行逻辑的处理。


首先根据mCommitOpen变量,判断开关是否打开,如果为true,证明需要进行Git规范检查,否则就是不需要,直接绿色通道,正常执行即可。在mCommitOpen为true之后,紧接着需要判断mCommitIncrement变量,判断是增量规范检查还是全量文件检查。


无论是增量检查还是全量检查,针对文件的名字,图片的名字等,都是要获取提交的文件列表的,而获取提交的文件列表,需要执行Git相关命令,这个命令是:


gitdiffHEAD--name-only--diff-filter=ACMR


通过执行上述的命令,我们就可以拿到本次提交修改过的文件,进而就可以针对这些文件进行遍历检查了,代码如下,由于增量和全量检查,所输出的日志信息不一样,以及所判断的逻辑也是不一样的,需要进行分别处理。


//根据配置文件进行逻辑判断//如果mCommitOpen为true,意味着git开关打开,需要执行检查if (mCommitOpen.indexOf("true") !==-1) {
//mCommitIncrement是否为true,true:增量检查(仅仅适用于命令行操作),false:整个文件的检索if (mCommitIncrement.indexOf("true") !==-1) {
console.log("");
log('增量检查中,铁子,开始了哦~', 1);
            } else {
//进行整个文件的检查,全量检查console.log("\n");
log('铁子,我要开始检查你的代码了!', 1);
            }
// 通过node子进程执行git命令,查看提交的文件列表exec('git diff HEAD --name-only --diff-filter=ACMR', function (error, stdout, stderr) {
if (stdout) {
//先检查文件名字是否符合规范log("这次你commit文件列表如下:\n", 1);
console.log(stdout+"\n");
if (mCommitIncrement.indexOf("true") !==-1) {
//执行增量文件检查//获取当前项目根路径letpath=require('path');
letdirname=path.join(__dirname);
checkDiffFile(cb, stdout, dirname);
                    } else {
//整个文件开始逐一排查checkFile(stdout, cb);
                    }
return;
                }
//没有文件,直接放行log("铁子,你的代码暂时没得问题,放行!\n", 1);
cb(0);
            });
        } else {
//如果mCommitOpen为false,意味着不检查,直接绿色通道,通过cb(0);
        }


二、判断提交文件类型


在第一步中,我们通过Git命令拿到了所更改的文件,在上面的代码中,根据全量还是增量,分别定义了不同的方法,checkFile和checkDiffFile,在这两个方法里就是针对所有的更改文件进行规范的检查,大家重点关注这两个方法即可,log方法第二章中有过讲述,就是用来输出日志信息的,就是一个简单的打印。


目前配置文件中,列出了9种类型的判断,上篇文章说过,我们再来看下配置文件定义的参数gitCheckType,这个是自己定义的,需要暴露给使用者的,所以啊,老铁,根据自己公司的规范标准来。


#git检测类型,0:全部,1:string文件Name,2:图片命名,3:layout,4:类命名,#5:类注释,6:方法注释,7:方法命名,8:变量命名,9:try catchgitCheckType=0


以上的9种类型,通过拆分,我们可以发现,4到9,都是通过类文件进行判断的,而1到3是根据文件名字进行判断的,在实际的规范检查中,我们就可以按条件进行判断。


在第一项中,我们通过命令已经拿到了文件的列表,而且还定义了两个方法,增量和全量,但是,我们拿到的文件列表是一个字符串,如果要获得每一个文件,那么我们就需要进行切割,由于文件都是一行一个,我们就可以以“\n”的方式进行分割,当然了,对于最后一个换行符号我们是要进行去掉的。


letpath=require('path');
letdirname=path.join(__dirname);
letarray=files.split('\n');//通过切割换行,拿到文件列表array.pop();// 去掉最后一个换行符号log('【针对以上提交文件检查结果如下:】\n', 1);
array.forEach(function (value) {
//value 就是每一个文件    });

 

拿到Git所提交的每一个文件,其实我们已经完成了一大步了,起码说,规范的前提所需要的条件,均已具备,后面就是针对这些提交的文件,进行逐个的规范检查了,9种类型,我们已经划分,下面针对9种类型如何做判断做一个简单的概述。


1、类文件


类文件暂时只包含java和Kotlin文件,如果大家想要拓展其他的文件类型,比如Flutter的项目等,大家可以自己定义,毕竟程序是自己搞的,想搞成什么,如何搞,还不是自己说的算,是吧,老铁!OK,针对这样的文件,我用的方法比较简单,你提交的kotlin文件,肯定以”kt“结尾,同样,提交的java文件,也肯定以”java“结尾,直接判断当前的文件名字是否包含”kt“或者”java“这不就搞定了,哈哈,老铁们,是不是特简单,类文件判断之后,就可以针对类文件,进行一系列的规范检查编写,如,类命名,类注释,方法命名,方法注释,变量等等,后面我们会一一阐述。


2、图片文件


和类文件一样的道理,还是用文件的结尾进行判断,一个图片有哪几种格式,肯定是固定的,比如png,jpg,gif,webp等等,只需要判断是否包含这些结尾的文件格式即可。


3、layout资源文件


layout需要注意,不仅要以最后的结尾xml来判断,还要判断当前的目录是不是在layout目录下,比较drawable下也有很多的xml资源,这个需要大家注意一下。


4、string文件Name


没什么好说的,直接判断文件名字是否包含”string“即可。


如果大家想要拓展,这里简单补充一下,关于文件命名是否规范,我的判断宗旨是,提交上来的文件,是否包含某一个特性,比如上述所说的类文件和图片文件,以及xml文件等等,都可以按照这样的逻辑进行判断,大家可以看下面的代码。


全量检查代码类型判断


/** * 整个文件进行检查,也就是全量文件检查 * files:当前commit的文件列表 * cb:进程,1,终止,0,执行 * */functioncheckFile(files, cb) {
letpath=require('path');
letdirname=path.join(__dirname);
letarray=files.split('\n');//通过切割换行,拿到文件列表array.pop();// 去掉最后一个换行符号log('【针对以上提交文件检查结果如下:】\n', 1);
array.forEach(function (value) {
//判断文件是什么类型if (value.indexOf("kt") !==-1||value.indexOf("java") !==-1) {
//kotlin文件或者java文件checkClassOrString(dirname+"/"+value, value, 0);
        } elseif (value.indexOf("string") !==-1&& (
mCommitType.indexOf("0") !==-1||mCommitType.indexOf("1") !==-1        )) {
//string文件name命名规范检查checkClassOrString(dirname+"/"+value, value, 1);
        } elseif ((value.indexOf("png") !==-1||value.indexOf("jpg") !==-1||value.indexOf("gif") !==-1||value.indexOf("webp") !==-1) &&            (mCommitType.indexOf("0") !==-1||mCommitType.indexOf("2") !==-1)) {
//图片文件命名规范检查checkImageOrLayout(value);
        } elseif ((value.indexOf("layout") !==-1&&value.indexOf("xml") !==-1) && (
mCommitType.indexOf("0") !==-1||mCommitType.indexOf("3") !==-1        )
        ) {
//layout 检查资源命名规范检查checkImageOrLayout(value);
        }
    });
setTimeout(function () {
console.log("\n");
if (isCheck) {
cb(1);
        } else {
log("所有文件均检查完毕,暂未发现问题,真棒!!!\n", 2);
cb(0);
        }
    }, 1500);
}


增量检查代码类型判断


/** * 增量文件检查 * */functioncheckDiffFile(cb, stdout, dirname) {
//通过切割换行,拿到文件列表letarray=stdout.split('\n');
// 去掉最后一个换行符号array.pop();
log('【针对以上提交文件检查结果如下:】\n', 1);
//遍历文件,检查相关规范是否符合array.forEach(function (value) {
if (((value.indexOf("png") !==-1||value.indexOf("jpg") !==-1||value.indexOf("gif") !==-1||value.indexOf("webp") !==-1) ||            (value.indexOf("layout") !==-1&&value.indexOf("xml") !==-1)) && (
mCommitType.indexOf("0") !==-1||mCommitType.indexOf("2") !==-1||mCommitType.indexOf("3") !==-1        )) {
//图片或者layout 规范检查checkImageOrLayout(value);
        } elseif (value.indexOf("kt") !==-1||value.indexOf("java") !==-1) {
//Kotlin或者Java,规范检查letlastPosition=value.lastIndexOf("/");
letclassName=value.substring(lastPosition+1, value.length);
//检查类的名字是否规范checkClassName(className, value);
        }
    });
//生成增量文件,并使用命令,写入增量代码fs.writeFile(dirname+"/androidCommit.diff", "", function (err) {
if (err) {
log('增量检查中断', 0);
return;
        }
exec('git diff >> androidCommit.diff', function (error, stdout, stderr) {
//增量代码写入后,进行读取diff文件checkDiff(cb, dirname);
        });
    });
setTimeout(function () {
console.log("\n");
if (isCheck) {
cb(1);
        } else {
log("增量检查完毕,暂未发现问题,真棒!!!\n", 2);
cb(0);
        }
    }, 1500);
}


无论增量还是全量,上面的代码在程序结束的时候,都做了一个延时操作,此延时的目的在于等待上述检查的程序执行,因为检查各个规范是耗时的,为了避免还未检查完毕就结束,所以做了一个延时操作,不过大家在实际的开发中,可以采用逐个检查,也就是同步检查,一个检查完毕再执行另一个,直至检查结束,再进行进程判断也可以的,人云亦云,看大家实际的操作了。


对了,还有一个isCheck变量,它是定义的一个全局变量,我们是要根据这个变量来决定最终的执行程序。


//这个比较重要的,要用这个变量定义最终的执行程序  false符合,通过,不提示,true不符合,不符合就要终止执行,给出提示varisCheck=false;


三、各中规范类型规范检测


各位老铁,需要注意是的,无论检查什么规范,前提一定得有自己的一套规范标准,我们所有的程序编写都是根据这套标准而来的,而不是凭空的捏造,我相信大家公司基本上都有,我们要做的就是,把公司的标准做成程序的检查。


根据上述的9中类型,无论增量还是全量,都进行了文件类型的判断,下面,我们针对不同的类型进行一一的拆解。


1、kotlin文件或者java文件相关规范检查


针对类文件的检查,上述已经说过,包含了,类命名,方法命名,类注释,方法注释,变量命名等,我们看下面的代码,由于类文件和String的Name检查公用了一个方法,这里用了一个type做了区分,为了保证程序的执行顺序,我这里简单的一一做了延时操作,当然了,大家如果有更好的方式,可以自行修改。


/** * 检查类文件或者String文件 * type:0,kotlin文件或者java文件,1,string文件name命名规范检查 * */functioncheckClassOrString(path, value, type) {
letmoduleName=getModuleName(value);//模块名字letdata=fs.readFileSync(path, 'utf-8');// 拿到文件内容if (type===0) {
//java和kotlin文件//首先检查命名,然后在类注释,方法,变量等letlastPosition=value.lastIndexOf("/");
letclassName=value.substring(lastPosition+1, value.length);
//首先检查类命名是否规范checkClassName(className, value);
setTimeout(function () {
//检查类注释是否规范if (mCommitType.indexOf("0") !==-1||mCommitType.indexOf("5") !==-1) {
checkClassNotes(className, data);
            }
        }, 200);
setTimeout(function () {
//检查方法注释是否规范if (mCommitType.indexOf("0") !==-1||mCommitType.indexOf("6") !==-1) {
checkMethodNotes(className, data);
            }
        }, 400);
setTimeout(function () {
//检查方法命名是否规范if (mCommitType.indexOf("0") !==-1||mCommitType.indexOf("7") !==-1) {
checkMethodName(className, data);
            }
        }, 600);
setTimeout(function () {
//检查变量命名是否规范if (mCommitType.indexOf("0") !==-1||mCommitType.indexOf("8") !==-1) {
checkVariableName(className, data);
            }
        }, 800);
setTimeout(function () {
//检查try catch 是否添加if (mCommitType.indexOf("0") !==-1||mCommitType.indexOf("9") !==-1) {
checkTry(className, data);
            }
        }, 1000);
    } elseif (type===1) {
// stringif (moduleName.indexOf("app") ===-1&&moduleName.indexOf("libBase") ===-1) {
letstringArr=data.split("name=\"");
stringArr.forEach(function (item, position) {
if (item.indexOf("encoding") ===-1) {
leti=item.indexOf("\"");
letendString=item.substring(0, i);
if (endString!==""&&!endString.startsWith(moduleName)) {
//开头不是isCheck=true;
log("【"+value+"中,name为"+endString+"】,命名不规范", 0);
                    }
                }
            });
        }
    }
}


针对上述代码,我把关于类的相关规范都定义了不同的方法,简单检查罗列一下,分享如下,还是那句话,这些所谓的规范检查,你必须有一套属于自己的规范标准。


类命名是否规范


类命令,无非就是,检查下是否是大驼峰命名规则,我这里简单的以首字母是否是大写,还有是否有下划线进行判断了,大家可以自行更改。


/** * 检查类的名字是否规范 * */functioncheckClassName(className, value) {
if (mCommitType.indexOf("0") !==-1||mCommitType.indexOf("4") !==-1) {
if (!checkCase(className.substring(0, 1)) ||className.indexOf("_") !==-1) {
//不符合isCheck=true;
log("【"+value+"】,类命名不规范", 0);
        }
    }
}


检查类注释是否规范


类注释,我们公司定义的是必须包含,author,date,desc这个三个参数,我的判断就是是否包含了这三个参数,没包含就提示不规范,当然了,大家可以按照自己公司的标准去执行即可。


/** * 类注释检查是否规范 * */functioncheckClassNotes(className, data) {
if (data.indexOf("{") !==-1) {
letdd=data.split("{")[0];
if (dd.indexOf("author") ===-1||dd.indexOf("date") ===-1||dd.indexOf("desc") ===-1) {
//不符合isCheck=true;
log("【"+className+"】,类注释不规范", 0);
        }
    }
}


方法注释是否规范


方法注释,这个稍微逻辑复杂些,第一,首先,得找到方法,第二,判断是否有”//“,”*/“,相关注释标准,第三,一些重写的方法就没必要添加注释了,还有就是,java和Kotlin的方法定义还不太一样,kotlin是”fun“来定义,Java就更不规则了,目前我的判断代码如下,基本上可以实现,问题不大,哈哈~


/** * 检查方法注释是否规范 * */functioncheckMethodNotes(className, data) {
vareachOk=0;
vareachNo=0;
varcaseNode= [];//不符合的方法if (className.indexOf("kt")) {
//kotlinletkotlin=data.split("fun");
kotlin.forEach(function (item, position) {
letendItem=item.trim();
letoverride=endItem.substring(endItem.length-20, endItem.length);
//判断是否包含if (position!==kotlin.length-1) {
if (override.indexOf("override") ===-1) {
letendM=kotlin[position+1];
//有注释的也要另行添加letkE=endItem.lastIndexOf("}");
letendK=endItem.substring(kE, endItem.length);
if (endK.indexOf("//") !==-1||endK.indexOf("*/") !==-1) {
//带有注释eachOk++;
                    } else {
//没有注释//不符合的方法lettr=endM;
if (tr!=null) {
letpositionCase=tr.indexOf("(");
letendCase=tr.substring(0, positionCase);
//去掉构造函数if (endCase.length<30&&className.indexOf(endCase) ===-1) {
eachNo++;
caseNode.push(endCase);
                            }
                        }
                    }
                }
            }
        });
    } else {
//java//遍历方法letjava=data.split(") {");
java.forEach(function (item, position) {
if (item.indexOf("public") !==-1||item.indexOf("protected") !==-1||item.indexOf("private") !==-1) {
//判断是否包含}if (item.indexOf("}") !==-1) {
letlastDesc=item.lastIndexOf("}");
letendDesc=item.substring(lastDesc, item.length);
if (endDesc.indexOf("Override") ===-1) {
if (endDesc.indexOf("//") !==-1||endDesc.indexOf("/*") !==-1) {
//包含eachOk++;
                        } else {
if (item.indexOf("while") ===-1&&item.indexOf("if") ===-1&&item.indexOf("for") ===-1) {
//添加方法letlastK=item.lastIndexOf("(");
letlasetContent=item.substring(0, lastK);
letendContent=lasetContent.split(" ");//取最后一个letjavaMethod=endContent[endContent.length-1];
if (className.indexOf(javaMethod) ===-1) {
//不符合的方法eachNo++;
caseNode.push(javaMethod);
                                }
                            }
                        }
                    }
                } else {
letlastPrivate=item.lastIndexOf("private");
letlastPublic=item.lastIndexOf("public");
letlastProtected=item.lastIndexOf("protected");
varendLast=lastPrivate;
if (lastPublic>endLast) {
endLast=lastPublic;
                    }
if (lastProtected>endLast) {
endLast=lastPublic;//获取最后一个                    }
letendString=item.substring(endLast-50, endLast);
if (endString.indexOf("Override") ===-1) {
if (endString.indexOf("//") !==-1||endString.indexOf("*/") !==-1) {
//包含eachOk++;
                        } else {
//添加方法letlastK=item.lastIndexOf("(");
letlasetContent=item.substring(0, lastK);
letendContent=lasetContent.split(" ");//取最后一个letjavaMethod=endContent[endContent.length-1];
if (className.indexOf(javaMethod) ===-1) {
//不符合的方法eachNo++;
caseNode.push(javaMethod);
                            }
                        }
                    }
                }
            }
        });
    }
if (eachNo!==0) {
isCheck=true;
log("\n【"+className+"】,未添加注释的方法如下:\n", 1);
log(caseNode, 0);
    }
}


方法命名是否规范


这个相对于方法注释,就简单了许多了,无非就是获取方法名字,然后这对方法名字判断是否符合公司定义的规范即可,没啥好说的,看代码即可。


/** * 检查方法命名是否规范 * */functioncheckMethodName(className, data) {
//遍历方法vareachOk=0;
vareachNo=0;
varcaseNode= [];//不符合的方法//遍历所有的方法,判断是kt还是javaif (className.indexOf("kt") !==0) {
//kotlinletkotlin=data.split("fun");
kotlin.forEach(function (item, position) {
if (position!==0) {
//判断开头是大写还是小写lettr=item.trim();
letindexCase=tr.substring(0, 1);
letpositionCase=tr.indexOf("(");
letendCase=tr.substring(0, positionCase);
if (endCase.indexOf("<") ===-1&&endCase!==""&&className.indexOf(endCase) ===-1) {
if ((checkCase(indexCase)
||endCase.indexOf("_") !==-1)) {
//不符合eachNo++;
//添加方法caseNode.push(endCase);
                    } else {
//符合eachOk++;
                    }
                }
            }
        });
    } else {
//java//遍历方法letjava=data.split(") {");
java.forEach(function (item, position) {
if (item.indexOf("public") !==-1||item.indexOf("protected") !==-1||item.indexOf("private") !==-1) {
//获取最后一个括号letlastK=item.lastIndexOf("(");
letlasetContent=item.substring(0, lastK);
letendContent=lasetContent.split(" ");//取最后一个letendMethod=endContent[endContent.length-1];
if (endMethod.indexOf("<") ===-1&&endMethod!==""&&className.indexOf(endMethod) ===-1&&endMethod.indexOf("(") ===-1) {
if (checkCase(endMethod.substring(0, 1)) ||endMethod.indexOf("_") !==-1) {
//不符合eachNo++;
//添加方法caseNode.push(endMethod);
                    } else {
//符合eachOk++;
                    }
                }
            }
        });
    }
if (eachNo!==0) {
//不符合isCheck=true;
log("\n【"+className+"】,方法命名不规范的如下:\n", 1);
log(caseNode, 0);
    }
}


变量命名是否规范


变量的命名相对比较负责,因为Kotlin和Java所定义的变量格式是不一样的,还有就是得忽略一些常量的命名,Kotlin我是以val或者var来进行截取分割,拿到变量名,Java呢,相对就比较局限,只能以大众的常见格式进行获取,然后再进行分割,具体的,大家直接看相关代码。


/** * 检查变量命名是否规范 * */functioncheckVariableName(className, data) {
vareachOk=0;
vareachNo=0;
varcaseNode= [];//不符合的方法//遍历所有的方法,判断是kt还是javaif (className.indexOf("kt") !==-1) {
//以等号分割letspD=data.split("=");
spD.forEach(function (item, position) {
//然后判断val 和 varletlastVal=item.lastIndexOf("val");
letlastVar=item.lastIndexOf("var");
varendLast=lastVal;
if (lastVar>lastVal) {
endLast=lastVar;
            }
letlastContent=item.substring(endLast, item.length);
if (lastContent.indexOf("val") !==-1||lastContent.indexOf("var") !==-1) {
if (lastContent.indexOf("fun") ===-1) {
letendK=lastContent.split(" ")[1];
//判断变量是否符合要求if (endK.indexOf("R") ===-1&&endK.indexOf("!") ===-1&&endK.indexOf(")") ===-1&&endK.indexOf("{") ===-1&&endK.indexOf("}") ===-1) {
if (endK.indexOf("<") ===-1&&endK!=="") {
//这里进行判断大小写constp=/^[A-Z_]*$/g;
if (p.test(endK)) {
//符合eachOk++;
                            } else {
if ((checkCase(endK.substring(0, 1))
||endK.indexOf("_") !==-1)) {
//不符合eachNo++;
//添加方法caseNode.push(endK);
                                } else {
//符合eachOk++;
                                }
                            }
                        }
                    }
                }
            }
        });
    } else {
//java//判断letspF=data.split(";");
spF.forEach(function (item, position) {
letlastPrivate=item.lastIndexOf("private");
letlastPublic=item.lastIndexOf("public");
letlastProtected=item.lastIndexOf("protected");
varendLast=lastPrivate;
if (lastPublic>endLast) {
endLast=lastPublic;
            }
if (lastProtected>endLast) {
endLast=lastPublic;//获取最后一个            }
letlastContent=item.substring(endLast, item.length);
if (lastContent.indexOf("public") !==-1||lastContent.indexOf("protected") !==-1||lastContent.indexOf("private") !==-1) {
//是否包含等号if (lastContent.indexOf("=") !==-1) {
leta=lastContent.trim().split("=");
letb=a[0].trim().split(" ");
letendC=b[b.length-1];
if (endC.indexOf("R") ===-1&&endC.indexOf("!") ===-1&&endC.indexOf(")") ===-1&&endC.indexOf("(") ===-1&&endC.indexOf("{") ===-1&&endC.indexOf("}") ===-1) {
//判断变量是否符合要求constp=/^[A-Z_]*$/g;
if (p.test(endC)) {
eachOk++;
                        } else {
if (endC.indexOf("<") ===-1&&endC!=="") {
if ((checkCase(endC.substring(0, 1))
||endC.indexOf("_") !==-1)) {
//不符合eachNo++;
//添加方法caseNode.push(endC);
                                } else {
//符合eachOk++;
                                }
                            }
                        }
                    }
                } else {
//普通的成员变量letendItem=lastContent.trim().split(" ");
letendContent=endItem[endItem.length-1];//最后的内容if (endContent.indexOf("R") ===-1&&endContent.indexOf("!") ===-1&&endContent.indexOf(")") ===-1&&endContent.indexOf("(") ===-1&&endContent.indexOf("{") ===-1&&endContent.indexOf("}") ===-1) {
//判断变量是否符合要求if (endContent.indexOf("<") ===-1&&endContent!=="") {
constp=/^[A-Z_]*$/g;
if (p.test(endContent)) {
eachOk++;
                            } else {
if ((checkCase(endContent.substring(0, 1))
||endContent.indexOf("_") !==-1)) {
//不符合eachNo++;
//添加方法caseNode.push(endContent);
                                } else {
//符合eachOk++;
                                }
                            }
                        }
                    }
                }
            }
        });
    }
if (eachNo!==0) {
//不符合isCheck=true;
log("\n【"+className+"】,变量命名不规范的如下:\n", 1);
log(caseNode, 0);
    }
}


try catch 是否添加


try catch是我们公司自己定义的一项标准,就是在业务函数中,需要增加try catch,以防止由于空,类型不一等情况造成的崩溃,具体的判断就是,在获取到方法后,判断方法里是否包含try catch即可。


/** * try  catch 是否添加 * */functioncheckTry(className, data) {
//遍历所有的方法,判断是kt还是javavarkj;
if (className.indexOf("kt") !==-1) {
//kotlinkj=data.split("fun");
    } elseif (className.indexOf("java") !==-1) {
//javakj=data.split("void");
    } else {
kj= [];
    }
//遍历方法vareachOk=0;
vareachNo=0;
kj.forEach(function (item, position) {
if (position!==0) {
if (item.indexOf("try") !==-1&&item.indexOf("catch") !==-1) {
//符合的方法eachOk++;
            } else {
//不符合的方法eachNo++;
            }
        }
    });
if (eachNo!==0) {
//不符合isCheck=true;
log("【"+className+"】,检测到有未添加try catch的方法", 0);
    }
}


2、string文件name命名规范检查


string相对来说还是比较简单的,首先拿到string文件,然后获取文件里面的内容,接着进行关键字分割,拿到所有的name的Key,针对Key做规范检查即可,当然了,在组件化的开发中,有一些组件是不需要检查的,我们进行过滤即可,下面的代码是和类文件检查公用的,在Kotlin文件或Java文件相关检查中有。


if (moduleName.indexOf("app") ===-1&&moduleName.indexOf("libBase") ===-1) {
letstringArr=data.split("name=\"");
stringArr.forEach(function (item, position) {
if (item.indexOf("encoding") ===-1) {
leti=item.indexOf("\"");
letendString=item.substring(0, i);
if (endString!==""&&!endString.startsWith(moduleName)) {
//开头不是isCheck=true;
log("【"+value+"中,name为"+endString+"】,命名不规范", 0);
                    }
                }
            });
        }


3、图片文件命名规范检查


这里再重述一下啊各位老铁,所有的规范,前提必须得有自己的一套规范标准啊,不然,我们的程序就没有参照依据了,关于图片的规范,根据实际的规范标准,我举一个例子,下面是我们公司的规范:


图片命名规则:组件名称_(背景用bg,图片用ic,按钮用btn,分隔线用divider)_**

例如:


①、community模块下

community_ic_publish

②、common模块下

common_bg_publish

common_ic_publish


根据上述的标准,我所开发的检查如下,当然了,还是那句话,程序是活的,大家可以根据自己公司的规范标准去执行即可。


/** * 检查图片或者layout资源命名是否规范 * */functioncheckImageOrLayout(value) {
//图片和layout  直接判断命名letmoduleName=getModuleName(value);
//过滤app和libBaseif (moduleName.indexOf("app") ===-1&&moduleName.indexOf("libBase") ===-1) {
letlastPosition=value.lastIndexOf("/");
letxmlName=value.substring(lastPosition, value.length);
if (!xmlName.startsWith(moduleName)) {
isCheck=true;
log("【"+xmlName+"】,命名不规范", 0);
        }
    }
}


4、layout 检查资源命名规范检查


layout的资源命名规范检查,和上述的图片检查基本是一致的,可以进行复用。需要注意的是,组件化开发的项目,可能对于app组件以及中间层组件,组件名是可以不带的,当然了,看大家实际的业务需求,不带就进行过滤即可。


获取模块的名字,也就是当前提交的文件是属于哪个组件,这种检查方式适用于组件化开发的项目,这里我进行了一个简单的判断,主要是我们公司有的组件名字带了一个module,我这里给删除了。


/** * 获取模块的名字 * */functiongetModuleName(value) {
letimagePosition=value.indexOf("/");
varmoduleName=value.substring(0, imagePosition);//模块名字//去除moduleif (moduleName.indexOf("module_") !==-1) {
//包含moduleName=moduleName.replace("module_", "");
    }
returnmoduleName;
}


四、补充说明


在上述中代码中,包含了所有的全量代码逻辑,但是唯独缺少了增量代码检查的逻辑,考虑到增量代码的判断和全量有着巨大的差异,毕竟增量规范检查,只检查你所提交的那部分代码,也许是一行,也许是几行,相关的逻辑判断,还是和全量有所区别的,所以啊,各位老铁,至于增量代码如何实现规范检查,我们放到下篇文章去陈述,好了,各位铁子,这篇就到这里,欢迎感兴趣的老铁,持续关注,我们下篇见。


相关文章
|
3天前
|
缓存 数据处理 Android开发
Android经典实战之Kotlin常用的 Flow 操作符
本文介绍 Kotlin 中 `Flow` 的多种实用操作符,包括转换、过滤、聚合等,通过简洁易懂的例子展示了每个操作符的功能,如 `map`、`filter` 和 `fold` 等,帮助开发者更好地理解和运用 `Flow` 来处理异步数据流。
25 4
|
3天前
|
API Android开发 开发者
Android经典实战之使用ViewCompat来处理View兼容性问题
本文介绍Android中的`ViewCompat`工具类,它是AndroidX库核心部分的重要兼容性组件,确保在不同Android版本间处理视图的一致性。文章列举了设置透明度、旋转、缩放、平移等功能,并提供了背景色、动画及用户交互等实用示例。通过`ViewCompat`,开发者可轻松实现跨版本视图操作,增强应用兼容性。
21 5
|
8天前
|
缓存 API Android开发
Android经典实战之Kotlin Flow中的3个数据相关的操作符:debounce、buffer和conflate
本文介绍了Kotlin中`Flow`的`debounce`、`buffer`及`conflate`三个操作符。`debounce`过滤快速连续数据,仅保留指定时间内的最后一个;`buffer`引入缓存减轻背压;`conflate`仅保留最新数据。通过示例展示了如何在搜索输入和数据流处理中应用这些操作符以提高程序效率和用户体验。
21 6
|
6天前
|
API Android开发 开发者
Android经典实战之用WindowInsetsControllerCompat方便的显示和隐藏状态栏和导航栏
本文介绍 `WindowInsetsControllerCompat` 类,它是 Android 提供的一种现代化工具,用于处理窗口插入如状态栏和导航栏的显示与隐藏。此类位于 `androidx.core.view` 包中,增强了跨不同 Android 版本的兼容性。主要功能包括控制状态栏与导航栏的显示、设置系统窗口行为及调整样式。通过 Kotlin 代码示例展示了如何初始化并使用此类,以及如何设置系统栏的颜色样式。
27 2
|
6天前
|
API Android开发 Kotlin
Android实战经验分享之如何获取状态栏和导航栏的高度
在Android开发中,掌握状态栏和导航栏的高度对于优化UI布局至关重要。本文介绍两种主要方法:一是通过资源名称获取,简单且兼容性好;二是利用WindowInsets,适用于新版Android,准确性高。文中提供了Kotlin代码示例,并对比了两者的优缺点及适用场景。
43 1
|
10天前
|
自然语言处理 定位技术 API
Android经典实战之如何获取图片的经纬度以及如何根据经纬度获取对应的地点名称
本文介绍如何在Android中从图片提取地理位置信息并转换为地址。首先利用`ExifInterface`获取图片内的经纬度,然后通过`Geocoder`将经纬度转为地址。注意操作需在子线程进行且考虑多语言支持。
34 4
|
2天前
|
编译器 Android开发 开发者
Android经典实战之Kotlin 2.0 迁移指南:全方位优化与新特性解析
本文首发于公众号“AntDream”。Kotlin 2.0 已经到来,带来了 K2 编译器、多平台项目支持、智能转换等重大改进。本文提供全面迁移指南,涵盖编译器升级、多平台配置、Jetpack Compose 整合、性能优化等多个方面,帮助开发者顺利过渡到 Kotlin 2.0,开启高效开发新时代。
5 0
|
4天前
|
IDE 开发工具 Android开发
Android c++ core guideline checker 应用问题之clang-tidy 检查后发现的问题如何解决
Android c++ core guideline checker 应用问题之clang-tidy 检查后发现的问题如何解决
|
4天前
|
XML 数据可视化 API
Android经典实战之约束布局ConstraintLayout的实用技巧和经验
ConstraintLayout是Android中一款强大的布局管理器,它通过视图间的约束轻松创建复杂灵活的界面。相较于传统布局,它提供更高灵活性与性能。基本用法涉及XML定义约束,如视图与父布局对齐。此外,它支持百分比尺寸、偏移量控制等高级功能,并配有ConstraintSet和编辑器辅助设计。合理运用可显著提高布局效率及性能。
14 0
|
5天前
|
API 调度 Android开发
Android经典实战之处理后台任务的2个工具
本文介绍Android后台任务管理,涵盖WorkManager与JobScheduler的使用方法及区别。WorkManager属Jetpack库,确保任务可靠执行,支持延迟与条件依赖。JobScheduler则针对特定条件下的任务调度,如网络类型。两者各有优势,WorkManager适用于多数场景。
11 0