FC2ブログ

記事一覧

Androidでスリープ中でもバックグラウンド処理を定期的に実行する方法 | Xamarin.Forms


以前の記事で、Android端末においてOS起動時に自動実行するバックグラウンドサービスの作成方法をご紹介していました。今回はその続きで定期的なバックグラウンド処理を行う方法をご紹介いたします。
OS起動時に一度実行されたバックグラウンドサービスをそのまま待機させて、ループすることにより繰り返し処理を実行すればよいと思っておりましたが、調べてみるとAndroidにもありました。Dozeというバッテリーの消耗を防ぐためにスリープ時にはバックグラウンドサービスはKillされる機能が。
そこで定期的に実行するアプリといえばアラームアプリですが、アラームアプリで使用されているAlarmManagerを使用して実行していきたいと思います。



前提条件
・Windows10 Pro 64Bit
・Visual Studio 2015 Community Update3
・Xamarin 4.3.0.795 (NuGet Xamarin.Forms 2.3.4.247)
・macOS Sierra 10.12.4 / Xcode8.3.1 / Xamarin.iOS 10.6.0.10



1.パーミッション追加

AndroidManifest.xmlに以下のパーミッションを追加します。

AndroidManifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />



2.ホワイトリストに登録

Android6.0以降の端末で動作せる場合は次の記事「Dozeのホワイトリストにアプリを登録する方法」でご紹介しています内容を実装する必要があります。



3.BroadcastReceiverを修正する

以前の記事のBroadcastReceiverを継承したクラスにPowerManager(画面ロックを解除する機能)とAlarmManagerによるリマインダー機能を追加します。

BootReceiver.cs
[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionBootCompleted,
                        "android.intent.action.QUICKBOOT_POWERON",
                        "com.htc.intent.action.QUICKBOOT_POWERON",
                        "android.intent.action.PACKAGE_INSTALL",
                        "android.intent.action.PACKAGE_ADDED",
                        Intent.ActionMyPackageReplaced })]
public class BootReceiver : BroadcastReceiver
{
    private static PowerManager.WakeLock _wakeLock = null;

    public override void OnReceive(Context context, Intent intent)
    {
        //画面ロックの取得
        PowerManager pm = (PowerManager)context.GetSystemService(Context.PowerService);
        _wakeLock = pm.NewWakeLock(WakeLockFlags.Partial, "BootReceiver");
        _wakeLock.Acquire();

//リマインダーをセット
this.SetReminder(context);

        //サービスの起動
        //以前の記事でご紹介済みなので割愛

    }

    //Android用のリマインダー
    public void SetReminder(Context context)
    {
        Intent alarmIntent = new Intent(context, typeof(BootReceiver));
        PendingIntent pendingIntent = PendingIntent.GetBroadcast(context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
        AlarmManager alarmManager = (AlarmManager)context.GetSystemService(Context.AlarmService);

        //AlarmManagerで1時間に1回の実行を予約する
long fireTime = SystemClock.ElapsedRealtime() + 60 * 1000 * 60; //60s*1000ms*60minutes=1hour
        alarmManager.SetInexactRepeating(AlarmType.ElapsedRealtimeWakeup, fireTime, AlarmManager.IntervalHour, pendingIntent);
    }

    public static void ReleaseWakeLock()
    {
        if (_wakeLock != null)
        {
            _wakeLock.Release();
        }
    }
}


Android.App.AlarmType:
項目説明
RtcWakeup
(値0)
UTC時刻を指定する
(スリープ状態のときは電源をONにしてくれる)
Rtc
(値1)
UTC時刻を指定する
ElapsedRealtimeWakeup
(値2)
端末が起動してからの経過時間で指定する
(スリープ状態のときは電源をONにしてくれる)
ElapsedRealtime
(値3)
端末が起動してからの経過時間で指定する


※AlarmManagerは端末を再起動すると予約されているスケジュールは無効となってしましいますが、Intent.ActionBootCompletedにより再起動後に再度スケジューリングされるようにしてあります。
※SetInexactRepeatingメソッドはDozeモードの影響を受け、発火しない場合もあります。ほかのメソッドについては次の記事「AlarmManagerで指定した時間に実行する方法」をご参考ください。

また、Androidバージョン毎にAlarmManagerで有効な設定が異なりますので、以下のURL(外部サイト)をご参考頂いた方が良いかもしれません。
http://blog.integrityworks.co.jp/2016/06/21/post-1003/
https://www.gaprot.jp/pickup/tips/android-m-summary



4.バックグラウンドサービスの修正

以前の記事のBackgroundService.csではServiceクラスを継承していましたが、それを変更してIntentServiceを継承させます。

BackgroundService.cs
[Service(Name = "com.CompanyName.BootReceiverTest.BackgroundService", Exported = false, Process = ":TestProcess")]
public class BackgroundService : IntentService
{
    public override IBinder OnBind(Intent intent)
    {
        return null;
    }
//ServicのOnStartCommandはコメントアウトする(バックグラウンドサービスが再起動しないように)
    //public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId)
//{
// Thread t = new Thread(() =>
// {
// //Xamarinを有効化
// var bundle = new Bundle();
// global::Xamarin.Forms.Forms.Init(this, bundle);

// while (true)
// {
// System.Threading.Thread.Sleep(10000);
// NotificationService nService = new NotificationService(this);
// nService.On("BackgroundService", "BackgroundService.OnStartCommand");
// }
// });
// t.Start();
// return StartCommandResult.Sticky;
//}

//OnHandleIntentを追加する
private bool _endThread = false;
protected override void OnHandleIntent(Intent intent)
{
//Xamarinを有効化
var bundle = new Bundle();
global::Xamarin.Forms.Forms.Init(this, bundle);

_endThread = false;

while (true)
{
System.Threading.Thread.Sleep(10000);
NotificationService nService = new NotificationService(this);
nService.On("BackgroundService", "BackgroundService.OnStartCommand");
break;
}
BootReceiver.ReleaseWakeLock();

_endThread = true;
}

public void StartBackgroundService()
{
System.Diagnostics.Debug.WriteLine("●StartBackgroundService");

//サービスを起動する
base.StartService(this.GetServiceIntent());
}

public void StopBackgroundService()
{
System.Diagnostics.Debug.WriteLine("●StopBackgroundService");

//サービスを停止する
base.StopService(this.GetServiceIntent());
}

private Intent GetServiceIntent()
{
System.Diagnostics.Debug.WriteLine("●BackgroundService.GetServiceIntent");

//サービスを起動する
Intent serviceIntent = new Intent(this, typeof(BackgroundService));
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop &&
Build.VERSION.SdkInt <= BuildVersionCodes.LollipopMr1)
{
//Android5 Lollipop対応
string packageName = this.PackageManager.GetPackageInfo(this.PackageName, 0).PackageName;
serviceIntent.SetPackage(packageName);
serviceIntent.SetClassName(this, packageName + ".BackgroundService");
}
else
{
serviceIntent.AddFlags(ActivityFlags.NewTask);
}
return serviceIntent;
}

public override void OnDestroy()
{
base.OnDestroy();

//処理が中断された場合
if (!_endThread)
{
//Killされてもサービスを再起動する。
this.StartBackgroundService();
}
}
}



5.トラブルシューティング

AlarmManagerが正しく動作しない場合は以下を確認してください。

(1)正しく予約されているかどうかを確認する方法はadbコマンドプロンプトから以下のコマンドを入力します。
adb shell dumpsys alarm

(2)AndroidManifest.xmlのminSdkVersionを確認してください。
ターゲットAndroidバージョンにより動作するかどうかも変化するようです。




最後までお読みいただきありがとうございます。
当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
http://itblogdsi.blog.fc2.com/blog-entry-81.html


関連記事

コメント

コメントの投稿

カテゴリ別記事一覧

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語・データベース】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
Oracle10g SQLServer2008R2 SQLAnywhere8/11/16
ActiveReport CrystalReport ReportNet(IBM)
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。