/** * 批量生成sel的xml文件 <br> * 比如图片名字是ic_img.png和按下的ic_img_pressed.png,那么最终生成的就是封装好的ic_img_sel.xml * * @param path 包含全部图片的文件路径 * @param end 特殊状态(pressed按下/checked选中)后缀名 */ public static void batchCreateSelFiles(String path, String end) { List<File> files = FileUtils.getAllFiles(path); for (File file : files) { String fileName = FileUtils.getName(file); // 用normal状态的图片名生成对应的_sel.xml文件 if (!fileName.endsWith(end)) { Document doc = createSelector(fileName, fileName + "_" + end, end); // fileName + "_" + end File nFile = new File(path, fileName + "_sel.xml"); XmlUtil.write2xml(nFile, doc); } } }
/** * 删除无用的src文件 * * @param rootPath 根目录的绝对路径 */ public static void delNoUseSrcFile(String rootPath) { List<File> files = FileUtils.getAllFiles(rootPath); out: for (File file : files) { String name = file.getName(); // 只需要删除src包下的文件 if (!file.getPath().contains("\\src\\")) { continue; } for (File compareFile : files) { String compareName = compareFile.getName(); if (name.equals(compareName)) { // 自己跟自己不匹配 continue; } // 只需要对比src包和layout包下的文件 if (!compareFile.getPath().contains("\\src\\") && !compareFile.getPath().contains("\\layout")) { continue; } if (!compareFile.exists()) { continue; } // 如果对比文件的本文内容中包含文件名,则视为有使用 String fileContent = FileUtils.readToString(compareFile); if (fileContent.contains(FileUtils.getName(file))) { continue out; } } // 删除没使用过的文件 String absname = file.getAbsoluteFile().getName(); boolean delete = file.delete(); System.out.println(absname + " ... delete=" + delete); } }
/** 生成adapter文件内容 */ private static String createAdapterContent(String layoutXml) { StringBuilder sbAdapterInfo = new StringBuilder(); sbAdapterInfo.append("\n"); // 成员变量,只设置最基本的集合类和context sbAdapterInfo.append(StringUtils.formatSingleLine(1, "private Context context;")); sbAdapterInfo.append( StringUtils.formatSingleLine(1, "// TODO change the MyItem class to your data bean class")); sbAdapterInfo.append(StringUtils.formatSingleLine(1, "private List<MyItem> datas;")); sbAdapterInfo.append("\n"); // 根据成员变量创建的构造函数 sbAdapterInfo.append( StringUtils.formatSingleLine(1, "public MyAdapter(Context context, List<MyItem> datas) {")); sbAdapterInfo.append(StringUtils.formatSingleLine(2, "this.context = context;")); sbAdapterInfo.append(StringUtils.formatSingleLine(2, "this.datas = datas;")); sbAdapterInfo.append(StringUtils.formatSingleLine(1, "}")); sbAdapterInfo.append("\n"); // 重写getCount方法 sbAdapterInfo.append(StringUtils.formatSingleLine(1, "@Override")); sbAdapterInfo.append(StringUtils.formatSingleLine(1, "public int getItemCount() {")); sbAdapterInfo.append(StringUtils.formatSingleLine(2, "return datas.size();")); sbAdapterInfo.append(StringUtils.formatSingleLine(1, "}")); sbAdapterInfo.append("\n"); // ViewHolder class的申明处理 sbAdapterInfo.append(StringUtils.formatSingleLine(1, "public static class ViewHolder{")); for (IdNamingBean bean : idNamingBeans) { // public TextView item_tv; sbAdapterInfo .append("\t\t") .append("public ") .append(bean.getViewName()) .append(" ") .append(bean.getIdName()) .append(";\n"); } sbAdapterInfo.append(StringUtils.formatSingleLine(1, "}")); // 重写getView方法,并进行优化处理 sbAdapterInfo.append(StringUtils.formatSingleLine(1, "@Override")); sbAdapterInfo.append( StringUtils.formatSingleLine( 1, "public View getView(int position, View convertView, ViewGroup parent) {")); sbAdapterInfo.append(StringUtils.formatSingleLine(2, "ViewHolder holder;")); sbAdapterInfo.append(StringUtils.formatSingleLine(2, "if(convertView == null) {")); sbAdapterInfo.append(StringUtils.formatSingleLine(3, "holder = new ViewHolder();")); sbAdapterInfo.append( StringUtils.formatSingleLine( 3, "convertView = View.inflate(context, R.layout." + FileUtils.getName(layoutXml) + ", null);")); // getView中viewholder的变量赋值处理 // 根据view名-id名的实体类,依次生成控件对应的holder变量,变量名取id名称赋值 for (IdNamingBean bean : idNamingBeans) { // holder.item_tv = (TextView) convertView.findViewById(R.id.item_tv); sbAdapterInfo .append("\t\t\t") .append("holder.") .append(bean.getIdName()) .append(" = (") .append(bean.getViewName()) .append(") ") .append("convertView.findViewById(R.id.") .append(bean.getIdName()) .append(");\n"); } sbAdapterInfo.append(StringUtils.formatSingleLine(3, "convertView.setTag(holder);")); sbAdapterInfo.append(StringUtils.formatSingleLine(2, "} else {")); sbAdapterInfo.append( StringUtils.formatSingleLine(3, "holder = (ViewHolder) convertView.getTag();")); sbAdapterInfo.append(StringUtils.formatSingleLine(2, "}")); sbAdapterInfo.append("\n"); sbAdapterInfo.append(StringUtils.formatSingleLine(2, "// TODO set data")); sbAdapterInfo.append("\n"); sbAdapterInfo.append(StringUtils.formatSingleLine(2, "return convertView;")); sbAdapterInfo.append(StringUtils.formatSingleLine(1, "}")); sbAdapterInfo.append("\n"); sbAdapterInfo.append("\n"); return sbAdapterInfo.toString(); }
/** 生成activity对应的测试文件内容(针对已经写好的页面代码生成) */ public static String createActivityContent4EspressoTest(String projectPath, String activityPath) { StringBuilder sb = new StringBuilder(); sb.append("\n\n"); File activityFile = new File(projectPath + activityPath); // 页面名 String activityName = FileUtils.getName(activityFile); // 页面内容 String activityContent = FileUtils.readToString(activityFile, "UTF-8"); // 布局内容元素 List<IdNamingBean> layoutElements; // setContentView(R.layout.activity_login); String setContentViewRegex = "setContentView\\(R.layout.([\\w_]+)\\);"; Pattern setContentViewPattern = Pattern.compile(setContentViewRegex); Matcher setContentViewMatcher = setContentViewPattern.matcher(activityContent); if (setContentViewMatcher.find()) { // projectPath = D:\PlayFun\HaveFun // layoutPath = projectPath + \app\src\main\res\layout String layoutPath = projectPath + "\\app\\src\\main\\res\\layout\\" + setContentViewMatcher.group(1) + ".xml"; parseElementFromXml(layoutPath, true); layoutElements = idNamingBeans; } else { throw new RuntimeException("页面必须要setContentView绑定布局"); } // 类名: 页面名+Test String className = activityName + "Test"; // @RunWith(AndroidJUnit4.class) // public class RegistActivityTest { // // @Rule // public ActivityTestRule<RegistActivity> mActivityRule = new // ActivityTestRule<>(RegistActivity.class, true, false); sb.append(StringUtils.formatSingleLine(0, "@RunWith(AndroidJUnit4.class)")); sb.append(StringUtils.formatSingleLine(0, "public class " + className + " {")); sb.append("\n"); sb.append(StringUtils.formatSingleLine(1, "@Rule")); sb.append( StringUtils.formatSingleLine( 1, "public ActivityTestRule<" + activityName + "> mActivityRule = new ActivityTestRule<>(" + activityName + ".class, true, false);")); sb.append("\n"); // @Test // public void test() { sb.append(StringUtils.formatSingleLine(1, "@Test")); sb.append(StringUtils.formatSingleLine(1, "public void test() {")); // 页面初始化 sb.append(StringUtils.formatSingleLine(2, "Intent intent = new Intent();")); // 判断页面初始化时是否有getExtra,如果有需要在测试代码中putExtra // userId = getIntent().getLongExtra("userId", 0); String getExtraRegex = ".get([\\w]+)Extra\\(\"([\\w_]+)\""; Pattern getExtraPattern = Pattern.compile(getExtraRegex); Matcher getExtraMatcher = getExtraPattern.matcher(activityContent); if (getExtraMatcher.find()) { // Intent intent = new Intent(); // intent.putExtra("userId", 1016l); // mActivityRule.launchActivity(intent); sb.append(StringUtils.formatSingleLine(2, "// 待测试页面需要Extra数据如下")); String type = getExtraMatcher.group(1); String key = getExtraMatcher.group(2); sb.append( StringUtils.formatSingleLine(2, "intent.putExtra(\"" + key + "\", 添加" + type + "类型的值);")); } sb.append(StringUtils.formatSingleLine(2, "mActivityRule.launchActivity(intent);")); sb.append("\n"); // 用onView定位控件,并执行动作 // onView(withId(R.id.et_username)).perform(typeText("boredream"), closeSoftKeyboard()); for (IdNamingBean bean : layoutElements) { // 控件名 String viewName = bean.getViewName(); // 不同控件对应的操作 String perform = ""; // 一般自定义控件都会在名字里表明自己的类型,因此使用contains判断 if (viewName.contains("EditText")) { // EditText对应输入 perform = ".perform(typeText(输入测试内容), closeSoftKeyboard())"; } else if (viewName.contains("Button") || viewName.contains("CheckBox")) { // Button/RadioButton/CheckBox对应点击 perform = ".perform(click())"; } else { // 无法判断的类型,不添加动作 } sb.append( StringUtils.formatSingleLine( 2, "onView(withId(R.id." + bean.getIdName() + "))" + perform + ";")); } // 最后验证部分,留给开发者自己根据业务处理,添加部分注释引导 // TODO 复制上面的onView部分定位控件,然后根据需要编写期望的check结果 // 示例: 比如需要验证dialog/toast是否显示可以如下(如果验证页面上控件则不需要.inRoot部分) // onView(withText("登录")) // // .inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView())))) // .check(matches(isDisplayed())); sb.append("\n"); sb.append(StringUtils.formatSingleLine(2, "// TODO 复制上面的onView部分定位控件,然后根据需要编写期望的check结果")); sb.append( StringUtils.formatSingleLine( 2, "// 示例: 比如需要验证dialog/toast是否显示可以如下(如果验证页面上控件则不需要.inRoot部分)")); sb.append(StringUtils.formatSingleLine(2, "// onView(withText(\"请输入密码\"))")); sb.append( StringUtils.formatSingleLine( 2, "// .inRoot(withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))))")); sb.append(StringUtils.formatSingleLine(2, "// .check(matches(isDisplayed()));")); sb.append("\n"); sb.append(StringUtils.formatSingleLine(1, "}")); sb.append(StringUtils.formatSingleLine(0, "}")); return sb.toString(); }