MD5 校验值:195005882709ac21163d7a1b97aeec73
DynamicComponents.java 文件包含反编译后的源代码,请注意,该内容仅供学习和参考使用,不得用于非法用途。
package com.yusufcihan.DynamicComponents; import android.app.Activity; import android.view.View; import android.view.ViewGroup; import com.google.appinventor.components.annotations.DesignerComponent; import com.google.appinventor.components.annotations.DesignerProperty; import com.google.appinventor.components.annotations.PropertyCategory; import com.google.appinventor.components.annotations.SimpleEvent; import com.google.appinventor.components.annotations.SimpleFunction; import com.google.appinventor.components.annotations.SimpleObject; import com.google.appinventor.components.annotations.SimpleProperty; import com.google.appinventor.components.common.ComponentCategory; import com.google.appinventor.components.common.ComponentDescriptorConstants; import com.google.appinventor.components.common.PropertyTypeConstants; import com.google.appinventor.components.runtime.AndroidNonvisibleComponent; import com.google.appinventor.components.runtime.AndroidViewComponent; import com.google.appinventor.components.runtime.Component; import com.google.appinventor.components.runtime.ComponentContainer; import com.google.appinventor.components.runtime.EventDispatcher; import com.google.appinventor.components.runtime.errors.YailRuntimeError; import com.google.appinventor.components.runtime.util.YailDictionary; import com.google.appinventor.components.runtime.util.YailList; import com.microsoft.appcenter.ingestion.models.CommonProperties; import com.microsoft.appcenter.ingestion.models.properties.DoubleTypedProperty; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Objects; import java.util.Set; import java.util.UUID; import kawa.lang.SyntaxForms; import org.apache.commons.lang3.StringUtils; import org.jose4j.jwk.JsonWebKeySet; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @DesignerComponent(category = ComponentCategory.EXTENSION, description = "Dynamic Components is an extension that creates any component in your App Inventor distribution programmatically, instead of having pre-defined components. Made with ❤️ by Yusuf Cihan", helpUrl = "https://github.com/ysfchn/DynamicComponents-AI2", iconName = "aiwebres/icon.png", nonVisible = SyntaxForms.DEBUGGING, version = 6, versionName = "2.1.0") @SimpleObject(external = SyntaxForms.DEBUGGING) public class DynamicComponents extends AndroidNonvisibleComponent { private final String BASE_PACKAGE; private final HashMap<String, Component> COMPONENTS; private JSONArray PROPERTIESARRAY; private Activity activity; private Internal internal; private boolean isAsync; public class Internal { public Internal() { } public String checkId(Object obj, String str) { if (str == null || str.trim().isEmpty()) { throw new YailRuntimeError("DynamicComponents-AI2: ID can't be blank.", "Invalid ID"); } if (DynamicComponents.this.internal.isIdTaken(str)) { throw new YailRuntimeError("DynamicComponents-AI2: ID must be unique for all components.", "Duplicate ID"); } return DynamicComponents.this.internal.getClassName(obj); } public void createBySchema(AndroidViewComponent androidViewComponent, int i, JSONArray jSONArray) { if (jSONArray.getJSONObject(i).has("in")) { DynamicComponents.this.Create((AndroidViewComponent) DynamicComponents.this.GetComponent(jSONArray.getJSONObject(i).getString("in")), jSONArray.getJSONObject(i).getString(CommonProperties.TYPE), jSONArray.getJSONObject(i).getString(CommonProperties.ID)); } else { DynamicComponents.this.Create(androidViewComponent, jSONArray.getJSONObject(i).getString(CommonProperties.TYPE), jSONArray.getJSONObject(i).getString(CommonProperties.ID)); } } public Method findMethod(Method[] methodArr, String str, Integer num) { for (Method method : methodArr) { if (method.getName().equals(str.trim()) && method.getParameterTypes().length == num.intValue()) { return method; } } return null; } public <T extends Annotation> T getAnnotation(Class<T> cls, Component component, Method method) { return component != null ? (T) DynamicComponents.this.internal.getClass(component).getAnnotation(cls) : (T) method.getAnnotation(cls); } public Class<?> getClass(Object obj) { return obj.getClass(); } public String getClassName(Object obj) { if ((obj instanceof String) && obj.toString().contains(".")) { return obj.toString().replace(StringUtils.SPACE, ""); } if (obj instanceof String) { return "com.google.appinventor.components.runtime." + obj.toString().replace(StringUtils.SPACE, ""); } if (obj instanceof Component) { return obj.getClass().getName(); } throw new YailRuntimeError("DynamicComponents-AI2: Not a Component block or a String.", "Invalid Component"); } public boolean isDynamicComponent(Component component) { return DynamicComponents.this.COMPONENTS.containsValue(component); } public boolean isIdTaken(String str) { return DynamicComponents.this.COMPONENTS.containsKey(str); } public String loopReplace(JSONObject jSONObject, YailList yailList, String str) { String str2 = str; for (int i = 0; i < jSONObject.optJSONArray(JsonWebKeySet.JWK_SET_MEMBER_NAME).length(); i++) { str2 = str2.replace("{" + jSONObject.optJSONArray(JsonWebKeySet.JWK_SET_MEMBER_NAME).getString(i) + "}", yailList.getString(i).replace("\"", "")); } return str2; } public boolean methodHasAnnotation(Class<? extends Annotation> cls, Method method) { return method.isAnnotationPresent(cls); } public void parseJson(String str, JSONObject jSONObject) throws JSONException { JSONObject jSONObject2 = new JSONObject(jSONObject.toString()); jSONObject2.remove("components"); if (!"".equals(str)) { jSONObject2.put("in", str); } DynamicComponents.this.PROPERTIESARRAY.put(jSONObject2); if (jSONObject.has("components")) { for (int i = 0; i < jSONObject.getJSONArray("components").length(); i++) { parseJson(jSONObject2.optString(CommonProperties.ID, ""), jSONObject.getJSONArray("components").getJSONObject(i)); } } } public void putInJsonArray(JSONArray jSONArray, Object obj) { try { jSONArray.put(obj); } catch (JSONException e) { e.printStackTrace(); } } public void putInJsonObject(JSONObject jSONObject, String str, Object obj) { try { jSONObject.put(str, obj); } catch (JSONException e) { e.printStackTrace(); } } public String replaceKeys(JSONObject jSONObject, YailList yailList, String str) { if (jSONObject.has(JsonWebKeySet.JWK_SET_MEMBER_NAME)) { if (jSONObject.optJSONArray(JsonWebKeySet.JWK_SET_MEMBER_NAME).length() > yailList.length()) { throw new YailRuntimeError("Input parameter count is lower than the requirement!", "Error"); } loopReplace(jSONObject, yailList, str); } return str; } public void setPropertiesBySchema(int i, JSONArray jSONArray) { JSONArray names = jSONArray.getJSONObject(i).getJSONObject("properties").names(); for (int i2 = 0; i2 < names.length(); i2++) { DynamicComponents.this.Invoke((Component) DynamicComponents.this.GetComponent(jSONArray.getJSONObject(i).getString(CommonProperties.ID)), names.getString(i2), YailList.makeList(new Object[]{jSONArray.getJSONObject(i).getJSONObject("properties").get(names.getString(i2))})); } } } public DynamicComponents(ComponentContainer componentContainer) { super(componentContainer.$form()); this.internal = null; this.isAsync = false; this.COMPONENTS = new HashMap<>(); this.BASE_PACKAGE = "com.google.appinventor.components.runtime"; this.PROPERTIESARRAY = new JSONArray(); this.activity = componentContainer.$context(); this.internal = new Internal(); } @SimpleProperty(description = "Sets whether component creation should rely on the UI thread.") @DesignerProperty(defaultValue = "False", editorType = "boolean") public void Async(boolean z) { this.isAsync = z; } @SimpleProperty(category = PropertyCategory.BEHAVIOR, description = "Gets whether component creation should rely on the UI thread.") public boolean Async() { return this.isAsync; } @SimpleFunction(description = "Replaces the specified ID with the given new ID. The old ID must be bound to a component and the new ID must be unique, i.e., not used already.") public void ChangeId(String str, String str2) { if (!this.COMPONENTS.containsKey(str) || this.COMPONENTS.containsKey(str2)) { throw new YailRuntimeError("Old ID must exist and new ID mustn't exist.", "Error"); } this.COMPONENTS.put(str2, this.COMPONENTS.remove(str)); } @SimpleEvent(description = "Raises after a component has been created using the Create block. It also will be raised for components that created with Schema.") public void ComponentCreated(String str, String str2) { EventDispatcher.dispatchEvent(this, "ComponentCreated", str, str2); } @SimpleFunction(description = "Creates a new dynamic component. It supports all component that added to your current AI2 distribution. In componentName, you can type the component's name like 'Button', or you can pass a static component then it can create a new instance of it, or just type the full class name of component.") public void Create(final AndroidViewComponent androidViewComponent, final Object obj, final String str) { if (this.isAsync) { this.activity.runOnUiThread(new Runnable() { @Override public void run() { DynamicComponents.this.CreateMethod(androidViewComponent, obj, str); } }); } else { CreateMethod(androidViewComponent, obj, str); } } public void CreateMethod(AndroidViewComponent androidViewComponent, Object obj, String str) { String checkId = this.internal.checkId(obj, str); try { if ("".equals(checkId)) { return; } Class<?> cls = Class.forName(checkId.trim().replace(StringUtils.SPACE, "")); Component component = (Component) cls.getConstructor(ComponentContainer.class).newInstance((ComponentContainer) androidViewComponent); if (checkId.contains("ImageSprite") || checkId.contains("Sprite")) { Invoke(component, "Initialize", new YailList()); } this.COMPONENTS.put(str, component); ComponentCreated(str, cls.getSimpleName()); } catch (Exception e) { throw new YailRuntimeError("DynamicComponents-AI2: " + e.toString(), "Error"); } } @SimpleFunction(description = "Returns the component itself for setting properties. ID must be a valid ID which is added with Create block.") public Object GetComponent(String str) { return this.COMPONENTS.get(str); } @SimpleFunction(description = "Returns the ID of the specified component. The desired component must created using the \"Create\" block, else it will return a blank string. Component --> ID") public String GetId(Component component) { for (String str : this.COMPONENTS.keySet()) { if (this.COMPONENTS.get(str).equals(component)) { return str; } } return ""; } @SimpleFunction(description = "Returns the internal name of any component or object.") public String GetName(Object obj) { return this.internal.getClass(obj).getName(); } @SimpleFunction(description = "Returns the position of the component with respect to other sibling components in it's parent arrangement. Index starts from 1.") public int GetOrder(AndroidViewComponent androidViewComponent) { View view = androidViewComponent.getView(); View view2 = (View) androidViewComponent.getView().getParent(); if (view == null || view2 == null) { return 0; } View view3 = androidViewComponent.getView(); return ((ViewGroup) view3.getParent()).indexOfChild(view3) + 1; } @SimpleFunction(description = "Returns the specified properties value of the given component. Can be known as a Getter property block. It can be also used to get properties that only exists in Designer.") public Object GetProperty(Component component, String str) { try { return Invoke(component, str, YailList.makeEmptyList()); } catch (Exception e) { throw new YailRuntimeError("" + e, "Error"); } } @SimpleFunction(description = "Invokes a method with parameters.") public Object Invoke(Component component, String str, YailList yailList) { String replace = str.trim().replace(StringUtils.SPACE, ""); try { if (component == null) { throw new YailRuntimeError("Component is not specified.", "Error"); } Method findMethod = this.internal.findMethod(this.internal.getClass(component).getMethods(), replace.replace(StringUtils.SPACE, ""), Integer.valueOf(yailList.toArray().length)); if (findMethod == null) { throw new YailRuntimeError("Method can't found with that name.", "Error"); } Object[] array = yailList.toArray(); Class<?>[] parameterTypes = findMethod.getParameterTypes(); ArrayList arrayList = new ArrayList(); for (int i = 0; i < parameterTypes.length; i++) { if ("int".equals(parameterTypes[i].getName())) { arrayList.add(Integer.valueOf(Integer.parseInt(array[i].toString()))); } else if (PropertyTypeConstants.PROPERTY_TYPE_FLOAT.equals(parameterTypes[i].getName())) { arrayList.add(Float.valueOf(Float.parseFloat(array[i].toString()))); } else if (DoubleTypedProperty.TYPE.equals(parameterTypes[i].getName())) { arrayList.add(Double.valueOf(Double.parseDouble(array[i].toString()))); } else if ("java.lang.String".equals(parameterTypes[i].getName())) { arrayList.add(array[i].toString()); } else if ("boolean".equals(parameterTypes[i].getName())) { arrayList.add(Boolean.valueOf(Boolean.parseBoolean(array[i].toString()))); } else { arrayList.add(array[i]); } } Object invoke = findMethod.invoke(component, arrayList.toArray()); return invoke == null ? "" : invoke; } catch (Exception e) { throw new YailRuntimeError(e.toString(), "Error"); } } @SimpleFunction(description = "Returns 'true' if component was created by the Dynamic Components extension. Otherwise, 'false'.") public Object IsDynamic(Component component) { return Boolean.valueOf(this.internal.isDynamicComponent(component)); } @SimpleFunction(description = "Returns the ID of the last component created using the \"Create\" block.") public String LastUsedID() { Object[] array = this.COMPONENTS.keySet().toArray(); return array.length > 0 ? array[array.length - 1].toString() : ""; } @SimpleFunction(description = "Gives the information of the specified component with all properties, events, methods as JSON text.") public String ListDetails(Component component) { String str; Class<?> cls = this.internal.getClass(component); DesignerComponent designerComponent = (DesignerComponent) this.internal.getAnnotation(DesignerComponent.class, component, null); JSONObject jSONObject = new JSONObject(); try { jSONObject.put(ComponentDescriptorConstants.ANDROIDMINSDK_TARGET, designerComponent.androidMinSdk()); jSONObject.put("category", designerComponent.category()); jSONObject.put("dateBuilt", designerComponent.dateBuilt()); jSONObject.put("description", designerComponent.description()); jSONObject.put("helpUrl", designerComponent.helpUrl()); jSONObject.put("iconName", designerComponent.iconName()); jSONObject.put("name", cls.getSimpleName()); jSONObject.put("nonVisible", designerComponent.nonVisible()); jSONObject.put("showOnPalette", designerComponent.showOnPalette()); jSONObject.put(CommonProperties.TYPE, cls.getName()); jSONObject.put("version", designerComponent.version()); jSONObject.put("versionName", designerComponent.versionName()); } catch (JSONException e) { e.printStackTrace(); } Method[] methods = cls.getMethods(); JSONArray jSONArray = new JSONArray(); JSONArray jSONArray2 = new JSONArray(); JSONArray jSONArray3 = new JSONArray(); JSONArray jSONArray4 = new JSONArray(); for (Method method : methods) { JSONObject jSONObject2 = new JSONObject(); DesignerProperty designerProperty = (DesignerProperty) this.internal.getAnnotation(DesignerProperty.class, null, method); SimpleEvent simpleEvent = (SimpleEvent) this.internal.getAnnotation(SimpleEvent.class, null, method); SimpleFunction simpleFunction = (SimpleFunction) this.internal.getAnnotation(SimpleFunction.class, null, method); SimpleProperty simpleProperty = (SimpleProperty) this.internal.getAnnotation(SimpleProperty.class, null, method); this.internal.putInJsonObject(jSONObject2, "name", method.getName()); if (this.internal.methodHasAnnotation(DesignerProperty.class, method)) { this.internal.putInJsonObject(jSONObject2, "editorType", designerProperty.editorType()); this.internal.putInJsonObject(jSONObject2, "defaultValue", designerProperty.defaultValue()); this.internal.putInJsonObject(jSONObject2, "editorArgs", new JSONArray((Collection) Arrays.asList(designerProperty.editorArgs()))); this.internal.putInJsonArray(jSONArray4, jSONObject2); } if (this.internal.methodHasAnnotation(SimpleEvent.class, method)) { this.internal.putInJsonObject(jSONObject2, "description", simpleEvent.description()); this.internal.putInJsonObject(jSONObject2, "visible", Boolean.valueOf(simpleEvent.userVisible())); JSONArray jSONArray5 = new JSONArray(); for (Class<?> cls2 : method.getParameterTypes()) { this.internal.putInJsonArray(jSONArray5, cls2.getName()); } this.internal.putInJsonObject(jSONObject2, "parameterTypes", jSONArray5); } if (this.internal.methodHasAnnotation(SimpleFunction.class, method)) { this.internal.putInJsonObject(jSONObject2, "description", simpleFunction.description()); this.internal.putInJsonObject(jSONObject2, "visible", Boolean.valueOf(simpleFunction.userVisible())); this.internal.putInJsonObject(jSONObject2, "returnType", method.getReturnType().getSimpleName()); JSONArray jSONArray6 = new JSONArray(); for (Class<?> cls3 : method.getParameterTypes()) { this.internal.putInJsonArray(jSONArray6, cls3.getName()); } this.internal.putInJsonObject(jSONObject2, "parameterTypes", jSONArray6); } if (this.internal.methodHasAnnotation(SimpleProperty.class, method)) { this.internal.putInJsonObject(jSONObject2, "category", simpleProperty.category()); this.internal.putInJsonObject(jSONObject2, "description", simpleProperty.description()); this.internal.putInJsonObject(jSONObject2, "visible", Boolean.valueOf(simpleProperty.userVisible())); boolean z = this.internal.findMethod(methods, method.getName(), 1) != null; boolean z2 = this.internal.findMethod(methods, method.getName(), 0) != null; if (!z2 || z) { str = (!z || z2) ? "read-write" : "write-only"; this.internal.putInJsonObject(jSONObject2, CommonProperties.TYPE, ((Method) Objects.requireNonNull(this.internal.findMethod(methods, method.getName(), 1))).getParameterTypes()[0].getSimpleName()); } else { str = "read-only"; this.internal.putInJsonObject(jSONObject2, CommonProperties.TYPE, ((Method) Objects.requireNonNull(this.internal.findMethod(methods, method.getName(), 0))).getReturnType().getSimpleName()); } boolean z3 = simpleProperty.category() == PropertyCategory.DEPRECATED; this.internal.putInJsonObject(jSONObject2, "rw", str); this.internal.putInJsonObject(jSONObject2, "deprecated", Boolean.valueOf(z3)); if (simpleProperty.category() != PropertyCategory.UNSET) { this.internal.putInJsonArray(jSONArray, jSONObject2); } } } this.internal.putInJsonObject(jSONObject, "blockProperties", jSONArray); this.internal.putInJsonObject(jSONObject, "events", jSONArray2); this.internal.putInJsonObject(jSONObject, "methods", jSONArray3); this.internal.putInJsonObject(jSONObject, "properties", jSONArray4); return jSONObject.toString(); } @SimpleFunction(description = "Moves the specified component to the given arrangement.") public void Move(AndroidViewComponent androidViewComponent, AndroidViewComponent androidViewComponent2) { View view = androidViewComponent2.getView(); ((ViewGroup) view.getParent()).removeView(view); ((ViewGroup) ((ViewGroup) androidViewComponent.getView()).getChildAt(0)).addView(view); } @SimpleFunction(description = "Generates a unique ID that can be used to create a component.") public String RandomUUID() { String uuid; do { uuid = UUID.randomUUID().toString(); } while (this.internal.isIdTaken(uuid)); return uuid; } @SimpleFunction(description = "Removes the component with specified ID from screen/layout and the component list so you can use its ID again after it's deleted.") public void Remove(String str) { if (this.internal.isIdTaken(str)) { Component component = this.COMPONENTS.get(str); if (component != null) { try { View view = (View) component.getClass().getMethod("getView", new Class[0]).invoke(component, new Object[0]); ((ViewGroup) view.getParent()).removeView(view); } catch (Exception e) { e.printStackTrace(); } } this.COMPONENTS.remove(str); } } @SimpleFunction(description = "Imports a JSON string that is a template for creating the dynamic components automatically with single block. Templates can also contain parameters that will be replaced with the values which defined in the 'parameters' list.") public void Schema(final AndroidViewComponent androidViewComponent, final String str, final YailList yailList) { if (this.isAsync) { this.activity.runOnUiThread(new Runnable() { @Override public void run() { DynamicComponents.this.SchemaMethod(androidViewComponent, yailList, str); } }); } else { SchemaMethod(androidViewComponent, yailList, str); } } @SimpleEvent(description = "Raises after a schema has created with the \"Schema\" block.") public void SchemaCreated(String str, YailList yailList) { EventDispatcher.dispatchEvent(this, "SchemaCreated", str, yailList); } public void SchemaMethod(AndroidViewComponent androidViewComponent, YailList yailList, String str) { try { this.PROPERTIESARRAY = new JSONArray(); JSONObject jSONObject = new JSONObject(str); this.internal.parseJson("", new JSONObject(this.internal.replaceKeys(jSONObject, yailList, str))); this.PROPERTIESARRAY.remove(0); for (int i = 0; i < this.PROPERTIESARRAY.length(); i++) { if (!this.PROPERTIESARRAY.getJSONObject(i).has(CommonProperties.ID)) { throw new YailRuntimeError("One or more of the components has not an ID in template!", "Error"); } this.internal.createBySchema(androidViewComponent, i, this.PROPERTIESARRAY); if (this.PROPERTIESARRAY.getJSONObject(i).has("properties")) { this.internal.setPropertiesBySchema(i, this.PROPERTIESARRAY); } } SchemaCreated(jSONObject.optString("name"), yailList); } catch (Exception e) { throw new YailRuntimeError(e.getMessage(), "Error"); } } @SimpleFunction(description = "Sets the position of the specified component with respect to other sibling components in it's parent arrangement. Index starts from 1. Typing 0 (zero) will move the component to the end.") public void SetOrder(AndroidViewComponent androidViewComponent, int i) { View view = androidViewComponent.getView(); ViewGroup viewGroup = (ViewGroup) view.getParent(); viewGroup.removeView(view); int i2 = i - 1; int childCount = viewGroup.getChildCount(); if (i2 > childCount) { i2 = childCount; } viewGroup.addView(view, i2); } @SimpleFunction(description = "Set multiple properties of a component at once.") public void SetProperties(Component component, YailDictionary yailDictionary) throws JSONException { JSONObject jSONObject = new JSONObject(yailDictionary.toString()); JSONArray names = jSONObject.names(); for (int i = 0; i < jSONObject.length(); i++) { String string = names.getString(i); Invoke(component, string, YailList.makeList(new Object[]{jSONObject.get(string)})); } } @SimpleFunction(description = "Sets the specified property of the component to the given value. It can be also used to set properties that only exists in Designer. Supported values are; 'string', 'boolean', 'integer' and 'float'. For other values, you should use Any Component blocks.") public void SetProperty(Component component, String str, Object obj) { try { Invoke(component, str, YailList.makeList(new Object[]{obj})); } catch (Exception e) { throw new YailRuntimeError(e.getMessage(), "Error"); } } @SimpleFunction(description = "Returns a list of IDs of every created component.") public YailList UsedIDs() { return YailList.makeList((Set) this.COMPONENTS.keySet()); } @SimpleProperty(description = "Returns the version number of the extension.") public int Version() { return ((DesignerComponent) DynamicComponents.class.getAnnotation(DesignerComponent.class)).version(); } @SimpleProperty(description = "Returns the extension version name.") public String VersionName() { return ((DesignerComponent) DynamicComponents.class.getAnnotation(DesignerComponent.class)).versionName(); } }