web-dev-qa-db-ja.com

バックグラウンドタスクまたはサービスから現在のフォアグラウンドアプリケーションを決定する

バックグラウンドで実行する1つのアプリケーションが必要です。このアプリケーションは、組み込みアプリケーション(メッセージング、連絡先など)が実行されていることを認識しています。

だから私の質問は:

  1. バックグラウンドでアプリケーションを実行する方法。

  2. バックグラウンドアプリケーションが、現在フォアグラウンドで実行されているアプリケーションをどのように知ることができるか。

経験のある人からの回答は大歓迎です。

104
dhaiwat

「2.フォアグラウンドで現在実行中のアプリケーションが何であるかを、私のバックグラウンドアプリケーションがどのように知ることができるか」に関して。

getRunningAppProcesses()メソッドを使用しないでください。これは私の経験からあらゆる種類のシステムのごみを返すため、_RunningAppProcessInfo.IMPORTANCE_FOREGROUND_を持つ複数の結果が得られます。代わりにgetRunningTasks()を使用してください

これは、現在のフォアグラウンドアプリケーションを識別するために私のサービスで使用するコードで、非常に簡単です。

_ActivityManager am = (ActivityManager) AppService.this.getSystemService(ACTIVITY_SERVICE);
// The first in the list of RunningTasks is always the foreground task.
RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
_

これで、フォアグラウンドアプリ/アクティビティの詳細に簡単にアクセスできます。

_String foregroundTaskPackageName = foregroundTaskInfo .topActivity.getPackageName();
PackageManager pm = AppService.this.getPackageManager();
PackageInfo foregroundAppPackageInfo = pm.getPackageInfo(foregroundTaskPackageName, 0);
String foregroundTaskAppName = foregroundAppPackageInfo.applicationInfo.loadLabel(pm).toString();
_

これには、アクティビティメニフェストに追加の許可が必要であり、完全に機能します。

_<uses-permission Android:name="Android.permission.GET_TASKS" />
_
100
Oliver Pearmain

私は正しい方法を難しい方法で見つけなければなりませんでした。以下のコードはcyanogenmod7(タブレットの調整)の一部であり、Android 2.3.3/Gingerbreadでテストされています。

メソッド:

  • getForegroundApp-フォアグラウンドアプリケーションを返します。
  • getActivityForApp-見つかったアプリのアクティビティを返します。
  • isStillActive-以前に見つかったアプリがまだアクティブなアプリであるかどうかを判断します。
  • isRunningService-getForegroundAppのヘルパー関数

これは、この問題に全面的に答えることを望んでいます(:

private RunningAppProcessInfo getForegroundApp() {
    RunningAppProcessInfo result=null, info=null;

    if(mActivityManager==null)
        mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
    List <RunningAppProcessInfo> l = mActivityManager.getRunningAppProcesses();
    Iterator <RunningAppProcessInfo> i = l.iterator();
    while(i.hasNext()){
        info = i.next();
        if(info.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                && !isRunningService(info.processName)){
            result=info;
            break;
        }
    }
    return result;
}

private ComponentName getActivityForApp(RunningAppProcessInfo target){
    ComponentName result=null;
    ActivityManager.RunningTaskInfo info;

    if(target==null)
        return null;

    if(mActivityManager==null)
        mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
    List <ActivityManager.RunningTaskInfo> l = mActivityManager.getRunningTasks(9999);
    Iterator <ActivityManager.RunningTaskInfo> i = l.iterator();

    while(i.hasNext()){
        info=i.next();
        if(info.baseActivity.getPackageName().equals(target.processName)){
            result=info.topActivity;
            break;
        }
    }

    return result;
}

private boolean isStillActive(RunningAppProcessInfo process, ComponentName activity)
{
    // activity can be null in cases, where one app starts another. for example, astro
    // starting rock player when a move file was clicked. we dont have an activity then,
    // but the package exits as soon as back is hit. so we can ignore the activity
    // in this case
    if(process==null)
        return false;

    RunningAppProcessInfo currentFg=getForegroundApp();
    ComponentName currentActivity=getActivityForApp(currentFg);

    if(currentFg!=null && currentFg.processName.equals(process.processName) &&
            (activity==null || currentActivity.compareTo(activity)==0))
        return true;

    Slog.i(TAG, "isStillActive returns false - CallerProcess: " + process.processName + " CurrentProcess: "
            + (currentFg==null ? "null" : currentFg.processName) + " CallerActivity:" + (activity==null ? "null" : activity.toString())
            + " CurrentActivity: " + (currentActivity==null ? "null" : currentActivity.toString()));
    return false;
}

private boolean isRunningService(String processname){
    if(processname==null || processname.isEmpty())
        return false;

    RunningServiceInfo service;

    if(mActivityManager==null)
        mActivityManager = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
    List <RunningServiceInfo> l = mActivityManager.getRunningServices(9999);
    Iterator <RunningServiceInfo> i = l.iterator();
    while(i.hasNext()){
        service = i.next();
        if(service.process.equals(processname))
            return true;
    }

    return false;
}
38
Sven Dawitz

次のコードを試してください:

ActivityManager activityManager = (ActivityManager) newContext.getSystemService( Context.ACTIVITY_SERVICE );
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for(RunningAppProcessInfo appProcess : appProcesses){
    if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
        Log.i("Foreground App", appProcess.processName);
    }
}

プロセス名は、フォアグラウンドで実行されているアプリのパッケージ名です。アプリケーションのパッケージ名と比較してください。同じ場合、アプリケーションはフォアグラウンドで実行されています。

これがあなたの質問に答えることを願っています。

33
Friedrich Bhaer

Lollipop以降、これは変更されました。ユーザーが[設定]-> [セキュリティ]->(最後まで下にスクロール)使用権限のあるアプリ->アプリに権限を付与する前に、以下のコードを見つけてください。

private void printForegroundTask() {
    String currentApp = "NULL";
    if(Android.os.Build.VERSION.SDK_INT >= Android.os.Build.VERSION_CODES.Lollipop) {
        UsageStatsManager usm = (UsageStatsManager) this.getSystemService(Context.USAGE_STATS_SERVICE);
        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(TAG, "Current App in foreground is: " + currentApp);
}
23
Suman

getRunningTasks()は非推奨であり、getRunningAppProcesses()は信頼できないことを考慮して、StackOverflowで言及されている2つのアプローチを組み合わせることにしました。

   private boolean isAppInForeground(Context context)
    {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Lollipop)
        {
            ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
            ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
            String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();

            return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase());
        }
        else
        {
            ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
            ActivityManager.getMyMemoryState(appProcessInfo);
            if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE)
            {
                return true;
            }

            KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
            // App is foreground, but screen is locked, so show notification
            return km.inKeyguardRestrictedInputMode();
        }
    }
8
Ayaz Alifov

ActivityManager クラスは、実行中のプロセスを確認するための適切なツールです。

バックグラウンドで実行するには、通常 Service を使用します。

6
Charles Duffy

フォアグラウンドアプリケーションを決定するために、フォアグラウンドアプリの検出に使用できます。 https://github.com/ricvalerio/foregroundappchecker を使用できます。 Androidデバイスのバージョンに応じて異なる方法を使用します。

サービスに関しては、リポジトリは必要なコードも提供します。基本的に、Android studioがサービスを作成し、onCreateがappCheckerを使用するスニペットを追加します。ただし、許可を要求する必要があります。

5
rvalerio

アプリがフォアグラウンドにあるかどうかを独自のサービス/バックグラウンドスレッドから確認する必要がある場合。これは私がそれを実装した方法であり、私にとってはうまく機能します:

public class TestApplication extends Application implements Application.ActivityLifecycleCallbacks {

    public static WeakReference<Activity> foregroundActivityRef = null;

    @Override
    public void onActivityStarted(Activity activity) {
        foregroundActivityRef = new WeakReference<>(activity);
    }

    @Override
    public void onActivityStopped(Activity activity) {
        if (foregroundActivityRef != null && foregroundActivityRef.get() == activity) {
            foregroundActivityRef = null;
        }
    }

    // IMPLEMENT OTHER CALLBACK METHODS
}

ここで、アプリがフォアグラウンドにあるかどうかにかかわらず、他のクラスから確認するには、単に呼び出します:

if(TestApplication.foregroundActivityRef!=null){
    // APP IS IN FOREGROUND!
    // We can also get the activity that is currently visible!
}

更新( [〜#〜] shs [〜#〜] ):で指摘されているとおり

ApplicationクラスのonCreateメソッドでコールバックを登録することを忘れないでください。

@Override
public void onCreate() {
    ...
    registerActivityLifecycleCallbacks(this);
}
4
Sarthak Mittal

これは私のために働いた。ただし、メインメニュー名のみが表示されます。つまり、ユーザーが[設定]-> [Bluetooth]-> [デバイス名]画面を開いた場合、RunningAppProcessInfoは単に[設定]として呼び出します。 furthurをドリルダウンできません

ActivityManager activityManager = (ActivityManager) context.getSystemService( Context.ACTIVITY_SERVICE );
                PackageManager pm = context.getPackageManager();
                List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
                for(RunningAppProcessInfo appProcess : appProcesses) {              
                    if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                        CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(appProcess.processName, PackageManager.GET_META_DATA));
                        Log.i("Foreground App", "package: " + appProcess.processName + " App: " + c.toString());
                    }               
                }
1
NakulSargur

これは、アプリがフォアグラウンドにあるかどうかを確認する方法です。注:AsyncTaskを公式のAndroidドキュメントで提案されているように使用しています。

`

_    private class CheckIfForeground extends AsyncTask<Void, Void, Void> {
    @Override
    protected Void doInBackground(Void... voids) {

        ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                Log.i("Foreground App", appProcess.processName);

                if (mContext.getPackageName().equalsIgnoreCase(appProcess.processName)) {
                    Log.i(Constants.TAG, "foreground true:" + appProcess.processName);
                    foreground = true;
                    // close_app();
                }
            }
        }
        Log.d(Constants.TAG, "foreground value:" + foreground);
        if (foreground) {
            foreground = false;
            close_app();
            Log.i(Constants.TAG, "Close App and start Activity:");

        } else {
            //if not foreground
            close_app();
            foreground = false;
            Log.i(Constants.TAG, "Close App");

        }

        return null;
    }
}
_

このようにAsyncTaskを実行します。 new CheckIfForeground().execute();

0
Hammad Tariq

Lollipop以降:

メインフェストに追加:

<uses-permission Android:name="Android.permission.GET_TASKS" />

そして、このようなことをしてください:

if( mTaskId < 0 )
{
    List<AppTask> tasks = mActivityManager.getAppTasks(); 
    if( tasks.size() > 0 )
        mTaskId = tasks.get( 0 ).getTaskInfo().id;
}
0
rubmz

このようなことをしてください:

int showLimit = 20;

/* Get all Tasks available (with limit set). */
ActivityManager mgr = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> allTasks = mgr.getRunningTasks(showLimit);
/* Loop through all tasks returned. */
for (ActivityManager.RunningTaskInfo aTask : allTasks) 
{                  
    Log.i("MyApp", "Task: " + aTask.baseActivity.getClassName()); 
    if (aTask.baseActivity.getClassName().equals("com.Android.email.activity.MessageList")) 
        running=true;
}
0
ChristianS

2つのソリューションを1つのメソッドに組み合わせましたが、API 24とAPI 21で機能します。その他はテストしませんでした。

Kotlinのコード:

private fun isAppInForeground(context: Context): Boolean {
    val appProcessInfo = ActivityManager.RunningAppProcessInfo()
    ActivityManager.getMyMemoryState(appProcessInfo)
    if (appProcessInfo.importance == IMPORTANCE_FOREGROUND ||
            appProcessInfo.importance == IMPORTANCE_VISIBLE) {
        return true
    } else if (appProcessInfo.importance == IMPORTANCE_TOP_SLEEPING ||
            appProcessInfo.importance == IMPORTANCE_BACKGROUND) {
        return false
    }

    val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    val foregroundTaskInfo = am.getRunningTasks(1)[0]
    val foregroundTaskPackageName = foregroundTaskInfo.topActivity.packageName
    return foregroundTaskPackageName.toLowerCase() == context.packageName.toLowerCase()
}

そしてマニフェストで

<!-- Check whether app in background or foreground -->
<uses-permission Android:name="Android.permission.GET_TASKS" />