Android 5.1.1以降-getRunningAppProcesses()がアプリケーションパッケージのみを返す


100

現在のフォアグラウンドアプリケーションパッケージを入手するために、Googleはついにすべての扉を閉めたようです。

殺されたLollipopの更新後、この回答のgetRunningTasks(int maxNum)おかげで、私はこのコードを使用して、Lollipop以降のフォアグラウンドアプリケーションパッケージを取得しました。

final int PROCESS_STATE_TOP = 2;
RunningAppProcessInfo currentInfo = null;
Field field = null;
try {
    field = RunningAppProcessInfo.class.getDeclaredField("processState");
} catch (Exception ignored) { 
}
ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appList = am.getRunningAppProcesses();
for (RunningAppProcessInfo app : appList) {
    if (app.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
        app.importanceReasonCode == 0 ) {
        Integer state = null;
        try {
            state = field.getInt( app );
        } catch (Exception ignored) {
        }
        if (state != null && state == PROCESS_STATE_TOP) {
            currentInfo = app;
            break;
        }
    }
}
return currentInfo;

Android 5.1.1以上(6.0 Marshmallow)getRunningAppProcesses()も殺されたようです。これで、独自のアプリケーションパッケージのリストが返されます。


UsageStatsManager

ここで説明するように新しいUsageStatsManagerAPIを使用できますが、すべてのアプリケーションで機能するわけではありません。一部のシステムアプリケーションは同じパッケージを返します

com.google.android.googlequicksearchbox

AccessibilityService(2017年12月:Googleによる使用が禁止されます)

一部のアプリケーションはAccessibilityServiceここに示すように)使用しますが、いくつかの欠点があります。


現在実行中のアプリケーションパッケージを取得する別の方法はありますか?


1
Du Speed Boosterは機能しているようです。UsageStatsManagerを使用しているかどうかはわかりません。
thecr0w 2015

3
いくつかの主要ベンダーは、デバイスからUsageStats APIへのアクセスを許可するシステムアクティビティを削除していることに注意してください。つまり、これらのデバイス上のアプリは必要な権限を取得できません。
Kevin Krumwiede 2015

3
サムスンはその一つです。それは市場の60%以上です。
Kevin Krumwiede、2015

3
ここでは、この問題に関してアンドロイドバグトラッカーからのチケットは次のとおりです。code.google.com/p/android-developer-preview/issues/...
フロリアン・バルト

2
psシェルでの実行の出力を解析し、ポリシーが"fg"で、コンテンツが/proc/[pid]/oom_adj_score等しい0場合、アプリはフォアグラウンドアプリケーションです。残念ながら、それ/proc/[pid]/oom_adj_scoreはもはやAndroid 6.0では読めないようです。gist.github.com/jaredrummler/7d1498485e584c8a120e
Jared Rummler 2015

回答:


93

Android 1.6-Android 6.0で実行中のプロセスのリストを取得するには、私が書いたこのライブラリを使用できます。https//github.com/jaredrummler/AndroidProcessesライブラリは/ procを読み取り、プロセス情報を取得します。

Googleでは、Android Nougatの/ procへのアクセスを大幅に制限しています。Android Nougatで実行中のプロセスのリストを取得するには、UsageStatsManagerを使用するか、rootアクセスが必要です。

以前の代替ソリューションの編集履歴をクリックします。


4
@androiddeveloperいいえ、libsuperuserのみを使用しました。これは、シェルコマンド(非ルートまたはルート)を実行して出力を取得する簡単な方法を提供するためです。十分な需要があれば、libsuperuserなしで書き直すことができます。
Jared Rummler、2015

1
そのために残念。ただ好奇心旺盛でした。:(
Android開発者

1
@JaredRummler現在、アプリにソリューションを実装しています。私の知る限り、問題なく動作しているようです
guy.gc

1
@androiddeveloper、別の属性に基づいて並べ替える場合は、Process実装ComparableしてcompareToメソッドをオーバーライドします。次に、を使用するとCollections.sort(processesList)、指定した順序が使用されます。
Srini、2015年

2
@BruceWayne Jaredがこのリンクを参照していると思います:https
Eduardo

24
 private String printForegroundTask() {
    String currentApp = "NULL";
    if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats");
        long time = System.currentTimeMillis();
        List<UsageStats> appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,  time - 1000*1000, time);
        if (appList != null && appList.size() > 0) {
            SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
            for (UsageStats usageStats : appList) {
                mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
            }
            if (mySortedMap != null && !mySortedMap.isEmpty()) {
                currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
            }
        }
    } else {
        ActivityManager am = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> tasks = am.getRunningAppProcesses();
        currentApp = tasks.get(0).processName;
    }

    Log.e("adapter", "Current App in foreground is: " + currentApp);
    return currentApp;
}

フォアグラウンドタスクを取得するには、このメソッドを使用します。Uにはシステム権限「android:get_usage_stats」が必要です

public static boolean needPermissionForBlocking(Context context){
    try {
        PackageManager packageManager = context.getPackageManager();
        ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
        AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);
        return  (mode != AppOpsManager.MODE_ALLOWED);
    } catch (PackageManager.NameNotFoundException e) {
        return true;
    }
}

ユーザーが設定->セキュリティ->使用法アクセスのあるアプリでこれを有効にする場合。その後、あなたはフォアグラウンドタスクを取得します。同様のプロセスCheetahamobileのグーグルプレイリンクによるクリーンマット


OPとコメントで指摘されているように、を使用することには大きな欠点がありUsageStatsManagerます。Samsungはリクエストを削除したため、ユーザーがシステム権限を付与するのはかなり面倒です。
Jared Rummler、2015

私はmoto e2デバイスでテストしました。それは正常に機能しており、はい、この権限を実装する必要があります。私たちは皆同じ問題に直面しています。私たちは本当により良いアプローチを必要としています。頑張ってください
Tarun Sharma

2
この方法は、少なくとも[LG G3]では機能しません。[設定]-> [セキュリティ]-> [使用アクセス権のあるアプリ]メニュー項目がないためです
Dmitry

2
それは私の質問に対する答えではありません。さらに、この回答では新しい情報は提供されていません。
Lior Iluz、2015

1
マシュマロではうまくいきますが、適切に機能しません。通知が来た場合、現在実行中のプロセスは受信したパッケージ通知になります。実際にはアプリがフォアグラウンドまたはバックグラウンドで実行されていません:(。解決策が必要です
。– WonderSoftwares

6

見てくださいhttps://github.com/ricvalerio/foregroundappcheckerを、それは何が必要かもしれません。サンプルコードを提供し、クロスバージョンのフォアグラウンド検出器を実装する必要があるという苦痛を取り除きます。

以下に2つのサンプルを示します。

AppChecker appChecker = new AppChecker();
String packageName = appChecker.getForegroundApp();

または定期的に確認してください:

AppChecker appChecker = new AppChecker();
appChecker
    .when("com.other.app", new AppChecker.Listener() {
        @Override
        public void onForeground(String packageName) {
            // do something
        }
    )
    .when("com.my.app", new AppChecker.Listener() {
        @Override
        public void onForeground(String packageName) {
            // do something
        }
    )
    .other(new AppChecker.Listener() {
        @Override
        public void onForeground(String packageName) {
            // do something
        }
    )
    .timeout(1000)
    .start(this);

2
ありがとうございますが、ここでは新しいことは何もありません。彼はOPで言及されているUsageStatsManager APIをラップしました。Android 5.1.1以降の他の方法と同様に、ユーザーはアクセスを有効にする必要があります
Lior Iluz

@Jérémy必要な権限をリクエストしましたか?
rvalerio

常にポーリングしているようですね?
Android開発者

4

Googleはこの機能をシステムアプリのみに制限しました。バグチケットで報告されているように、そこにアクセスするにはREAL_GET_TASKS権限が必要です。

すべてのアプリケーションのプロセス情報を取得できるようにするには、アプリケーションに... permission.REAL_GET_TASKSが必要です。アプリに権限がない場合は、呼び出し元のアプリケーションのプロセス情報のみが返されます。特権アプリは、新しい権限がない場合は一時的にすべてのアプリケーションのプロセス情報を取得できますが、... permission.GET_TASKSは廃止されました。また、REAL_GET_TASKS権限を取得できるのはシステムアプリのみです。


applockが引き続き5.1.1で動作しているのを確認しました。いったんアプリがsecurity-> "apps with usage access"で許可を取得すると...これはやや意外です
mahesh ren

「保護レベル署名、privileged、またはsignatureOrSystemの権限は、システムアプリにのみ付与されます。アプリが通常の非システムアプリである場合、これらの権限を使用することはできません。」アンドロイドスタジオといいます。グーグルが「システムアプリ」として認められる。
ジェレミー

2

Android Mの最上位のアプリケーションを検出するために、コピーを貼り付けたコードのビットを想像して最適化の可能性を捨てるだけです。

この

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
    UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats");
    long time = System.currentTimeMillis();
    List<UsageStats> appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,  time - 1000*1000, time);
    if (appList != null && appList.size() > 0) {
        SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
        for (UsageStats usageStats : appList) {
            mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
        }
        if (mySortedMap != null && !mySortedMap.isEmpty()) {
            currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
        }
    }
}

これに簡略化できます

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
    UsageStatsManager usm = (UsageStatsManager) context.getSystemService(
        Context.USAGE_STATS_SERVICE);
    long time = System.currentTimeMillis();
    List<UsageStats> appStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
            time - 1000 * 1000, time);
    if (appStatsList != null && !appStatsList.isEmpty()) {
        currentApp = Collections.max(appStatsList, (o1, o2) ->
            Long.compare(o1.getLastTimeUsed(), o2.getLastTimeUsed())).getPackageName();
    }
}

2秒ループでこのコードを使用していることに気付き、O(n * log(n))である複雑なソリューションを使用していた理由を疑問に思いました。 )。


0
public class AccessibilityDetectingService extends AccessibilityService {

@Override
protected void onServiceConnected() {
    super.onServiceConnected();

    //Configure these here for compatibility with API 13 and below.

    AccessibilityServiceInfo config = new AccessibilityServiceInfo();
    config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
    config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;

    if (Build.VERSION.SDK_INT >= 16)
        //Just in case this helps
        config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;

    setServiceInfo(config);
}

@Override
public void onAccessibilityEvent(final AccessibilityEvent event) {
        if (event == null ) {
            return;
        } else if(event.getPackageName() == null && event.getClassName() == null){
            return;
        }

            if (activityInfo != null){

                Log.d("CurrentActivity", componentName.flattenToShortString());
        }

}

private ActivityInfo tryGetActivity(ComponentName componentName) {
    try {
        return getPackageManager().getActivityInfo(componentName, 0);
    } catch (PackageManager.NameNotFoundException e) {
        return null;
    }
}
@Override
public void onInterrupt() {
}                
}
}//`enter code here`uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
<uses-permission android:name="android.permission.GET_TASKS" />

次に、そのサービスのデバイス設定->アクセシビリティ->アプリでサービスとアプリのアクセシビリティを開始します。


これは既に質問でカバーされており、StackOverflowの元のソースからコードをコピーして貼り付けただけです。
サム

-2

メソッドのgetRunningServices()代わりに使用してみてくださいgetRunningAppProcesses()

 ActivityManager mActivityManager = (ActivityManager) getSy stemService(Context.ACTIVITY_SERVICE);

 List<ActivityManager.RunningServiceInfo> appProcessInfoList = mActivityManager.getRunningServices(Integer.MAX_VALUE);

3
Stack Overflowへようこそ!フォアグラウンドアプリがサービスを実行していない可能性があるため、これは機能しないと思います。
サム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.