19c7535590
This was causing compilation errors when building Objective C++ source files. Introduce a unit test that utilizes the Objective C++ compiler, to prevent future issues. ref: #136 |
||
---|---|---|
.github | ||
.swiftpm/xcode/package.xcworkspace | ||
Config | ||
Documentation | ||
SampleNHAppLegacyObjC | ||
SampleNHAppLegacySwift | ||
SampleNHAppMacObjC | ||
SampleNHAppMacSwift | ||
SampleNHAppMacSwiftUI | ||
SampleNHAppObjC | ||
SampleNHAppSwift | ||
SampleNHAppSwiftUI | ||
SampleNHAppSwiftUI2 | ||
SampleVOIPApp | ||
Scripts | ||
Vendor | ||
WindowsAzureMessaging | ||
WindowsAzureMessaging.xcworkspace | ||
.clang-format | ||
.gitignore | ||
.gitmodules | ||
AzureNotificationHubs-iOS.podspec | ||
CHANGELOG.md | ||
LICENSE | ||
NOTICE.txt | ||
Package.swift | ||
Package@swift-5.3.swift | ||
README.md | ||
SECURITY.md | ||
appcenter-pre-build.sh | ||
clang-format-changed-files.sh |
README.md
Microsoft Azure Notification Hubs SDK for Apple
Microsoft Azure Notification Hubs provide a multiplatform, scaled-out push infrastructure that enables you to send mobile push notifications from any backend (in the cloud or on-premises) to any mobile platform. To learn more, visit our Developer Center.
The Azure Notification Hubs SDK for Apple provides capabilities for registering your device and receive push notifications on macOS and iOS including platforms including tvOS, watchOS and Mac Catalyst.
Getting Started
The Azure Notification Hubs can be added to your app via Cocoapods, Carthage, Swift Package Manager, or by manually adding the binaries to your project. We have a number of sample applications available written in both Swift and Objective-C to help you get started for both iOS with Mac Catalyst support, and a macOS sample, and SwiftUI coming soon.
This introduces a new API as of version 3.0, and the usage of SBNotificationHub
with registrations is still supported, but discouraged as we have the new MSNotificationHub
which uses the Installation API and modern Apple APIs.
- NH Sample App for iOS/Mac Catalyst (Swift | Objective-C)
- NH Sample App for macOS (Swift | Objective-C)
- NH Sample App for SwiftUI (iOS | macOS)
- NH Sample Legacy App using Legacy APIs (Swift | Objective-C)
Integration with Cocoapods
Add the following into your podfile
to pull in the Azure Notification Hubs SDK:
pod 'AzureNotificationHubs-iOS'
Run pod install
to install the pod and then open your project workspace in Xcode.
Integration with Carthage
Below are the steps on how to integrate the Azure Notification Huds SDK in your Xcode project using Carthage version 0.30 or higher. Add the following to your Cartfile
to include GitHub repository.
# Gets the latest release
github "Azure/azure-notificationhubs-ios"
You can also specify a specific version of the Azure Notification Hubs SDK such as 3.1.4.
# Get version in the format of X.X.X such as 3.1.4
github "Azure/azure-notificationhubs-ios" ~> 3.1.4
Once you have this, run carthage update
. This will fetch the SDK and put it into the Carthage/Checkouts
folder. Open Xcode and drag the WindowsAzureMessaging.framework
from the Carthage/Builds/iOS
for iOS or Carthage/Builds/macOS
for macOS. Ensure the app target is checked during the import.
Integration via Swift Package Manager
The Azure Notification Hubs SDK also supports the Swift Package Manager. To integrate, use the following steps:
- From the Xcode menu click File > Swift Packages > Add Package Dependency.
- In the dialog, enter the repository URL:
http://github.com/Azure/azure-notificationhubs-ios.git
- In the Version, select Up to Next Major and take the default option.
- Choose WindowsAzureMessaging in the Package Product column.
Integration via copying binaries
The Azure Notification Hubs SDK can also be added manually by downloading the release from GitHub on the Azure Notification Hubs SDK Releases.
The SDK supports the use of XCframework. If you want to integrate XCframeworks into your project, download the WindowsAzureMessaging-SDK-Apple-XCFramework.zip from the releases page and unzip it. Resulting folder contents are not platform-specific, instead it contains the XCframework.
Unzip the file and you will see a folder called WindowsAzureMessaging-SDK-Apple that contains the framework files each platform folder. Copy the framework to a desired location and then add to Xcode. Ensure the app target is checked during the import.
Initializing the SDK
To get started with the SDK, you need to configure your Azure Notification Hub with your Apple credentials. To integrate the SDK, you will need the name of the hub as well as a connection string from your Access Policies. Note that you only need the "Listen" permission to intercept push notifications.
You can then import the headers for Swift:
import WindowsAzureMessaging
And Objective-C as well:
#import <WindowsAzureMessaging/WindowsAzureMessaging.h>
Then we can initialize the SDK with our hub name and connection string. This will automatically register the device using the Installation API with your device token.
Using Swift, we can use the start
method, which then starts the installation and device registration process for push notifications.
Swift:
let connectionString = "<connection-string>"
let hubName = "<hub-name>"
MSNotificationHub.start(connectionString: connectionString!, hubName: hubName!)
With Objective-C, it is largely the same with calling the startWithConnectionString
method:
Objective-C:
NSString *connectionString = @"<connection-string>";
NSString *hubName = @"<hub-name>";
[MSNotificationHub startWithConnectionString:connectionString hubName:hubName];
By default, the SDK will initialize with the UNAuthorizationOptions
for alert, badge and sound, however, if you wish to change that, you can use the startWithConnectionString:hubName:options
method specifying which options you wish to use.
Swift:
// Create with alert, badge and sound
let hubOptions = MSNotificationHubOptions(withOptions: [.alert, .badge, .sound])
// Start SDK
MSNotificationHub.start(connectionString: connectionString!, hubName: hubName!, options: hubOptions!)
Objective-C:
// Create with alert, badge and sound
MSNotificationHubOptions *hubOptions = [[MSNotificationHubOptions alloc] initWithAuthorizationOptions:(UNAuthorizationOptions)(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge)];
// Start SDK
[MSNotificationHub startWithConnectionString:connectionString hubName:hubName options:hubOptions];
Intercepting Push Notifications
You can set up a delegate to be notified whenever a push notification is received in foreground or a background push notification has been tapped by the user. To get started with intercepting push notifications, implement the MSNotificationHubDelegate
, and use the MSNotificationHub.setDelegate
method to set the delegate implementation.
Swift:
class SetupViewController: MSNotificationHubDelegate // And other imports
// Set up the delegate
MSNotificationHub.setDelegate(self)
// Implement the method
func notificationHub(_ notificationHub: MSNotificationHub!, didReceivePushNotification notification: MSNotificationHubMessage!) {
let title = notification.title ?? ""
let body = notification.body ?? ""
if (UIApplication.shared.applicationState == .background) {
NSLog("Notification received in background: title:\"\(title)\" body:\"\(body)\"")
} else {
let alertController = UIAlertController(title: title, message: body, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .cancel))
self.present(alertController, animated: true)
}
}
Objective-C:
@interface SetupViewController <MSNotificationHubDelegate /* Other protocols */>
// Set up the delegate
[MSNotificationHub setDelegate:self];
// Implement the method
- (void)notificationHub:(MSNotificationHub *)notificationHub didReceivePushNotification:(MSNotificationHubMessage *)notification {
NSString *title = notification.title ?: @"";
NSString *body = notification.body ?: @"";
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) {
NSLog(@"Notification received in the background: title: %@ body: %@", title, body);
} else {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:notification.title
message:notification.body
preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alertController animated:YES completion:nil];
}
}
Tag Management
One of the ways to target a device or set of devices is through the use of tags, where you can target a specific tag, or a tag expression. The Azure Notification Hub SDK for Apple handles this through top level methods that allow you to add, clear, remove and get all tags for the current installation. In this example, we can add some recommended tags such as the app language preference, and device country code.
Swift:
// Get language and country code for common tag values
let language = Bundle.main.preferredLocalizations.first!
let countryCode = NSLocale.current.regionCode!
// Create tags with type_value format
let languageTag = "language_" + language
let countryCodeTag = "country_" + countryCode
MSNotificationHub.addTags([languageTag, countryCodeTag])
Objective-C:
// Get language and country code for common tag values
NSString *language = [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0];
NSString *countryCode = [[NSLocale currentLocale] countryCode];
// Create tags with type_value format
NSString *languageTag = [NSString stringWithFormat:@"language_%@", language];
NSString *countryCodeTag = [NSString stringWithFormat:@"country_%@", countryCode];
[MSNotificationHub addTags:@[languageTag, countryCodeTag]];
Template Management
With Azure Notification Hub Templates, you can enable a client application to specify the exact format of the notifications it wants to receive. This is useful when you want to create a more personalized notification, with string replacement to fill the values. The Installation API allows multiple templates for each installation which gives you greater power to target your users with rich messages.
For example, we can create a template with a body, some headers, and some tags.
Swift:
// Get language and country code for common tag values
let language = Bundle.main.preferredLocalizations.first!
let countryCode = NSLocale.current.regionCode!
// Create tags with type_value format
let languageTag = "language_" + language
let countryCodeTag = "country_" + countryCode
let body = "{\"aps\": {\"alert\": \"$(message)\"}}"
let template = MSInstallationTemplate()
template.body = body
template.addTags([languageTag, countryCodeTag])
MSNotificationHub.setTemplate(template, forKey: "template1")
Objective-C:
NSString *language = [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0];
NSString *countryCode = [[NSLocale currentLocale] countryCode];
// Create tags with type_value format
NSString *languageTag = [NSString stringWithFormat:@"language_%@", language];
NSString *countryCodeTag = [NSString stringWithFormat:@"country_%@", countryCode];
NSString *body = @"{\"aps\": {\"alert\": \"$(message)\"}}";
MSInstallationTemplate *template = [MSInstallationTemplate new];
template.body = body;
[template addTags:@[languageTag, countryCodeTag]];
[MSNotificationHub setTemplate:template forKey:@"template1"];
Push to User Management
The SDK supports the ability to associate a user with an installation. This allows you to be able to target all devices associated with a particular User ID. The user's identity set through the SDK can be whatever the developer wants it to be: the user's name, email address, phone number, or some other unique identifier. This is supported through the MSNotificationHub
and the setUserId
method.
Swift:
let userId = "iosUser123"
MSNotificationHub.setUserId(userId);
Objective-C:
NSString *userId = @"iosUser123";
[MSNotificationHub setUserId:userId];
To target a particular user on the backend, you can specify a tag such as $UserId:{VALUE}
where VALUE is the user name you have specified, just as you can target an installation using the $InstallationId:{VALUE}
tag.
Intercepting Installation Management
The SDK will handle saving the installation for you, however, we provide hooks where you can intercept both the successful installation or any failure through the MSInstallationLifecycleDelegate
. This has two methods, didSaveInstallation
for successful saves, and didFailToSaveInstallation
for any failures. We can implement this to have our own logging for example.
Swift:
// Set the delegate
MSNotificationHub.setLifecycleDelegate(self)
// Handle success
func notificationHub(_ notificationHub: MSNotificationHub!, didSave installation: MSInstallation!) {
let installationId = installation.installationId;
NSLog("Successful save with Installation ID: \"\(installationId)\"")
}
// Handle failure
func notificationHub(_ notificationHub: MSNotificationHub!, didFailToSave installation: MSInstallation!, withError error: Error!) {
NSLog("Failed to save installation")
}
Objective-C:
// Set the delegate
[MSNotificationHub setLifecycleDelegate:self];
// Handle successes
- (void)notificationHub:(MSNotificationHub *)notificationHub didSaveInstallation:(MSInstallation *)installation {
NSLog(@"Successful save with Installation ID: %@", installation.installationId);
}
// Handle failure
- (void)notificationHub:(MSNotificationHub *)notificationHub
didFailToSaveInstallation:(MSInstallation *)installation
withError:(NSError *)error {
NSLog(@"Failed to save installation with error %@", [error localizedDescription]);
}
Enriching Installations
The SDK will update the installation on the device any time you change its properties such as adding a tag or adding an installation template. Before the installation is sent to the backend, you can intercept this installation to modify anything before it goes to the backend, for example, if you wish to add or modify tags. This is implemented in the MSInstallationEnrichmentDelegate
protocol with a single method of willEnrichInstallation
.
Swift:
// Set the delegate
MSNotificationHub.setEnrichmentDelegate(self)
// Handle the enrichment
func notificationHub(_ notificationHub: MSNotificationHub!, willEnrichInstallation installation: MSInstallation!) {
installation.addTag("customTag")
}
Objective-C:
// Set the delegate
[MSNotificationHub setEnrichmentDelegate:self];
// Handle the enrichment
- (void)notificationHub:(MSNotificationHub *)notificationHub willEnrichInstallation:(MSInstallation *)installation {
// Add another tag
[installation addTag:@"customTag"];
}
Saving Installations to a Custom Backend
The Azure Notification Hubs SDK will save the installation to our backend by default. If, however, you wish to skip our backend and store it on your backend, we support that through the MSInstallationManagementDelegate
protocol. This has a method to save the installation willUpsertInstallation
, passing in the installation, and then a completion handler is called with either an error if unsuccessful, or nil if successful. To set the delegate, instead of specifying the connection string and hub name, you specify the installation manager with startWithInstallationManagement
Swift:
// Set the delegate
MSNotificationHub.startWithInstallationManagement(self)
func notificationHub(_ notificationHub: MSNotificationHub!, willUpsertInstallation installation: MSInstallation!, withCompletionHandler completionHandler: @escaping (NSError?) -> Void) {
// Save to your own backend
// Call the completion handler with no error if successful
completionHandler(nil);
}
Objective-C:
// Set the delegate
[MSNotificationHub startWithInstallationManagement:self];
// Save to your own backend
- (void)notificationHub:(MSNotificationHub *)notificationHub
willUpsertInstallation:(MSInstallation *)installation
completionHandler:(void (^)(NSError *_Nullable))completionHandler {
// Save to your own backend
// Call the completion handler with no error if successful
completionHandler(nil);
}
Disabling Automatic Swizzling
By default, the SDK will swizzle methods to automatically intercept calls to UIApplicationDelegate
/NSApplicationDelegate
for calls to registering and intercepting push notifications, as well as UNUserNotificationCenterDelegate
methods. Note this is only available for iOS, watchOS, and Mac Catalyst. This is not supported on macOS and tvOS.
Disabling UIApplicationDelegate/NSApplicationDelegate
-
Open the project's Info.plist
-
Add the
NHAppDelegateForwarderEnabled
key and set the value to 0. This disables the UIApplicationDelegate/NSApplicationDelegate auto-forwarding to MSNotificaitonHub. -
Implement the
MSApplicationDelegate
/NSApplicationDelegate
methods for push notifications.Implement the application:didRegisterForRemoteNotificationsWithDeviceToken: callback and the application:didFailToRegisterForRemoteNotificationsWithError: callback in your AppDelegate to register for Push notifications. In the code below, if on macOS, not Mac Catalyst, replace
UIApplication
withNSApplication
.Swift:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { // Pass the device token to MSNotificationHub MSNotificationHub.didRegisterForRemoteNotifications(withDeviceToken: deviceToken) } func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { // Pass the error to MSNotificationHub MSNotificationHub.didFailToRegisterForRemoteNotificationsWithError(error) }
Objective-C:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // Pass the device token to MSNotificationHub [MSNotificationHub didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; } - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { // Pass the error to MSNotificationHub [MSNotificationHub didFailToRegisterForRemoteNotificationsWithError:error]; }
-
Implement the callback to receive push notifications
Implement the application:didReceiveRemoteNotification:fetchCompletionHandler callback to forward push notifications to MSNotificationHub In the code below, if on macOS, not Mac Catalyst, replace
UIApplication
withNSApplication
.Swift:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // Forward to MSNotificationHub MSNotificationHub.didReceiveRemoteNotification(userInfo) // Complete handling the notification completionHandler(.noData) }
Objective-C:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // Forward to MSNotificationHub [MSNotificationHub didReceiveRemoteNotification:userInfo]; // Complete handling the notification completionHandler(UIBackgroundFetchResultNoData); }
Disabling UNUserNotificationCenterDelegate
-
Open the project's Info.plist
-
Add the
NHUserNotificationCenterDelegateForwarderEnabled
key and set the value to 0. This disables the UNUserNotificationCenterDelegate auto-forwarding to MSNotificaitonHub. -
Implement UNUserNotificationCenterDelegate callbacks and pass the notification's payload to
MSNotificationHub
.Swift:
@available(iOS 10.0, *) func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { //... // Pass the notification payload to MSNotificationHub MSNotificationHub.didReceiveRemoteNotification(notification.request.content.userInfo) // Complete handling the notification completionHandler([]) } @available(iOS 10.0, *) func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { //... // Pass the notification payload to MSNotificationHub MSNotificationHub.didReceiveRemoteNotification(response.notification.request.content.userInfo) // Complete handling the notification completionHandler() }
Objective-C:
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler API_AVAILABLE(ios(10.0), tvos(10.0), watchos(3.0)) { //... // Pass the notification payload to MSNotificationHub [MSNotificationHub didReceiveRemoteNotification:notification.request.content.userInfo]; // Complete handling the notification completionHandler(UNNotificationPresentationOptionNone); } - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10.0), tvos(10.0), watchos(3.0)) { //... [MSNotificationHub didReceiveRemoteNotification:response.notification.request.content.userInfo]; // Complete handling the notification completionHandler(); }
Useful Resources
- Tutorials and product overview are available at Microsoft Azure Notification Hubs Developer Center.
- Our product team actively monitors the Notification Hubs Developer Forum to assist you with any troubles.
Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
All Objective-C files follow LLVM coding style (with a few exceptions) and are formatted accordingly. To format your changes, make sure you have the clang-format tool. It can be installed with Homebrew using the command brew install clang-format
. Once you have installed clang-format, run ./clang-format-changed-files.sh
from the repository root - this will format all files that have changes against the remote main
branch (it will also perform a git fetch).
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.