After a few weeks of fighting with the Push Notifications in NET8 MAUI using Azure Notification Hub for iOS and it wasn’t working, I finally found the way to do it. In this post, I will explain every step and how to implement the push notification, jumping from the Apple developer website, Azure portal and the code in C#.
So, I show you everything I discovered without using external plugin but only what MAUI offers and HttpClient
. I split this topic in a few posts:
- MAUI Push Notifications using Azure Notification Hub for Windows
- MAUI Push Notifications using Azure Notification Hub for Android
- MAUI Push Notifications using Azure Notification Hub for iOS
Now, it is time to start the journey and discover how to do it.
Configure push notification in the Apple Developer portal
First, I have to create the certificates from the Apple Developer portal specifically for the application. The prerequisites for that are:
- An active Apple Developer account.
- A Mac running Xcode, along with a valid developer certificate, is installed into your Keychain.
- An iPhone or iPad running iOS version 10 or later.
- Your physical device registered in the Apple Portal and associated with your certificate.
Generate the certificate-signing request file
The Apple Push Notification Service (APNS) uses certificates to authenticate your push notifications. Follow these instructions to create the necessary push certificate to send and receive notifications. For more information on these concepts, see the official Apple Push Notification Service documentation.
Generate the Certificate Signing Request (CSR) file, which Apple uses to generate a signed push certificate:
- On your Mac, run the Keychain Access tool. It can be opened from the Utilities folder or the Other folder on the Launchpad.
- The application is asking you what I want to open. You should see the following window. Select Open Keychain access.
- Select Keychain Access, expand Certificate Assistant, and then select Request a Certificate from a Certificate Authority.
- Select your User Email Address, enter your Common Name value, make sure that you specify Saved to disk, and then select Continue. Leave CA Email Address blank as it isn’t required.
- Enter a name for the CSR file in Save As, select the location in Where, and then select Save. This action saves the CSR file in the selected location. The default location is Desktop. Remember the location chosen for the file.
Next, register your app with Apple, enable push notifications, and upload the exported CSR to create a push certificate.
Register your app for push notifications
To send push notifications to an iOS app, register your application with Apple, and also register for push notifications.
- If you haven’t already registered your app, browse to the iOS Provisioning Portal at the Apple Developer Center. Sign in to the portal with your Apple ID, and select Identifiers. Then select + to register a new app.
- On the Register a New Identifier screen, select the App IDs radio button. Then select Continue.
- Update the following three values for your new app, and then select Continue:
- Description: Type a descriptive name for your app.
- Bundle ID: Enter a Bundle ID of the form Organization Identifier.Product Name as mentioned in the App Distribution Guide. The Organization Identifier and Product Name values must match the organization identifier and product name you use when you create your Xcode project. In the following screenshot, the NotificationHubs value is used as an organization identifier and the GetStarted value is used as the product name. Make sure the Bundle Identifier value matches the value in your Xcode project so that Xcode uses the correct publishing profile.
- Push Notifications: Check the Push Notifications option in the Capabilities section.This action generates your App ID and requests that you confirm the information. Select Continue, then select Register to confirm the new App ID.After you select Register, you see the new App ID as a line item on the Certificates, Identifiers & Profiles page.
- In the Certificates, Identifiers & Profiles page, under Identifiers, locate the App ID line item that you just created, and select its row to display the Edit your App ID Configuration screen.
Create a certificate for Notification Hubs
With the release of iOS 13, you can only receive silent notifications using token based authentication. If you are using certificate-based authentication for your APNS credentials, you must switch to using token-based authentication.
A certificate is required to enable the notification hub to work with APNS. This can be done in one of two ways:
- Create a .p12 file that can be uploaded directly to Notification Hubs.
- Create a .p8 file that can be used for token-based authentication (the newer approach).
The second option has a number of benefits compared to using certificates, as documented in Token-based (HTTP/2) authentication for APNS. However, steps are provided for both approaches.
Option 1: Create a .p12 push certificate that can be uploaded directly to Notification Hubs
- Scroll down to the checked Push Notifications option, and then select Configure to create the certificate.
- The Apple Push Notification service SSL Certificates window appears. Select the Create Certificate button in the Development SSL Certificate section. The Create a new Certificate screen is displayed. Follow the same process for the Production certificate.
- Select Choose File, browse to the location at which you saved the CSR file from the first task, and then double-click the certificate name to load it. Then select Continue.
- After the portal creates the certificate, select the Download button. Save the certificate, and remember the location to which it’s saved. The certificate is downloaded and saved in your Downloads folder. By default, the downloaded development certificate is named aps_development.cer.
- Double-click the downloaded push certificate aps_development.cer. This action installs the new certificate in the Keychain, as shown in the following image
- In Keychain Access, right-click the new push certificate that you created in the Certificates category. Select Export, name the file, select the .p12 format, and then select Save.
You can choose to protect the certificate with a password, but this is optional. Click OK if you want to bypass password creation. Make a note of the file name and location of the exported .p12 certificate. They are used to enable authentication with APNS.
Option 2: Create a .p8 certificate that can be used for token-based authentication
- Make note of the following details:
- App ID Prefix (this is a Team ID)
- Bundle ID
- Back in Certificates, Identifiers & Profiles, click Keys. If you already have a key configured for APNS, you can re-use the .p8 certificate that you downloaded right after it was created. If so, you can ignore steps 3 through 5.
- Click the + button (or the Create a key button) to create a new key.
- Provide a suitable Key Name value, check the Apple Push Notifications service (APNS) option, and then click Continue, followed by Register on the next screen.
- Click Download and then move the .p8 file (prefixed with
AuthKey_
) to a secure local directory, then click Done. Important: Be sure to keep your .p8 file in a secure place (and save a backup). After downloading your key, it cannot be re-downloaded; the server copy is removed. - On Keys, click on the key that you just created (or an existing key if you have chosen to use that instead).
- Make note of the Key ID value.
- Open your .p8 certificate in a suitable application of your choice, such as Visual Studio Code, then make note of the key value. This is the value between —–BEGIN PRIVATE KEY—– and —–END PRIVATE KEY—–
-----BEGIN PRIVATE KEY-----
<key_value>
-----END PRIVATE KEY-----
At the end of these steps you should have the following information for use later in Configure your notification hub with APNS information:
- Team ID (see step 1)
- Bundle ID (see step 1)
- Key ID (see step 7)
- Token value (the .p8 key value, see step 8)
Configure the notification hub with APNS information
Under Notification Services, select Apple (APNS), then follow the appropriate steps based on the approach you chose previously in the Creating a Certificate for Notification Hubs section.
Option 1: Use a .p12 push certificate
- Select Certificate.
- Select the file icon.
- Select the .p12 file that you exported earlier, and then select Open.
- If required, specify the correct password.
- Select Sandbox mode.
- Save
Option 2: Use token-based authentication
- Select Token.
- Enter the following values that you acquired earlier:
- Key ID
- Bundle ID
- Team ID
- Token
- Choose Sandbox
- Select Save.
You’ve now configured your notification hub with APNS. You also have the connection strings needed to register your app and send push notifications.
Create a provisioning profile
- Return to the iOS Provisioning Portal, select Certificates, Identifiers & Profiles, select Profiles from the left menu, and then select + to create a new profile. The Register a New Provisioning Profile screen appears.
- Select iOS App Development under Development as the provisioning profile type, and then select Continue.
- Next, select the app ID you created from the App ID drop-down list, then select Continue.
- In the Select certificates window, select the development certificate that you use for code signing, and select Continue. This certificate isn’t the push certificate you created. If one does not exist, you must create it. If a certificate does exist, skip to the next step. To create a development certificate if one does not exist:
- If you see No Certificates are available, select Create Certificate.
- In the Software section, select Apple Development. Then select Continue.
- In the Create a New Certificate screen, select Choose File.
- Browse to the Certificate Signing Request certificate you created earlier, select it, and then select Open.
- Select Continue.
- Download the development certificate, and remember the location in which it’s saved.
- Return to the Certificates, Identifiers & Profiles page, select Profiles from the left menu, and then select + to create a new profile. The Register a New Provisioning Profile screen appears.
- In the Select certificates window, select the development certificate that you just created. Then select Continue.
- Next, select the devices to use for testing, and select Continue.
- Finally, choose a name for the profile in Provisioning Profile Name, then select Generate.
- When the new provisioning profile is created, select Download. Remember the location in which it’s saved.
- Browse to the location of the provisioning profile, and then double-click it to install it on your Xcode development machine.
Configure the Azure Notification Hub
In the first post of this series about the implementation of Push Notifications in MAUI using Azure Notification Hub, I have created an Azure Notification Hub. From the Apple Developer website, I can download the Apple Push Notification service SSL Certificates for development and production.
Now, go to the Azure portal and open the Notification Hub. Here I can upload the certificate that I created from the Apple Developer portal.
One important thing I learned and blocked me for more than 2 weeks is that I can import only one certificate. You see in the Application Mode, there are 2 options:
- Production
- Sandbox
What I did was to upload first the certificate for Production and Save and then the one for Sandbox and save. I was thinking that Azure saves both certificates but it was only my idea and I was wrong. Only one certificate is available. Now, I use the Sandbox and this is important because I have to configure the Entitlements.plist
accordingly.
Add Entitlements.plist to the iOS Platform
To add a new entitlements file to your .NET MAUI app project, add a new XML file named Entitlements.plist to the Platforms\iOS folder of your app project. Then add the following XML to the file:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>
If I want to add the entitlement for push notifications, I have to add those lines
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)yourappnamespace</string>
</array>
<key>aps-environment</key>
<string>development</string>
</dict>
</plist>
The keychain-access-groups
is the value that identifies your application. The aps-environment
defines the environment for the push notification. It can have 2 values: development or production. This is explained in the Apple documentation. In the case of this post, I’m using development. When I deploy the application on the Apple Store, I should change it.
That has made me think that I have to create 2 Notification Hubs: one for development and one for production. Only Apple has 2 different settings. Windows and Android don’t distinguish between environments.
If you want to read more about the Entitlements.plist, there is a Microsoft documentation that explains every key.
Another thing it is important to know and I haven’t found anything about it is what Properties I have to set for the Entitlements.plist
. There are no particular properties to set but I have to change the project properties as I describe in the next section.
Consume entitlements
A .NET MAUI iOS app must be configured to consume the entitlements defined in the Entitlements.plist file. So, in Visual Studio follow those steps:
- In Solution Explorer, right-click on your .NET MAUI app project and select Properties. Then, navigate to the iOS > Bundle Signing tab.
- In the Bundle Signing settings, click the Browse… button for the Custom Entitlements field.
- In the Custom Entitlements dialog, navigate to the folder containing your Entitlements.plist file, select the file, and click the Open button.
- In the project properties, the Custom Entitlements field will be populated with your entitlements file:
I think there is a bug in Visual Studio. Sometimes, when I set the Custom Entitlements and deploy on a device, I get some weird errors like
error MT1045: Failed to execute 'devicectl': 'devicectl -j /var/folders/dm/bwmxpbzn6bvdsyy73c_b453w0000gn/T/tmpBkAavG.tmp device install app --device "Enrico???s iPhone" /Users/enrico/Library/Caches/Xamarin/mtbs/builds/LanguageInUse/1fa03704bb15e35c6f47a701d9d92131e3e0740198296a93338bb3c829bc9cf7/bin/Debug/net8.0-ios/ios-arm64/device-builds/iphone15.2-17.3.1/LanguageInUse.app' returned the exit code 1. 0
After a few days, I saw that not only the Custom Entitlements but also the Custom Resource Rules had the same configuration but I haven’t set it. I deleted the Custom Resources Rules and I could deploy the application.
The code
Finally, I can go into my code to implement the Push Notification for iOS. First step is to ask the permissions to the user to send push notification.
Require user authorization
Now, open your AppDelegate.cs
and in the FinishedLaunching
add the request for the authorization. This will open a request from the system to the user if it wants to authorize your application to receive the notifications.
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
var result = base.FinishedLaunching(application, launchOptions);
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) =>
{
if (granted && error == null)
{
this.InvokeOnMainThread(() =>
{
UIApplication.SharedApplication.RegisterForRemoteNotifications();
UNUserNotificationCenter.Current.Delegate = this;
});
}
});
return result;
}
If the user authorizes your app to receive the push notification, the function RegisterForRemoteNotifications is called. This is an important function that is coming from Apple.
Configure RegisterForRemoteNotifications
I can’t stress how much pain was to understand all the processes until here and how much time I spent in debugging without finding a reason why my code wasn’t working. I must use this function to set the push notification. First, I have to add and define this function in the code in this way
[Export("application:didRegisterForRemoteNotificationsWithDeviceToken:")]
public async void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
// ...
}
In the deviceToken
iOS gives to me what I have to use to set the push channel in the call to the Azure Notification Hub. This NSData
is an Apple structure that contains an array of bytes. The problem was how to transform this sequence of bytes in a correct value to use. Fost forward to the solution, this is how to convert the deviceToken
to the string I must use to register the device with the Azure Notification Hub.
string token = null!;
if (deviceToken.Length > 0)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
var data = deviceToken.ToArray();
token = BitConverter
.ToString(data)
.Replace("-", "")
.Replace("\"", "");
}
else if (!string.IsNullOrEmpty(deviceToken.Description))
{
token = deviceToken.Description.Trim('<', '>');
}
}
It is important to check what version of the iOS operating system the user is currently on. If the version is a new one, I have to use BitConverter
to get the string I need.
Now, I have to find the device Id. This is quite straightforward after spending a few hours googling and binging. This is the code
string deviceId = UIDevice.CurrentDevice.IdentifierForVendor.AsString();
Finally, I can call the Azure Notification Hub to register the device.
var deviceInstallation = new
{
InstallationId = deviceId,
Platform = "apns",
PushChannel = token
};
using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("x-ms-version", "2015-01");
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization",
CreateToken($"https://{Constants.PushNotificationHubNamespace}.servicebus.windows.net",
"DefaultListenSharedAccessSignature",
Constants.PushNotificationSecret));
var t = await httpClient.PutAsJsonAsync($"https://{Constants.PushNotificationHubNamespace}.servicebus.windows.net/" +
$"{Constants.PushNotificationHub}/installations/{deviceInstallation.InstallationId}?api-version=2015-01",
deviceInstallation);
Receive the notification
Now, I have to tell iOS what has to happen when a message from push notification arrives. For that, there is a specific function called WillPresentNotification and my basic implementation is the following
[Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification(UNUserNotificationCenter center,
UNNotification notification,
Action<UNNotificationPresentationOptions> completionHandler)
{
var userInfo = notification.Request.Content.UserInfo;
// tell the system to display the notification in a standard way
// or use None to say app handled the notification locally
completionHandler(UNNotificationPresentationOptions.Alert);
}
Wrap up
In conclusion, after a few long weeks, I finally managed to have my project working and receiving push notifications from Azure Notification Hub. I created those posts because I couldn’t find much documentation and the process, in particular for iOS, was very painful. Hopefully, this can help someone else avoid the mistakes I made. Please let me know in the comment below or the Forum if you have any questions, comments or suggestions.
If you want to support my job or just send a token of appreciation, you can consider paying me a beer using the Sponsor on GitHub.
Is this code available? I am inferring some things, one that when you say UNUserNotificationCenter.Current.Delegate = this;
that the IUNUserNotificationCenterDelegate has been added to the class. Also hard to understand where the rest of the code goes.
The code is in the posts. Do you need the implementation for iOS?
Yes using Azure Hub and Maui 8 IOS
Also CreateToken is undefined. I appreciate you posting this. I was about to give up and use google firebase.
I can guarantee you the solution with Azure is working just fine.
Hi Enrico,
Thank you very much for providing guidance on implementing push notifications using Azure Notification Hub for the .NET MAUI iOS platform. I have meticulously followed your code and integrated it into my project, but I am currently unable to receive push notifications.
Could you please share a sample repository containing all the necessary code? This would greatly help me identify where I might be going wrong.
Additionally, could you provide instructions on how to test the iOS platform by sending test notifications from the Azure Portal Notification Hub? At the moment, my device is not being registered, and I do not see any registered devices on the portal. Any assistance with this issue would be greatly appreciated. Thank you.
Hi.
I´m having the same problem as Chad. CreateToken method is undefined. Can you give us more information about this?
I’m on holiday right now. I’ll create a project for it when I’m back.