[Android] Oreo、Pieで端末起動時にServiceを起動する方法 

2019年4月時点での情報をメモしておきます。

今回はKotlinを使って記述します。

 

目的

端末の起動時に連動させてServiceを起動させたい。

対象

下記のバージョンで動作を確認済

Android 8.0 (Oreo)

Android 9.0 (Pie)

結論

"ACTION_LOCKED_BOOT_COMPLETED"インテントを受信するBroadcastReceiverを実装して、受信したときの処理の中でServiceを起動する。

ServiceはForegroundServiceで実装しなければならない。

 

【参考】

 

サンプル

MainActivity.kt

class MainActivity : AppCompatActivity() {
 override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
 }
}

 

MyBroadcastReceiver.kt

今回はついでに暗黙的インテントを受信してみました。

class MyBroadcastReceiver : BroadcastReceiver() {
 override fun onReceive(context: Context?, intent: Intent?) {

  when (intent?.action) {
   // 端末起動時に送信されるインテント
   Intent.ACTION_LOCKED_BOOT_COMPLETED -> {
    val startService = Intent(context?.applicationContext, MyForegroundService::class.java)

    // Context.startForegroundService()を使ってServiceを起動する
    context?.startForegroundService(startService)
   }

   // ロック解除時のインテント
   Intent.ACTION_USER_PRESENT -> {
    println("ロックを解除しました")
   }
  }
 }
}

 

MyForegroundService.kt

暗黙的インテントを受信できるようにレシーバーを登録してみました。

class MyForegroundService : Service() {
 // 初期化を遅延できる
 lateinit var mReceiver: BroadcastReceiver

 override fun onCreate() {
  super.onCreate()

  // 暗黙的インテントを受け取るレシーバーを登録する
  mReceiver = MyBroadcastReceiver()
  val filter = IntentFilter()
  // ロック解除時のインテント
  filter.addAction(Intent.ACTION_USER_PRESENT)
  registerReceiver(mReceiver, filter)
 }

 override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
  super.onStartCommand(intent, flags, startId)

  //通知の設定をする。今回はお試しなので雑です。
  val notification = Notification.Builder(this,"channelId")
                     .setContentTitle(applicationContext.getString(R.string.app_name))
                     .build()
  val channel = NotificationChannel("channelId","channelName",NotificationManager.IMPORTANCE_DEFAULT)
  channel.description = "description"

  val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
  notificationManager.createNotificationChannel(channel)

  startForeground(1, notification)

  return START_STICKY
 }

 override fun onBind(intent: Intent?): IBinder? {
  return null
 }

 override fun onDestroy() {
  super.onDestroy()
  // レシーバーを解除する
  unregisterReceiver(mReceiver)
 }
}

 

AndroidManifest.xml

permissionを追加する

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- Android 9.0(Pie)から必要 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

BroadcastReceiverとServiceを登録する

<receiver
 android:name=".MyBroadcastReceiver"
 android:directBootAware="true">
  <intent-filter>
   <!-- 端末起動時のインテント -->
   <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
  </intent-filter>
</receiver>
<service
 android:name=".MyForegroundService"
 android:directBootAware="true">
</service>