Android 5.1.1 이상-getRunningAppProcesses ()는 내 애플리케이션 패키지 만 반환합니다.


100

Google은 마침내 현재 포 그라운드 애플리케이션 패키지를 얻기 위해 모든 문을 닫은 것 같습니다.

이 답변getRunningTasks(int maxNum) 덕분에 Lollipop 업데이트 후 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

3
여러 주요 공급 업체가 해당 장치에서 UsageStats API에 대한 액세스 권한을 부여하는 시스템 활동을 제거했습니다. 즉, 해당 장치의 앱은 필요한 권한을 얻을 수 없습니다.
Kevin Krumwiede 2015 년

3
삼성 은 그들 중 하나입니다. 이는 시장의 60 % 이상입니다.
Kevin Krumwiede 2015 년

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_scoreAndroid 6.0에서는 더 이상 읽을 수없는 것 같습니다 . gist.github.com/jaredrummler/7d1498485e584c8a120e
Jared Rummler

답변:


93

Android 1.6-Android 6.0에서 실행중인 프로세스 목록을 얻으려면 내가 작성한이 라이브러리를 사용할 수 있습니다. https://github.com/jaredrummler/AndroidProcesses 라이브러리는 프로세스 정보를 얻기 위해 / proc을 읽습니다.

Google은 Android Nougat에서 / proc에 대한 액세스를 크게 제한했습니다. Android Nougat에서 실행중인 프로세스 목록을 얻으려면 UsageStatsManager를 사용하거나 루트 액세스 권한이 있어야합니다.

이전 대체 솔루션에 대한 편집 내역을 클릭하십시오.


4
@androiddeveloper 아니요, 셸 명령 (루트 또는 루트가 아닌)을 실행하고 출력을 얻는 쉬운 방법을 제공하기 때문에 libsuperuser 만 사용했습니다. 충분한 수요가 있으면 libsuperuser없이 다시 쓸 수 있습니다.
Jared Rummler 2015 년

1
그 죄송합니다. 호기심이 많았습니다. :(
안드로이드 개발자

1
@JaredRummler 현재 내 앱에 솔루션을 구현하는 중입니다. 내가 말할 수있는 지금까지의 벌금을 작동하는 것 같군
guy.gc

1
@androiddeveloper, 다른 속성을 기반으로 정렬하려면 메소드를 Process구현 Comparable하고 재정의하십시오 compareTo. 그런 다음을 사용할 때 Collections.sort(processesList)지정한 순서를 사용합니다.
Srini

2
: 나는 제라드가이 링크를 다스 려 생각 @BruceWayne https://source.android.com/devices/tech/security/selinux/index.html
에두아르도 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;
}

이 방법을 사용하여 포 그라운드 작업을 가져옵니다. 시스템 권한 "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;
    }
}

사용자가 설정-> 보안-> 사용 액세스 권한이있는 앱에서이를 활성화하는 경우. 그 후 u는 포 그라운드 작업을 받게됩니다. 유사 프로세스 Clean matser by Cheetahamobile google play link


OP 및 주석에서 지적했듯이 UsageStatsManager. 삼성은 요청을 제거했으며 사용자가 시스템 권한을 부여하는 것은 매우 성가신 일입니다.
Jared Rummler 2015-09-01

moto e2 장치에서 테스트했습니다. 잘 작동하고 있으며 예,이 권한을 구현해야합니다. 우리는 모두 같은 문제에 직면 해 있습니다. 우리 모두는 더 나은 접근 방식이 정말로 필요합니다. 행운을 빕니다 친구
Tarun Sharma

2
이 접근 방식은 "설정-> 보안-> 사용 권한이있는 앱"메뉴 항목이 없기 때문에 적어도 LG G3에서 작동하지 않습니다
Dmitry

2
제 질문에 대한 답이 아닙니다. 또한이 답변에는 새로운 정보가 제공되지 않습니다.
Lior Iluz 2015 년

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
고맙지 만 여기에 새로운 것은 없습니다. 그는 OP에 언급 된 UsageStatsManager API를 방금 래핑했습니다. 사용자는 안드로이드 5.1.1 이후 다른 방법으로, 액세스 할 수 있도록해야합니다
리 오르 Iluz

@ Jérémy 필요한 권한을 요청 했습니까?
rvalerio

그것은 또한 항상 투표하는 것 같습니다.
안드로이드 개발자

4

Google은 시스템 앱에 대해서만이 기능을 제한했습니다. 버그 티켓 에보고 된대로 여기에 액세스 하려면 REAL_GET_TASKS 권한 이 필요합니다 .

모든 애플리케이션에 대한 프로세스 정보를 가져올 수 있으려면 애플리케이션에 ... permission.REAL_GET_TASKS가 있어야합니다. 앱에 권한이없는 경우 호출 애플리케이션에 대한 프로세스 정보 만 반환됩니다. 권한 앱은 새 권한이 없지만 더 이상 사용되지 않는 ... permission.GET_TASKS가있는 모든 애플리케이션에 대한 프로세스 정보를 일시적으로 가져올 수 있습니다. 또한 시스템 앱만 REAL_GET_TASKS 권한을 얻을 수 있습니다.


응용 프로그램이 보안 권한을 일단 I의 톱 applock 여전히 5.1.1에 노력하고 있습니다 -> "사용 액세스 할 수있는 응용 프로그램은"...이 다소 놀라운 일이다
르네 마헤

"보호 수준 서명, 권한 또는 signatureOrSystem이있는 권한은 시스템 앱에만 부여됩니다. 앱이 일반 비 시스템 앱인 경우 이러한 권한을 사용할 수 없습니다."라고 Android 스튜디오와 협상 할 수 있습니다. 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) 인 Collections.max ()에서 더 간단한 솔루션을 사용할 수있을 때 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의 원래 소스에서 코드를 복사하여 붙여 넣었습니다.
Sam

-2

방법 getRunningServices()대신 사용 해보세요 getRunningAppProcesses().

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

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

3
Stack Overflow에 오신 것을 환영합니다! 포 그라운드 앱이 서비스를 실행하지 않을 수 있기 때문에 이것이 작동하지 않을 것이라고 생각합니다.
Sam
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.