El sistema Android modifica aplicaciones comunes sin código fuente en el Iniciador predeterminado y oculta el ícono de información de la aplicación en Configuración

En el desarrollo de la personalización del sistema Android, a veces necesitamos implementar algunas funciones especiales, como cambiar la aplicación al iniciador predeterminado u ocultar el ícono de la aplicación para que los usuarios no puedan iniciar o desinstalar la aplicación directamente. Estas funciones se pueden utilizar en algunos escenarios personalizados, como televisores inteligentes, señalización digital, etc. Pero si no tenemos el código fuente, no es tan fácil implementar estas funciones (principalmente porque los clientes de Shabi no están dispuestos a cambiar). Debido a que el sistema Android tiene algunas restricciones y mecanismos de protección para estas funciones, debemos evitar estas restricciones para lograr nuestros objetivos.

En este artículo, presentaré cómo modificar la aplicación como iniciador predeterminado y ocultar el ícono de la aplicación en el sistema Android. Estos métodos no se basan en ningún código fuente, solo es necesario modificar parte de la lógica de análisis de pms del sistema Androidmanifes.xml. Por supuesto, estos métodos pueden no ser universales y pueden diferir en diferentes dispositivos y versiones del sistema. Es necesario ajustarlos y probarlos de acuerdo con circunstancias específicas. Aquí solo estoy brindando ideas.

Estudio de referencia:

Análisis del código fuente de Android 11 PackageManagerService (1): proceso general de inicio de PMS
Análisis del principio de funcionamiento de PMS: proceso de análisis del directorio de aplicaciones (Android12)

Análisis simple de la parte de análisis de PMS.

PMS (PackageManagerService) es el servicio central responsable de administrar aplicaciones en el sistema Android, sus principales funciones incluyen:

  • Analizar e instalar archivos apk de aplicaciones, incluidas aplicaciones del sistema y aplicaciones de usuario
  • Mantenga la información y el estado de la aplicación, incluido el nombre del paquete, la versión, los permisos, las firmas, los componentes, etc.
  • Haga coincidir los componentes apropiados según los filtros de Intención, como Actividad, Servicio, Proveedor y Receptor, etc.
  • Verifique los permisos y las firmas de las aplicaciones para garantizar la seguridad y coherencia del sistema.
  • Proporcionar la interfaz PackageManager para que otras aplicaciones o servicios llamen para obtener o modificar información relacionada con la aplicación.

Android11+ realizó cierta reconstrucción y optimización de la parte de análisis de pms, separó algunas clases y métodos de PackageManagerService y PackageParser, y los colocó bajo el paquete de análisis y el paquete de componentes.

frameworks/base/core/java/android/content/pm/ 文件夹下

Existen principalmente las siguientes categorías en el paquete de análisis:

  • ParsingPackage: esta es una interfaz que define una colección de información y componentes básicos de una aplicación, equivalente al objeto Paquete original.
  • ParsingPackageImpl: esta es la clase de implementación de la interfaz ParsingPackage que proporciona algunos constructores y métodos auxiliares.
  • ParsingPackageRead: esta es una clase abstracta heredada de ParsingPackageImpl, que proporciona algunos métodos de solo lectura para obtener información y componentes de la aplicación.
  • ParsingPackageUtils: esta es una clase de herramienta que proporciona algunos métodos estáticos para obtener o convertir algunos datos del objeto ParsingPackage.
  • ParsingUtils: esta es una clase de herramienta que proporciona algunos métodos estáticos para analizar o verificar algunos datos.

Existen principalmente las siguientes clases en el paquete de componentes:

  • ParsedComponent: esta es una clase abstracta que define la información básica de un componente de la aplicación, equivalente al objeto Componente original.
  • ParsedComponentUtils: esta es una clase de herramienta que proporciona algunos métodos estáticos para obtener o convertir algunos datos del objeto ParsedComponent.
  • ParsedActivity, ParsedService, ParsedProvider, ParsedInstrumentation: son subclases de ParsedComponent, correspondientes a los componentes Actividad, Servicio, Proveedor e Instrumentación respectivamente.
  • ParsedActivityUtils, ParsedServiceUtils, ParsedProviderUtils, ParsedInstrumentationUtils: estas son clases de herramientas que proporcionan algunos métodos estáticos para obtener o convertir algunos datos de los objetos componentes correspondientes.
  • ParsedIntentInfo: esta es una clase que define información sobre un filtro de intención, equivalente al objeto IntentFilter original.
  • ParsedIntentInfoUtils: esta es una clase de herramienta que proporciona algunos métodos estáticos para analizar o verificar filtros de intención.
  • ParsedMainComponent: esta es una clase abstracta que hereda de ParsedComponent e implementa la interfaz Parcelable para representar componentes que se pueden iniciar a través de Intent.
  • ParsedMainComponentUtils: esta es una clase de herramienta que proporciona algunos métodos estáticos para obtener o convertir algunos datos del objeto ParsedMainComponent.
  • ParsedPermission, ParsedPermissionGroup: son clases que corresponden a los componentes Permission y PermissionGroup respectivamente.
  • ParsedPermissionUtils: esta es una clase de herramienta que proporciona algunos métodos estáticos para analizar o verificar componentes de permisos.
  • ParsedProcess: esta es una clase que define información sobre un proceso.
  • ParsedProcessUtils: esta es una clase de herramienta que proporciona algunos métodos estáticos para obtener o convertir algunos datos de objetos ParsedProcess.

Lo anterior es la función y la relación de los archivos principales bajo el paquete de análisis y el paquete de componentes.

Modificar la aplicación como iniciador predeterminado

Launcher es una aplicación de escritorio del sistema Android, responsable de mostrar e iniciar otras aplicaciones. Normalmente, el sistema tendrá un Iniciador predeterminado y los clientes también pueden descargar e instalar otros Iniciadores desde la tienda de aplicaciones. Cuando un cliente instala varios Lanzadores, el sistema mostrará un cuadro de selección que le permitirá elegir qué Lanzador usar y puede configurar si desea recordar esta elección.

Si queremos que nuestra propia aplicación desarrollada sea el iniciador predeterminado sin permitir que los usuarios la elijan o la cambien, podemos hacerlo mediante los siguientes pasos:

  1. En el archivo AndroidManifest.xml de nuestra aplicación, agregue el siguiente filtro de Intención a la Actividad principal:
<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.HOME" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

Esto permite que nuestra aplicación responda a eventos de clic en la tecla INICIO y el icono del iniciador.

  1. Agregue el siguiente contenido al código fuente de nuestro sistema mk o al archivo prop:
persist.custom_package.launcher=true
persist.custom_package.name=com.example.myapp

persist.custom_package.launcherEs un atributo de cambio, que indica si se habilita la función de modificar el Launcher sin código fuente, persist.custom_package.namees el nombre del paquete de nuestra aplicación.

Si desea modificar la configuración de implementación de la aplicación del código fuente para agregar el atributo HOME, busque el método en el archivo frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java y agregue el siguiente código parseIntentInfo:

launcherProperty = SystemProperties.get("persist.custom_package.launcher", "");
customPackageProperty = SystemProperties.get("persist.custom_package.name", "");
customClassNameProperty = SystemProperties.get("persist.custom_package.classname", "");


// ...

case "category": {
    
    
    String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
            "name");
    // 添加的代码在这里
    if (launcherProperty.equals("true") && customPackageProperty.equals(className)) {
    
    
        intentInfo.addCategory("android.intent.category.HOME");
        intentInfo.addCategory("android.intent.category.DEFAULT");
        intentInfo.setPriority(1000);
    }
    // 到此为止
    if (value == null) {
    
    
        result = input.error("No value supplied for <android:name>");
    } else if (value.isEmpty()) {
    
    
        result = input.error("<android:name> has empty value");
    } else {
    
    
        intentInfo.addCategory(value.intern());
    }
    break;
}

El propósito de este código es leer las propiedades del sistema, determinar si se deben agregar las categorías INICIO y DEFAULT a la Actividad con el nombre del paquete especificado según los valores de propiedad y establecer la prioridad en 1000 (la más alta). De esta forma, la Actividad puede convertirse en el Lanzador al que se agrega HOME.

Esto permite que la aplicación responda al botón de Inicio y a los eventos de encendido, y en conjunto con mi artículo (el sistema Android establece aplicaciones de terceros como implementación predeterminada del Lanzador y análisis de principios ) y no será reemplazada por otros Lanzadores.

Incluso si no agrega mi otro artículo sobre cómo configurar el iniciador de bloqueo forzado predeterminado, aparecerá una ventana emergente para que pueda seleccionarlo manualmente.

Ocultar icono de aplicación

En ocasiones, es posible que necesitemos ocultar algunos íconos de aplicaciones para que no aparezcan en el Iniciador. Por ejemplo, algunos servicios del sistema o funciones auxiliares, etc. En este caso, podemos implementar los siguientes pasos:

  1. En el archivo AndroidManifest.xml de nuestra aplicación, agregue las siguientes propiedades a la Actividad principal:
android:enabled="false"

 <activity
            android:name=".view.MainActivity"
            android:exported="true" android:theme="@style/Theme.AppCompat.Light.NoActionBar"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
               <!-- 添加-->
                <data android:name="com.custom.package.CustomActivity" ></data>
            </intent-filter>
        </activity>

Esto evitará que se muestre nuestra aplicación.

2. Agregue el siguiente contenido al código fuente de nuestro sistema mk o al archivo prop o configure manualmente la configuración de prop:

persist.custom_package.hide_icon=true
persist.custom_package.name=com.example.myapp

persist.custom_package.hide_iconEs un atributo de cambio, que indica si se habilita la función de ocultar iconos sin código fuente, persist.custom_package.namees el nombre del paquete de nuestra aplicación.

  1. En el archivo frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java, busque parseIntentInfoel método y agregue el siguiente código:
launcherProperty = SystemProperties.get("persist.custom_package.launcher", "");
hideIconProperty = SystemProperties.get("persist.custom_package.hide_icon", "");
customPackageProperty = SystemProperties.get("persist.custom_package.name", "");
excludeFromRecentsProperty = SystemProperties.get("persist.custom_package.exclude_from_recents", "");
screenOrientationProperty = SystemProperties.get("persist.custom_package.screen_orientation", "");
customClassNameProperty = SystemProperties.get("persist.custom_package.classname", "");
Log.d("pms_test", "launcherProperty:"+launcherProperty+","+hideIconProperty+","+hideIconProperty+","+customPackageProperty+","+screenOrientationProperty);

// ...

case "data":
    /*if (hideIconProperty.equals("true") && customClassNameProperty.equals(className)) {
        intentInfo.addDataScheme("com.custom.package");
        intentInfo.addDataAuthority("CustomActivity", null);

        intentInfo.addDataAttribute("android:name", "com.custom.package.CustomActivity");
    }*/
    result = parseData(intentInfo, res, parser, allowGlobs, input);
    break;

El propósito de este código es leer las propiedades del sistema y determinar si se debe agregar un filtro de datos personalizado a la Actividad con el nombre de clase especificado según el valor de la propiedad. De esta manera, el Iniciador no coincidirá con la Actividad y no se mostrará el icono. Tenga en cuenta que este código está comentado porque causará algunos problemas, como no poder iniciar la Actividad, etc. Por lo tanto, esta función solo se usa como demostración y no se recomienda su uso (aún no la he estudiado...).

Ocultar la visualización de la aplicación de gestión de aplicaciones de Configuración

Además de ocultar los iconos y las notificaciones de las aplicaciones, es posible que también necesitemos ocultar cierta información de las aplicaciones para que no aparezcan en la lista de administración de aplicaciones. Por ejemplo, algunos servicios del sistema o funciones auxiliares, etc. En este caso, podemos implementar los siguientes pasos:

  1. Agregue el siguiente contenido al código fuente de nuestro sistema mk o al archivo prop o configure manualmente la configuración de prop:
persist.custom_package.hide_icon=true
persist.custom_package.name=com.example.myapp

persist.custom_package.hide_iconEs un atributo switch que indica si se habilita la función de ocultar iconos e información sin código fuente, persist.custom_package.namees el nombre del paquete de nuestra aplicación.

  1. En el archivo packages/apps/Settings/src/com/android/settings/applications/manageapplications/ManageApplications.java, busque el método updateState y agregue el siguiente código:
// 导入SystemProperties类
import android.os.SystemProperties;

// 定义两个静态变量,分别存储系统属性的值
private static String hideIconProperty;
private static String customPackageProperty;

@Override
public void onCreate(Bundle savedInstanceState) {
    
    
    super.onCreate(savedInstanceState);
    // ...
    // 在onCreate方法中读取系统属性,并赋值给静态变量
    hideIconProperty = SystemProperties.get("persist.custom_package.hide_icon", "true");
    customPackageProperty = SystemProperties.get("persist.custom_package.name", "com.btf.rk3568_11_fw");
}

private void updateState() {
    
    
    // ...
    if (filterType == FILTER_APPS_POWER_WHITELIST ||
            filterType == FILTER_APPS_POWER_WHITELIST_ALL) {
    
    
        entries = removeDuplicateIgnoringUser(entries);
    }

    // 遍历应用列表,如果某个应用的包名与系统属性指定的包名相同,并且开关属性为true,则从列表中移除该应用
    for (int i = 0; i < entries.size(); i++) {
    
    
        AppEntry appEntry = entries.get(i);
        if (hideIconProperty.equals("true") && customPackageProperty.equals(appEntry.info.packageName)) {
    
    
            entries.remove(i);
            i--;
        }
    }
    mEntries = entries;
    mOriginalEntries = entries;
    notifyDataSetChanged();
}

La función de este código es leer las propiedades del sistema y determinar si se debe eliminar la aplicación con el nombre del paquete especificado en función del valor de la propiedad y no agregarla a la lista de administración de aplicaciones.

  1. En el archivo paquetes/apps/Settings/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java, busque el método displayRecentApps y agregue el siguiente código:
// 导入SystemProperties类
import android.os.SystemProperties;

// 定义两个静态变量,分别存储系统属性的值
private static String hideIconProperty;
private static String customPackageProperty;

public RecentNotifyingAppsPreferenceController(Context context, NotificationBackend backend,
        IUsageStatsManager usageStatsManager, UserManager userManager,
        Application app, Fragment host) {
    
    
    this(context, backend, usageStatsManager, userManager,
            app == null ? null : ApplicationsState.getInstance(app), host);
    // 在构造方法中读取系统属性,并赋值给静态变量
    hideIconProperty = SystemProperties.get("persist.custom_package.hide_icon", "");
    customPackageProperty = SystemProperties.get("persist.custom_package.name", "");
}

private void displayRecentApps() {
    
    
    // ...
    for (int i = 0; i < recentAppsCount; i++) {
    
    
        final NotifyingApp app = recentApps.get(i);
        // Bind recent apps to existing prefs if possible, or create a new pref.
        final String pkgName = app.getPackage();
        // 如果某个应用的包名与系统属性指定的包名相同,并且开关属性为true,则跳过该应用,不显示在最近通知应用列表中
        if (hideIconProperty.equals("true") && customPackageProperty.equals(pkgName)) {
    
    
            continue;
        }
        final ApplicationsState.AppEntry appEntry =
                mApplicationsState.getEntry(app.getPackage(), app.getUserId());
        if (appEntry == null) {
    
    
            continue;
        }
        // ...
    }
    // ...
}

La función de este código es leer las propiedades del sistema y determinar si se debe omitir la aplicación con el nombre del paquete especificado según el valor de la propiedad y no mostrarla en la lista de aplicaciones notificadas recientemente.

Resumir

Este artículo describe cómo modificar la aplicación como iniciador predeterminado y ocultar el ícono de la aplicación en Android 11 sin código fuente. Estas funciones se pueden lograr configurando algunas propiedades del sistema y modificando algunos archivos de configuración sin modificar el código fuente ni volver a compilar todo el sistema. Por supuesto, estas funciones son parte del aprendizaje de PMS. ¿Afectará al sistema el uso real de las piezas que requieren muchas pruebas y modificaciones? Por lo tanto, al utilizar estas funciones, es necesario realizar concesiones y elecciones basadas en necesidades y escenarios específicos.

Espero que este artículo te sea útil. ¡Gracias!

Supongo que te gusta

Origin blog.csdn.net/SHH_1064994894/article/details/132744252
Recomendado
Clasificación