Android システムは、ソースコードのない通常のアプリケーションをデフォルトのランチャーに変更し、設定でアプリケーション情報アイコンを非表示にします

Android システムのカスタマイズ開発では、アプリケーションをデフォルトのランチャーに変更したり、ユーザーがアプリケーションを直接起動したりアンインストールしたりできないようにアプリケーションのアイコンを非表示にするなど、いくつかの特別な機能を実装する必要がある場合があります。これらの機能は、スマート TV、デジタル サイネージなどの一部のカスタマイズされたシナリオで使用される場合があります。しかし、ソース コードがない場合、これらの機能を実装するのはそれほど簡単ではありません (主に Shabi の顧客が変更を望まないため)。Android システムにはこれらの機能に対していくつかの制限と保護メカニズムがあるため、目的を達成するにはこれらの制限を回避する必要があります。

この記事では、Android システムでアプリケーションをデフォルトのランチャーとして変更し、アプリケーションのアイコンを非表示にする方法を紹介します。これらのメソッドはソース コードに基づいていないため、システムの pms 解析 Androidmanifes.xml 解析ロジックの一部を変更するだけで済みます。もちろん、これらの方法は普遍的ではなく、デバイスやシステムのバージョンによって異なる場合があります。特定の状況に応じて調整およびテストする必要があります。ここではアイデアを提供しているだけです。

参考研究:

Android 11 PackageManagerServiceのソースコード解析(1):PMS起動全体の流れ
PMS動作原理の解析~アプリディレクトリ解析プロセス(Android12)

PMS分析部の簡易分析

PMS (PackageManagerService) は、Android システム内のアプリケーションの管理を担当するコア サービスであり、その主な機能は次のとおりです。

  • システム アプリケーションやユーザー アプリケーションを含むアプリケーション apk ファイルを解析してインストールします
  • パッケージ名、バージョン、権限、署名、コンポーネントなどのアプリケーション情報とステータスを維持します。
  • アクティビティ、サービス、プロバイダー、レシーバーなど、インテント フィルターに従って適切なコンポーネントを照合します。
  • アプリケーションの権限と署名をチェックして、システムのセキュリティと一貫性を確保します
  • アプリケーション関連の情報を取得または変更するために呼び出す他のアプリケーションまたはサービスに PackageManager インターフェイスを提供します。

Android11+ では、pms の解析部分の再構築と最適化が行われ、一部のクラスとメソッドが PackageManagerService と PackageParser から分離され、解析パッケージとコンポーネント パッケージの下に配置されました。

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

解析パッケージには主に次のカテゴリがあります。

  • ParsingPackage: これは、アプリケーションの基本情報とコンポーネントのコレクションを定義するインターフェイスであり、元の Package オブジェクトに相当します。
  • ParsingPackageImpl: これは、いくつかのコンストラクターと補助メソッドを提供する ParsingPackage インターフェイスの実装クラスです。
  • ParsingPackageRead: これは ParsingPackageImpl から継承された抽象クラスで、アプリケーション情報とコンポーネントを取得するためのいくつかの読み取り専用メソッドを提供します。
  • ParsingPackageUtils: これは、ParsingPackage オブジェクトからデータを取得または変換するためのいくつかの静的メソッドを提供するツール クラスです。
  • ParsingUtils: これは、一部のデータを解析または検証するためのいくつかの静的メソッドを提供するツール クラスです。

コンポーネント パッケージには主に次のクラスがあります。

  • ParsedComponent: これは、アプリケーション コンポーネントの基本情報を定義する抽象クラスで、元の Component オブジェクトに相当します。
  • ParsedComponentUtils: これは、ParsedComponent オブジェクトからデータを取得または変換するための静的メソッドを提供するツール クラスです。
  • ParsedActivity、ParsedService、ParsedProvider、ParsedInstrumentation: これらは ParsedComponent のサブクラスで、それぞれ Activity、Service、Provider、および Instrumentation コンポーネントに対応します。
  • ParsedActivityUtils、ParsedServiceUtils、ParsedProviderUtils、ParsedInstrumentationUtils: これらは、対応するコンポーネント オブジェクトからデータを取得または変換するための静的メソッドを提供するツール クラスです。
  • ParsedIntentInfo: これは、元の IntentFilter オブジェクトに相当する、インテント フィルターに関する情報を定義するクラスです。
  • ParsedIntentInfoUtils: これは、インテント フィルターを解析または検証するためのいくつかの静的メソッドを提供するツール クラスです。
  • ParsedMainComponent: これは、ParsedComponent を継承し、Intent を通じて開始できるコンポーネントを表す Parcelable インターフェイスを実装する抽象クラスです。
  • ParsedMainComponentUtils: これは、ParsedMainComponent オブジェクトからデータを取得または変換するための静的メソッドを提供するツール クラスです。
  • ParsedPermission、ParsedPermissionGroup: これらは、それぞれ Permission コンポーネントと PermissionGroup コンポーネントに対応するクラスです。
  • ParsedPermissionUtils: これは、アクセス許可コンポーネントを解析または検証するためのいくつかの静的メソッドを提供するツール クラスです。
  • ParsedProcess: プロセスに関する情報を定義するクラスです。
  • ParsedProcessUtils: これは、ParsedProcess オブジェクトからデータを取得または変換するための静的メソッドを提供するツール クラスです。

以上が、解析パッケージおよびコンポーネントパッケージ配下の主なファイルの機能と関係です。

アプリケーションをデフォルトのランチャーとして変更する

ランチャーは Android システムのデスクトップ アプリケーションであり、他のアプリケーションの表示と起動を担当します。通常、システムにはデフォルトのランチャーがあり、顧客はアプリストアから他のランチャーをダウンロードしてインストールすることもできます。顧客が複数の Launcher をインストールすると、システムは選択ボックスをポップアップ表示して、顧客が使用する Launcher を選択できるようにし、この選択を記憶するかどうかを設定できます。

ユーザーに選択または変更を許可せずに、独自に開発したアプリケーションをデフォルトのランチャーにしたい場合は、次の手順でこれを行うことができます。

  1. アプリの AndroidManifest.xml ファイルで、次のインテント フィルターをメイン アクティビティに追加します。
<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>

これにより、アプリケーションは HOME キーとランチャー アイコンのクリック イベントに応答できるようになります。

  1. 次のコンテンツをシステム ソース コードの mk または prop ファイルに追加します。
persist.custom_package.launcher=true
persist.custom_package.name=com.example.myapp

persist.custom_package.launcherこれは、ソース コードなしで Launcher を変更する機能を有効にするかどうかを示す switch 属性であり、persist.custom_package.nameアプリケーションのパッケージ名です。

ソース コード アプリケーションの実装設定を変更して HOME 属性を追加する場合は、frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java ファイルでメソッドを見つけて、次のコードを追加します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;
}

このコードの目的は、システム プロパティを読み取り、プロパティ値に基づいて指定されたパッケージ名のアクティビティに HOME および DEFAULT カテゴリを追加するかどうかを決定し、優先度を 1000 (最高) に設定することです。このようにして、アクティビティは HOME が追加されるランチャーになることができます。

これにより、アプリケーションはホーム ボタンや電源投入イベントに応答できるようになり、私の記事 ( Android システムはサードパーティ アプリケーションをデフォルトのランチャー実装として設定し、原理分析を行う) と連動して、他のランチャーに置き換えられることはありません。

デフォルトの強制ロック ランチャーの設定に関する私の他の記事を追加しなくても、手動で選択するためのポップアップが表示されます。

アプリアイコンを隠す

場合によっては、ランチャーに表示されないように、一部のアプリケーション アイコンを非表示にする必要がある場合があります。たとえば、一部のシステム サービスや補助機能などです。この場合、次の手順を実装できます。

  1. アプリの AndroidManifest.xml ファイルで、次のプロパティをメインのアクティビティに追加します。
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>

これにより、アプリケーションが表示されなくなります。

2. 次のコンテンツをシステム ソース コード mk または prop ファイルに追加するか、手動で setprop 設定を追加します。

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

persist.custom_package.hide_iconこれは、ソース コードなしでアイコンを非表示にする機能を有効にするかどうかを示す switch 属性であり、persist.custom_package.nameアプリケーションのパッケージ名です。

  1. Frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java ファイルでparseIntentInfoメソッドを見つけて、次のコードを追加します。
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;

このコードの目的は、システム プロパティを読み取り、プロパティ値に基づいて、指定されたクラス名を持つアクティビティにカスタム データ フィルターを追加するかどうかを決定することです。このようにすると、アクティビティはランチャーと一致せず、アイコンは表示されません。このコードはアクティビティを開始できないなどの問題が発生するため、コメントアウトされていることに注意してください。したがって、この機能はデモンストレーションとしてのみ使用されており、使用は推奨されません(私はまだ勉強していません...)。

設定アプリ管理のアプリ表示を非表示にする

アプリのアイコンと通知を非表示にすることに加えて、アプリ管理リストに表示されないように一部のアプリ情報を非表示にする必要がある場合もあります。たとえば、一部のシステム サービスや補助機能などです。この場合、次の手順を実装できます。

  1. 次のコンテンツをシステム ソース コードの mk または prop ファイルに追加するか、手動で setprop 設定を追加します。
persist.custom_package.hide_icon=true
persist.custom_package.name=com.example.myapp

persist.custom_package.hide_iconソースコードを使わずにアイコンや情報を非表示にする機能を有効にするかどうかを示すスイッチ属性であり、persist.custom_package.nameアプリケーションのパッケージ名です。

  1. package/apps/Settings/src/com/android/settings/applications/manageapplications/ManageApplications.java ファイルで、updateState メソッドを見つけて、その中に次のコードを追加します。
// 导入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();
}

このコードの機能は、システム プロパティを読み取り、プロパティ値に基づいて指定されたパッケージ名のアプリケーションを削除するか、アプリケーション管理のリストに追加しないかを決定することです。

  1. package/apps/Settings/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java ファイルで、displayRecentApps メソッドを見つけて、次のコードを追加します。
// 导入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;
        }
        // ...
    }
    // ...
}

このコードの機能は、システム プロパティを読み取り、プロパティ値に基づいて、指定されたパッケージ名のアプリケーションをスキップするか、最近通知されたアプリケーションのリストに表示しないかを決定することです。

要約する

この記事では、ソースコードを使用せずに、Android 11 でアプリケーションをデフォルトのランチャーとして変更し、アプリケーションのアイコンを非表示にする方法について説明します。これらの機能は、ソース コードを変更したり、システム全体を再コンパイルしたりせずに、いくつかのシステム プロパティを設定し、いくつかの構成ファイルを変更することで実現できます。もちろん、これらの機能はPMSの学習の一部ですが、多くのテストと修正が必要な部分を実際に使用すると、システムに影響を与えるのでしょうか?したがって、これらの機能を使用する場合は、特定のニーズとシナリオに基づいてトレードオフと選択を行う必要があります。

この記事がお役に立てば幸いです。ありがとう!

Guess you like

Origin blog.csdn.net/SHH_1064994894/article/details/132744252