Android 5.1.1 ve üzeri - getRunningAppProcesses () yalnızca uygulama paketimi döndürür


100

Görünüşe göre Google nihayet mevcut ön plan uygulama paketini almak için tüm kapıları kapattı.

Öldüren Lollipop güncellemesinden sonra ve bu cevapgetRunningTasks(int maxNum) sayesinde Lollipop'tan beri ön plan uygulama paketini almak için şu kodu kullandım:

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;

Görünüşe göre Android 5.1.1 ve üstü (6.0 Marshmallow) da öldürüldü getRunningAppProcesses(). Şimdi kendi uygulama paketinizin bir listesini döndürür.


UsageStatsManager

Yeni UsageStatsManagerAPI'yi burada açıklandığı gibi kullanabiliriz ancak tüm uygulamalar için çalışmaz. Bazı sistem uygulamaları aynı paketi döndürecek

com.google.android.googlequicksearchbox

Erişilebilirlik Hizmeti (Aralık 2017: Google tarafından kullanılması yasaklanacak)

Bazı uygulamalar AccessibilityService( burada görüldüğü gibi ) kullanır ancak bazı dezavantajları vardır.


Geçerli çalışan uygulama paketini almanın başka bir yolu var mı?


1
Du Speed ​​Booster işe yarıyor gibi görünüyor. UsageStatsManager kullanıp kullanmadığından emin değilim.
thecr0w

3
Birkaç büyük satıcının cihazlarından UsageStats API'ye erişim sağlayan sistem etkinliğini kaldırdığını unutmayın. Bu, bu cihazlardaki uygulamaların asla gerekli izni alamayacağı anlamına gelir.
Kevin Krumwiede

3
Samsung onlardan biri. Bu, pazarın% 60'ından fazlası.
Kevin Krumwiede

3
İşte bu sorunla ilgili android hata takipçisinden bir bilet: code.google.com/p/android-developer-preview/issues/…
Florian Barth

2
psBir kabukta çalışmanın çıktısını ayrıştırırsam ve ilke eşittir "fg"ve içeriği /proc/[pid]/oom_adj_scoreeşitse 0, uygulama ön plan uygulamasıdır. Maalesef /proc/[pid]/oom_adj_scoreartık Android 6.0'da okunabilir görünmüyor . gist.github.com/jaredrummler/7d1498485e584c8a120e
Jared Rummler

Yanıtlar:


93

Android 1.6 - Android 6.0'da çalışan işlemlerin bir listesini almak için yazdığım bu kitaplığı kullanabilirsiniz: https://github.com/jaredrummler/AndroidProcesses Kitaplık, işlem bilgilerini almak için / proc okur.

Google, Android Nougat'ta / proc'a erişimi önemli ölçüde kısıtladı. Android Nougat'ta çalışan işlemlerin bir listesini almak için UsageStatsManager'ı kullanmanız veya root erişimine sahip olmanız gerekir.

Önceki alternatif çözümler için düzenleme geçmişini tıklayın.


4
@androiddeveloper hayır, sadece libsuperuser kullandım çünkü bir kabuk komutunu (kök olmayan veya kök) çalıştırmanın ve çıktıyı almanın kolay bir yolunu sağlıyor. Yeterli talep varsa libsuperuser olmadan yeniden yazabilirim.
Jared Rummler

1
Bunun için özür dilerim. Sadece merak ediyordum. :(
android geliştiricisi

1
@JaredRummler Şu anda çözümünüzü uygulamama uygulama sürecindeyim. Anladığım kadarıyla iyi çalışıyor gibi görünüyor
guy.gc

1
@androiddeveloper, Farklı bir özniteliğe göre sıralamak istiyorsanız, Processuygulayın Comparableve compareToyöntemi geçersiz kılın . Daha sonra Collections.sort(processesList)kullandığınızda belirttiğiniz sırayı kullanacaktır.
Srini

2
@BruceWayne Sanırım Jared bu bağlantıya atıfta bulunuyor: https://source.android.com/devices/tech/security/selinux/index.html
Eduardo Herzer

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;
}

Ön plan görevi almak için bu yöntemi kullanın. U'nun "android: get_usage_stats" Sistem İznine ihtiyacı olacak

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;
    }
}

EĞER kullanıcı bunu ayar -> Güvenlik-> kullanım erişimli uygulamada etkinleştirir. Bundan sonra ön plan görevi alacaksınız. Benzer süreç Cheetahamobile google play bağlantısı tarafından temiz matser


OP'de ve yorumlarda belirtildiği gibi, kullanmanın önemli dezavantajları vardır UsageStatsManager. Samsung istekleri kaldırdı ve bir kullanıcının bir sistem izni vermesi oldukça can sıkıcı.
Jared Rummler

Moto e2 cihazında test ettim. İyi çalışıyor ve evet, bu izni uygulamamız gerekiyor. hepimiz aynı sorunlarla karşı karşıyayız. Hepimizin gerçekten daha iyi bir yaklaşıma ihtiyacı var. İyi şanslar dostum
Tarun Sharma

2
Bu yaklaşım en azından LG G3'te çalışmıyor çünkü "Ayarlar -> Güvenlik-> Kullanım erişimi olan uygulama" menü öğesi yok
Dmitry

2
Sorumun cevabı bu değil. Üstelik bu cevapta yeni bilgi verilmemiştir.
Lior Iluz

1
Hatmi içinde iyi çalışıyor ama düzgün değil. Bildirim geldiyse, mevcut çalışan süreç alınan paket bildirimi olacaktır. aslında uygulama ön planda veya arka planda çalışmıyor :(. çözüme ihtiyaç var.
WonderSoftwares

6

Https://github.com/ricvalerio/foregroundappchecker'a bir göz atın , ihtiyacınız olan şey bu olabilir. Örnek kod sağlar ve çapraz sürüm ön plan dedektörünü uygulama zorunluluğunu ortadan kaldırır.

İşte iki örnek:

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

Veya düzenli olarak kontrol edin:

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
Teşekkürler ama burada yeni hiçbir şey yok. OP'de bahsedilen UsageStatsManager API'sini paketledi. Android 5.1.1
Lior Iluz

@ Jérémy gerekli izinleri talep ettiniz mi?
rvalerio

Görünüşe göre her zaman yoklama yapıyor, değil mi?
android geliştiricisi

4

Google, bu işlevi yalnızca sistem uygulamaları için sınırladı. Bir hata biletinde bildirildiği gibi , ihtiyacınız olacak oraya erişmek REAL_GET_TASKS iznine .

Uygulamaların artık tüm uygulamalara ilişkin işlem bilgilerini alabilmesi için ... izni.REAL_GET_TASKS olması gerekir. Uygulamanın izni yoksa, yalnızca arayan uygulamanın işlem bilgileri iade edilecektir. Ayrıcalıklı uygulamalar, yeni izne sahip değillerse ancak kullanımdan kaldırılmışsa ... tüm uygulamalar için işlem bilgilerini geçici olarak alabilir.GET_TASKS Ayrıca, yalnızca sistem uygulamaları REAL_GET_TASKS iznini alabilir.


Uygulama güvenlik iznini aldıktan sonra -> "kullanım erişimi olan uygulamalar" ... Bu biraz şaşırtıcı
mahesh ren

"Koruma seviyesi imzası, ayrıcalıklı veya imzaOrSystem içeren izinler yalnızca sistem uygulamalarına verilir. Bir uygulama normal bir sistem dışı uygulama ise, bu izinleri asla kullanamaz." Deyin android studio .. ile pazarlık yapmak için iyi şanslar Google'ın bir "sistem uygulaması" olarak kabul edilmesi.
Jérémy

2

Hayal ettiğim şeye potansiyel bir optimizasyon atmak, Android M'de en çok kullanılan uygulamayı tespit etmek için yoğun bir şekilde kopyalanıp yapıştırılan bir kod parçası.

Bu

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();
        }
    }
}

Buna basitleştirilebilir

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();
    }
}

Kendimi bu kodu 2 saniyelik bir döngüde kullanırken buldum ve neden daha basit bir çözüm olan Collections.max () olan O (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" />

Ardından, cihaz ayarınızda -> erişilebilirlik-> o hizmetteki Uygulamada hizmet ve uygulama erişilebilirliğini başlatın.


Bu zaten soruda ele alınmıştır ve kodu StackOverflow'daki orijinal kaynağından kopyalayıp yapıştırdınız.
Sam

-2

Lütfen yöntem getRunningServices()yerine kullanmayı deneyin getRunningAppProcesses().

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

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

3
Stack Overflow'a hoş geldiniz! Ön plan uygulaması bir hizmet çalıştırmadığından bunun işe yarayacağını sanmıyorum.
Sam
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.