Skip to content

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実装で発生します。具体的には:

kotlin
startForeground(125, notification)

Android 14におけるForeground Serviceの要件変更が原因で発生します。以降の解決方法を適用しない場合、アプリはAndroid 14デバイス上でクラッシュを引き起こします。

原因:Android 14のForeground Serviceタイプ要件

Android 14(APIレベル34)から、すべてのForeground Serviceで具体的な実行タイプの指定が必須になりました(公式ドキュメント)。これにより:

  1. マニフェストにforegroundServiceType属性の宣言が必要
  2. サービス起動時にFOREGROUND_SERVICE_TYPE_xxxフラグの指定が必要
  3. 必要な権限(FOREGROUND_SERVICE_xxx)の追加が必要

以下で具体的な修正手順を説明します。

解決方法

Step 1: マニフェストの更新

AndroidManifest.xmlに以下を追加します:

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音楽再生サービス
phoneCallVoIP関連サービス
location位置情報追跡サービス
healthヘルスケア関連サービス
specialUse特定用途(デフォルト代替)

Step 2: サービス起動コードの修正

Kotlin実装を以下のように修正します:

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を利用している場合、サービスクラスに属性を指定します:

csharp
[Service(
    ForegroundServiceType = 
        global::Android.Content.PM.ForegroundService.TypeLocation
)]
public class AndroidLocationService : Service
{
    // サービスの実装...
}

重要事項

  1. タイプと権限の整合性
    マニフェストのforegroundServiceType値とstartForeground()に渡すタイプ定数は一致させる必要があります

  2. minSdVersionの指定(オプション)
    権限宣言時にminSdkVersionを指定することで、古いOSでの権限要求を回避できます:

    xml
    <uses-permission 
        android:name="android.permission.FOREGROUND_SERVICE_LOCATION"
        android:minSdkVersion="34" />
  3. ユーザーへの説明義務
    FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACKなど一部のタイプは、Play Consoleでのポリシー説明が必要です

完全な修正コードサンプル

Android 14対応済みのサービス実装例:

kotlin
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は一般的なフォールバックですが、アプリの機能に適したタイプを選択してください:

  1. 位置情報サービスの場合

    kotlin
    ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION
    xml
    <service
        android:name=".LocationService"
        android:foregroundServiceType="location" />
  2. メディア再生の場合

    kotlin
    ServiceInfo.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に更新する際は、この対応が必須となります。