Trouver toutes les classes d'un package dans Android

Comment puis-je trouver toutes les classes dans un package sur Android? J'utilise PathClassLoader, mais il renvoie toujours une énumération vide?

information additionnelle

  • Comment puis-je spécifier une hauteur dynamique pour un ImageView?
  • Edittext modifie la couleur de bordure avec shape.xml
  • Bitmap non dessiné anti-alias
  • Comment récupérer le numéro de série de Android Mobile Browser à l'aide de Java Scripting, qui sera de la source d'application Web en cours d'exécution dans le navigateur mobile
  • FragmentPagerAdapter getItem erreur avec ListFragment
  • Horloge Android qui fonctionne lorsque le périphérique dort
  • Essayé l'approche de réflexions proposée. Un couple de points importants sur la bibliothèque des réflexions. La bibliothèque disponible via maven central n'est pas compatible avec Android et donne des erreurs dex. J'ai dû inclure la source et compiler dom4j, java-assist.

    Le problème avec les réflexions et ma solution d'origine est que PathClassLoader dans Android renvoie une énumération vide pour le package.

    Le problème avec l'approche est que getResource dans Android renvoie toujours l'énumération vide.

    final String resourceName = aClass.getName().replace(".", "/") + ".class"; for (ClassLoader classLoader : loaders) { try { final URL url = classLoader.getResource(resourceName); if (url != null) { final String normalizedUrl = url.toExternalForm().substring(0, url.toExternalForm().lastIndexOf(aClass.getPackage().getName().replace(".", "/"))); return new URL(normalizedUrl); } } catch (MalformedURLException e) { e.printStackTrace(); } } 

    6 Solutions collect form web for “Trouver toutes les classes d'un package dans Android”

    Utilisation de DexFile pour répertorier toutes les classes dans votre apk:

      try { DexFile df = new DexFile(context.getPackageCodePath()); for (Enumeration<String> iter = df.entries(); iter.hasMoreElements();) { String s = iter.nextElement(); } } catch (IOException e) { e.printStackTrace(); } 

    Le reste utilise regexp ou autre chose pour filtrer votre classe souhaitée.

    En fait, j'ai trouvé une solution. Merci pour la réponse de tao .

     private String[] getClassesOfPackage(String packageName) { ArrayList<String> classes = new ArrayList<String>(); try { String packageCodePath = getPackageCodePath(); DexFile df = new DexFile(packageCodePath); for (Enumeration<String> iter = df.entries(); iter.hasMoreElements(); ) { String className = iter.nextElement(); if (className.contains(packageName)) { classes.add(className.substring(className.lastIndexOf(".") + 1, className.length())); } } } catch (IOException e) { e.printStackTrace(); } return classes.toArray(new String[classes.size()]); } 

    Testé sur Android 5.0 Lolipop

    essaye ça..

      Reflections reflections = new Reflections("my.project.prefix"); Set<Class<? extends Object>> allClasses = reflections.getSubTypesOf(Object.class); 

    Voici une solution qui vous apporte non seulement le nom de la classe,
    Mais aussi l'objet Class<?> .

    Et tandis que PathClassLoader.class.getDeclaredField("mDexs") échoue fréquemment,
    new DexFile(getContext().getPackageCodePath()) semble beaucoup plus stable.

     public abstract class ClassScanner { private static final String TAG = "ClassScanner"; private Context mContext; public ClassScanner(Context context) { mContext = context; } public Context getContext() { return mContext; } void scan() throws IOException, ClassNotFoundException, NoSuchMethodException { long timeBegin = System.currentTimeMillis(); PathClassLoader classLoader = (PathClassLoader) getContext().getClassLoader(); //PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();//This also works good DexFile dexFile = new DexFile(getContext().getPackageCodePath()); Enumeration<String> classNames = dexFile.entries(); while (classNames.hasMoreElements()) { String className = classNames.nextElement(); if (isTargetClassName(className)) { //Class<?> aClass = Class.forName(className);//java.lang.ExceptionInInitializerError //Class<?> aClass = Class.forName(className, false, classLoader);//tested on 魅蓝Note(M463C)_Android4.4.4 and Mi2s_Android5.1.1 Class<?> aClass = classLoader.loadClass(className);//tested on 魅蓝Note(M463C)_Android4.4.4 and Mi2s_Android5.1.1 if (isTargetClass(aClass)) { onScanResult(aClass); } } } long timeEnd = System.currentTimeMillis(); long timeElapsed = timeEnd - timeBegin; Log.d(TAG, "scan() cost " + timeElapsed + "ms"); } protected abstract boolean isTargetClassName(String className); protected abstract boolean isTargetClass(Class clazz); protected abstract void onScanResult(Class clazz); } 

    Et c'est un exemple de l'utilisation:

     new ClassScanner(context) { @Override protected boolean isTargetClassName(String className) { return className.startsWith(getContext().getPackageName())//I want classes under my package && !className.contains("$");//I don't need none-static inner classes } @Override protected boolean isTargetClass(Class clazz) { return AbsFactory.class.isAssignableFrom(clazz)//I want subclasses of AbsFactory && !Modifier.isAbstract(clazz.getModifiers());//I don't want abstract classes } @Override protected void onScanResult(Class clazz) { Constructor constructor = null; try { constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); constructor.newInstance(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }.scan(); 

    J'ai trouvé la même solution de Sergey Shustikov, avec le nom du paquet dérivé du contexte et gère les classes intérieures. Malheureusement, tout en travaillant sur Galaxy Nexus, il ne fonctionne pas sur Nexus 6 et Nexus 6p (pas testé sur d'autres périphériques).

    Voici le code:

     private HashMap<String, String> loadClassFullnames() { final HashMap<String, String> ret = new HashMap<>(); try { final String thisPackage = context.getPackageName(); final DexFile tmp = new DexFile(context.getPackageCodePath()); for (Enumeration<String> iter = tmp.entries(); iter.hasMoreElements(); ) { final String classFullname = iter.nextElement(); if (classFullname.startsWith(thisPackage)) { // TODO filter out also anonymous classes (es Class1$51) final int index = classFullname.lastIndexOf("."); final String c = (index >= 0) ? classFullname.substring(index + 1) : classFullname; ret.put(c.replace('$', '.'), classFullname); } } } catch (Throwable ex) { Debug.w("Unable to collect class fullnames. Reason: " + ex.getCause() + "\n\rStack Trace:\n\r" + ((ex.getCause() != null)? ex.getCause().getStackTrace(): "none")); } return ret; } 

    Il couvre que sur Galaxy Nexus, le DexFile contient également les paquets d'application (celui que nous essayons de trouver!), Alors que sur Nexus 6 [p] aucun paquet correspondant à ce paquet n'est trouvé alors que d'autres paquets sont là … Quelqu'un Ont le même problème?

    Ceci est tiré de http://mindtherobot.com/

    Exemple de code

    Disons que nous avons une annotation appelée Foo et quelques classes décorées avec elle:

     @Retention(RetentionPolicy.RUNTIME) public @interface Foo { String value(); } @Foo("person") public class Person { } @Foo("order") public class Order { } 

    Voici une classe simple qui passe sur toutes les classes de votre application en cours d'exécution, trouve celles marquées avec @Foo et obtenez la valeur de l'annotation. Ne copiez pas et ne collez ce code dans votre application. Il est important de réparer et d'ajouter, tel que décrit ci-dessous le code.

     public class ClasspathScanner { private static final String TAG = ClasspathScanner.class.getSimpleName(); private static Field dexField; static { try { dexField = PathClassLoader.class.getDeclaredField("mDexs"); dexField.setAccessible(true); } catch (Exception e) { // TODO (1): handle this case gracefully - nobody promised that this field will always be there Log.e(TAG, "Failed to get mDexs field"); } } public void run() { try { // TODO (2): check here - in theory, the class loader is not required to be a PathClassLoader PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader(); DexFile[] dexs = (DexFile[]) dexField.get(classLoader); for (DexFile dex : dexs) { Enumeration<String> entries = dex.entries(); while (entries.hasMoreElements()) { // (3) Each entry is a class name, like "foo.bar.MyClass" String entry = entries.nextElement(); Log.d(TAG, "Entry: " + entry); // (4) Load the class Class<?> entryClass = dex.loadClass(entry, classLoader); if (entryClass != null) { Foo annotation = entryClass.getAnnotation(Foo.class); if (annotation != null) { Log.d(TAG, entry + ": " + annotation.value()); } } } } } catch (Exception e) { // TODO (5): more precise error handling Log.e(TAG, "Error", e); } } } 
    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.