[Android] Oreo、Pieで端末起動時にServiceを起動する方法
2019年4月時点での情報をメモしておきます。
今回はKotlinを使って記述します。
目的
端末の起動時に連動させてServiceを起動させたい。
対象
下記のバージョンで動作を確認済
Android 8.0 (Oreo)
Android 9.0 (Pie)
結論
"ACTION_LOCKED_BOOT_COMPLETED"インテントを受信するBroadcastReceiverを実装して、受信したときの処理の中でServiceを起動する。
ServiceはForegroundServiceで実装しなければならない。
【参考】
- ダイレクトブートのサポート … 端末起動時について
- バックグラウンド実行制限 … Service、Broadcastの制限事項について
- 通知チャネルの作成と管理 … 通知について
- Android 9.0 動作の変更点 … ForegroundServiceを実行するのに必要なパーミッションについて
- 既存のAndroidアプリのAndroid 9.0互換性確認方法 … Android 9.0での互換性確認について
サンプル
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>