CommunitySchreiben & Editierengithub.com

Marukon/skill-upgrade-libxposed-102

Fachkenntnis zur Migration von Xposed-Modulen auf LibXposed API 102.

Was ist skill-upgrade-libxposed-102?

Diese Fachkenntnis bietet eine umfassende Anleitung zur Migration traditioneller Xposed-Module (basierend auf XposedBridge API 54–93) zur modernen LibXposed API 102, die von Frameworks wie LSPosed 1.9.3+ und Vector verwendet wird. Sie deckt alle Aspekte ab: von der Abhängigkeitsaktualisierung (Ersetzung von `de.robv.android.xposed:api:82` durch `io.github.libxposed:api:102.0.0`) über die Neukonfiguration der Metadaten (`META-INF/xposed/`) bis hin zur grundlegenden Umstellung des Hook-Programmiermodells von herkömmlichen Callbacks (`XC_MethodHook`) auf eine OkHttp-ähnliche Interceptor-Kette (`chain.proceed()`). Die Fachkenntnis beschreibt detailliert das neue API-Design, einschließlich der Unterstützung für Hot Reload, das Verbot von Zygote-Injection und die native R8/Obfuscation-Kompatibilität. Darüber hinaus enthält sie spezifische Optimierungsstrategien für Hochfrequenz-Hooks, wie z. B. schnelle Null-Overhead-Pfade für Zustandsabfragen und die Verwendung von `StackWalker` unter Android 14+ für effizientes Stack-Tracing. Praktische Checklisten für häufige Fallstricke und Validierungsschritte helfen Entwicklern, einen reibungslosen Übergang zu gewährleisten.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add Marukon/skill-upgrade-libxposed-102

Installed? Explore more Schreiben & Editieren skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Xposed-Modul-Upgrade auf LibXposed API 102 – Vollständiger Leitfaden

Dieses Dokument fasst den Standardprozess, die Code-Paradigmen, Metadaten-Spezifikationen und Leistungsoptimierungsstrategien für die Migration traditioneller Xposed-Module (basierend auf XposedBridge API 54-93) zur modernen LibXposed API 102 (für LSPosed 1.9.3+, Vector und andere moderne Frameworks) zusammen.

Zukünftige Upgrade-Anweisungen für andere Module können direkt auf diese Spezifikation verweisen.


1. Wichtigste Änderungen im Vergleich

Eigenschaft / DimensionTraditionelles Xposed (API 54-93)Modernes LibXposed (API 102)
Abhängigkeitskoordinatende.robv.android.xposed:api:82 (oder 93)io.github.libxposed:api:102.0.0
Einstiegsklasse/-schnittstelleIXposedHookLoadPackage, IXposedHookZygoteInitErbt von io.github.libxposed.api.XposedModule
Einstiegsdeklarationassets/xposed_initMETA-INF/xposed/java_init.list
Moduleigenschaften-Konfiguration<meta-data> in AndroidManifest.xmlMETA-INF/xposed/module.prop
Scope-Deklarationxposedscope Resource-ArrayMETA-INF/xposed/scope.list
Hook-ProgrammiermodellXC_MethodHook (before / after) CallbacksOkGO-ähnliche Interceptor-Kette Hooker (chain.proceed())
Hot ReloadNicht unterstützt (Neustart der Ziel-App oder des Systems erforderlich)Native Unterstützung (Überschreiben von onHotReloading / onHotReloaded)
Zygote-InjectionUnterstützt initZygote für globalen ZugriffZygote-Injection verboten; nur in Zielprozesse des Scopes
Obfuscation/R8-UnterstützungStrikte Beibehaltung von Hook-Methoden- und Klassennamen erforderlichNative Unterstützung; Deklaration von Anpassungsregeln ausreichend

2. Standard-Migrationsverfahren in vier Schritten

Schritt 1: Build & Abhängigkeiten migrieren (build.gradle)

  1. Abhängigkeiten aktualisieren: Ersetzen Sie die Abhängigkeit in der build.gradle des Moduls (z. B. app/build.gradle oder hook/build.gradle):

    dependencies {
        // Entfernen: compileOnly 'de.robv.android.xposed:api:82'
        // Einführen der modernen LibXposed 102 API
        compileOnly 'io.github.libxposed:api:102.0.0'
        compileOnly 'androidx.annotation:annotation:1.5.0'
    }
    
  2. Java-Kompilierungskompatibilität:

    android {
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_11
            targetCompatibility JavaVersion.VERSION_11
        }
    }
    
  3. ProGuard / R8-Regeln konfigurieren (proguard-rules.pro):

    -dontwarn io.github.libxposed.annotation.**
    -adaptresourcefilecontents META-INF/xposed/java_init.list
    -keep,allowoptimization,allowobfuscation public class * extends io.github.libxposed.api.XposedModule {
        public <init>();
    }
    

Schritt 2: Moderne Metadaten-Dateien konfigurieren (META-INF/xposed/)

Erstellen Sie die folgenden Dateien im Modul-Quellverzeichnis src/main/resources/META-INF/xposed/:

1. module.prop (Modul-Metadaten)

minApiVersion=102
targetApiVersion=102
autoHotReload=true
exceptionMode=protective
  • minApiVersion: Mindestens unterstützte API-Version, auf 102 setzen.
  • targetApiVersion: Ziel-API-Version, auf 102 setzen.
  • autoHotReload: Auf true setzen, um beim Installieren eines Modul-Updates automatisch ein Hot Reload auszulösen.
  • exceptionMode: protective (Standard-Schutzmodus; Hook-Ausnahmen stürzen die Host-App nicht ab) oder passthrough.

2. java_init.list (Einstiegsdeklaration)

Einzeilige Deklaration des vollqualifizierten Klassennamens des Modul-Einstiegs:

com.example.myhook.MainHook

3. scope.list (Empfohlener Scope)

Ein Zielpaketname pro Zeile, der die Standard-Applikationen deklariert, in die das Modul injected werden soll:

com.android.chrome
com.microsoft.emmx
com.example.targetapp

Schritt 3: Manifest-Datei konfigurieren (AndroidManifest.xml)

Aktualisieren Sie die AndroidManifest.xml des Moduls:

<application ...>
    <!-- Traditionelle Metadaten für Kompatibilität beibehalten; wichtig: xposedminversion auf 102 setzen -->
    <meta-data
        android:name="xposedmodule"
        android:value="true" />
    <meta-data
        android:name="xposeddescription"
        android:value="Modul-Funktionsbeschreibung" />
    <meta-data
        android:name="xposedminversion"
        android:value="102" />
    <meta-data
        android:name="xposedscope"
        android:resource="@array/xposed_scope" />
</application>

Schritt 4: Hook-Logik umschreiben (XposedModule)

1. Basis-Template und Lebenszyklus

package com.example.myhook;

import android.util.Log;
import androidx.annotation.NonNull;
import io.github.libxposed.api.XposedInterface;
import io.github.libxposed.api.XposedModule;

public class MainHook extends XposedModule {

    private static final String TAG = "MyHookModule";
    private volatile boolean mHooked = false;

    public MainHook() {
        super();
    }

    /**
     * Wird ausgelöst, wenn der ClassLoader der Host-App bereit ist und kurz vor der Erstellung der Application ist
     */
    @Override
    public void onPackageReady(@NonNull PackageReadyParam param) {
        if (mHooked) return;
        synchronized (this) {
            if (mHooked) return;
            mHooked = true;
            initHooks(param.getPackageName(), param.getClassLoader());
        }
    }

    /**
     * Hot-Reload-Vorbereitungs-Callback (wird in der alten Version des Codes ausgeführt)
     * Rückgabe true erlaubt dem Framework, die neue Version zu ersetzen
     */
    @Override
    public boolean onHotReloading(@NonNull HotReloadingParam param) {
        return true;
    }

    /**
     * Hot-Reload-Abschluss-Callback (wird in der neuen Version des Codes ausgeführt)
     */
    @Override
    public void onHotReloaded(@NonNull HotReloadedParam param) {
        // Alle in der alten Version registrierten Hooks entfernen
        param.getOldHookHandles().forEach(XposedInterface.HookHandle::unhook);
        synchronized (this) {
            mHooked = false;
            initHooks("hot-reload", getClass().getClassLoader());
        }
    }

    private void initHooks(String packageName, ClassLoader classLoader) {
        // Führen Sie hier die spezifische Hook-Logik aus
    }
}

2. Wichtige Hook-Syntax im Vergleich

ZieloperationTraditionelle Xposed-SchreibweiseModerne LibXposed 102-Schreibweise
Methode finden und HookenXposedHelpers.findAndHookMethod("Klassenname", cl, "methode", argTypes..., callback)Method m = Clazz.class.getDeclaredMethod("methode", argTypes...);hook(m).intercept(chain -> { ... });
Originalmethode ausführenStandardmäßig direkt ausgeführt; Aufruf von param.getResult()Object result = chain.proceed();
Parameter ändern und aufrufenparam.args[0] = newVal;Object result = chain.proceed(new Object[]{ newVal, ... });
Rückgabewert abfangen und ersetzenparam.setResult(customVal);Direkt benutzerdefinierten Wert zurückgeben (ohne chain.proceed() aufzurufen):hook(m).intercept(chain -> customVal);
Eingabeparameter abrufenparam.args[i]chain.getArg(i) oder chain.getArgs()
This-Instanz abrufenparam.thisObjectchain.getThisObject()
Konstruktor hookenfindAndHookConstructor(...)Constructor<?> ctor = ...;hook(ctor).intercept(chain -> ...);
Statischen Block hookenTraditionell kein Standard-APIhookClassInitializer(TargetClass.class).intercept(...)

3. Hochfrequente Hook-Szenarien und tiefgehende Leistungsoptimierungsmuster

Die goldene Optimierungsregel für hochfrequente Aufrufe (z. B. isEnabled, View-Zeichnen, Touch-Weiterleitung):

  1. Schneller Null-Overhead-Pfad (Sondierungs-Durchgriff): Wenn es sich um eine Zustandsabfragemethode handelt (z. B. isEnabled(), isLoaded()), rufen Sie zunächst die leichtgewichtige native Feldlesung chain.proceed() auf. Wenn der tatsächliche Zustand bereits falsch ist, geben Sie direkt false zurück und überspringen die gesamte nachfolgende Logik und Stack-Überprüfungen.

  2. Android 14+ (API 34+) – Verwendung von StackWalker für lazy Traversierung: Herkömmliches new Throwable().getStackTrace() führt zu einer vollständigen Thread-Stack-Entfaltung (Native Unwind) und Hunderten von String-Allokationen, was leicht zu GC-Drops führt. Verwenden Sie java.lang.StackWalker aus Java 9 / Android 14+, für eine bedarfsgesteuerte, schrittweise Abtastung ohne vollständige Stack-Allokation.

  3. Dynamische Stack-Positionierung unter Android < 34 (keine fest codierten Indizes): Führen Sie nur einmalig new Throwable().getStackTrace() aus, durchlaufen Sie ihn nach unten, um die Systemklasse zu finden, die die Zielmethode enthält (z. B. AccessibilityManager). Der unmittelbar folgende Stackframe ist der tatsächliche Aufrufer. Niemals [3] oder [4] fest codieren, um einen stabilen Betrieb über verschiedene LSPosed-Versionen hinweg zu gewährleisten.

Beispielcode für Leistungsoptimierung:

// Prüfung auf Android 14+ StackWalker
private static final boolean HAS_STACK_WALKER;
static {
    boolean has;
    try {
        Class.forName("java.lang.StackWalker");
        has = (Build.VERSION.SDK_INT >= 34);
    } catch (Throwable t) {
        has = false;
    }
    HAS_STACK_WALKER = has;
}

// Beispiel für einen hochfrequenten Methoden-Hook
Method isEnabled = AccessibilityManager.class.getDeclaredMethod("isEnabled");
hook(isEnabled).intercept(chain -> {
    Object real = chain.proceed();
    if (Boolean.FALSE.equals(real)) {
        return false; // System ist bereits aus; Null-Overhead-Durchgriff
    }
    return isCallerWhitelisted() ? real : false;
});

private static boolean isCallerWhitelisted() {
    if (HAS_STACK_WALKER) {
        try {
            return Api34StackWalker.check();
        } catch (Throwable ignored) {}
    }
    return checkLegacy();
}

@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
private static final class Api34StackWalker {
    private static final StackWalker WALKER = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);

    static boolean check() {
        return Boolean.TRUE.equals(WALKER.walk(frames -> {
            boolean foundTarget = false;
            var it = frames.iterator();
            while (it.hasNext()) {
                var f = it.next();
                if ("android.view.accessibility.AccessibilityManager".equals(f.getClassName())) {
                    foundTarget = true;
                } else if (foundTarget) {
                    return isPackageAllowed(f.getClassName());
                }
            }
            return false;
        }));
    }
}

4. Häufige Upgrade-Fallstricke und Prüfliste

  1. Muss assets/xposed_init beibehalten werden?
    • Die moderne API 102 liest nur META-INF/xposed/java_init.list. Wenn assets/xposed_init beibehalten wird, könnte das alte Framework versuchen, es per Reflection zu laden und einen Fehler auslösen. Es wird empfohlen, es zu entfernen oder leer zu lassen.
  2. compileSdk und Android SDK-Plattform:
    • Es wird empfohlen, compileSdk und targetSdk auf Android 33 oder 34 zu aktualisieren, um moderne Schnittstellen und Java 11/17-Sprachfunktionen problemlos nutzen zu können.
  3. Gradle-Kompatibilität:
    • Wenn die Build-Umgebung JDK 17/21 verwendet, muss sichergestellt werden, dass Gradle Wrapper auf 7.4+ (empfohlen 7.5.1 oder 8.x) und AGP auf 7.3+ aktualisiert wird.
  4. Modulerkennung validieren:
    • Überprüfen Sie mit einem Entpackungstool das Wurzelverzeichnis der finalen APK. Es muss enthalten:
      • META-INF/xposed/module.prop
      • META-INF/xposed/java_init.list
      • META-INF/xposed/scope.list

Verwandte Skills