La première partie du développement du plug-in Android [apk de chargement dynamique]

introduction


Avec l'itération continue de la version de l'application, l'application devient très volumineuse et gonflée. Les nouvelles exigences se succèdent, les anciennes sont abandonnées, inutiles et prennent de la place, et le projet devient chaotique. Bien que différents noms de packages soient utilisés pour isoler chaque module d'exigence, on pense souvent que si l'exigence peut être divisée en modules comme un plug-in, elle peut être connectée en cas de besoin et déconnectée lorsqu'elle est supprimée. Ctrip a ouvert son cadre de développement de plug-ins ( Ctrip Plug-in Development Framework ). Ensuite, j'apprendrai et présenterai le cadre de développement de plug-ins open source de Ctrip à partir de cet article, afin que davantage de personnes puissent comprendre le développement de plug-ins d'Android. . Ici, je tiens à remercier l'équipe Ctrip pour leurs contributions. S'il y a des erreurs dans la description ou la compréhension de l'article, j'espère que tout le monde pourra me le signaler.

Dans cet article, nous allons imiter un exemple simple de développement de plug-in. Le principe de ce petit exemple est simplement d'écrire du code auxiliaire (comme xxxUtils.java) dans le projet B pour générer B.apk, et de mettre B Put le .apk dans le dossier assets du projet principal A, et utilisez le principe de réflexion pour permettre au projet A d'appeler xxxUtils.java dans B.apk. En fait, cela peut être compris plus simplement car B est une bibliothèque Android. De cette façon, l'un des avantages d'utiliser directement l'appel de réflexion apk au lieu d'utiliser le formulaire de bibliothèque est d'éviter le bogue que le nombre de méthodes dex dépasse 65535 lors de la compilation du projet, et cela peut également être pour un support futur tel que le partage de ressources, le saut d'interface, etc., car la bibliothèque Android traditionnelle Il n'est pas possible d'obtenir des ressources auprès de l'hôte. De plus, nous savons que la réflexion est en fait une méthode d'appel qui consomme relativement des ressources, donc si les performances du framework seront affectées, nous réservons des doutes et continuons à apprendre.

Création de démo


  1. Créez un projet PluginA , créez un fichier PluginAUtils.java et écrivez le code que vous voulez. comme:
public class PluginAUtils {
    public void showToastInfo(Context context) {
        Toast.makeText(context,"This is from pluginA",Toast.LENGTH_SHORT).show();

Générer pluginA.apk après une compilation réussie

  1. Ensuite, créez le projet PluginApp , créez un dossier asserts
    dans le répertoire app/src/main/ , et placez-y le pluginA.apk que vous venez de compiler. Créez un AssertsDexLoader.java pour charger dynamiquement le projet pluginA. Le code clé est le suivant :
// 依据不同的系统版本动态加载apk dex文件到ClassLoader中
private static void installBundleDexs(ClassLoader loader, File dexDir, List<File> files, boolean isHotFix)        throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException,InstantiationException,        InvocationTargetException, NoSuchMethodException, IOException {    
    if (!files.isEmpty()) {
        if (Build.VERSION.SDK_INT >= 23) {
            V23.install(loader, files, dexDir,isHotFix);
        } else if (Build.VERSION.SDK_INT >= 19) {
            V19.install(loader, files, dexDir,isHotFix);
        } else if (Build.VERSION.SDK_INT >= 14) {
            V14.install(loader, files, dexDir,isHotFix);
        } else {
            V4.install(loader, files,isHotFix);
        }
    }
}

La logique d' AssertsDexLoader est de copier le fichier apk dans les assertions vers /data/data/appPackageDir/ du système, puis de passer les trois paramètres de ClassLoader, le répertoire copié et le fichier à installBundleDexs() pour charger dynamiquement sa méthode en mémoire.

  1. Vous pouvez l'appeler par réflexion partout où vous en avez besoin
    private void runAssertsDexMethod() throws Exception {
        Class<?> clazz = Class.forName("h3c.plugina.PluginAUtils");
//        Class<?> clazz = getClassLoader()
//                .loadClass("h3c.plugina.PluginAUtils");
        Constructor<?> constructor = clazz.getConstructor();
        Object bundleUtils = constructor.newInstance();
        Method printSumMethod = clazz.getMethod("showToastInfo", Context.class);
        printSumMethod.setAccessible(true);
        printSumMethod.invoke(bundleUtils, getApplicationContext());
    }

[ Les codes clés peuvent être trouvés ici ]
[ La démo peut être trouvée ici ]

expliquer


  • ClassLoader
    ClassLoader, comme son nom l'indique, est un chargeur de classe. En termes simples, il charge les classes du fichier de classe en mémoire. Lorsque l'application démarre, elle crée sa propre instance ClassLoader et monte le ClassLoader que nous avons créé sur le ClassLoader de l'application pour réaliser le chargement dynamique des classes.
    [ Présentation détaillée de ClassLoader ]

  • Problèmes pouvant être rencontrés
    L'application n'ajoute pas d'autorisations de stockage en lecture et en écriture , ce qui entraîne un échec de la copie de l'apk
    Impossible trouver la classe ou la méthode dans le plug-in apk , la plus grande possibilité est que le plug-in apk compilé ne le fasse vraiment pas contenir cette classe ou cette méthode. Il est recommandé de décompiler le plug-in apk ( décompilation en ligne Android ) pour vérifier si la classe ou la méthode est bien compilée dedans. (Joignez la méthode de compilation AS du Mac : Build-> Build APK Après l'exécution, recherchez l'apk signé Debug dans le dossier du projet /app/build/outputs/apk/app-debug.apk )

Résumer


  • Lorsque la taille du plug-in apk devient importante, le processus de chargement temporaire devient plus long, mais heureusement, le chargement dynamique peut être chargé en mémoire lorsque l'hôte en a besoin.
  • L'appel de réflexion doit également être appelé conformément à la convention de nommage convenue, sinon il est facile de provoquer l'échec de la recherche de la classe ou de la méthode.
  • De plus, le chargement de Dex dépend fortement de la version du système, ce qui peut entraîner des problèmes tels que la nouvelle version du SDK non prise en charge.

On peut voir que cette méthode convient au développement de plug-ins légers.

Guess you like

Origin blog.csdn.net/h3c4lenovo/article/details/50729395