preface
I. Requirement realization
Principle of Requirement Realization
The code analysis
public void bindView(Object obj,Activity activity, View.OnClickListener clickListener){
bindView(obj,null,clickListener,activity);
}
public void bindView(Object obj,View v, View.OnClickListener clickListener,Activity activity){
Field[] field = obj.getClass().getDeclaredFields();
for (Field f:field){
try {
f.setAccessible(true); Class clz = f.getType(); // If it is a basic data type, skip itif (clz.isPrimitive()){
continue; } // Check whether the instance is a subclass of viewif(! View.class.isAssignableFrom(f.getType())){continue; String name = f.toString().subString (f.tostring ().lastIndexof ()".") + 1); Int ID = activity.getResources().getidentifier (name,"id",activity.getPackageName()); // instantiate view view;if (v == null){
view = activity.findViewById(id);
}else{ view = v.findViewById(id); } // Set the click eventif(clickListener ! = null && view ! = null){ view.setOnClickListener(clickListener); } // set view f.et (obj,view); } catch (IllegalAccessException e) { Log.e("FindViewUtilsError"."reason:"+e.getLocalizedMessage()); e.printStackTrace(); }}}Copy the code
The code above actually uses one sentence instead of findViewById. Of course, the above code must be called after the page is loaded, otherwise the view will be empty. Although the above implementation does not frequently findViewById and skip to set the click listener code, but we still have to manually declare the control property name, and the property name must be consistent with the LAYOUT ID, which is not only easy to error, but also a bit of trouble, after all, a property name write wrong, view is empty, which is not to tolerate. So how to implement along with the code declaration step, this time we can develop a plug-in to implement.
Ii. Plug-in development
The plug-in development tool is ready
Establish project engineering
After the project is built, remember to create the package name in the SRC directory. Otherwise, there may be a situation where the plugin is allowed under Intellij IDEA, but is allowed under Android Studio.
The code
public class Test extends AnAction { private HashMap<String,String> map; @override public void actionPerformed(AnActionEvent e) {// Obtain Editor data = LLDB data (platformDatakeys.editor); SelectionModel = data.getSelectionModel();if (selectionModel == null){
return; } // TODO: insert Action Logic here // This map holds the class and class name of the declared object to be written to. map = new HashMap<>(); // Read the XML file. SelectionModel. GetSelectedText () this sentence for the mouse to click highlight area part of the text. The following sentence is used to find the file named xxx.xml in the project. The XXX value is the highlighted text selected by the mouse. PsiFileSystemItem[] timeUtils = FilenameIndex.getFilesByName(e.getProject(), selectionModel.getSelectedText()+".xml", GlobalSearchScope.allScope(e.getProject()), false); // If not, terminate the operation.if(timeUtils ! = null && timeUtils.length ! VirtualFile VirtualFile = timeUtils[0].getVirtualFile(); PsiFile manifestFile = psiManager.getInstance (LLDB etProject()).findfile (virtualFile); // XmlDocument xml = (XmlDocument) manifestFile.getOriginalFile(); XmlFile XmlFile = (XmlFile) psiManager.getInstance (LLDB Project()).findfile (virtualFile); XmlDocument document = xmlFile.getDocument();if(document ! XmlTag rootTag = document.getrootTag (); XmlTag rootTag = document.getrootTag ();if(rootTag ! XmlTag[] subTags = rootTag.getSubtags ();for(XmlTag tag: subTags) {// Get the contents of each tag with methods that use recursion. getTag(tag); }}}}else {
return; } / / = = = = = = = = = = = = = = = = = = = = = = the following code is to declare and reference written in the Java file = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Document Document = data.getDocument(); Runnable runnable = newRunnable() {
@Override
public void runStringBuffer stringBuffer = new stringBuffer (); // This map is used to load packages to be imported. The hashmap is used because the hashmap key is not repeatable to avoid importing package names repeatedly. HashMap<String,String> importPackage = new HashMap<>();for (String key:map.keySet()){
if(! map.get(key).contains("."){// there should be no ". Importpackage.put (map.get(key)), importPackage.get (key), importPackage.get (key), importPackage.get (key), importPackage.get (key), importPackage.get (key)"import android.widget."+map.get(key)+"; \n");
stringBuffer.append("\tprivate "+map.get(key)+""+key+"; \n");
}else{// If "is included. These layouts are usually preceded by a string of package names and control class names, which we can introduce directly. importPackage.put(map.get(key),"import "+map.get(key)+"; \n");
stringBuffer.append("\tprivate "+map.get(key).substring(map.get(key).lastIndexOf(".") + 1) +""+key+"; \n");
}
//System.out.println(key+","+map.get(key));
}
StringBuffer packageResult = new StringBuffer();
for(String key:importPackage.keySet()){ packageResult.append(importPackage.get(key)); } System.out.println(stringBuffer.toString()); // Write attributes to the class. Write to the line after the first occurrence of "{" in the class file document.insertString(document.gettext ().indexof ("{") + 1."\n"+stringBuffer.toString()); // Write the code to guide the package. Write position is the first occurrence of "; "in the class file. , package XXX; Document.insertstring (document.gettext ().indexof (";") + 1."\n"+packageResult.toString()); }}; WriteCommandAction.runWriteCommandAction(e.getProject(),runnable); } private void getTag(XmlTag tag) {xmllattribute [] Attributes = tag.getAttributes();for(XmlAttribute Attribute: Attributes){// We just need to get the content of the ID and the content of the tag. So the ID content here is the ID value in the Android XML, and the tag content is the ID and the name of the object that the ID refers to, like the LinearLayout or something like that.if ("android:id".equals(attribute.getName())){// Saves the ID and the object it refers to as key-value pairs to the HashMap. map.put(attribute.getValue().split("/")[1],tag.getName());
//System.out.println(attribute.getValue().split("/") [1] +","+tag.getName()); XmlTag[] subTags = tag.getSubtags (); XmlTag[] subTags = tag.getSubtags ();for(XmlTag t : subTags) { getTag(t); }}}Copy the code
After writing the above code, you can implement the function of code injection. Of course, some interfaces are unique to Intellij Idea and may not have been seen before, but it doesn’t matter, just remember it.
Debug your plug-in
The obfuscated code cannot be used because the variable names declared after obfuscating will change and the view will not be able to find it properly. What I can think of is adding annotations to declared properties and reading the annotations instead of variable names on reflection.)