Skip to content

Commit a484f9f

Browse files
hahagutheproducer
andauthored
Android actionTypeId action support (#122)
* fix(android): correct actionTypeID to actionTypeId and add action intent handling in notifications fix(android): enhance notification intent handling to ensure app launch intent is properly set fix(android): improve notification action intent handling by making intents explicit and updating PendingIntent flags for compatibility fix(android): enhance action intent handling in Notifications to ensure fallback for invalid actionTypeId * feat(android): Add notification action handling and listener methods * feat(iOS): Add notification listener and delegate methods for background runner * Add changeset * fmt * build --------- Co-authored-by: Joseph Pender <joey.pender@outsystems.com>
1 parent b76dbd4 commit a484f9f

File tree

13 files changed

+345
-239
lines changed

13 files changed

+345
-239
lines changed

.changeset/hungry-onions-jog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@capacitor/background-runner": minor
3+
---
4+
5+
Adding handling for Android notifications

README.md

Lines changed: 83 additions & 82 deletions
Large diffs are not rendered by default.

packages/capacitor-plugin/API.md

Lines changed: 21 additions & 72 deletions
Large diffs are not rendered by default.

packages/capacitor-plugin/README.md

Lines changed: 83 additions & 82 deletions
Large diffs are not rendered by default.

packages/capacitor-plugin/android/src/main/java/io/ionic/backgroundrunner/plugin/BackgroundRunnerPlugin.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import kotlinx.coroutines.Dispatchers
1414
import kotlinx.coroutines.GlobalScope
1515
import kotlinx.coroutines.launch
1616
import kotlinx.coroutines.runBlocking
17+
import android.content.Intent
18+
import com.getcapacitor.Bridge
1719

1820

1921
@CapacitorPlugin(
@@ -125,4 +127,46 @@ class BackgroundRunnerPlugin: Plugin() {
125127
fun registerBackgroundTask(call: PluginCall) {
126128
call.resolve()
127129
}
130+
131+
override fun handleOnNewIntent(intent: Intent) {
132+
super.handleOnNewIntent(intent)
133+
134+
Log.d("BackgroundRunner", "handleOnNewIntent with action: ${intent.action}")
135+
136+
if (intent.action == ".NOTIFICATION_CLICKED") {
137+
val actionTypeId = intent.getStringExtra("actionTypeId")
138+
val notificationId = intent.getIntExtra("notificationId", -1)
139+
140+
// Create notification action data
141+
val notificationAction = if (actionTypeId != null) {
142+
JSObject().apply {
143+
put("actionTypeId", actionTypeId)
144+
put("notificationId", notificationId)
145+
}
146+
} else null
147+
148+
// Launch the app using proper intent flags
149+
val packageName = context.packageName
150+
val launchIntent = context.packageManager.getLaunchIntentForPackage(packageName)?.apply {
151+
action = Intent.ACTION_MAIN
152+
addCategory(Intent.CATEGORY_LAUNCHER)
153+
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
154+
}
155+
156+
if (launchIntent != null) {
157+
context.startActivity(launchIntent)
158+
159+
// Notify listeners about the action with retention
160+
notificationAction?.let {
161+
notifyListeners("backgroundRunnerNotificationReceived", it, true)
162+
}
163+
}
164+
}
165+
}
166+
167+
@PluginMethod
168+
fun removeNotificationListeners(call: PluginCall) {
169+
notifyListeners("backgroundRunnerNotificationReceived", null)
170+
call.resolve()
171+
}
128172
}

packages/capacitor-plugin/android/src/main/java/io/ionic/backgroundrunner/plugin/api/Notification.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class Notification(jsonObject: JSONObject) {
2020
var sound: String? = null
2121
var smallIcon: String? = null
2222
var largeIcon: String? = null
23-
var actionTypeID: String? = null
23+
var actionTypeId: String? = null
2424
var extra: HashMap<String, Any>? = null
2525
var group: String? = null
2626
var groupSummary: String? = null
@@ -35,6 +35,7 @@ class Notification(jsonObject: JSONObject) {
3535
smallIcon = jsonObject.optString("smallIcon", "")
3636
ongoing = jsonObject.optBoolean("ongoing", false)
3737
autoCancel = jsonObject.optBoolean("autoCancel", false)
38+
actionTypeId = jsonObject.optString("actionTypeId", null)
3839

3940
val scheduleDateString = jsonObject.optString("scheduleAt", "")
4041
if (scheduleDateString.isNotEmpty()) {

packages/capacitor-plugin/android/src/main/java/io/ionic/backgroundrunner/plugin/api/Notifications.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,27 @@ class Notifications(context: Context) : NotificationsAPI {
9292
builder.setGroupSummary(it.groupSummary != null)
9393
builder.setSmallIcon(it.smallIcon(this.context, getDefaultSmallIcon()))
9494

95+
// Add action intent handling
96+
val actionIntent = Intent(".NOTIFICATION_CLICKED").apply {
97+
`package` = context.packageName
98+
putExtra("actionTypeId", it.actionTypeId)
99+
putExtra("notificationId", it.id)
100+
}
101+
102+
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
103+
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
104+
} else {
105+
PendingIntent.FLAG_UPDATE_CURRENT
106+
}
107+
108+
val pendingActionIntent = PendingIntent.getActivity(
109+
context,
110+
it.id,
111+
actionIntent,
112+
flags
113+
)
114+
builder.setContentIntent(pendingActionIntent)
115+
95116
val largeBody = it.largeBody
96117
if (largeBody != null) {
97118
val style = NotificationCompat.BigTextStyle()
49 Bytes
Binary file not shown.

packages/capacitor-plugin/ios/Plugin/BackgroundRunnerPlugin.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
CAP_PLUGIN_METHOD(registerBackgroundTask, CAPPluginReturnPromise);
99
CAP_PLUGIN_METHOD(checkPermissions, CAPPluginReturnPromise);
1010
CAP_PLUGIN_METHOD(requestPermissions, CAPPluginReturnPromise);
11+
CAP_PLUGIN_METHOD(removeNotificationListeners, CAPPluginReturnPromise);
1112
)

packages/capacitor-plugin/ios/Plugin/BackgroundRunnerPlugin.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Foundation
22
import Capacitor
33
import WatchConnectivity
4+
import UserNotifications
45

56
@objc(BackgroundRunnerPlugin)
67
public class BackgroundRunnerPlugin: CAPPlugin {
@@ -14,6 +15,9 @@ public class BackgroundRunnerPlugin: CAPPlugin {
1415
object: nil
1516
)
1617

18+
// Register as notification delegate
19+
registerNotificationCategories()
20+
1721
initWatchConnectivity()
1822
}
1923

@@ -95,6 +99,11 @@ public class BackgroundRunnerPlugin: CAPPlugin {
9599
call.resolve()
96100
}
97101

102+
@objc func removeNotificationListeners(_ call: CAPPluginCall) {
103+
notifyListeners("backgroundRunnerNotificationReceived", data: nil)
104+
call.resolve()
105+
}
106+
98107
@objc private func didEnterBackground() {
99108
do {
100109
try impl.scheduleBackgroundTasks()
@@ -175,4 +184,45 @@ public class BackgroundRunnerPlugin: CAPPlugin {
175184

176185
print("Watch Connectivity Enabled")
177186
}
187+
188+
@objc func registerNotificationCategories() {
189+
let notificationCenter = UNUserNotificationCenter.current()
190+
191+
// Set the plugin as the notification delegate
192+
notificationCenter.delegate = self
193+
}
194+
}
195+
196+
// MARK: - UNUserNotificationCenterDelegate
197+
extension BackgroundRunnerPlugin: UNUserNotificationCenterDelegate {
198+
// This method will be called when a notification is tapped
199+
public func userNotificationCenter(_ center: UNUserNotificationCenter,
200+
didReceive response: UNNotificationResponse,
201+
withCompletionHandler completionHandler: @escaping () -> Void) {
202+
let actionTypeId = response.notification.request.content.categoryIdentifier
203+
let notificationId = Int(response.notification.request.identifier) ?? -1
204+
205+
// Create event data
206+
let eventData: [String: Any] = [
207+
"actionTypeId": actionTypeId,
208+
"notificationId": notificationId
209+
]
210+
211+
// Notify listeners with the action data - the 'true' parameter is for retaining the event
212+
notifyListeners("backgroundRunnerNotificationReceived", data: eventData, retainUntilConsumed: true)
213+
214+
completionHandler()
215+
}
216+
217+
// This is needed to present notifications when the app is in the foreground
218+
public func userNotificationCenter(_ center: UNUserNotificationCenter,
219+
willPresent notification: UNNotification,
220+
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
221+
// Show the notification even when the app is in foreground
222+
if #available(iOS 14.0, *) {
223+
completionHandler([.banner, .sound, .badge])
224+
} else {
225+
completionHandler([.alert, .sound, .badge])
226+
}
227+
}
178228
}

0 commit comments

Comments
 (0)