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()เช่นกัน ตอนนี้จะส่งคืนรายการแพ็คเกจแอปพลิเคชันของคุณเอง


การใช้ StatsManager

เราสามารถใช้UsageStatsManagerAPI ใหม่ได้ตามที่อธิบายไว้ที่นี่แต่ใช้ไม่ได้กับทุกแอปพลิเคชัน แอปพลิเคชันระบบบางตัวจะส่งคืนแพ็กเกจเดียวกัน

com.google.android.googlequicksearchbox

AccessibilityService (ธันวาคม 2017: Google จะถูกห้ามใช้)

บางแอพพลิเคชั่นใช้งานAccessibilityService(ดังที่เห็นที่นี่ ) แต่ก็มีข้อเสียอยู่บ้าง


มีวิธีอื่นในการรับแพ็กเกจแอปพลิเคชันที่กำลังทำงานอยู่ในปัจจุบันหรือไม่?


1
Du Speed ​​Booster ดูเหมือนจะใช้งานได้ ฉันไม่แน่ใจว่ามันใช้ UsageStatsManager หรือไม่
thecr0w

3
โปรดทราบว่าผู้ขายรายใหญ่หลายรายได้ลบกิจกรรมระบบที่ให้สิทธิ์การเข้าถึง UsageStats API จากอุปกรณ์ของตน ซึ่งหมายความว่าแอปบนอุปกรณ์เหล่านั้นจะไม่ได้รับการอนุญาตที่จำเป็น
Kevin Krumwiede

3
ซัมซุงเป็นหนึ่งในนั้น มีมากกว่า 60% ของตลาด
Kevin Krumwiede

3
นี่คือตั๋วจากตัวติดตามข้อบกพร่องของ Android เกี่ยวกับปัญหานี้: code.google.com/p/android-developer-preview/issues/…
Florian Barth

2
หากฉันแยกวิเคราะห์ผลลัพธ์ของการทำงานpsในเชลล์และนโยบายคือ"fg"และเนื้อหา/proc/[pid]/oom_adj_scoreเท่ากับ0แอปจะเป็นแอปพลิเคชันเบื้องหน้า น่าเสียดายที่ดูเหมือนว่า/proc/[pid]/oom_adj_scoreจะไม่สามารถอ่านได้บน Android 6.0 อีกต่อไป gist.github.com/jaredrummler/7d1498485e584c8a120e
Jared Rummler

คำตอบ:


93

หากต้องการรับรายการกระบวนการทำงานบน Android 1.6 - Android 6.0 คุณสามารถใช้ไลบรารีนี้ที่ฉันเขียน: https://github.com/jaredrummler/AndroidProcessesไลบรารีอ่าน / proc เพื่อรับข้อมูลกระบวนการ

Google ได้ จำกัด การเข้าถึง / proc อย่างมากใน Android Nougat ในการรับรายการกระบวนการทำงานบน Android Nougat คุณจะต้องใช้ UsageStatsManager หรือมีการเข้าถึงรูท

คลิกประวัติการแก้ไขสำหรับโซลูชันทางเลือกก่อนหน้านี้


4
@androiddeveloper ไม่ฉันใช้ libsuperuser เท่านั้นเพราะมีวิธีง่ายๆในการเรียกใช้คำสั่งเชลล์ (ไม่ใช่รูทหรือรูท) และรับผลลัพธ์ ฉันสามารถเขียนซ้ำได้โดยไม่ต้องใช้ libsuperuser หากมีความต้องการเพียงพอ
Jared Rummler

1
ขอโทษสำหรับสิ่งนั้น. แค่อยากรู้อยากเห็น :(
นักพัฒนา Android

1
@JaredRummler ฉันกำลังอยู่ในขั้นตอนการนำโซลูชันของคุณไปใช้ในแอปของฉัน ดูเหมือนว่าจะทำงานได้ดีเท่าที่ฉันสามารถบอกได้
guy.gc

1
@androiddeveloper หากคุณต้องการจัดเรียงตามแอตทริบิวต์อื่นให้Processใช้งานComparableและแทนที่compareToวิธีการ จากนั้นเมื่อคุณใช้Collections.sort(processesList)ก็จะใช้คำสั่งที่คุณระบุ
Srini

2
@BruceWayne ฉันคิดว่า Jared กำลังอ้างถึงลิงก์นี้: https://source.android.com/devices/tech/security/selinux/index.html
Eduardo Herzer

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

ใช้วิธีนี้เพื่อรับงานเบื้องหน้า คุณจะต้องได้รับอนุญาตระบบ "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;
    }
}

หากผู้ใช้เปิดใช้งานสิ่งนี้ในการตั้งค่า -> ความปลอดภัย -> แอพที่มีการเข้าถึงการใช้งาน หลังจากนั้นคุณจะได้รับงานเบื้องหน้า กระบวนการที่คล้ายกัน Clean matser โดย Cheetahamobile google play link


เป็นแหลมออกใน OP UsageStatsManagerและความคิดเห็นที่มีข้อเสียสำคัญของการใช้ Samsung ได้ลบคำขอและค่อนข้างน่ารำคาญสำหรับผู้ใช้ในการให้สิทธิ์ระบบ
Jared Rummler

ฉันได้ทดสอบในอุปกรณ์ moto e2 มันใช้งานได้ดีและใช่เราจำเป็นต้องใช้การอนุญาตนี้ เราทุกคนประสบปัญหาเดียวกัน เราทุกคนต้องการแนวทางที่ดีกว่า ขอให้โชคดี
Tarun Sharma

2
วิธีนี้ใช้ไม่ได้ผลอย่างน้อยใน LG G3 เนื่องจากไม่มีรายการเมนู "การตั้งค่า -> ความปลอดภัย -> แอปที่เข้าถึงการใช้งาน"
Dmitry

2
นั่นไม่ใช่คำตอบสำหรับคำถามของฉัน นอกจากนี้ยังไม่มีข้อมูลใหม่ในคำตอบนี้
Lior Iluz

1
ทำงานได้ดี แต่ไม่ถูกต้องในขนมหวาน หากมีการแจ้งเตือนกระบวนการทำงานปัจจุบันจะเป็นการแจ้งเตือนแพ็กเกจที่ได้รับ จริงๆแล้วแอพไม่ได้ทำงานอยู่เบื้องหน้าหรือเบื้องหลัง :( ต้องการโซลูชัน
WonderSoftwares

6

ดูที่https://github.com/ricvalerio/foregroundappcheckerอาจเป็นสิ่งที่คุณต้องการ ให้รหัสตัวอย่างและขจัดความเจ็บปวดจากการต้องใช้ตัวตรวจจับเบื้องหน้าข้ามเวอร์ชัน

นี่คือสองตัวอย่าง:

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
ขอบคุณ แต่ไม่มีอะไรใหม่ที่นี่ เขาเพิ่งห่อ UsageStatsManager API ซึ่งกล่าวถึงใน OP ผู้ใช้จะต้องเปิดใช้งานการเข้าถึงเช่นเดียวกับวิธีการอื่น ๆ ตั้งแต่ Android 5.1.1
Lior Iluz

@ Jérémyคุณขอสิทธิ์ที่จำเป็นหรือไม่?
rvalerio

4

Google จำกัด ฟังก์ชันนี้สำหรับแอประบบเท่านั้น ตามที่ได้รับรายงานในตั๋วข้อบกพร่องคุณจะต้องมีสิทธิ์REAL_GET_TASKSเพื่อเข้าถึงที่นั่น

ขณะนี้แอปพลิเคชันต้องมี ... permission.REAL_GET_TASKS จึงจะสามารถรับข้อมูลกระบวนการสำหรับแอปพลิเคชันทั้งหมดได้ เฉพาะข้อมูลกระบวนการสำหรับแอปพลิเคชันการโทรเท่านั้นที่จะถูกส่งคืนหากแอปไม่ได้รับอนุญาต แอปพลิเคชันสิทธิ์จะสามารถรับข้อมูลกระบวนการสำหรับแอปพลิเคชันทั้งหมดได้ชั่วคราวหากไม่ได้รับอนุญาตใหม่ แต่เลิกใช้แล้ว ... อนุญาต GET_TASKS นอกจากนี้แอประบบเท่านั้นที่สามารถได้รับสิทธิ์ REAL_GET_TASKS


ฉันเห็นว่า applock ยังคงทำงานบน 5.1.1 เมื่อแอปได้รับอนุญาตในด้านความปลอดภัย -> "แอปที่เข้าถึงการใช้งาน" ... สิ่งนี้ค่อนข้างน่าแปลกใจ
mahesh ren

"สิทธิ์ที่มีลายเซ็นระดับการป้องกันสิทธิพิเศษหรือ signatureOrSystem จะมอบให้กับแอประบบเท่านั้นหากแอปเป็นแอปที่ไม่ใช่ระบบปกติแอปจะไม่สามารถใช้สิทธิ์เหล่านี้ได้" android studio กล่าว .. ขอให้โชคดีที่ได้ยกเลิกการเชื่อมต่อกับ Google ได้รับการยอมรับให้เป็น "แอประบบ"
Jérémy

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)) เมื่อมีโซลูชันที่ง่ายกว่านั้นอยู่ใน Collections.max () ซึ่งเป็น 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" />

จากนั้นเริ่มบริการและการเข้าถึงแอพในการตั้งค่าอุปกรณ์ของคุณ -> การเข้าถึง -> แอพในบริการนั้น


คำถามนี้ครอบคลุมอยู่แล้วและคุณเพิ่งคัดลอกโค้ดจากซอร์สดั้งเดิมบน 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.