alexalok / dotapns Goto Github PK
View Code? Open in Web Editor NEWdotAPNS 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
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
Current status on how dotAPNS works on Mono:
Apns.CreateUsingCert()
0.9.2342.19200300.100.1.1=...
extension as it does on .NET Framework and .NET Core.Apns.CreateUsingJwt()
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.
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()
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?
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.
I want to sent silent push notification. can some one give example how we can achieve this.
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?
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!
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
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;
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
Hi,
Thank you for this beautiful library. I have .net framework 4.6 wcf service project and objective-c iOS mobile project. I have added this library to my wcf project and i can send notifications.
Do I need to make changes to my iOS project before the date (March 31, 2021) specified by the apple company?
Best regards.
Current status: partial support
WinHttpHandler
, see #3)Target level: .NET Framework 4.6
`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?
I want to send image in APNS payload using this library
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,
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!
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.
returns : "Failed to send a push, APNs reported an error: BadDeviceToken"
What am I doing wrong?
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
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??
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
Dear,
it could be interesting support also notification's expiration date.
According to documentation, It needs to add in the HttpRequestMessage the header 'apns-expiration' with a 'UNIX epoch date expressed in seconds (UT'').
Thanks,
Denis.
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)
BouncyCastle portable version with support for .NET 4, .NET Standard 2.0, MonoAndroid, Xamarin.iOS, .NET Core
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.
How does the dotAPNS package handle JWT expiration?
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.
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()
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)
Hi! This library is very useful. Thank you for creating it. I would like to view the changelogs for every version released in nuget. Is there a changelog? I can't find it in the Tags / Release part of this github repo. Thanks!
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.
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
I get the message:
the await operator can only be used within an async method
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.
External issue, see actions/runner-images#1090 and actions/setup-dotnet#155.
Suggested workaround: actions/runner-images#1090 (comment)
As stated in the Apple documentation the APNS has 2 Ports 443 as well as 2197.
There should be a property for the port in order to switch between those two.
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;
});
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!
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!
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.
Best Regards.
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!
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
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;
}
Code examples in the README use obsolete constructions. They should be updated to the latest supported format.
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);
}
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.
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!
Add an example showing how to add a custom field to the push payload in the README - both to the root and the aps
sections.
.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()
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.