実現したいこと
前提
アプリ開発初心者です
Androidアプリ開発の教科書という参考書の第13章
バックグラウンド処理と通知機能というテーマの課題に取り組んでいる
開発環境
win11
Android Studio Giraffe | 2022.3.1 Patch 3
発生している問題・エラーメッセージ
Call requires permission which may be rejected by user: code should explicitly check to see if permission is available (with checkPermission) or explicitly handle a potential SecurityException //通知 manager.notify(100,notification) SoundManageServiceの上記コードに常に赤線 マニフェスト文が反映されてない?と思いました
該当のソースコード
SoundManageService.kt
1package com.example.servicesample 2 3import android.app.Notification 4import android.app.NotificationChannel 5import android.app.NotificationManager 6import android.app.Service 7import android.content.Context 8import android.content.Intent 9import android.content.pm.PackageManager 10import android.media.MediaPlayer 11import android.net.Uri 12import android.os.IBinder 13import androidx.core.app.ActivityCompat 14import androidx.core.app.NotificationCompat 15import androidx.core.app.NotificationManagerCompat 16import androidx.core.content.ContextCompat 17 18class SoundManageService : Service() { 19 companion object{ 20 //通知チャネルID文字列定数 21 private const val CHANNEL_ID = "soundmanagerservice_notification_channel" 22 } 23 override fun onBind(intent: Intent): IBinder { 24 TODO("Return the communication channel to the service.") 25 } 26 //メディアプレーヤープロパティ 27 private var _player: MediaPlayer? = null 28 29 override fun onCreate() { 30 //プロパティのメディアプレーヤーオブジェクトを生成 31 _player = MediaPlayer() 32 //通知チャネル名をstring.xmlから取得 33 val name = getString(R.string.notification_channel_name) 34 //通知チャネルの重要度を標準に設定 35 val importance = NotificationManager.IMPORTANCE_DEFAULT 36 //通知チャネルを生成 37 val channel = NotificationChannel(CHANNEL_ID, name, importance) 38 //NotificationManagerオブジェクトを取得 39 val manager = getSystemService(NotificationManager::class.java) 40 //通知チャネルを設定 41 manager.createNotificationChannel(channel) 42 } 43 44 override fun onStartCommand(intent: Intent,flags: Int,startId: Int): Int{ 45 //音声ファイルのURI文字列を生成 46 val mediaFileUriStr = "android.resource://${packageName}/${R.raw.keiryu}" 47 //音声ファイルのURI文字列をもとにURIオブジェクトを生成 48 val mediaFileUri = Uri.parse(mediaFileUriStr) 49 //プロパティのプレーヤーがnullじゃなかったら 50 _player?.let{ 51 //メディアプレーヤーに音声ファイルを指定 52 it.setDataSource(this@SoundManageService,mediaFileUri) 53 //非同期でのメディア再生準備が完了した際のリスナの設定 54 it.setOnPreparedListener(PlayerPreparedListener()) 55 //メディア再生が終了した際のリスナを設定 56 it.setOnCompletionListener(PlayerCompletionListener()) 57 //非同期でメディア再生を準備 58 it.prepareAsync() 59 } 60 61 //定数を返す 62 return START_NOT_STICKY 63 } 64 65 override fun onDestroy() { 66 //プロパティのプレーヤーがnullじゃなかったら 67 _player?.let{ 68 //プレーヤーが再生中なら 69 if(it.isPlaying){ 70 //プレーヤーを停止 71 it.stop() 72 } 73 //プレーヤーを解放 74 it.release() 75 } 76 } 77 //メディア再生準備が完了したときのリスナクラス 78 private inner class PlayerPreparedListener : MediaPlayer.OnPreparedListener{ 79 override fun onPrepared(mp: MediaPlayer) { 80 //メディアを再生 81 mp.start() 82 } 83 } 84 //メディア再生が終了したときのリスナクラス 85 private inner class PlayerCompletionListener : MediaPlayer.OnCompletionListener{ 86 override fun onCompletion(mp: MediaPlayer) { 87 //Notificationを作成するBuilderクラス生成 88 val builder = NotificationCompat.Builder(this@SoundManageService, CHANNEL_ID) 89 //通知エリアに表示されるアイコンを設定 90 builder.setSmallIcon(android.R.drawable.ic_dialog_info) 91 //通知ドロワーでの表示タイトルを設定 92 builder.setContentTitle(getString(R.string.msg_notification_title_finish)) 93 //通知ドロワーでの表示メッセージを設定 94 builder.setContentText(getString(R.string.msg_notification_text_finish)) 95 //BuilderからNotificationオブジェクトを生成 96 val notification = builder.build() 97 //NotificationManagerCompatオブジェクトを取得 98 val manager = NotificationManagerCompat.from(this@SoundManageService) 99 //通知 100 manager.notify(100,notification) 101 //自分自身を終了 102 stopSelf() 103 } 104 } 105}
AndroidManifest.xml
1<?xml version="1.0" encoding="utf-8"?> 2<manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:tools="http://schemas.android.com/tools"> 4 5 <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> 6 7 <application 8 android:allowBackup="true" 9 android:dataExtractionRules="@xml/data_extraction_rules" 10 android:fullBackupContent="@xml/backup_rules" 11 android:icon="@mipmap/ic_launcher" 12 android:label="@string/app_name" 13 android:roundIcon="@mipmap/ic_launcher_round" 14 android:supportsRtl="true" 15 android:theme="@style/Theme.ServiceSample" 16 tools:targetApi="31"> 17 18 <service 19 android:name=".SoundManageService" 20 android:enabled="true" 21 android:exported="false"></service> 22 23 <activity 24 android:name=".MainActivity" 25 android:exported="true"> 26 <intent-filter> 27 <action android:name="android.intent.action.MAIN" /> 28 29 <category android:name="android.intent.category.LAUNCHER" /> 30 </intent-filter> 31 </activity> 32 </application> 33 34</manifest>
MainActivity.kt
1package com.example.servicesample 2 3import android.content.Intent 4import androidx.appcompat.app.AppCompatActivity 5import android.os.Bundle 6import android.view.View 7import android.widget.Button 8 9class MainActivity : AppCompatActivity() { 10 override fun onCreate(savedInstanceState: Bundle?) { 11 super.onCreate(savedInstanceState) 12 setContentView(R.layout.activity_main) 13 } 14 15 fun onPlayButtonClick(view: View){ 16 //インテントオブジェクトを生成 17 val intent = Intent(this@MainActivity,SoundManageService::class.java) 18 //サービスを起動 19 startService(intent) 20 //再生ボタンをタップ不可に、停止ボタンをタップ可に変更 21 val btPlay = findViewById<Button>(R.id.btPlay) 22 val btStop = findViewById<Button>(R.id.btStop) 23 btPlay.isEnabled = false 24 btStop.isEnabled = true 25 } 26 fun onStopButtonClick(view: View){ 27 //インテントオブジェクトを生成 28 val intent = Intent(this@MainActivity,SoundManageService::class.java) 29 //サービスを起動 30 stopService(intent) 31 //再生ボタンをタップ不可に、停止ボタンをタップ可に変更 32 val btPlay = findViewById<Button>(R.id.btPlay) 33 val btStop = findViewById<Button>(R.id.btStop) 34 btPlay.isEnabled = true 35 btStop.isEnabled = false 36 } 37 38}
試したこと
logcatで見てみてもわからず、誤字脱字等も確認した
またパーミッションの判定処理も試してみたが、うまくいかなかった
0 コメント