Giter Site home page Giter Site logo

alexalok / dotapns Goto Github PK

View Code? Open in Web Editor NEW
106.0 6.0 33.0 138 KB

dotAPNS is a library used to send push notifications to Apple devices using Apple Push Notification service via HTTP/2 API.

License: Apache License 2.0

C# 100.00%
apns-http2 dotnet-core3 csharp netstandard20 apns apple apnsservice ios

dotapns's Introduction

๐ŸŽ What is dotAPNS?

Build status Nuget package Nuget package downloads

dotAPNS is a small library used to send pushes to Apple devices via the HTTP/2 APNs API, which is an officially recommended way of interacting with APNs (Apple Push Notification service).

dotAPNS itself targets .NET Framework 4.6, netstandard2.0 and netstandard2.1, while dotAPNS ASP.NET Core integration library targets netstandard2.0. The latter, however, is not needed to use the main library - it just provides some infrastructure helpers to ease the integration of the library into ASP.NET Core projects.

๐Ÿ› ๏ธ How to use it?

  1. Register your app with APNs (?)
  2. Decide whether you will use certificate-based or token-based connection to APNs. Token-based is easier since you won't have to perform any certificate conversions. For specific instructions, see below.
  3. Start sending pushes!

๐Ÿ“ƒ Certificate-based connection

Important: dotAPNS supports certificate-based connection only on .NET Core 3.0 and above. Full .NET Framework and .NET Core 2.2 and below are not supported! (Why?)

var apns = ApnsClient.CreateUsingCert("voip.p12");

or

var cert = new X509Certificate2("voip.p12");
var apns = ApnsClient.CreateUsingCert(cert);

Change voip.p12 so that it points to the certificate you are intended to use.

Note: dotAPNS supports certificates only in x509 format. You might have to convert the certificate you download from Developer Center to the supported format.

๐Ÿ” Token-based connection

Important: on .NET Core 2.0, 2.1 and 2.2 you need to execute the following code once before using library: AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);. Again, this needs to be called only once.

First, you need to specify some options that the library will use to create an authentication token:

var options = new ApnsJwtOptions() 
{
    BundleId = "bundle", 
    CertContent = "-----BEGIN PRIVATE KEY-----\r\nMIGTA ... -----END PRIVATE KEY-----", 
    // CertFilePath = "secret.p8", // use either CertContent or CertFilePath, not both
    KeyId = "key", 
    TeamId = "team"
};

BundleId - your appโ€™s bundle ID. Should not include specific topics (i.e. com.myapp but not com.myapp.voip).

CertFilePath - path to the .p8 certificate you have downloaded from the Developer Center.

CertContent - contents of the .p8 certificate. If specified, CertFilePath must not be set. This option allows you to use the library without having to store the actual certificate file. Contents may include everything in the certificate file (even the BEGIN/END PRIVATE KEY lines) or just the base64-encoded body, with or without line breaks (both \r\n and \r are supported ).

KeyId - The 10-character Key ID you obtained from your developer account (?).

TeamId - The 10-character Team ID you use for developing your companyโ€™s apps. Obtain this value from your developer account.

Once you've gathered all the information needed and created an options instance, it's time to call

var options = new ApnsJwtOptions() { ... };
var apns = ApnsClient.CreateUsingJwt(new HttpClient(), options);

Important: when on .NET Framework, make sure that the HttpClient instance you pass to CreateUsingJwt() has a HTTP2 support. The default HttpClient does not have it and will not work. As a workaround it is suggested to install System.Net.Http.WinHttpHandler .nuget package and instantiate the HttpClient with this custom handler as follows: new HttpClient(new WinHttpHandler()).

Note that the library requires you to supply HttpClient instance - this is done so that you can manage its lifecycle. Please see this article to learn more about why this is important. Also note that certificate-based connection method does not support HttpClient injection as of moment of writing.

๐ŸŽ‰You're now all set to start sending pushes!๐ŸŽ‰


๐Ÿ”” Send a push

To send the most basic alert notifications you might use the following code:

var options = new ApnsJwtOptions() { ... };
var apns = ApnsClient.CreateUsingJwt(new HttpClient(), options); 
var push = new ApplePush(ApplePushType.Alert)
    .AddAlert("title", "body")
    .AddToken("token");

try
{
    var response = await apns.Send(push);
    if (response.IsSuccessful)
    {
        Console.WriteLine("An alert push has been successfully sent!");
    }
    else
    {
        switch (response.Reason)
        {
            case ApnsResponseReason.BadCertificateEnvironment:
                // The client certificate is for the wrong environment.
                // TODO: retry on another environment
                break;
                // TODO: process other reasons we might be interested in
            default:
                throw new ArgumentOutOfRangeException(nameof(response.Reason), response.Reason, null);
        }
        Console.WriteLine("Failed to send a push, APNs reported an error: " + response.ReasonString);
    }
}
catch (TaskCanceledException)
{
    Console.WriteLine("Failed to send a push: HTTP request timed out.");
}
catch (HttpRequestException ex)
{
    Console.WriteLine("Failed to send a push. HTTP request failed: " + ex);
}
catch (ApnsCertificateExpiredException)
{
    Console.WriteLine("APNs certificate has expired. No more push notifications can be sent using it until it is replaced with a new one.");
}

Background (aka "silent") push

var push = new ApplePush(ApplePushType.Background)
    .AddContentAvailable()
    .AddToken("replaceme");

Note that background pushes are subject to certain limitations. There is no way to circumvent this.

Custom payload fields

To add your own fields to the push payload you may use the ApplePush.AddCustomProperty method, for example:

To add the field to the root of the payload

var push = new ApplePush(ApplePushType.Alert)
.AddCustomProperty("thread-id", "123");

Or to the aps section

var push = new ApplePush(ApplePushType.Alert)
.AddCustomProperty("thread-id", "123", true);

An example can also be found here.

Check out more examples here.


dotAPNS ASP.NET Core integration

NuGet

dotAPNS.AspNetCore is a library containing ApnsService class and some helpers methods to simplify its usage.

ApnsService is a class that is supposed to be consumed by controllers or other services of ASP.NET Core application. It is expected to be registered as a singleton.

ApnsService provides caching - it will reuse ApnsClients created earlier if they have the same certificate thumbprint (for certificate-based connections) or the same bundle id (for token-based connections). At the moment of writing cached ApnsClients never expire and there is no way to make them expire manually.

Note: at the moment of writing caching cannot be disabled for ApnsService!

You can register ApnsService automatically within your application by calling

services.AddApns(); in ConfigureServices method of your Startup class:

public void ConfigureServices(IServiceCollection services)
{
	services.AddRazorPages();
	services.AddApns(); // <-- this call registers ApnsService
    // ...
}

AddApns does the following:

  1. Registers named HttpClient with name dotAPNS.
  2. Registers ApnsClientFactory as a singleton - this is the factory used by ApnsService to create ApnsClient instances.
  3. Registers ApnsService as a singleton itself.

After registering, you can inject the ApnsService into any controller:

readonly IApnsService _apnsService;

public MyController(IApnsService apnsService)
{
	_apnsService = apnsService;
}

Note: you need to inject the interface (IApnsService), not the type itself!

IApnsService defines 4 methods that can be used to send pushes:

Task<ApnsResponse> SendPush(ApplePush push, X509Certificate2 cert);

Task<ApnsResponse> SendPush(ApplePush push, ApnsJwtOptions jwtOptions);

Task<List<ApnsResponse>> SendPushes(IReadOnlyCollection<ApplePush> pushes, X509Certificate2 cert);

Task<List<ApnsResponse>> SendPushes(IReadOnlyCollection<ApplePush> pushes, ApnsJwtOptions jwtOptions);

For example, the following code can be used to send a simple background push:

 var push = new ApplePush(ApplePushType.Background)
     .AddContentAvailable()
     .AddToken("token");
var options = new ApnsJwtOptions() { ... };
var response = await _apnsService.SendPush(push, options);

dotapns's People

Contributors

alexalok avatar dependabot[bot] avatar jboehle avatar m-frankiedsg avatar markerpen avatar maximilianast avatar mtalaga avatar veteroggg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

dotapns's Issues

There is no information about 3.x.x versions.

Hello,
I am using 2.6.1 version but you have published 3.x.x versions.
I can not find any information about what happens in 3.x.x versions.

  • What should I pay attention to when using 3.x versions?
  • What are the new features?

Best Regards.

Azure web app iOS notifications are not working.

When we publish this code on Azure - we are getting below error.

We have talked, azure technical support and they are saying -> your code is trying to write something to server area and that is not possible in azure.

this code is generating error on azure server.
var apns = ApnsClient.CreateUsingJwt(new HttpClient(new WinHttpHandler()), options);

can you help with this, any help is much appreciated.

System.Security.Cryptography.NCryptNative.ImportKey(SafeNCryptProviderHandle provider, Byte[] keyBlob, String format)
at System.Security.Cryptography.CngKey.Import(Byte[] keyBlob, String curveName, CngKeyBlobFormat format, CngProvider provider)
at dotAPNS.ApnsClient.CreateUsingJwt(HttpClient http, ApnsJwtOptions options)
at FileReadDemo.Helper.PushNotification.d__1.MoveNext()

How to Handle Unsuccessful: Unregistered

Hi,

We encountered a lot of unsuccessful APNS with a reason of: Unregistered (it seems that this is a enum). Is there a way to retrieve the HTTP Status code that is being returned by the APNS Api? It would be better to include the HTTP Status code as well and also the raw message (not only the library ENUM).

Also what does this error mean: Reason: Unregistered | Reason String: Unregistered , and how do we handle this? Does this mean that the push token is not accessible anymore and we can safely delete this from our DB?

Issue with SendAsync()

I'm currently trying to migrate away from PushSharp to support http/2 with sending apns notifications in my project. I was able to setup notifications within a test app (all done in .Net 4.6), but when trying to implement it within my actual app, I'm having issues with the SendAsync() function in the ApnsClient. It seems to make the request, and send the notification correctly, but it never returns a response (app just hangs after making the request). I've had similar issues to this with async tasks and solved it by adding ConfigureAwait(false) to the problem task, so I'm not sure if this is an issue with .Net (/something specific in my project), or if it should be changed within this package.

The message received was unexpected or badly formatted.

Hi I am using .NET Core 3.1 for writing AWS Lambda and using the Certificate based option to send push notification to APNS however I am getting the error - The message received was unexpected or badly formatted.

this is the code, I am using:

private async Task SendAsync(
byte[] certificate,
string certPassword,
string message,
string destination)
{
var x509 = new X509Certificate2(certificate, certPassword);
var applePushNotificationService = ApnsClient.CreateUsingCert(x509);
var push = new ApplePush(ApplePushType.Alert)
.AddAlert(message)
.AddToken(destination);
return await applePushNotificationService.SendAsync(push);
}

BadDeviceToken response

Hi,
I am using the following code to get the device token
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken) { byte[] bytes = deviceToken.ToArray<byte>(); string[] hexArray = bytes.Select(b => b.ToString("x2")).ToArray(); GlobalData.Instance.NotificationToken = string.Join(string.Empty, hexArray); }

Using this token in "Push Notification Tester' application I was able to send a notification to that device.

But the following code

var options = new ApnsJwtOptions()
{
BundleId = "bundle",
CertContent = "-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----",
KeyId = "",
TeamId = ""
};
var apns = ApnsClient.CreateUsingJwt(new HttpClient(new WinHttpHandler()), options);
var push = new ApplePush(ApplePushType.Alert)
.AddAlert("title", "body")
.AddToken("");
var response = await apns.SendAsync(push);

returns : "Failed to send a push, APNs reported an error: BadDeviceToken"

What am I doing wrong?

Support FCM Push Notifs

Hi! Thanks again for this great library. I hope FCM push notifs can be added in this library as well, to support the major mobile push notifs already. Right now we are still using different library just for FCM push (PushSharp), and it seems that pushsharp is still using the old FCM APIs.

Revisit JWT generation logic

It seems that there are some issues with how the method works in some environments (see #16, #52). Perhaps we can do everything strictly in-memory?

APNs subtitles

The APNs documentation indicates that push notifications may include a subtitle, in addition to the title and body. Is this something that can be added here? Thanks!

Allow setting "UseSandbox()" on per-push basis

Can you help me understand how to apply the UseSandbox() directive?

I have three iOS devices, one of which is a development device, which requires using the sandbox. When sending a push notification, my code checks to see if the target device is a development device (contained in the user database table). The process runs through this short segment:

If dicAPNS("isdev").ToLower = "true" Then
apns.UseSandbox()
End If

(All Push data is sent to the Push method in a dictionary, dicAPNS.)

Which works fine. However, I'm finding that with any subsequent alerts, it continues to try to use the sandbox, and then returns an error for non-development devices. For it to work for all of them, I am having to make sure the development device is last on the list.

I should mention that often the push notifications are issued in a loop, sending each notification rapidly firing one right after another. I don't know how important that is to this issue.

Thanks!

Apple AAA Certificate

Today I received:
On March 29, 2021, token and certificate-based HTTP/2 connections to the Apple Push Notification service must incorporate the new root certificate (AAACertificateServices 5/12/2020) which replaces the old GeoTrust Global CA root certificate.

I am using dotAPNS cause of HTTP/2 support.
So, is there any further action needed, to integrate the AAACertificate which can be downloaded from Apple I have seen so far?

I am using PC...

Thanks!

Exception when using token-based authentication in ASP.NET app hosted in IIS

The cause is explained at https://stackoverflow.com/a/1345402

System.TypeInitializationException: The type initializer for 'RestService.RestServiceImpl' threw an exception. ---> System.Security.Cryptography.CryptographicException: The system cannot find the file specified.

   at System.Security.Cryptography.NCryptNative.ImportKey(SafeNCryptProviderHandle provider, byte[] keyBlob, string format)
   at System.Security.Cryptography.CngKey.Import(byte[] keyBlob, string curveName, CngKeyBlobFormat format, CngProvider provider)
   at System.Security.Cryptography.CngKey.Import(byte[] keyBlob, CngKeyBlobFormat format, CngProvider provider)
   at dotAPNS.ApnsClient.CreateUsingJwt(HttpClient http, ApnsJwtOptions options)
   at [REDACTED].Common.Extensions.DotApnsExtensions+<>c.<.cctor>b__2_0() in C:\[REDACTED]\[REDACTED]\Common\Extensions\DotApnsExtensions.cs:line 11
   at System.Lazy<T>.CreateValue()
   at System.Lazy<T>.LazyInitValue()
   at System.Lazy<T>.get_Value()
   at [REDACTED].Common.Extensions.DotApnsExtensions.GetApnsClient() in C:\[REDACTED]\[REDACTED]\Common\Extensions\DotApnsExtensions.cs:line 21
   at RestService.RestServiceImpl..cctor() in C:\[REDACTED]\[REDACTED]\RestService\RestServiceImpl.svc.cs:line 45   --- End of inner exception stack trace ---
   at RestService.RestServiceImpl..ctor() in C:\[REDACTED]\[REDACTED]\RestService\RestServiceImpl.svc.cs:line 40
   at CreateRestService.RestServiceImpl()
   at System.ServiceModel.Dispatcher.InstanceProvider.GetInstance(InstanceContext instanceContext, Message message)
   at System.ServiceModel.Dispatcher.InstanceBehavior.GetInstance(InstanceContext instanceContext, Message request)
   at System.ServiceModel.InstanceContext.GetServiceInstance(Message message)
   at System.ServiceModel.Dispatcher.InstanceBehavior.EnsureServiceInstance(ref MessageRpc rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(ref MessageRpc rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(ref MessageRpc rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(ref MessageRpc rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(ref MessageRpc rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(ref MessageRpc rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(ref MessageRpc rpc)
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(ref MessageRpc rpc)
   at System.ServiceModel.Dispatcher.MessageRpc.Process(bool isOperationContextSet)

Making the Send method thread-safe

The Send() method calls GetOrGenerateJwt() (source) which is in turn not thread-safe. As a result multiple JWT tokens may be created at the very beginning of push sending and/or when JWT token is recreated due to its expiration.

Including emojis in push messages

With the legacy APNs system, emojis could be added inline with the text using Java escape code values, i.e. "Here \uD83D\uDC49 is an emoji." With the new system, the notifications displays the undecoded string literal. Using dotAPNS, do I need to be doing it another way? Thank you again!

There is a problem with sending multiple notifications.

Hi,
There is no problem sending notifications to a single device. When sending notifications to more than 20 devices, it does not send a notification to most of them. In addition, no exception logs occur for devices that it cannot send. I am writing my notification method below. Do you have any idea about this error?
Not: I am using v3.3.1 version.

Best regards

private async Task<BaseResponseModel> SendNotificationToAppleDeviceHTTP2(List<NotificationDevices> devices, string title, string body, AppNames appName)
        {
            BaseResponseModel result = new BaseResponseModel() { SonucKodu = 0 };
            String apiMessage = "";
            try
            {
                AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
                ApnsJwtOptions options = new ApnsJwtOptions();
                if (appName == AppNames.XXX)
                {
                    options = new ApnsJwtOptions()
                    {
                        BundleId = "com.xxxx.xxx",
                        CertContent = "-----BEGIN PRIVATE KEY-----MIGT-----END PRIVATE KEY-----",
                        KeyId = "5XXXXXXXX",
                        TeamId = "5XXXXXXX"
                    };
                }
                else
                {
                    return new BaseResponseModel()
                    {
                        SonucKodu = 0,
                        SonucMsj = "There is no apple certificate!",
                        SonucDegeri1 = "0"
                    };
                }
                ApnsClient apns = ApnsClient.CreateUsingJwt(new HttpClient(new WinHttpHandler()), options);
                foreach (var item in devices)
                {
                    try
                    {
                        ApplePush push;
                        if (appName == AppNames.XXX)
                        {
                            push = new ApplePush(ApplePushType.Alert)
                            .AddAlert(title, body)
                            .AddSound(generalNotificationSound)
                            .AddBadge(1)
                            .AddToken(item.RegID);
                        }
                        else
                        {
                            push = new ApplePush(ApplePushType.Alert)
                            .AddAlert(title, body)
                            .AddBadge(1)
                            .AddToken(item.RegID);
                        }

                        ApnsResponse response = await apns.SendAsync(push);
                        if (response.IsSuccessful)
                        {
                            Console.WriteLine("An alert push has been successfully sent!");
                            //apiMessage = "An alert push has been successfully sent!";
                        }
                        else
                        {
                            switch (response.Reason)
                            {
                                case ApnsResponseReason.BadCertificateEnvironment:
                                    // The client certificate is for the wrong environment.
                                    // TODO: retry on another environment
                                    apiMessage = "The client certificate is for the wrong environment.";
                                    WriteLog("The client certificate is for the wrong environment. " + DateTime.Now.ToString(), "SendNotificationToAppleDeviceHTTP2", masterLogPath);
                                    break;
                                // TODO: process other reasons we might be interested in
                                default:
                                    throw new ArgumentOutOfRangeException(nameof(response.Reason), response.Reason, null);
                            }
                            WriteLog("Failed to send a push, APNs reported an error: " + response.ReasonString + " " + DateTime.Now.ToString(), "SendNotificationToAppleDeviceHTTP2", masterLogPath);
                            apiMessage = "Failed to send a push, APNs reported an error: " + response.ReasonString;
                        }
                    }
                    catch (TaskCanceledException)
                    {
                        WriteLog("Failed to send a push: HTTP request timed out. " + DateTime.Now.ToString(), "SendNotificationToAppleDeviceHTTP2", masterLogPath);
                        apiMessage = "Failed to send a push: HTTP request timed out.";
                    }
                    catch (HttpRequestException ex)
                    {
                        WriteLog("HttpRequestException: " + ex.ToString() + " " + DateTime.Now.ToString(), "SendNotificationToAppleDeviceHTTP2", masterLogPath);
                        apiMessage = "HttpRequestException: " + ex.ToString();
                    }
                }

                result.SonucKodu = String.IsNullOrEmpty(apiMessage) ? 1 : 0;
                result.SonucMsj = "Notifications have been sent to " + devices.Count + " ios devices. (SendNotificationToAppleDeviceHTTP2)";
                result.SonucMsj = devices.Count + apiMessage;
                result.SonucDegeri1 = devices.Count.ToString();
            }
            catch (Exception ex)
            {
                return new BaseResponseModel()
                {
                    SonucKodu = 0,
                    SonucMsj = "SendNotificationToAppleDeviceHTTP2 Ex: " + ex.Message + " " + ex.StackTrace.ToString(),
                    SonucDegeri1 = "0"
                };
            }

            return result;
        }

Refresh Your Token Regularly

Hi,

It is stated in the APNS documentation that when using Token based, it should be refresh at least once per 60 mins: https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_token-based_connection_to_apns

Can i instantiate then reuse the APNS client up to more or less 50 mins? Then create a new one again after 50 mins and so forth? Is it thread safe? Like we plan to use the same APNS client from a multi thread?

Add multiple push tokens support?

Add a new AddTokens method allowing us to pass an array of push tokens so that the push is sent to each one of them instead of one.

Why not give a detailed example๏ผŸ

I have read it several times, but I don't know how to use it. I want to use P18 certificate and password to send information to Apple's interface. Why did I look for the code and didn't find an example? What's the point of your code

Support multiple apps from single server

I'm having a Push Notification server in .Net Framework and I want to use the same server for multiple apps under my Apple developer account. Since I cannot use the .p12 certificate, is there a way to achieve this using the token based mechanism?

Why I'm asking is, I saw the JWT token requires the bundle ID, and if so I may need to make different builds for each of my applications.

As of now, I'm using PushSharp (which doesn't support HTTP/2 based APNS) and .p12 certificate. So I can use one build and differentiate each client by giving in their respective APNS certificate.

Is there any solution other making different builds with each Bundle ID?

Thanks

System.net.http.winhttpexception a security error occurred Exception when using token-based authentication in ASP.NET app hosted in IIS

Hi,
I have made a wpf test application and i can sent notification perfectly. I moved send notification method to my real wcf project.
I get an error from my wcf project as follows.
Wcf project details

  • .Net Framework 4.6 wcf service project.
  • Token-based connection

Error info
system.net.http.httprequestexception an error occurred while sending the request system.net.http.winhttpexception a security error occurred.
I also added screenshot of exception.

Best regards;

natroHata_23_10_2020_12_49

Thread-id support

Hello,

I'd like to add a "thread-id" field to the payload, but after reading the documentation and checking the source code I couldn't figure it out how to do it. Is there a way already to do this, or if there isn't, are there any plants to implement it?

Thanks,
Tamรกs

APNS Header Information

Hi,
can someone help me with the Header properties which apple offer?

Iam looking for the Following:

apns-topic
apns-collapse-id
apns-priority
apns-expiration
apns-id
apns-push-type

https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns/

I found ApplePushType, Priority which I guess are apns-push-type and apns-priority, but what about the others?
Do I have to add them though AddCustomProperty??

.NET Framework support

Current status: partial support

  • JWT support
  • Certificate support (there's an external blocking bug, probably in WinHttpHandler, see #3)

Target level: .NET Framework 4.6

  • .NET Framework 4.5.2 (WinHttpHandler doesn't support this version)
  • .NET Framework 4.6 (partial support, certificate connection doesn't work)

MissingMethodException dotAPNS.ApnsClient dotAPNS.ApnsClient.CreateUsingJwt

Sending of push notification is done in a class library. Calling this library from a ASP.NET MVC application (.NET Framework 4.6.1) works. But when calling the library from a WEB API (.NET Framework 4.6.1) using Postman it is not working. It breaks on this line of code:

var apns = ApnsClient.CreateUsingJwt(new HttpClient(new WinHttpHandler()), options);

I see this in my log file:

System.MissingMethodException
HResult=0x80131513
Message=Methode niet gevonden: dotAPNS.ApnsClient dotAPNS.ApnsClient.CreateUsingJwt(System.Net.Http.HttpClient, dotAPNS.ApnsJwtOptions).
Source=ML.DomainModel
StackTrace:
at ML.DomainModel.PushMessaging.PushNotificationLogic.d__3.MoveNext() in C:\Projects\Makelaarsland-FEA-Push\ML.DomainModel\PushMessaging\PushNotificationLogic.cs:line 166

Mono support status

Current status on how dotAPNS works on Mono:

  • Apns.CreateUsingCert() - doesn't work due to a different X509Certificate2.Subject property handling. It doesn't include 0.9.2342.19200300.100.1.1=... extension as it does on .NET Framework and .NET Core.
  • Apns.CreateUsingJwt() - doesn't work, throws NotImplementedException somewhere in this method.

Since I don't use Mono and do not have resources to debug and test it, for library to support Mono an invested collaborator is required. Everyone is more than welcome to work on this.

Bouncy Castle warning with NETCoreApp,Version=v3.1

When i add dotAPNS.AspNetCore to my project i get this warning:
Warning NU1701: Package 'BouncyCastle 1.8.5' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework '.NETCoreApp,Version=v3.1'. This package may not be fully compatible with your project. (NU1701)

Is it maybe possible to use the netcore package of bouncycastle? https://www.nuget.org/packages/BouncyCastle.NetCore/
Maybe you could add add .NETCoreApp as target to your app and use the dotnet core variant of the lib.

Update README

Code examples in the README use obsolete constructions. They should be updated to the latest supported format.

Persisting last token time and value

I'm recreating the ApnsClient class when needed and then disposing of it, so there is no permanent instance to keep track of the last token and generation time. It seems to be working so far - I am able to send multiple messages in a short period without errors - but I'm not sure if this is something I should be concerned about.

Bouncy Castle - support for 3.1

Warning NU1701: Package 'BouncyCastle 1.8.5' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework '.NETCoreApp,Version=v3.1'. This package may not be fully compatible with your project. (NU1701)

Support apns-collapse-id Header

Hi,

I'd like to replace the content of notification ,then I need to add a "apns-collapse-id" field to the header.
Are there any plans to implement it?

Thanks,

Notification is sent, but always in the background

`ApplePushAlert pushAlert = new ApplePushAlert("TITLE", "BODY");

        ApplePush push = ApplePush
            .CreateAlert(pushAlert)
            .AddToken("12b5bb89699ca2a0068f4b01444d0cc49670c489b8e661c37e9029de3101141c");

        var apns = ApnsClient.CreateUsingJwt(new HttpClient(), options);

        ApnsResponse response = await apns.Send(push);`

I'm using the code above to send notifications to my passes. the notification is sent but I can't see it, it's always in the background.

Am I doing something wrong?

Not Returning Response After Calling SendAsync

I have tried using below option but not receiving any response. Please assist me what is going wrong

string certpath=@"F:\MyApplication\dotAPNS-master\ABMS_Distribution_Push_Notification_Certificate.p12";
string pass="XXX";
//var jwtOpt = new ApnsJwtOptions()
//{
// BundleId = bundleid,
// CertFilePath = p8privateKey,
// KeyId = p8privateKeyId,
// TeamId = TeamId
// };
//var client = ApnsClient.CreateUsingJwt(new HttpClient(), jwtOpt);
var client = ApnsClient.CreateUsingCert(certpath, pass);
Task sCode = Task.Run(async () =>
{
Console.WriteLine("Start 1");
var push = new ApplePush(ApplePushType.Alert)
.AddAlert("title", "body")
.AddToken("AAAA");
Console.WriteLine("Start 2");
var response = await client.SendAsync(push);
return response;
});

Error when used in a VB.Net project

I'm getting the below error when I used dotAPNS in a VB.Net project. I have System.Net.Http 4.3.4 and System.Diagnostics.DiagnosticSource also installed

System.IO.FileLoadException: Could not load file or assembly 'System.Diagnostics.DiagnosticSource, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'System.Diagnostics.DiagnosticSource, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
at System.Net.Http.WinHttpHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at dotAPNS.ApnsClient.d__17.MoveNext()

Null exception when using CertFilePath

Hey there,

I'm getting an error when using the CertFilePath of the ApnsJwtOptions.
I debugged through it and it looks like the code is doing some replacing on the options.CertContent, instead of the "certContent".

This is where the certContent is read.

if (options.CertFilePath != null)
{
      Debug.Assert(options.CertContent == null);
      certContent = File.ReadAllText(options.CertFilePath);   //certContent is read and saved to a local variable certContent
}

This is where the replace happens shortly after the if/else statement: (line 151 ApnsClient.cs)

 certContent = options.CertContent.Replace("\r", "").Replace("\n", "")
                .Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "");
//certContent is being set, but using the options? 

As you can see, options.CertContent is never set in the options. (As the documentation says, set one or the other, but not both - an exception is thrown if you try).

A work around is to do the file read yourself into the Options.CertContent.

Thanks!

.NET Core support status

.NET Core 3.x

  • ApnsClient.ConnectUsingJwt()
  • ApnsClient.ConnectUsingCert()

.NET Core 2.x

  • ApnsClient.ConnectUsingJwt() - works if AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false); is specified somewhere in the program before the connection is created.
  • ApnsClient.ConnectUsingCert() - doesn't work and probably will never do. Gets the same exception as in .NET Framework (see #3, #4)

Badge-only alerts?

I have tried to search this out on my own so I wouldn't trouble you with it, but I am having no luck. Under certain circumstances, I would like to send an alert that ONLY updates the badge, and not show an alert or play a sound. Is there a way to do that?

I've tried sending all blank fields except the badge field, and that didn't work. I also tried not adding the .AddAlert and the .AddSound parameters to the push command, and that didn't work.

Do you have any suggestions? Or is this just something that Apple doesn't allow?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.