
#開発環境
Visual Studio 2017 Community 15.9.4
Xamarin.Forms 3.4.0.1009999
Xamarin.Forms.GoogleMaps 3.0.4
Xam.Plugin.Geolocator 4.5.0.6
#やりたいこと
Xamarin.Formsを用い、Androidアプリを開発しています。
常に位置情報を送りたいので、サービスを実装したいのですが上手く動いてくれません。
AndroidでOS起動時に自動実行するバックグラウンドサービスの作成方法
バックグラウンドサービスからDependencyServiceをコールする方法
上記リンクを参考に実装したのですが、情報が古いのでしょうか?
AndroidのバージョンはLolipop以降を想定しています。
今後iOSにも対応する予定の為、一部DependencyService等を使用しています。
上記リンク先にあったサンプルコードを実行してみましたが動作しませんでした。
#コード
実際に実装したコードは以下になります。
######BackgroundService.cs
C#
1namespace App.Droid 2{ 3 [Service(Name = "com.CompanyName.App.BackgroundService", Exported =true, Process =":Process")] 4 public class BackgroundService : Service 5 { 6 public override IBinder OnBind(Intent intent) 7 { 8 return null; 9 } 10 11 [return: GeneratedEnum] 12 public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId) 13 { 14 // Oreo対応 15 if (Build.VERSION.SdkInt >= BuildVersionCodes.O) 16 { 17 this.RegisterForegroundService(); 18 } 19 20 Thread t = new Thread(() => 21 { 22 var bundle = new Bundle(); 23 global::Xamarin.Forms.Forms.Init(this, bundle); 24 25 App.BackgroundThread.Main(); 26 }); 27 t.Start(); 28 29 return StartCommandResult.Sticky; 30 } 31 32 void RegisterForegroundService() 33 { 34 var notification = new Notification.Builder(this) 35 .SetContentTitle("アプリ") 36 .SetContentText("Start ForegroundService") 37 .SetSmallIcon(Resource.Mipmap.icon) // Android7.0対応 38 .SetColor(ActivityCompat.GetColor(Android.App.Application.Context, Resource.Color.notification_color)) // Android7.0対応 39 .SetOngoing(true) 40 .Build(); 41 42 this.StartForeground(99999, notification); 43 } 44 45 public void StartBackgroundService() 46 { 47 Intent serviceIntent = new Intent(this, typeof(BackgroundService)); 48 49 // Lollipop対応 50 if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop && 51 Build.VERSION.SdkInt <= BuildVersionCodes.LollipopMr1) 52 { 53 string packageName = this.PackageManager.GetPackageInfo(this.PackageName, 0).PackageName; 54 serviceIntent.SetPackage(packageName); 55 } 56 else 57 { 58 serviceIntent.AddFlags(ActivityFlags.NewTask); 59 } 60 61 base.StartService(serviceIntent); 62 } 63 64 public override void OnDestroy() 65 { 66 base.OnDestroy(); 67 this.StartBackgroundService(); 68 } 69 } 70}
######BootReceiver.cs
C#
1namespace App.Droid 2{ 3 [BroadcastReceiver] 4 [IntentFilter(new[] { Intent.ActionBootCompleted, 5 "android.intent.action.QUICKBOOT_POWERON", 6 "com.htc.intent.action.QUICKBOOT_POWERON", 7 "android.intent.action.PACKAGE_INSTALL", 8 "android.intent.action.PACKAGE_ADDED", 9 Intent.ActionMyPackageReplaced 10 })] 11 public class BootReceiver : BroadcastReceiver 12 { 13 public BootReceiver() : base() 14 { 15 } 16 17 public override void OnReceive(Context context, Intent intent) 18 { 19 Intent serviceIntent = new Intent(context, typeof(BackgroundService)); 20 21 // Lollipop対応 22 if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop && 23 Build.VERSION.SdkInt <= BuildVersionCodes.LollipopMr1) 24 { 25 string packageName = context.PackageManager.GetPackageInfo(context.PackageName, 0).PackageName; 26 serviceIntent.SetPackage(packageName); 27 serviceIntent.SetClassName(context, packageName + ".BackgroundService"); 28 } 29 else 30 { 31 serviceIntent.AddFlags(ActivityFlags.NewTask); 32 } 33 34 // Oreo対応 35 if (Build.VERSION.SdkInt >= BuildVersionCodes.O) 36 { 37 context.StartForegroundService(serviceIntent); 38 } 39 else 40 { 41 context.StartService(serviceIntent); 42 } 43 } 44 } 45}
######BackgroundThread.cs
C#
1namespace App 2{ 3 public static class BackgroundThread 4 { 5 public static async void Main() 6 { 7 DependencyService.Get<INotificationService>().Regist(); 8 DependencyService.Get<ILocationService>().Initialize(); 9 DependencyService.Get<ILocationService>().OnLocationChanged += new OnLocationChangedDelegate(GlobalClass.Instance.LocationChanged); 10 DependencyService.Get<ILocationService>().OnLocationError += new OnLocationErrorDelegate(GlobalClass.Instance.LocationError); 11 DependencyService.Get<ILocationService>().StartListening(10000, 10, true); 12 13 while (true) 14 { 15 Plugin.Geolocator.Abstractions.Position pos = await DependencyService.Get<ILocationService>().GetPositionAsync(1000); 16 17 // 送信処理 18 Communication.AddParam("Command", "pos"); 19 Communication.AddParam("Lat", pos.Latitude.ToString()); 20 Communication.AddParam("Lng", pos.Longitude.ToString()); 21 string response = await Communication.Send(); 22 23 DependencyService.Get<INotificationService>().On("通信結果", response); 24 25 await Task.Delay(30000); 26 } 27 } 28 } 29}
#試したこと
AndroidManifesto.xmlに以下の行を追加しました。
XML
1<application android:label="App.Droid"> 2 <service android:name="com.CompanyName.App.BackgroundService"/> 3 <receiver android:name="com.CompanyName.App.BootReceiver"> 4 <intent-filter> 5 <action android:name="android.intent.action.BOOT_COMPLETED"/> 6 <action android:name="android.intent.action.QUICKBOOT_POWERON"/> 7 <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/> 8 <action android:name="android.intent.action.PACKAGE_INSTALL"/> 9 <action android:name="android.intent.action.PACKAGE_ADDED"/> 10 <action android:name="android.intent.action.MY_PACKGE_REPLACED"/> 11 </intent-filter> 12 </receiver> 13</application>
しかし動きませんでした。
1度位置情報の取得、送信部分のコードを削除し、それぞれの関数の1行目にConsole.WriteLineを追加し、出力を見てみました。
Console.WriteLine("OnStartCommand");
Console.WriteLine("RegisterForegroundService");
Console.WriteLine("StartBackgroundService");
Console.WriteLine("OnDestroy");
Console.WriteLine("OnReceive");
Console.WriteLine("Main");
「BackgroundThread.cs」のwhile文の中に下記行を追加しました。
Console.WriteLine("Main While");
結果としていずれも出力されませんでした。
その後、「MainActivity.cs」に下記の行を追加しました。
StartService(new Intent(this, typeof(BackgroundService)));
結果は「OnStartCommand」、「Main」、「Main While」のみ出力されました。
タスクをキルすると「Main While」の出力が止まってしまうため、目的とする動作ではありません。
どうすれば常にタスクを維持出来るでしょうか。
また、起動した瞬間やアプリを入れ替えた瞬間に動作を開始させたいのですが「BootReceiver.cs」の処理に入ってきません。

回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2019/01/11 06:51