diff --git a/Examples/AblyPush/AblyPushExample.xcodeproj/project.pbxproj b/Examples/AblyPush/AblyPushExample.xcodeproj/project.pbxproj index aa2be5061..66a370156 100644 --- a/Examples/AblyPush/AblyPushExample.xcodeproj/project.pbxproj +++ b/Examples/AblyPush/AblyPushExample.xcodeproj/project.pbxproj @@ -8,6 +8,9 @@ /* Begin PBXBuildFile section */ 219F937A2A4E0E44007DE767 /* LocationPushEventsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 219F93792A4E0E44007DE767 /* LocationPushEventsView.swift */; }; + 801880802B87E7BA00A698F0 /* PushButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8018807F2B87E7BA00A698F0 /* PushButton.swift */; }; + 801880822B87E80D00A698F0 /* StatelessButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 801880812B87E80D00A698F0 /* StatelessButton.swift */; }; + 801880872B87E8A300A698F0 /* VerticalLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 801880862B87E8A300A698F0 /* VerticalLabelStyle.swift */; }; 8405EE8427F0B06800C9E461 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8405EE8327F0B06800C9E461 /* App.swift */; }; 8405EE8627F0B06800C9E461 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8405EE8527F0B06800C9E461 /* ContentView.swift */; }; 8405EE8827F0B06C00C9E461 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8405EE8727F0B06C00C9E461 /* Assets.xcassets */; }; @@ -52,6 +55,9 @@ /* Begin PBXFileReference section */ 219F93782A4DFE41007DE767 /* AblyLocationPush.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AblyLocationPush.entitlements; sourceTree = ""; }; 219F93792A4E0E44007DE767 /* LocationPushEventsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPushEventsView.swift; sourceTree = ""; }; + 8018807F2B87E7BA00A698F0 /* PushButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushButton.swift; sourceTree = ""; }; + 801880812B87E80D00A698F0 /* StatelessButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatelessButton.swift; sourceTree = ""; }; + 801880862B87E8A300A698F0 /* VerticalLabelStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalLabelStyle.swift; sourceTree = ""; }; 8405EE8027F0B06800C9E461 /* Ably Push.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Ably Push.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 8405EE8327F0B06800C9E461 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; 8405EE8527F0B06800C9E461 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -95,6 +101,16 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 801880852B87E86600A698F0 /* Buttons */ = { + isa = PBXGroup; + children = ( + 801880812B87E80D00A698F0 /* StatelessButton.swift */, + 8018807F2B87E7BA00A698F0 /* PushButton.swift */, + 801880862B87E8A300A698F0 /* VerticalLabelStyle.swift */, + ); + path = Buttons; + sourceTree = ""; + }; 8405EE7727F0B06800C9E461 = { isa = PBXGroup; children = ( @@ -122,6 +138,7 @@ 8405EE8327F0B06800C9E461 /* App.swift */, 842F124927F0B29D0029692E /* AblyHelper.swift */, 8405EE8527F0B06800C9E461 /* ContentView.swift */, + 801880852B87E86600A698F0 /* Buttons */, 219F93792A4E0E44007DE767 /* LocationPushEventsView.swift */, 842F124B27F0BFC10029692E /* Info.plist */, 84E3D1A32A6D886E0081E898 /* InfoLP.plist */, @@ -300,7 +317,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 801880822B87E80D00A698F0 /* StatelessButton.swift in Sources */, 219F937A2A4E0E44007DE767 /* LocationPushEventsView.swift in Sources */, + 801880872B87E8A300A698F0 /* VerticalLabelStyle.swift in Sources */, + 801880802B87E7BA00A698F0 /* PushButton.swift in Sources */, 8405EE8627F0B06800C9E461 /* ContentView.swift in Sources */, 842F124A27F0B29D0029692E /* AblyHelper.swift in Sources */, 8405EE8427F0B06800C9E461 /* App.swift in Sources */, @@ -458,10 +478,11 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = AblyPushExample/AblyPushExample.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AblyPushExample/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = XXY98AVDR6; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AblyPushExample/Info.plist; @@ -491,10 +512,11 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = AblyPushExample/AblyPushExample.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AblyPushExample/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = XXY98AVDR6; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AblyPushExample/Info.plist; @@ -526,7 +548,7 @@ CODE_SIGN_ENTITLEMENTS = AblyLocationPush/AblyLocationPush.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = XXY98AVDR6; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AblyLocationPush/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = AblyLocationPush; @@ -554,7 +576,7 @@ CODE_SIGN_ENTITLEMENTS = AblyLocationPush/AblyLocationPush.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = XXY98AVDR6; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AblyLocationPush/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = AblyLocationPush; @@ -585,7 +607,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AblyPushExample/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = XXY98AVDR6; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AblyPushExample/InfoLP.plist; @@ -621,7 +643,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"AblyPushExample/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = XXY98AVDR6; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AblyPushExample/InfoLP.plist; diff --git a/Examples/AblyPush/AblyPushExample/AblyHelper.swift b/Examples/AblyPush/AblyPushExample/AblyHelper.swift index 547ae9857..f40d33ce8 100644 --- a/Examples/AblyPush/AblyPushExample/AblyHelper.swift +++ b/Examples/AblyPush/AblyPushExample/AblyHelper.swift @@ -2,7 +2,7 @@ import Ably import UIKit import CoreLocation -class AblyHelper: NSObject { +class AblyHelper: NSObject, ObservableObject { static let shared = AblyHelper() @@ -18,6 +18,10 @@ class AblyHelper: NSObject { var activatePushCallback: ((String?, String?, ARTErrorInfo?) -> ())? + @Published var isSubscribedToExampleChannel1 = false + @Published var isSubscribedToExampleChannel2 = false + @Published var isPushActivated = false + private override init() { super.init() guard key != "" else { @@ -87,6 +91,64 @@ extension AblyHelper { print("Publish result: \(error?.localizedDescription ?? "Success")") } } + + func sendPushToChannel(_ channel: Channel) { + let message = ARTMessage(name: "example", data: "rest data") + message.extras = [ + "push": [ + "notification": [ + "title": "Channel Push", + "body": "Sent push to \(channel.rawValue)" + ], + "data": [ + "foo": "bar", + "baz": "qux" + ] + ] + ] as any ARTJsonCompatible + + realtime.channels.get(channel.rawValue).publish([message]) { error in + if let error { + print("Error sending push to \(channel.rawValue) with error: \(error.localizedDescription)") + } else { + print("Sent push to \(channel.rawValue)") + } + } + } + + func subscribeToChannel(_ channel: Channel) { + realtime.channels.get(channel.rawValue).push.subscribeDevice { error in + guard error == nil else { + print("Error subscribing to \(channel.rawValue) with error: \(error!.localizedDescription)") + return + } + print("Succesfully subscribed to \(channel.rawValue)") + + switch channel { + case .exampleChannel1: + self.isSubscribedToExampleChannel1 = true + case .exampleChannel2: + self.isSubscribedToExampleChannel2 = true + } + } + } + + func unsubscribeFromChannel(_ channel: Channel) { + realtime.channels.get(channel.rawValue).push.unsubscribeDevice { error in + guard error == nil else { + print("Error subscribing to \(channel.rawValue) with error: \(error!.localizedDescription)") + return + } + + print("Succesfully unsubscribed from \(channel.rawValue)") + switch channel { + case .exampleChannel1: + self.isSubscribedToExampleChannel1 = false + case .exampleChannel2: + self.isSubscribedToExampleChannel2 = false + } + } + } } extension AblyHelper: ARTPushRegistererDelegate { @@ -95,10 +157,16 @@ extension AblyHelper: ARTPushRegistererDelegate { print("Push activation: \(error?.localizedDescription ?? "Success")") activatePushCallback?(defaultDeviceToken, locationDeviceToken, error) activateLocationPush() + if error == nil { + isPushActivated = true + } } func didDeactivateAblyPush(_ error: ARTErrorInfo?) { print("Push deactivation: \(error?.localizedDescription ?? "Success")") + if error == nil { + isPushActivated = false + } } func didUpdateAblyPush(_ error: ARTErrorInfo?) { @@ -141,3 +209,8 @@ extension AblyHelper : CLLocationManagerDelegate { } } } + +enum Channel: String { + case exampleChannel1 + case exampleChannel2 +} diff --git a/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/Contents.json b/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/Contents.json new file mode 100644 index 000000000..6a2ca6ce7 --- /dev/null +++ b/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "filename" : "ably-brand-light-mode 1.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ], + "filename" : "ably-brand-light-mode.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "ably-brand-dark-mode.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/ably-brand-dark-mode.pdf b/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/ably-brand-dark-mode.pdf new file mode 100644 index 000000000..63621a4d9 Binary files /dev/null and b/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/ably-brand-dark-mode.pdf differ diff --git a/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/ably-brand-light-mode 1.pdf b/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/ably-brand-light-mode 1.pdf new file mode 100644 index 000000000..f96dc92f6 Binary files /dev/null and b/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/ably-brand-light-mode 1.pdf differ diff --git a/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/ably-brand-light-mode.pdf b/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/ably-brand-light-mode.pdf new file mode 100644 index 000000000..f96dc92f6 Binary files /dev/null and b/Examples/AblyPush/AblyPushExample/Assets.xcassets/ably-logo.imageset/ably-brand-light-mode.pdf differ diff --git a/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-disabled.imageset/Contents.json b/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-disabled.imageset/Contents.json new file mode 100644 index 000000000..eca39d820 --- /dev/null +++ b/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-disabled.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "push-disabled.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-disabled.imageset/push-disabled.pdf b/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-disabled.imageset/push-disabled.pdf new file mode 100644 index 000000000..4c4648cb0 Binary files /dev/null and b/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-disabled.imageset/push-disabled.pdf differ diff --git a/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-enabled.imageset/Contents.json b/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-enabled.imageset/Contents.json new file mode 100644 index 000000000..906081cb9 --- /dev/null +++ b/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-enabled.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "push-enabled.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-enabled.imageset/push-enabled.pdf b/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-enabled.imageset/push-enabled.pdf new file mode 100644 index 000000000..f0834c9dc Binary files /dev/null and b/Examples/AblyPush/AblyPushExample/Assets.xcassets/push-enabled.imageset/push-enabled.pdf differ diff --git a/Examples/AblyPush/AblyPushExample/Buttons/PushButton.swift b/Examples/AblyPush/AblyPushExample/Buttons/PushButton.swift new file mode 100644 index 000000000..192c2785f --- /dev/null +++ b/Examples/AblyPush/AblyPushExample/Buttons/PushButton.swift @@ -0,0 +1,52 @@ +import SwiftUI + +struct PushButton: View { + let systemImage: String + let activeTitle: String + let inactiveTitle: String + let action: () -> Void + let isButtonEnabled: Bool // is the button enabled + let isActive: Bool // is the action in it's on or off state + + let activeColor = Color(red: 1.00, green: 0.33, blue: 0.09) + let inActiveColor = Color(red: 0.00, green: 0.56, blue: 0.02) + + init( + isButtonEnabled: Bool, + systemImage: String, + activeTitle: String, + inactiveTitle: String, + isActive: Bool, + action: @escaping () -> Void + ) { + self.isButtonEnabled = isButtonEnabled + self.systemImage = systemImage + self.activeTitle = activeTitle + self.inactiveTitle = inactiveTitle + self.isActive = isActive + self.action = action + } + + var body: some View { + let button = Button { + action() // manage the toggling of isActive binding within the action. + } label: { + Label(isActive ? activeTitle : inactiveTitle, + systemImage: systemImage) + .frame(maxWidth: .infinity) + .labelStyle(VerticalLabelStyle()) + .padding(EdgeInsets(top: 8, leading: 0, bottom: 8, trailing: 0)) + } + .buttonStyle(.borderedProminent) + .buttonBorderShape(.roundedRectangle) + .tint(isActive ? activeColor : inActiveColor) + .disabled(!isButtonEnabled) + .animation(.easeInOut, value: isButtonEnabled) + + if #available(iOS 17.0, *) { + return button.contentTransition(.symbolEffect(.replace)) + } + + return button + } +} diff --git a/Examples/AblyPush/AblyPushExample/Buttons/StatelessButton.swift b/Examples/AblyPush/AblyPushExample/Buttons/StatelessButton.swift new file mode 100644 index 000000000..bef79f19a --- /dev/null +++ b/Examples/AblyPush/AblyPushExample/Buttons/StatelessButton.swift @@ -0,0 +1,48 @@ +import SwiftUI + +struct StatelessButton: View { + let isButtonEnabled: Bool + let systemImage: String + let title: String + let backgroundColor: Color + let action: () -> Void + + @State var taps: Int = 0 // purely to trigger animation on every tap + + init( + isButtonEnabled: Bool, + systemImage: String, + title: String, + backgroundColor: Color = Color(red: 0.00, green: 0.56, blue: 0.02), + action: @escaping () -> Void + ) { + self.isButtonEnabled = isButtonEnabled + self.systemImage = systemImage + self.title = title + self.backgroundColor = backgroundColor + self.action = action + } + + var body: some View { + let button = Button { + action() + taps += 1 + } label: { + Label(title, systemImage: systemImage) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .labelStyle(VerticalLabelStyle()) + .padding(EdgeInsets(top: 8, leading: 0, bottom: 8, trailing: 0)) + } + .buttonStyle(.bordered) + .buttonBorderShape(.roundedRectangle) + .tint(backgroundColor) + .disabled(!isButtonEnabled) + .animation(.easeInOut, value: isButtonEnabled) + + if #available(iOS 17.0, *) { + return button.symbolEffect(.bounce.down, value: taps) + } + + return button + } +} diff --git a/Examples/AblyPush/AblyPushExample/Buttons/VerticalLabelStyle.swift b/Examples/AblyPush/AblyPushExample/Buttons/VerticalLabelStyle.swift new file mode 100644 index 000000000..418fb27be --- /dev/null +++ b/Examples/AblyPush/AblyPushExample/Buttons/VerticalLabelStyle.swift @@ -0,0 +1,10 @@ +import SwiftUI + +struct VerticalLabelStyle: LabelStyle { + func makeBody(configuration: Configuration) -> some View { + VStack(alignment: .center, spacing: 8) { + configuration.icon + configuration.title + } + } +} diff --git a/Examples/AblyPush/AblyPushExample/ContentView.swift b/Examples/AblyPush/AblyPushExample/ContentView.swift index aad0bf210..1881b4806 100644 --- a/Examples/AblyPush/AblyPushExample/ContentView.swift +++ b/Examples/AblyPush/AblyPushExample/ContentView.swift @@ -2,7 +2,8 @@ import Ably import SwiftUI struct ContentView: View { - + @StateObject private var ablyHelper = AblyHelper.shared + @State var showDeviceDetailsAlert = false @State var deviceDetails: ARTDeviceDetails? @State var deviceDetailsError: ARTErrorInfo? @@ -11,19 +12,35 @@ struct ContentView: View { @State var defaultDeviceToken: String? @State var locationDeviceToken: String? @State var deviceTokensError: ARTErrorInfo? - + var body: some View { NavigationView { VStack { - Spacer() - Button("Activate Push") { - AblyHelper.shared.activatePush { - defaultDeviceToken = $0 - locationDeviceToken = $1 - deviceTokensError = $2 - showDeviceTokensAlert = true + Image("ably-logo") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(height: 44) + .padding() + + PushButton( + isButtonEnabled: true, // Button to toggle push activation is always enabled + systemImage: ablyHelper.isPushActivated ? "bell.slash" : "bell", + activeTitle: "Deactivate Push", + inactiveTitle: "Activate Push", + isActive: ablyHelper.isPushActivated, + action: { + if ablyHelper.isPushActivated { + ablyHelper.deactivatePush() + } else { + AblyHelper.shared.activatePush { + defaultDeviceToken = $0 + locationDeviceToken = $1 + deviceTokensError = $2 + showDeviceTokensAlert = true + } + } } - } + ) .alert(isPresented: $showDeviceTokensAlert) { if let deviceTokensError = deviceTokensError { return Alert(title: Text("Device Tokens"), message: Text("Error: \(deviceTokensError)")) @@ -37,22 +54,34 @@ struct ContentView: View { } return Alert(title: Text("Push activation"), message: Text("Success")) } - .padding() - Button("Dectivate") { - AblyHelper.shared.deactivatePush() - } - .padding() - Button("Print Token") { - AblyHelper.shared.printIdentityToken() - } - .padding() - Button("Device Details") { - AblyHelper.shared.getDeviceDetails { details, error in - deviceDetails = details - deviceDetailsError = error - showDeviceDetailsAlert = true - } + + HStack { + let backgroundColor = Color(red: 0.40, green: 0.44, blue: 0.52) + StatelessButton( + isButtonEnabled: ablyHelper.isPushActivated, + systemImage: "printer.fill", + title: "Print Token", + backgroundColor: backgroundColor, + action: { + ablyHelper.printIdentityToken() + } + ) + StatelessButton( + isButtonEnabled: ablyHelper.isPushActivated, + systemImage: "info.circle.fill", + title: "Device Details", + backgroundColor: backgroundColor, + action: { + AblyHelper.shared.getDeviceDetails { details, error in + deviceDetails = details + deviceDetailsError = error + showDeviceDetailsAlert = true + } + } + ) } + .fixedSize(horizontal: false, vertical: true) + .alert(isPresented: $showDeviceDetailsAlert) { if deviceDetails != nil { return Alert(title: Text("Device Details"), message: Text("\(deviceDetails!)")) @@ -62,11 +91,78 @@ struct ContentView: View { } return Alert(title: Text("Device Details Error"), message: Text("Unknown result.")) } - .padding() - Button("Send Push") { - AblyHelper.shared.sendAdminPush(title: "Hello", body: "This push was sent with deviceId") + Text("Device Push") + .fontWeight(.bold) + .padding(.top) + StatelessButton( + isButtonEnabled: ablyHelper.isPushActivated, + systemImage: "iphone.gen3", + title: "Send Push to deviceId", + action: { + AblyHelper.shared.sendAdminPush(title: "Hello", body: "This push was sent with deviceId") + } + ) + .fixedSize(horizontal: false, vertical: true) + Text("Channels Push") + .fontWeight(.bold) + .padding(.top) + + HStack { + PushButton( + isButtonEnabled: ablyHelper.isPushActivated, + systemImage: ablyHelper.isSubscribedToExampleChannel1 + ? "xmark.circle.fill" + : "checkmark.circle.fill", + activeTitle: "Unsubscribe from exampleChannel1", + inactiveTitle: "Subscribe to exampleChannel1", + isActive: ablyHelper.isSubscribedToExampleChannel1, + action: { + if ablyHelper.isSubscribedToExampleChannel1 { + ablyHelper.unsubscribeFromChannel(.exampleChannel1) + } else { + ablyHelper.subscribeToChannel(.exampleChannel1) + } + } + ) + PushButton( + isButtonEnabled: ablyHelper.isPushActivated, + systemImage: ablyHelper.isSubscribedToExampleChannel2 + ? "xmark.circle.fill" + : "checkmark.circle.fill", + activeTitle: "Unsubscribe from exampleChannel2", + inactiveTitle: "Subscribe to exampleChannel2", + isActive: ablyHelper.isSubscribedToExampleChannel2, + action: { + if ablyHelper.isSubscribedToExampleChannel2 { + ablyHelper.unsubscribeFromChannel(.exampleChannel2) + } else { + ablyHelper.subscribeToChannel(.exampleChannel2) + } + } + ) } - .padding() + .fixedSize(horizontal: false, vertical: true) + + HStack { + StatelessButton( + isButtonEnabled: ablyHelper.isPushActivated && ablyHelper.isSubscribedToExampleChannel1, + systemImage: "paperplane.circle.fill", + title: "Send Push to \(Channel.exampleChannel1.rawValue)", + action: { + AblyHelper.shared.sendPushToChannel(.exampleChannel1) + } + ) + StatelessButton( + isButtonEnabled: ablyHelper.isPushActivated && ablyHelper.isSubscribedToExampleChannel2, + systemImage: "paperplane.circle.fill", + title: "Send Push to \(Channel.exampleChannel2.rawValue)", + action: { + AblyHelper.shared.sendPushToChannel(.exampleChannel2) + } + ) + } + .fixedSize(horizontal: false, vertical: true) + #if USE_LOCATION_PUSH NavigationLink { LocationPushEventsView() @@ -77,7 +173,7 @@ struct ContentView: View { #endif Spacer() } - .navigationTitle("Ably Push Example") + .padding() } } } diff --git a/Examples/AblyPush/README.md b/Examples/AblyPush/README.md index 4aec5ea84..625bd90cf 100644 --- a/Examples/AblyPush/README.md +++ b/Examples/AblyPush/README.md @@ -8,10 +8,11 @@ You will need a real iOS device to test this functionality. - Insert it instead of an empty string in the `key` property's value inside the `AblyHelper` class. - Make sure you've selected your development team in the `Signing & Capabilities` tab of the Xcode project target settings and all the provisioning profiles created without errors (update the `bundle-id` for the `AblyPushExample` target as needed). - Build and Run the app on your device. -- Hit "Activate" button, then hit "Print Token". You should see "IDENTITY TOKEN: exists" printed in the debug output window. +- Hit "Activate Push" button, then hit "Print Token". You should see "IDENTITY TOKEN: exists" printed in the debug output window. - Hit "Device Details" to display Ably push device registration info after successful activation. - Go to the `Notifications` tab of the Ably's app dashboard again and scroll to the `Push Inspector` section. Fill in `Title` and `Body` fields of the push notification. Then insert "basic-apns-example" in the `Client ID` field and press enter. Then hit "Push to client" button. You should now see the notification on the screen of your device. -- Also you can send notifications from the app itself if you tick `Push Admin` capability in your API key settings in the app's dashboard. Just hit "Send Push" button to send a predefined push notification which is also will be displayed on your device's screen right away. You can change this behavior in the `UNUserNotificationCenterDelegate` extension for the `AblyHelper` by editing `completionHandler([.banner, .sound])` line of code. +- Also you can send notifications from the app itself if you tick `Push Admin` capability in your API key settings in the app's dashboard. Just hit "Send Push to deviceId" button to send a predefined push notification which is also will be displayed on your device's screen right away. You can change this behavior in the `UNUserNotificationCenterDelegate` extension for the `AblyHelper` by editing `completionHandler([.banner, .sound])` line of code. +- To test Channels based push, go to the `Settings` tab of the Ably dashboard and scroll down to `Channel rules`. Press `Add new rule` and name your channel ID `exampleChannel1`, tick `Push notifications enabled` before scrolling down and pressing `Create channel rule`. Repeat this step for a channel named `exampleChannel2`. You can now subscribe and send pushes to these two channels within the example app. You can also use the Push Inspector. ### Location pushes diff --git a/Source/ARTPushActivationStateMachine.m b/Source/ARTPushActivationStateMachine.m index 5d3679d22..3701a527a 100644 --- a/Source/ARTPushActivationStateMachine.m +++ b/Source/ARTPushActivationStateMachine.m @@ -400,11 +400,9 @@ - (void)callUpdatedCallback:(nullable ARTErrorInfo *)error { } - (void)registerForAPNS { -#if !TARGET_OS_SIMULATOR dispatch_async(dispatch_get_main_queue(), ^{ [[UIApplication sharedApplication] registerForRemoteNotifications]; }); -#endif } @end