Androidアプリ開発

Android14対応
(フォアグラウンドサービスタイプは必須)

この記事は約16分で読めます。
記事内に広告が含まれています。
スポンサーリンク

この記事は Androidスマホ用のアプリ開発の中で、
今後の開発で再使用性が高いと思われるコーディングをまとめたものです。
Java での開発経験、XML構文規則、Android のアプリ開発経験がある方を対象としています。
Android のアプリ開発でお役にたててれば、嬉しいです。
(これから Android のアプリ開発や Java での開発を始めたい方への案内は、
記事の最後で紹介します)

この記事のテーマ


Android14のコア機能の変更「フォアグラウンドサービスタイプは必須」に対応する

<strong>重要ポイント</strong>
重要ポイント

マニフェストファイルにフォアグラウンドサービスタイプの宣言を追加する場合、

Google Play Consoleからフォアグラウンドサービスタイプの申告が必要になりました。

権限の使用を申告していない、間違って申告している場合、ポリシー違反でリリースが否認されます。

ポイント

Android14でコア機能にいくつか変更がありました。
そのひとつが「フォアグラウンドサービスタイプは必須」です。
対応していないアプリは、フォアグラウンドサービスを起動したときに
アプリが落ちます
今回は、「フォアグラウンドサービスタイプは必須」の対応方法について、紹介します。

Android14の機能と変更点のリスト

フォアグラウンドサービスタイプは必須

フォアグラウンドサービスの起動

フォアグラウンドサービスは通知を表示することで、ユーザが起動していることを認識できるサービスです。

フォアグラウンドサービスタイプの宣言

マニフェストファイル(AndroidManifest.xml)にアプリから起動するフォアグラウンドサービスの使用をリクエストする権限を宣言します。
また、起動するフォアグラウンドサービスのタイプを要素内に新しく追加された
foregroundServiceTypeに定義します。
サンプルでは、タイプとして位置情報の権限をリクエスト、
foregroundServiceTypeを定義しています。

    …
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    …
    <service android:name=".TodoService"
        android:foregroundServiceType="location"/>
    …

選択可能なフォアグラウンドサービスタイプ、マニフェスト ファイルで宣言する必要がある権限は、公式サイトのフォアグラウンドサービスタイプは必須で確認できます。

マニフェストファイルにフォアグラウンドサービスタイプの宣言を追加する場合、Google Play Consoleからフォアグラウンドサービスの情報を申告が必要になりました。
申告では、使用するフォアグラウンドサービス機能がわかる
動画のリンクが必要になります。
動画では、ユーザーがその機能を使用するために、アプリで行う手順を示す必要があります。

Google Play Consoleアプリのコンテンツで、使用するフォアグラウンドサービスタイプを申告します。

フォアグラウンドサービスを使う手順をアプリで操作している動画をYoutubeに限定公開でアップロードします

実行時にフォアグラウンドサービスタイプを含める

Android14から、指定が必要なフォアグラウンドサービスは開始時にフォアグランドサービスタイプの指定が必須になりました。
Android10から、フォアグラウンドサービスタイプが指定できるようになりましたので、startForegroundの実行は OSバージョンの判断が必要です。
サンプルは音楽を再生するサービスのため、
ExoPlayerを使用しています。
また、位置情報を使用するサービスでもあるため、サービス開始時にフォアグランドサービスタイプとして、
FOREGROUND_SERVICE_TYPE_LOCATIONを指定しています。

public class TodoService extends Service
        implements FusedLocationManager.OnLocationResultListener {
    private static final String     TAG = TodoService.class.getSimpleName();
    private static final int        REQUEST_CODE = 2023;
    private ExoPlayer               exoPlayer;
    private NotificationManager     notificationManager;
    private MediaSession            mediaSession;
    private androidx.media3.session.MediaStyleNotificationHelper.MediaStyle
                                    mediaStyle;
    private PendingIntent           pendingIntentList;
    …
    @Override
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
        …
        exoPlayer = new ExoPlayer.Builder(context)
                .setHandleAudioBecomingNoisy(true)
                .build();
        …
        mediaSession = new MediaSession.Builder(context, exoPlayer).build();
        …
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        …
        // mediaStyle
        mediaStyle = new MediaStyleNotificationHelper.MediaStyle(mediaSession);
        mediaStyle.setShowActionsInCompactView(0,1,2);
        // PendingIntentList
        pendingIntentList = PendingIntent.getActivity(context, REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE);
        // Notification
        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationChannel channel = new NotificationChannel(TAG, TAG, NotificationManager.IMPORTANCE_DEFAULT);
        channel.setDescription("Silent Notification");
        channel.setSound(null, null);
        channel.enableLights(false);
        channel.setLightColor(R.color.blue);
        channel.enableVibration(false);
        if (notificationManager != null) {
            notificationManager.createNotificationChannel(channel);
            Notification notification;
            if (intent.getIntExtra("MUSIC", 0) > 0)
                notification = new NotificationCompat.Builder(context, TAG)
                        .setContentTitle(context.getString(R.string.app_name))
                        .setContentText(TAG)
                        .setContentIntent(pendingIntentList)
                        .setWhen(System.currentTimeMillis())
                        .setSmallIcon(R.drawable.ic_timer)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.logo))
                        .setStyle(mediaStyle)
                        .addAction(new NotificationCompat.Action(R.drawable.ic_round_rwd, RWD, CustomMediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)))
                        .addAction(pause ? new NotificationCompat.Action(R.drawable.ic_round_play, PLAY, CustomMediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_PLAY)) :
                                new NotificationCompat.Action(R.drawable.ic_round_pause, PAUSE, CustomMediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_PAUSE)))
                        .addAction(new NotificationCompat.Action(R.drawable.ic_round_fwd, FWD, CustomMediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_SKIP_TO_NEXT)))
                        .build();
             else
                notification = new NotificationCompat.Builder(context, TAG)
                        .setContentTitle(context.getString(R.string.app_name))
                        .setContentText(TAG)
                        .setContentIntent(pendingIntentList)
                        .setWhen(System.currentTimeMillis())
                        .setSmallIcon(R.drawable.ic_timer)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.logo))
                        .setStyle(new androidx.media.app.NotificationCompat.MediaStyle())
                        .build();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                startForeground(ID, notification, FOREGROUND_SERVICE_TYPE_LOCATION);
            } else {
                startForeground(ID, notification);
            }
        }
        …

指定が必要なフォアグランドサービス
FOREGROUND_SERVICE_TYPE_CAMERA
FOREGROUND_SERVICE_TYPE_LOCATION
FOREGROUND_SERVICE_TYPE_MICROPHONE

サンプルにある R.string.app_name、R.drawable.ic_timer、R.drawable.ic_round_rwd、R.drawable.ic_round_play、R.drawable.ic_round_pause、R.drawable.ic_round_fwd については、リソースの strins.xml に定義、アイコンファイルを格納します。

ExoPlayerについては、ExoPlayerで動画や音楽を再生するで紹介しています。

通知については、Android13対応(実行時の通知権限)で紹介しています。

USDケーブルは規格によって、性能が全く違います。
急速充電・高速データ転送で選ぶならコレです♪

今回は、ここまでです。

フォアグラウンドサービスタイプは必須に対応している Androidアプリです。
アプリの中でフォアグラウンドサービスを起動しています。

誤字脱字、意味不明でわかりづらい、
もっと詳しく知りたいなどのご意見は、
このページの最後にある
コメントか、
こちらから、お願いいたします♪

ポチッとして頂けると、
次のコンテンツを作成する励みになります♪

ブログランキング・にほんブログ村へ

これからAndroidのアプリ開発やJavaでの開発を始めたい方へ

アプリケーション開発経験がない方や、アプリケーション開発経験がある方でも、Java や C# などのオブジェクト指向言語が初めての方は、Android のアプリ開発ができるようになるには、かなりの時間がかかります。オンラインスクールでの習得を、強くおススメします。

未経験者からシステムエ