Android 14でForeground Service起動時のMissingForegroundServiceTypeException解決方法
問題
Android 13以前では正常に動作していたForeground Serviceが、Android 14環境で実行されると以下のエラーが発生します:
android.app.MissingForegroundServiceTypeException: Starting FGS without a type
at android.app.MissingForegroundServiceTypeException$1.createFromParcel
この問題は、コードAでstartForeground()
を呼び出しているService実装で発生します。具体的には:
startForeground(125, notification)
Android 14におけるForeground Serviceの要件変更が原因で発生します。以降の解決方法を適用しない場合、アプリはAndroid 14デバイス上でクラッシュを引き起こします。
原因:Android 14のForeground Serviceタイプ要件
Android 14(APIレベル34)から、すべてのForeground Serviceで具体的な実行タイプの指定が必須になりました(公式ドキュメント)。これにより:
- マニフェストに
foregroundServiceType
属性の宣言が必要 - サービス起動時に
FOREGROUND_SERVICE_TYPE_xxx
フラグの指定が必要 - 必要な権限(
FOREGROUND_SERVICE_xxx
)の追加が必要
以下で具体的な修正手順を説明します。
解決方法
Step 1: マニフェストの更新
AndroidManifest.xml
に以下を追加します:
<!-- 必要なパーミッションの宣言 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<application>
<!-- 対象のService定義を更新 -->
<service
android:name=".YourForegroundService"
android:foregroundServiceType="specialUse"
android:exported="false" />
</application>
タイプの選択
foregroundServiceType
にはサービスの用途に合わせた値を指定します。主要なタイプ:
タイプ値 | 用途例 |
---|---|
dataSync | データ同期サービス |
mediaPlayback | 音楽再生サービス |
phoneCall | VoIP関連サービス |
location | 位置情報追跡サービス |
health | ヘルスケア関連サービス |
specialUse | 特定用途(デフォルト代替) |
Step 2: サービス起動コードの修正
Kotlin実装を以下のように修正します:
private fun startForegroundService() {
// ... 既存のチャンネル/通知設定コード ...
val notification = builder.build()
// Android 14以上でタイプ指定
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startForeground(
SERVICE_ID,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
} else {
// Android 13以前の互換処理
startForeground(SERVICE_ID, notification)
}
}
補足ケース:.NET MAUI の場合
.NET MAUIを利用している場合、サービスクラスに属性を指定します:
[Service(
ForegroundServiceType =
global::Android.Content.PM.ForegroundService.TypeLocation
)]
public class AndroidLocationService : Service
{
// サービスの実装...
}
重要事項
タイプと権限の整合性
マニフェストのforegroundServiceType
値とstartForeground()
に渡すタイプ定数は一致させる必要がありますminSdVersionの指定(オプション)
権限宣言時にminSdkVersion
を指定することで、古いOSでの権限要求を回避できます:xml<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" android:minSdkVersion="34" />
ユーザーへの説明義務
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
など一部のタイプは、Play Consoleでのポリシー説明が必要です
完全な修正コードサンプル
Android 14対応済みのサービス実装例:
companion object {
private const val SERVICE_ID = 125
private const val CHANNEL_ID = "foreground_channel"
}
private fun startForegroundService() {
// 通知チャンネル作成 (全バージョン共通)
val channel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel(
CHANNEL_ID,
getString(R.string.app_name),
NotificationManager.IMPORTANCE_LOW
).apply {
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
}
} else null
(getSystemService(NOTIFICATION_SERVICE) as NotificationManager)
?.createNotificationChannel(channel)
// 通知ビルダー
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notify_icon)
.setContentTitle(getString(R.string.notificationTitle))
.setContentText(getString(R.string.notificationContent))
.setPriority(NotificationCompat.PRIORITY_LOW)
// PendingIntent設定
val intent = Intent(this, ActivityMain::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
}
val pendingIntent = PendingIntent.getActivity(
this, 0, intent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
builder.setContentIntent(pendingIntent)
val notification = builder.build()
// Android 14以上でタイプ指定
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startForeground(
SERVICE_ID,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
} else {
startForeground(SERVICE_ID, notification)
}
}
適切なForegroundServiceTypeの選択基準
specialUse
は一般的なフォールバックですが、アプリの機能に適したタイプを選択してください:
位置情報サービスの場合
kotlinServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION
xml<service android:name=".LocationService" android:foregroundServiceType="location" />
メディア再生の場合
kotlinServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
xml<service android:name=".MediaPlaybackService" android:foregroundServiceType="mediaPlayback" />
注意
- 位置情報タイプの制限:
タイプlocation
を使用する場合、追加でACCESS_FINE_LOCATION
権限が必要 - ユーザー可視性:
ユーザーは設定画面でアプリが使用しているFGSタイプを確認できます specialUse
使用時の制約:
特定のユースケースに該当しない場合にのみ使用すべきで、audio
/location
など既存タイプに適合する場合は厳格なタイプを選択
これらの修正により、Android 14環境でForeground Serviceを正常に実行できるようになります。アプリのターゲットSDKを34に更新する際は、この対応が必須となります。