記事一覧

AndroidでOS起動時に自動実行するバックグラウンドサービスの作成方法 | Xamarin.Forms


今回はXamarin.Androidで再起動後にアプリやサービスを実行する方法をご説明いたします。Xamarinの場合はAndroidManifest.xmlに記述するのではなく、クラスにAttribute(属性)を付けることで、ビルド時にAndroidManifest.xmlに追記してくれる機能があります。


xamarin_bootreceiver_01.png


前提条件
・Windows10
・Visual Studio 2015 Community Update3
・Xamarin 4.3.0.784 (NuGet Xamarin.Forms 2.3.4.224)
・macOS Sierra 10.12.4 / Xcode8.3.1 / Xamarin.iOS 10.4.0.123


1.バックグラウンドサービスを作成する

アプリとは別スレッドで動作するプログラムを作成します。ServiceまたはIntentServiceを継承します。ServiceAttributeのProcessに任意のプロセス名を指定することでアプリが実行されていなくてもサービス単体で起動する設定としています。尚、ServiceにIntentFilterを設定してはいけません。Android5 Lollipopで動作しなくなります。

BackgroundService.cs
[Service(Name = "com.CompanyName.AppName.BackgroundService", Process = ":TestProcess")]
public class BackgroundService : Service
{
    public override IBinder OnBind(Intent intent)
    {
        return null;
    }

    public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId)
    {
        Thread t = new Thread(() =>
        {
            while (true)
            {
                System.Threading.Thread.Sleep(10000);
            }
        });
        t.Start();

        return StartCommandResult.Sticky;
    }
public void StartBackgroundService()
{
//サービスを起動する
Intent serviceIntent = new Intent(this, typeof(BackgroundService));
serviceIntent.AddFlags(ActivityFlags.NewTask);
serviceIntent.SetPackage(this.PackageManager.GetPackageInfo(this.PackageName, 0).PackageName);
base.StartService(serviceIntent);
}
public override void OnDestroy()
{
base.OnDestroy();
//Killされてもサービスを再起動する。
this.StartBackgroundService();
}
}


XamarinではJavaと異なり、ServiceAttribute([Service]のこと)を記述することによりコンパイル時に「アプリ名.Android\obj\Debug\android\AndroidManifest.xml」へ以下のコードが挿入されます。
<service android:name="com.CompanyName.AppName.BackgroundService"/>

ただし、以下のように記述すると正しく動作しなくなりました。
[Service(Exported = true, IsolatedProcess = true)]


2.BroadcastReceiverで起動完了アナウンスを取得する

BroadcastReceiverを継承したクラスにてIntentFilterでIntent.ActionBootCompletedを設定するとスマホの再起動時に動作してくれます。
また、"android.intent.action.PACKAGE_ADDED"を追加するとアプリインストール時に実行してくれます。IntentFilterにはCategoryとかDataというプロパティもあるようですが、設定すると正しく受信できなくなります。

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" })]
public class BootReceiver : BroadcastReceiver
{
    public BootReceiver() : base()
    {
    }
    public override void OnReceive(Context context, Intent intent)
    {
        //アプリを起動する場合はこちら
        //Intent activityIntent = new Intent(context, typeof(MainActivity));
        //activityIntent.AddFlags(ActivityFlags.NewTask);
        //context.StartActivity(activityIntent);

        //サービスを起動する
        Intent serviceIntent = new Intent(context, typeof(BackgroundService));
        serviceIntent.AddFlags(ActivityFlags.NewTask);
serviceIntent.SetPackage(context.PackageManager.GetPackageInfo(context.PackageName, 0).PackageName);
        context.StartService(serviceIntent);
    }
}

XamarinではJavaと異なり、BroadcastReceiverAttribute([BroadcastReceiver]のこと)を記述することによりコンパイル時に「アプリ名.Android\obj\Debug\android\AndroidManifest.xml」へ以下のコードが挿入されます。
<receiver android:name="***********.BootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
<action android:name="android.intent.action.PACKAGE_INSTALL"/>
<action android:name="android.intent.action.PACKAGE_ADDED"/>
    </intent-filter>
</receiver>

ただし、以下のように記述すると正しく動作しなくなりました。
[BroadcastReceiver(Enabled = true, Name = "com.CompanyName.AppName.BoorReceiver", Exported = false, Permission = "android.permission.RECEIVE_BOOT_COMPLETED")]

また、BroadcastReceiver.OnReceiveはアプリをビルドして実行しただけでは動作しません。Adbコマンド等でOSを再起動した際にしか実行されませんので、お気を付けください。Adbコマンドについて詳しくは以下のURLよりご参考ください。
http://itblogdsi.blog.fc2.com/blog-entry-147.html


3.パーミッションを設定する

AndroidManifest.xml
  <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

尚、アプリを外部ストレージに保存されるとBroadcastReceiverが正しく受信できなくなります。以下のようにインストール場所を内部のみに設定しましょう。
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.CompanyName.AppName" android:installLocation="internalOnly">


4.Android5 Lollipop 対応

Androidバージョン5 Lollipop では、Googleの仕様変更により、明示的インテントが求められます。インテントにパッケージ名称をセットしなければなりません。しかしながら、Android4ではセットするとサービスが起動しなくなりました。
よって、私の環境では以下のように処理分岐しています。
Intent serviceIntent = new Intent(context, typeof(BackgroundService));
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop &&
    Build.VERSION.SdkInt <= BuildVersionCodes.LollipopMr1)
{
    //Android5 Lollipop対応
    string packageName = context.PackageManager.GetPackageInfo(context.PackageName, 0).PackageName;
    serviceIntent.SetPackage(packageName);
}
else
{
serviceIntent.AddFlags(ActivityFlags.NewTask);
}
context.StartService(serviceIntent);


5.サンプルコード

ソースコードを以下のURLにアップしてありますので、ご参考ください。
http://file.blog.fc2.com/itblogdsi/download/samplesource/xamarin/BootReceiverTest.zip


参考URL
http://www.jsucupira.com/2015/06/09/android-start-service-on-bootup/


今回の方法ではサービス単体で起動しており、再起動するプログラムにしていますので、Killしてもサービスは動作し続けます。



当ブログの内容をまとめた 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

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