質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

1回答

1241閲覧

動的にBroadcastReceiverを登録するとNotificationに設定したIntentをBroadcastRecevierで受け取れない

inzs

総合スコア17

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2023/03/11 19:05

編集2023/03/12 11:55

実現したいこと

動的に登録したBroadcastReceiverでNotificationに設定したIntentを受け取りたい

前提

最終的な目標として、Service内でループ処理を実行中にNotificationで進捗を表示して、キャンセルアクションをタップすることでループ処理を中止させることを考えています。

ですが今のところうまくいっておらず、原因の切り分けのために、もっとシンプルにBroadcastReceiverを動的に登録、Notification通知を行うだけのシンプルなアプリを作成しましたが、うまくいっておりません。

なお、AndroidManifest.xmlに静的に登録すると、正常に受信できることは確認しました。

しかし、今回は動的に登録したいと考えています。
できなければできないでも別に構わないのですが、Androidデベロッパーのページにも方法が書いてあるのにうまく動かない理由がわかりません。

なにか足りない処理があるのか、もしくはできない理由がわかればご教示ください。

発生している問題・エラーメッセージ

エラーは何も出ません

該当のソースコード

Kotlin

1class MainActivity : AppCompatActivity() { 2 companion object { 3 const val CHANNEL_ID = "a" 4 const val NOTIFICATION_ID = 1 5 const val ACTION_SNOOZE = "com.example.myapp.ACTION_SNOOZE" 6 const val CUSTOM_ACTION = "com.example.myapp.CUSTOM_ACTION" 7 } 8 private lateinit var receiver: MyBroadcastReceiver 9 10 fun createNotification(){ 11 val snoozeIntent = Intent(ACTION_SNOOZE, Uri.EMPTY,this,MyBroadcastReceiver::class.java) 12 val snoozePendingIntent: PendingIntent = 13 PendingIntent.getBroadcast(this, 0, snoozeIntent, 0) 14 15 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 16 val channel = 17 NotificationChannel(CHANNEL_ID, "チャンネル名", NotificationManager.IMPORTANCE_DEFAULT) 18 19 val notificationBuilder = NotificationCompat.Builder(applicationContext, CHANNEL_ID) 20 .setSmallIcon(R.drawable.ic_launcher_foreground) 21 .setContentTitle("My Notification") 22 .setContentText("This is a notification message.") 23 .addAction(R.drawable.ic_launcher_foreground, "タイトル", snoozePendingIntent) 24 25 26 val notificationManager = 27 getSystemService(Service.NOTIFICATION_SERVICE) as NotificationManager 28 notificationManager.createNotificationChannel(channel) 29 notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()) 30 } 31 } 32 33 override fun onCreate(savedInstanceState: Bundle?) { 34 super.onCreate(savedInstanceState) 35 setContentView(R.layout.activity_main) 36 37 val filter = IntentFilter().apply { 38 addAction(ACTION_SNOOZE) //NG 39 addAction(CUSTOM_ACTION) //OK 40 addAction(Intent.ACTION_SCREEN_OFF) //OK 41 addAction(Intent.ACTION_SCREEN_ON) //OK 42 } 43 44 // BroadcastReceiverを登録 45 receiver = MyBroadcastReceiver() 46 registerReceiver(receiver, filter) 47 48 // 通知を作成 49 createNotification() 50 51 //ボタンから独自アクションをsendBroadcast 52 val customIntent = Intent(CUSTOM_ACTION) 53 val buttonTest = findViewById<Button>(R.id.button_test) 54 buttonTest.setOnClickListener{ 55 sendBroadcast(customIntent) //OK 56 } 57 58 // ボタンから通知を作成 59 val buttonNotify = findViewById<Button>(R.id.button_notify) 60 buttonNotify.setOnClickListener{ 61 createNotification() //NG 62 } 63 } 64 65 override fun onDestroy() { 66 super.onDestroy() 67 unregisterReceiver(receiver) 68 69 } 70}

BroadcastReceiverには受信したIntentのactionをそのままログ出力するようにしています。

Kotlin

1class MyBroadcastReceiver : BroadcastReceiver() { 2 override fun onReceive(context: Context, intent: Intent) { 3 Log.d("tag",intent.action.toString()) 4 } 5}

build.gradle

1plugins { 2 id 'com.android.application' 3 id 'org.jetbrains.kotlin.android' 4} 5 6android { 7 namespace 'com.example.myapplication' 8 compileSdk 32 9 10 defaultConfig { 11 applicationId "com.example.myapplication" 12 minSdk 21 13 targetSdk 32 14 versionCode 1 15 versionName "1.0" 16 17 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 } 19 20 buildTypes { 21 release { 22 minifyEnabled false 23 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 } 25 } 26 compileOptions { 27 sourceCompatibility JavaVersion.VERSION_1_8 28 targetCompatibility JavaVersion.VERSION_1_8 29 } 30 kotlinOptions { 31 jvmTarget = '1.8' 32 } 33} 34 35dependencies { 36 37 implementation 'androidx.core:core-ktx:1.7.0' 38 implementation 'androidx.appcompat:appcompat:1.4.1' 39 implementation 'com.google.android.material:material:1.5.0' 40 implementation 'androidx.constraintlayout:constraintlayout:2.1.3' 41 testImplementation 'junit:junit:4.13.2' 42 androidTestImplementation 'androidx.test.ext:junit:1.1.5' 43 androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 44}

試したこと

・システムブロードキャストインテントは受信できることを確認しました。
試したのはACTION_SCREEN_OFFACTION_SCREEN_OFFで、実機の電源キーを押してディスプレイをON/OFFさせて確認しました。

・BroadcastReceiverの登録タイミングの問題かと思い、ボタンを押して任意のタイミングでsendBroadcastを送った時には受信できることを確認しました。

・sendBroadcastではなく、ボタンを押してNotificationを通知させてみましたが、こちらはActionをタップしても受信できませんでした。
※試したコードはsendBroadcastの部分をNotification関連のコードに置き換えただけです。

補足情報(FW/ツールのバージョンなど)

・確認中の端末は実機端末OPPO RENO A(Android 7)です。

以下のページを参照してサンプルを作成しています
通知を作成する | Android デベロッパー | Android developers
ブロードキャストの概要 | Android デベロッパー | Android developers
インテントとインテント フィルタ | Android デベロッパー | Android developers

追記(3/12)

よく考えたら「最終的な目的」であるServiceの進捗をキャンセルさせるというだけなら、BroadcastReceiverを介するほうが難してく、自身のServiceに向けてIntentを送ったほうが簡単に実現できることがわかりました。

ですが、疑問は疑問としてあるので質問はそのままにしておきます。

実際のアプリのService内のコード

Kotlin

1 val cancelActionIntent = Intent(this, DownloadService::class.java).apply { 2 action = ACTION_CANCEL 3 } 4 val cancelPendingIntent = 5 PendingIntent.getService(this, 0, cancelActionIntent, 0)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2023/03/12 06:52

>動的に登録したいと考えています。 >できなければできないでも別に構わないのですが、Androidデベロッパーのページにも方法が書いてある ちなみにどこに書いてあるでしょうか。
guest

回答1

0

ベストアンサー

通知からの呼び出しに使用されるインテントの定義

kotlin

1val snoozeIntent = Intent(ACTION_SNOOZE, Uri.EMPTY,this,MyBroadcastReceiver::class.java)

を、ボタンから直接呼出しに使用しているインテントの定義

kotlin

1val customIntent = Intent(CUSTOM_ACTION)

と同じ形にする

kotlin

1val snoozeIntent = Intent(ACTION_SNOOZE)

というのはどうでしょうか。

投稿2023/03/12 17:18

jimbe

総合スコア12648

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

inzs

2023/03/12 18:23

ありがとうございます。期待通りの動作になりました。 色々試してみたところ、Classを明示的に指定するか、Uriを指定するとダメなようです。 なぜこうなるのか私にはわかりませんが……
jimbe

2023/03/12 20:06

確信は無いのですが、 packageContext と cls は レシーバを androidmanifest.xml で登録した場合に探す為に使う情報で、 uri は extra と別にレシーバに渡すデータ(の uri 的な文字列にしたもの)のようです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問