Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make package safe for Swift 6 #50

Merged
merged 4 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Build
on:
pull_request: { types: [opened, reopened, synchronize, ready_for_review] }
push: { branches: [ main ] }

jobs:
build:
runs-on: ubuntu-latest
container: swift:6.0-jammy
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
run: swift builds

7 changes: 3 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// swift-tools-version:6.0

// swift-tools-version: 6.0
MihaelIsaev marked this conversation as resolved.
Show resolved Hide resolved
import PackageDescription

let package = Package(
Expand All @@ -8,13 +7,13 @@ let package = Package(
.macOS(.v13)
],
products: [
//Vapor client for Firebase Cloud Messaging
// Vapor client for Firebase Cloud Messaging
.library(name: "FCM", targets: ["FCM"]),
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"),
.package(url: "https://github.com/vapor/jwt.git", exact: "5.0.0-rc.1"),
.package(url: "https://github.com/vapor/jwt.git", from: "5.0.0"),
],
targets: [
.target(name: "FCM", dependencies: [
Expand Down
32 changes: 14 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,13 @@ Here's an example route handler with push notification sending using token
```swift
import FCM

func routes(_ app: Application) throws {
app.get("testfcm") { req -> EventLoopFuture<String> in
func routes(_ app: Application) async throws {
app.get("testfcm") { req async throws -> String in
let token = "<YOUR FIREBASE DEVICE TOKEN>" // get it from iOS/Android SDK
let notification = FCMNotification(title: "Vapor is awesome!", body: "Swift one love! ❤️")
let message = FCMMessage(token: token, notification: notification)
return req.fcm.send(message, on: req.eventLoop).map { name in
return "Just sent: \(name)"
}
let name = try await req.fcm.send(message, on: req.eventLoop)
return "Just sent: \(name)"
}
}
```
Expand Down Expand Up @@ -171,29 +170,26 @@ Next steps are optional
```swift
/// The simplest way
/// .env here means that FCM_SERVER_KEY and FCM_APP_BUNDLE_ID will be used
application.fcm.registerAPNS(.env, tokens: "token1", "token3", ..., "token100").flatMap { tokens in
/// `tokens` is array of `APNSToFirebaseToken` structs
/// which contains:
/// registration_token - Firebase token
/// apns_token - APNS token
/// isRegistered - boolean value which indicates if registration was successful
}
let tokens = try await application.fcm.registerAPNS(.env, tokens: "token1", "token3", ..., "token100")
/// `tokens` is array of `APNSToFirebaseToken` structs
/// which contains:
/// registration_token - Firebase token
/// apns_token - APNS token
/// isRegistered - boolean value which indicates if registration was successful

/// instead of .env you could declare your own identifier
extension RegisterAPNSID {
static var myApp: RegisterAPNSID { .init(appBundleId: "com.myapp") }
}

/// Advanced way
application.fcm.registerAPNS(
let tokens = try await application.fcm.registerAPNS(
appBundleId: String, // iOS app bundle identifier
serverKey: String?, // optional server key, if nil then env variable will be used
sandbox: Bool, // optional sandbox key, false by default
tokens: [String], // an array of APNS tokens
on: EventLoop? // optional event loop, if nil then application.eventLoopGroup.next() will be used
).flatMap { tokens in
/// the same as in above example
}
tokens: [String]
)
/// the same as in above example
```

> 💡 Please note that push token taken from Xcode while debugging is for `sandbox`, so either use `.envSandbox` or don't forget to set `sandbox: true`
Expand Down
33 changes: 22 additions & 11 deletions Sources/FCM/FCMAndroidConfig/FCMAndroidConfig.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
public struct FCMAndroidConfig: Codable, Equatable {
public struct FCMAndroidConfig: Sendable, Codable, Equatable {
enum CodingKeys: String, CodingKey {
case collapseKey = "collapse_key"
case priority
case ttl
case restrictedPackageName = "restricted_package_name"
case data
case notification
}

/// An identifier of a group of messages that can be collapsed, so that only the last message gets sent when delivery can be resumed.
/// A maximum of 4 different collapse keys is allowed at any given time.
public var collapse_key: String?
public var collapseKey: String?
ptoffy marked this conversation as resolved.
Show resolved Hide resolved

/// Message priority. Can take "normal" and "high" values.
/// For more information, see Setting the priority of a message.
Expand All @@ -20,7 +29,7 @@ public struct FCMAndroidConfig: Codable, Equatable {
public var ttl: String?

/// Package name of the application where the registration tokens must match in order to receive the message.
public var restricted_package_name: String?
public var restrictedPackageName: String?

/// Arbitrary key/value payload.
/// If present, it will override FCMMessage.data.
Expand All @@ -30,16 +39,18 @@ public struct FCMAndroidConfig: Codable, Equatable {
public var notification: FCMAndroidNotification?

/// Public Initializer
public init(collapse_key: String? = nil,
priority: FCMAndroidMessagePriority = .normal,
ttl: String? = nil,
restricted_package_name: String? = nil,
data: [String: String]? = nil,
notification: FCMAndroidNotification? = nil) {
self.collapse_key = collapse_key
init(
collapseKey: String? = nil,
priority: FCMAndroidMessagePriority,
ttl: String? = nil,
restrictedPackageName: String? = nil,
data: [String : String]? = nil,
notification: FCMAndroidNotification? = nil
) {
self.collapseKey = collapseKey
self.priority = priority
self.ttl = ttl
self.restricted_package_name = restricted_package_name
self.restrictedPackageName = restrictedPackageName
self.data = data
self.notification = notification
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
public enum FCMAndroidMessagePriority: String, Codable, Equatable {
public enum FCMAndroidMessagePriority: String, Sendable, Codable, Equatable {
/// Default priority for data messages.
/// Normal priority messages won't open network connections on a sleeping device,
/// and their delivery may be delayed to conserve the battery.
Expand Down
145 changes: 87 additions & 58 deletions Sources/FCM/FCMAndroidConfig/FCMAndroidNotification.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,32 @@
public struct FCMAndroidNotification: Codable, Equatable {
public struct FCMAndroidNotification: Sendable, Codable, Equatable {
enum CodingKeys: String, CodingKey {
case title
case body
case icon
case color
case sound
case tag
case clickAction = "click_action"
case bodyLocalizationKey = "body_loc_key"
case bodyLocalizationArgs = "body_loc_args"
case titleLocalizationKey = "title_loc_key"
case titleLocalizationArgs = "title_loc_args"
case channelID = "channel_id"
case ticker
case sticky
case eventTime = "event_time"
case localOnly = "local_only"
case notificationPriority = "notification_priority"
case defaultSound = "default_sound"
case defaultVibrateTimings = "default_vibrate_timings"
case defaultLightSettings = "default_light_settings"
case vibrateTimings = "vibrate_timings"
case visibility
case notificationCount = "notification_count"
case lightSettings = "light_settings"
case image
}

/// The notification's title.
/// If present, it will override FCMNotification.title.
public var title: String?
Expand All @@ -24,33 +52,33 @@ public struct FCMAndroidNotification: Codable, Equatable {

/// The action associated with a user click on the notification.
/// If specified, an activity with a matching intent filter is launched when a user clicks on the notification.
public var click_action: String?
public var clickAction: String?

/// The key to the body string in the app's string resources
/// to use to localize the body text to the user's current localization.
/// See String Resources for more information.
public var body_loc_key: String?
public var bodyLocalizationKey: String?

/// Variable string values to be used in place of the format specifiers
/// in body_loc_key to use to localize the body text to the user's current localization.
/// See Formatting and Styling for more information.
public var body_loc_args: [String]?
public var bodyLocalizationArgs: [String]?

/// The key to the title string in the app's string resources
/// to use to localize the title text to the user's current localization.
/// See String Resources for more information.
public var title_loc_key: String?
public var titleLocalizationKey: String?

/// Variable string values to be used in place of the format specifiers
/// in title_loc_key to use to localize the title text to the user's current localization.
/// See Formatting and Styling for more information.
public var title_loc_args: [String]?
public var titleLocalizationArgs: [String]?

/// The notification's channel id (new in Android O).
/// The app must create a channel with this channel ID before any notification with this channel ID is received.
/// If you don't send this channel ID in the request, or if the channel ID provided has not yet been created by the app,
/// FCM uses the channel ID specified in the app manifest.
public var channel_id: String?
public var channelID: String?

/// Sets the "ticker" text, which is sent to accessibility services.
/// Prior to API level 21 (Lollipop), sets the text that is displayed in the status bar when the notification first arrives.
Expand All @@ -64,12 +92,12 @@ public struct FCMAndroidNotification: Codable, Equatable {
/// A point in time is represented using protobuf.Timestamp.
/// A timestamp in RFC3339 UTC "Zulu" format, accurate to nanoseconds.
/// Example: "2014-10-02T15:01:23.045123456Z".
public var event_time: String?
public var eventTime: String?

/// Set whether or not this notification is relevant only to the current device.
/// Some notifications can be bridged to other devices for remote display, such as a Wear OS watch.
/// This hint can be set to recommend this notification not be bridged. See Wear OS guides
public var local_only: Bool?
public var localOnly: Bool?

/// Set the relative priority for this notification.
/// Priority is an indication of how much of the user's attention should be consumed by this notification.
Expand All @@ -78,23 +106,23 @@ public struct FCMAndroidNotification: Codable, Equatable {
/// Note this priority differs from AndroidMessagePriority.
/// This priority is processed by the client after the message has been delivered,
/// whereas AndroidMessagePriority is an FCM concept that controls when the message is delivered.
public var notification_priority: FCMAndroidNotificationPriority?
public var notificationPriority: FCMAndroidNotificationPriority?

/// If set to true, use the Android framework's default sound for the notification.
/// Default values are specified in config.xml.
public var default_sound: Bool?
public var defaultSound: Bool?

/// If set to true, use the Android framework's default vibrate pattern for the notification.
/// Default values are specified in config.xml.
/// If default_vibrate_timings is set to true and vibrate_timings is also set,
/// the default value is used instead of the user-specified vibrate_timings.
public var default_vibrate_timings: Bool?
public var defaultVibrateTimings: Bool?

/// If set to true, use the Android framework's default LED light settings for the notification.
/// Default values are specified in config.xml.
/// If default_light_settings is set to true and light_settings is also set,
/// the user-specified light_settings is used instead of the default value.
public var default_light_settings: Bool?
public var defaultLightSettings: Bool?

/// Set the vibration pattern to use.
/// Pass in an array of protobuf.Duration to turn on or off the vibrator.
Expand All @@ -104,7 +132,7 @@ public struct FCMAndroidNotification: Codable, Equatable {
/// If vibrate_timings is set and default_vibrate_timings is set to true,
/// the default value is used instead of the user-specified vibrate_timings.
/// A duration in seconds with up to nine fractional digits, terminated by 's'. Example: "3.5s".
public var vibrate_timings: [String]?
public var vibrateTimings: [String]?

/// Set the Notification.visibility of the notification.
public var visibility: FCMAndroidNotificationVisibility?
Expand All @@ -115,66 +143,67 @@ public struct FCMAndroidNotification: Codable, Equatable {
/// but you want the count here to represent the number of total new messages.
/// If zero or unspecified, systems that support badging use the default,
/// which is to increment a number displayed on the long-press menu each time a new notification arrives.
public var notification_count: Int?
public var notificationCount: Int?

/// Settings to control the notification's LED blinking rate and color if LED is available on the device.
/// The total blinking time is controlled by the OS.
public var light_settings: FCMAndroidNotificationLightSettings?
public var lightSettings: FCMAndroidNotificationLightSettings?

/// Contains the URL of an image that is going to be displayed in a notification.
/// If present, it will override google.firebase.fcm.v1.Notification.image.
public var image: String?

/// Public Initializer
public init(title: String? = nil,
body: String? = nil,
icon: String? = nil,
color: String? = nil,
sound: String? = nil,
tag: String? = nil,
click_action: String? = nil,
body_loc_key: String? = nil,
body_loc_args: [String]? = nil,
title_loc_key: String? = nil,
title_loc_args: [String]? = nil,
channel_id: String? = nil,
ticker: String? = nil,
sticky: Bool? = nil,
event_time: String? = nil,
local_only: Bool? = nil,
notification_priority: FCMAndroidNotificationPriority? = nil,
default_sound: Bool? = nil,
default_vibrate_timings: Bool? = nil,
default_light_settings: Bool? = nil,
vibrate_timings: [String]? = nil,
visibility: FCMAndroidNotificationVisibility? = nil,
notification_count: Int? = nil,
light_settings: FCMAndroidNotificationLightSettings? = nil,
image: String? = nil) {

init(
title: String? = nil,
body: String? = nil,
icon: String? = nil,
color: String? = nil,
sound: String? = nil,
tag: String? = nil,
clickAction: String? = nil,
bodyLocalizationKey: String? = nil,
bodyLocalizationArgs: [String]? = nil,
titleLocalizationKey: String? = nil,
titleLocalizationArgs: [String]? = nil,
channelID: String? = nil,
ticker: String? = nil,
sticky: Bool? = nil,
eventTime: String? = nil,
localOnly: Bool? = nil,
notificationPriority: FCMAndroidNotificationPriority? = nil,
defaultSound: Bool? = nil,
defaultVibrateTimings: Bool? = nil,
defaultLightSettings: Bool? = nil,
vibrateTimings: [String]? = nil,
visibility: FCMAndroidNotificationVisibility? = nil,
notificationCount: Int? = nil,
lightSettings: FCMAndroidNotificationLightSettings? = nil,
image: String? = nil
) {
self.title = title
self.body = body
self.icon = icon
self.color = color
self.sound = sound
self.tag = tag
self.click_action = click_action
self.body_loc_key = body_loc_key
self.body_loc_args = body_loc_args
self.title_loc_key = title_loc_key
self.title_loc_args = title_loc_args
self.channel_id = channel_id
self.clickAction = clickAction
self.bodyLocalizationKey = bodyLocalizationKey
self.bodyLocalizationArgs = bodyLocalizationArgs
self.titleLocalizationKey = titleLocalizationKey
self.titleLocalizationArgs = titleLocalizationArgs
self.channelID = channelID
self.ticker = ticker
self.sticky = sticky
self.event_time = event_time
self.local_only = local_only
self.notification_priority = notification_priority
self.default_sound = default_sound
self.default_vibrate_timings = default_vibrate_timings
self.default_light_settings = default_light_settings
self.vibrate_timings = vibrate_timings
self.eventTime = eventTime
self.localOnly = localOnly
self.notificationPriority = notificationPriority
self.defaultSound = defaultSound
self.defaultVibrateTimings = defaultVibrateTimings
self.defaultLightSettings = defaultLightSettings
self.vibrateTimings = vibrateTimings
self.visibility = visibility
self.notification_count = notification_count
self.light_settings = light_settings
self.notificationCount = notificationCount
self.lightSettings = lightSettings
self.image = image
}
}
Loading