一般的に、起動されると、ほとんどのアプリは実行されていない状態です。
Androidは起動が完了したら、 ACTION_BOOT_COMPLETED
インテントを渡して、アプリが実行されるようにします。
アプリは、このインテントを受けて、いくつかのタスクを処理することができます。
この記事では、 ACTION_BOOT_COMPLETED
インテントを受信する方法をご紹介します。
この記事で紹介されたSample AppはGitHub - StartForegroundServiceで確認することができます。 この記事の例では、Kotlinで作成されました。
権限の設定
Appが ACTION_BOOT_COMPLETED
インテントを受信するには、次のようにRECEIVE_BOOT_COMPLETED
権限をAndroidManifestに宣言する必要があります。
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application ...>
...
</application>
BroadcastReceiverを実装
イベントを半分ウリョミョンReceiverクラスを実装し、そのクラスをAndroidManifestに定義する必要があります。
起動すると、アプリが実行されていないとき、 Context.registerReceiver()
APIでレシーバを登録することができないからです。
次のようにReceiverクラスを生成します。
class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("Test", "Receive : ${intent.action}")
// Do something
}
}
そして、次のようにAndroidManifestにレシーバを定義します。
インテントを受信するために受信機のインテントフィルタに BOOT_COMPLETED
Actionを追加する必要があります。
<application ... >
...
<receiver android:name=".MyReceiver">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
今アプリをインストールして、デバイスを再起動すると、 BOOT_COMPLETED
がアプリに渡されることを確認することができます。
12-24 11:35:00.574 15143 15143 D Test : Receive : android.intent.action.BOOT_COMPLETED
サービスの実行
BOOT_COMPLETED
インテントを受けて、私のアプリのサービスを実行してどのような操作を処理することができます。
サービスの実装
まず、次のようにServiceを実装します。
class MyService : Service() {
companion object {
const val NOTIFICATION_ID = 10
const val CHANNEL_ID = "my_notification_channel"
}
override fun onCreate() {
super.onCreate()
Log.d("Test", "MyService is started")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel()
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("MyService is running")
.setContentText("MyService is running")
.build()
startForeground(NOTIFICATION_ID, notification)
}
}
private fun createNotificationChannel() {
val notificationChannel = NotificationChannel(
CHANNEL_ID,
"MyApp notification",
NotificationManager.IMPORTANCE_HIGH
)
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.RED
notificationChannel.enableVibration(true)
notificationChannel.description = "AppApp Tests"
val notificationManager = applicationContext.getSystemService(
Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(
notificationChannel)
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}
Android O(API 26)からBackground service実行が制限されてForegroundで実行する必要があります。
startForegroundService()
でサービスをForegroundに実行させることができます。しかし、サービスは5秒以内に startForeground()
を呼び出してNotificationにサービスがForegroundに実行中であることをユーザーに通知します。そうでなければ、システムは、サービスを終了させます。
そのため、上記のコードでNotificaiton ChannelとNotificaitonを作成しました。
注意すべき点は、上記のコードでは、次のように startForeground()
を呼び出すし、Channel IDを引数として渡したが、Channel IDは0以外の数値が渡されます。 0を渡すと、動作がされていません。
startForeground(NOTIFICATION_ID, notification)
Manifestにパーミッションとサービスの登録
次のようにAndroidManifestにサービスを定義して FOREGROUND_SERVICE
パーミッションを追加する必要があります。
FOREGROUND_SERVICE
はForegroundでサービスを実行させるために必要な権限です。
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application>
...
<service android:name=".MyService" />
</application>
レシーバでサービスを実行
次に、Receiverでインテントを受けた時のサービスを実行するように実装します。
class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("Test", "Receive : ${intent.action}")
val intent = Intent(context, MyService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}
}
}
上記のようにAndroid O(API 26)からBackground Serviceの実行を提案しています。
API 26以上では startForegroundService()
でサービスをForegroundで実行する必要があります。
テスト
上記のように実装したら、アプリをインストールして、デバイスを再起動してみてください。
起動後少し待てばReceiverで BOOT_COMPLETED
が伝達され、Foregroundでサービスが実行されることを確認することができます。
12-24 13:04:58.044 3793 3793 D Test : Receive : android.intent.action.BOOT_COMPLETED
12-24 13:04:58.054 3793 3793 D Test : MyService is started
Troubleshooting
FOREGROUND_SERVICE
権限をアプリに追加しない場合は、次のようなエラーでアプリが終了します。
12-24 12:58:32.783 3688 3688 E AndroidRuntime: FATAL EXCEPTION: main
12-24 12:58:32.783 3688 3688 E AndroidRuntime: Process: com.example.app, PID: 3688
12-24 12:58:32.783 3688 3688 E AndroidRuntime: java.lang.RuntimeException: Unable to create service com.example.example.MyService: java.lang.SecurityException: Permission Denial: startForeground from pid=3688, uid=10153 requires android.permission.FOREGROUND_SERVICE
startForegroundService()
の呼び出し後、実行されたサービスで、5秒以内に startForeground()
を呼び出していない場合、システムによってサービスが終了します。
12-24 11:53:19.793 504 530 W ActivityManager: Bringing down service while still waiting for start foreground: ServiceRecord{21733d5 u0 com.example.app/.MyService}
12-24 11:53:19.912 504 3971 I ActivityManager: Crashing app skipping ANR: ProcessRecord{1bdf9c0 3660:com.example.app/u0a153} Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{21733d5 u0 com.example.app/.MyService}
参考
Related Posts
- Android - FusedLocationProviderClientに位置情報を取得する
- Android - GPS、Network位置情報を取得する(LocationManager)
- Android - adbコマンドでActivity実行
- アンドロイド - MediaStoreにメディアファイルを保存する方法
- Android - Runtime permissionリクエスト方法と例(kotlin)
- Android11 - Storage(ストレージ)の変更まとめ
- Jetpack Compose - RowとColumn
- Android 13 - 細かいメディアファイルの権限
- Android 13でNotification権限をリクエスト、通知を表示する
- エラー解決:android gradle plugin requires java 11 to run. you are currently using java 1.8.
- Query method parameters should either be a type that can be converted into a database column or a List
- Android - TabLayoutの実装方法(+ ViewPager2)
- Android - adbコマンドで特定のパッケージのプロセスの終了
- Android - adb push、pullでファイルのコピー、ダウンロード
- Android - adbコマンドでsettings value確認、変更、
- Android 12 - IntentFilterのexported明示的な宣言
- Android - adb logcatコマンドでログ出力
- Android - ACTION_BOOT_COMPLETEDイベント受信
- Android - Foreground Service実行
- Android - ファイル入出力の例(Read、Write、内部、外部ストレージ)
- Android - アプリの権限を確認(Permission check)
- Android - adbで実行中のプロセス、スレッドリスト及びメモリ情報の確認
- Android - Broadcast Receiver登録およびイベントの受信方法
- Android - Cleartext HTTP ... not permitted例外解決方法
- Androidのビルドエラー - Calls to Java default methods are prohibited in JVM target 1.6
- アンドロイド - Assetsでファイルを読み取る方法
- アンドロイドのさまざまなNotification種類と実装方法
- アンドロイド - INSTALL_FAILED_TEST_ONLYエラー解決方法
- Android EspressoのCustom Matcher実装方法
- Android Espressoを使用してUIをテストする方法(3)
- アンドロイド - CTS hostsideをgradleで構築する方法
- Androidのアプリのデータフォルダーのパスと内部/外部ストレージ説明
- アンドロイド - 最初のApp作成
- Androidをインストールする方法(Windows)