0

職場では、ユーザーが職場に出入りするルートを追跡するアプリを作成しました。自動記録機能が組み込まれていますが、期待どおりに動作しません。この自動システムは、1 日か 2 日非アクティブな状態が続くと、OS によってオフにされているようです (その間、電話は動かず、基本的にはテストのみに使用されます)。

iOS では、CLRegions を使用して、ユーザーの現在の位置の周りにいくつかの領域を作成しています。ユーザーの正確な位置に異なる半径で 5 つの領域が作成され、10 メートルの距離でユーザーの周りの円内に 12 の領域が作成されています (これらは半径は 80 メートルです)。また、CLLocationManager オブジェクトは、重要な変更と訪問の監視を開始するように指示されます (ただし、これらはまだ一度も起動されていません)。

Android では、LocationServices API を介して Geofences を使用しています。ここでは、ユーザーの現在位置の周囲に 5 つの増分半径しかありません。ユーザーが Android でアプリを閉じるか、電話を再起動すると、バックグラウンド サービスが起動され、ジオフェンスが再初期化されて監視が開始されます。

どちらのシステムも、私が少し外を歩いてテストしているときは非常にうまく機能しますが、1 日か 2 日 (つまり週末) 何も操作しないと、機能しなくなったようです。私はこれをかなり長い間デバッグしてきましたが、改善されたとはいえ、まだ完全ではありません。

アプリがオフになっている時間に関係なく、ジオフェンス/リージョンがトリガーされたときにバックグラウンドでアプリを自動的に開始する信頼できるシステムを持つことさえ可能ですか? 両方の OS がバックグラウンド タスクを非常に異なる方法で処理することは知っていますが、この方法での GPS 使用の長期的な制限についてはよくわかりません。

私たちが作成しているアプリは Xamarin Forms で作成されていますが、これらのシステムはネイティブ プロジェクトで作成されています (まだ C# ですが、ネイティブ プラットフォーム全体にフル アクセスできます)。

4

1 に答える 1

0

Android サービスの問題は、OS がバックグラウンド サービスを強制終了することです。バックグラウンド サービスは優先度が低いと見なされ、一定の間隔で再起動します。これは数日間にわたって数回発生する可能性があり、そのたびにサービスを再起動するまでの時間が増加します (一部の電話では設​​定された時間を使用し、増加しません)。

私の提案は、常時サービスが必要な場合は、それをフォアグラウンド サービスにする必要があるということです。これを実装する方法のコード例をいくつか挙げたいと思いますが、私は Xamarin をよく知らないので、悪い例は示したくありません。

もう 1 つの方法は、AlarmManager を PendingIntent と共に使用してサービスが実行されているかどうかを確認し、実行されていない場合は開始することです。これを頻繁に行うと、顕著なバッテリーの消耗につながる可能性があることに注意してください。ただし、十分な頻度で行わないと、ジオフェンス イベントを見逃す可能性があります。

これがお役に立てば幸いです。幸運を祈ります。

更新 #1

以下は、サービスをフォアグラウンドで実行し、AlarmManager を実行するためのコード サンプルです。

前景

これは、アプリを維持する最も簡単な方法です。

public class ForegroundService extends Service{
    @Override
    public int onStartCommand(Intent intent, int flags, int startId){
        Notification notification = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.icon)
                .setContentTitle("TITLE")
                .setContentText("This is an example notification!")
                .build();
        startForeground(ID, notification);
        //Do your stuff here
    }

    @Override
    public void onDestroy(){
        super.onDestroy();
        stopForeground(true);
        //If you have anything else you want done here...
    }
}

アラームマネージャー

これにより、設定した間隔 (この例では 10 分) でこのサービスの作成が継続的に試行されます。ただし、ここにはいくつかの落とし穴があります。まず、Android 6.0 で Doze モードが導入されたため、電話がスリープ状態のときに AlarmManager が起動しない場合があります。これは、サービスがかなり長い間停止している可能性があることを意味します。2 つ目は、関数を数回呼び出すonStartCommandため、それを処理するロジックが必要になることです。

public class AlwaysOnService extends Service{
    @Override
    public int onStartCommand(Intent intent, int flags, int startId){

        AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
        PendingIntent pi = PendingIntent.getService(this, requestCode, new Intent(this, AlwaysOnService.class), PendingIntent.FLAG_UPDATE_CURRENT);
        am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + MIN_10_IN_MILLIS, pi);
        //Do your stuff here
        return START_STICKY;
    }

    @Override
    public void onDestroy(){
        super.onDestroy();
        AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
        PendingIntent pi = PendingIntent.getService(this, requestCode, new Intent(this, AlwaysOnService.class), PendingIntent.FLAG_NO_CREATE);
        if(pi != null){
            am.cancel(pi);
            pi.cancel();
        }
        //If you have anything else you want done here...
    }
}

これら 2 つのうち、サービスをフォアグラウンド サービスとして設定するのがおそらく最も簡単な方法ですが、それが本当にできない場合を除き、AlarmManager を使用する方法が適しています。

于 2016-07-25T17:10:29.620 に答える