草庐IT

带有 Apple 的 C# MDM 服务器,无法发送推送通知

coder 2024-01-15 原文

我们正在为 iOS 设备开发 MDM 解决方案。

我们已经能够通过网站安装带有 MDM-Payload 的配置文件,并且我们已经收到 iOS 设备发送的包含 PushMagic、deviceToken 和其他值的 PUT 请求。

我们使用以下描述创建了一个 COMPANY.pem SSL 证书: http://www.softhinker.com/in-the-news/iosmdmvendorcsrsigning

我们尝试使用库 push-sharp 发送推送通知: https://github.com/Redth/PushSharp

我们使用这些命令构建 MDM.p12 文件

openssl pkcs12 -export -in ./COMPANY.pem -inkey ./customerPrivateKey.pem -certfile ./CertificateSigningRequest.certSigningRequest -out MDM.p12

发送此通知的程序没有抛出任何错误并正常退出。 但是我们在我们的设备上没有收到任何推送通知,也没有通过反馈服务收到任何东西。

另外值得一提的是,我们也尝试使用沙箱服务器和生产服务器。

这是我们使用 push-sharp 库的代码:

    using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;
using PushSharp;
using PushSharp.Apple;


namespace PushSharp.Sample
{
    class Program
    {
        static void Main(string[] args)
        {

            //Create our service    
            PushService push = new PushService();

            //Wire up the events
            push.Events.OnDeviceSubscriptionExpired += new Common.ChannelEvents.DeviceSubscriptionExpired(Events_OnDeviceSubscriptionExpired);
            push.Events.OnDeviceSubscriptionIdChanged += new Common.ChannelEvents.DeviceSubscriptionIdChanged(Events_OnDeviceSubscriptionIdChanged);
            push.Events.OnChannelException += new Common.ChannelEvents.ChannelExceptionDelegate(Events_OnChannelException);
            push.Events.OnNotificationSendFailure += new Common.ChannelEvents.NotificationSendFailureDelegate(Events_OnNotificationSendFailure);
            push.Events.OnNotificationSent += new Common.ChannelEvents.NotificationSentDelegate(Events_OnNotificationSent);

            //Configure and start Apple APNS
            // IMPORTANT: Make sure you use the right Push certificate.  Apple allows you to generate one for connecting to Sandbox,
            //   and one for connecting to Production.  You must use the right one, to match the provisioning profile you build your
            //   app with!
            //var appleCert = File.ReadAllBytes("C:\\TEMP\\apns-mdm.p12");
            var appleCert = File.ReadAllBytes(@".\MDM.p12");

            //IMPORTANT: If you are using a Development provisioning Profile, you must use the Sandbox push notification server 
            //  (so you would leave the first arg in the ctor of ApplePushChannelSettings as 'false')
            //  If you are using an AdHoc or AppStore provisioning profile, you must use the Production push notification server
            //  (so you would change the first arg in the ctor of ApplePushChannelSettings to 'true')
            push.StartApplePushService(new ApplePushChannelSettings(true, appleCert, "PWD"));


            //String p12File = @".\apns-mdm.p12";
            //String p12Password = "PWD";
            String pushMagicString = "00454668-00B2-4122-A1DC-72ACD64E6AFB";
            //String deviceToken = "27asObngxvVNb3RvRMs3XVaEWC1DNa3TjFE12stKsig=";


            //Configure and start Android GCM
            //IMPORTANT: The SENDER_ID is your Google API Console App Project ID.
            //  Be sure to get the right Project ID from your Google APIs Console.  It's not the named project ID that appears in the Overview,
            //  but instead the numeric project id in the url: eg: https://code.google.com/apis/console/?pli=1#project:785671162406:overview
            //  where 785671162406 is the project id, which is the SENDER_ID to use!
            //push.StartGoogleCloudMessagingPushService(new GcmPushChannelSettings("785671162406", "AIzaSyC2PZNXQDVaUpZGmtsF_Vp8tHtIABVjazI", "com.pushsharp.test"));

            //Configure and start Windows Phone Notifications
            //push.StartWindowsPhonePushService(new WindowsPhone.WindowsPhonePushChannelSettings());

            //Fluent construction of a Windows Phone Toast notification
            //push.QueueNotification(NotificationFactory.WindowsPhone().Toast()
            //.ForEndpointUri(new Uri("http://sn1.notify.live.net/throttledthirdparty/01.00/AAFCoNoCXidwRpn5NOxvwSxPAgAAAAADAgAAAAQUZm52OkJCMjg1QTg1QkZDMkUxREQ"))
            //.ForOSVersion(WindowsPhone.WindowsPhoneDeviceOSVersion.MangoSevenPointFive)
            //.WithBatchingInterval(WindowsPhone.BatchingInterval.Immediate)
            //.WithNavigatePath("/MainPage.xaml")
            //.WithText1("PushSharp")
            //.WithText2("This is a Toast"));

            //Fluent construction of an iOS notification
            //IMPORTANT: For iOS you MUST MUST MUST use your own DeviceToken here that gets generated within your iOS app itself when the Application Delegate
            //  for registered for remote notifications is called, and the device token is passed back to you
            String test = "3d 58 64 4d 90 d3 18 09 22 5c 50 d2 12 16 b5 67 71 1e be 5c 13 6e 41 3c 3e 81 b5 52 30 68 09 a5";
            test = test.Replace(" ", string.Empty);
            Console.WriteLine("Device Token length is: " + test.Length);
            Console.WriteLine("DeviceToken is: " + test);
            Console.WriteLine("PushMagic is: " + pushMagicString);

            DateTime dayAfterTomorrow = DateTime.Now.AddDays(2);
            Console.WriteLine("Expiry date is: " + dayAfterTomorrow.ToString());

            push.QueueNotification(NotificationFactory.Apple()
                .ForDeviceToken(test).WithExpiry(dayAfterTomorrow).WithCustomItem("mdm", pushMagicString));


            //push.Events.RaiseNotificationSent(NotificationFactory.Apple()
            //    .ForDeviceToken(hex).WithCustomItem("mdm", pushMagicString));


            //Fluent construction of an Android GCM Notification
            //push.QueueNotification(NotificationFactory.AndroidGcm()
            //    .ForDeviceRegistrationId("APA91bG7J-cZjkURrqi58cEd5ain6hzi4i06T0zg9eM2kQAprV-fslFiq60hnBUVlnJPlPV-4K7X39aHIe55of8fJugEuYMyAZSUbmDyima5ZTC7hn4euQ0Yflj2wMeTxnyMOZPuwTLuYNiJ6EREeI9qJuJZH9Zu9g")
            //    .WithCollapseKey("NONE")
            //    .WithJson("{\"alert\":\"Alert Text!\",\"badge\":\"7\"}"));

            Console.WriteLine("Waiting for Queue to Finish...");

            //Stop and wait for the queues to drains
            push.StopAllServices(true);

            Console.WriteLine("Queue Finished, press return to exit...");
            Console.ReadLine();
        }

        static void Events_OnDeviceSubscriptionIdChanged(Common.PlatformType platform, string oldDeviceInfo, string newDeviceInfo)
        {
            //Currently this event will only ever happen for Android GCM
            Console.WriteLine("Device Registration Changed:  Old-> " + oldDeviceInfo + "  New-> " + newDeviceInfo);
        }

        static void Events_OnNotificationSent(Common.Notification notification)
        {
            Console.WriteLine("Sent: " + notification.Platform.ToString() + " -> " + notification.ToString());
        }

        static void Events_OnNotificationSendFailure(Common.Notification notification, Exception notificationFailureException)
        {
            Console.WriteLine("Failure: " + notification.Platform.ToString() + " -> " + notificationFailureException.Message + " -> " + notification.ToString());
        }

        static void Events_OnChannelException(Exception exception)
        {
            Console.WriteLine("Channel Exception: " + exception.ToString());
        }

        static void Events_OnDeviceSubscriptionExpired(Common.PlatformType platform, string deviceInfo)
        {
            Console.WriteLine("Device Subscription Expired: " + platform.ToString() + " -> " + deviceInfo);
        }
    }
}

我们使用这个网站对接收到的 deviceToken 进行了编码: http://home.paulschou.net/tools/xlate/ 从 base64 到 HEX。

我们还在 iOS 设备上使用 APS/PC 日志记录配置文件,以通过 IPCU 提供的调试控制台获得更多输出。

最佳答案

发送到推送通知服务的消息不得包含 aps 键。该消息应仅包含 PushMagic 字符串作为 mdm 键的值。例如,使用您定义为 pushMagicString 的值,推送通知服务的消息应如下所示:

{"mdm":"00454668-00B2-4122-A1DC-72ACD64E6AFB"}

我没有使用过你正在使用的 push-sharp 库。但是,我简要浏览了代码,似乎 AppleNotificationPayload.ToJson 方法总是向消息添加 aps 键。我建议注释掉第 114 行然后尝试。这是注释掉该行的 ToJson 方法:

    public string ToJson()
    {
        JObject json = new JObject();

        JObject aps = new JObject();

        if (!this.Alert.IsEmpty)
        {
            if (!string.IsNullOrEmpty(this.Alert.Body)
                && string.IsNullOrEmpty(this.Alert.LocalizedKey)
                && string.IsNullOrEmpty(this.Alert.ActionLocalizedKey)
                && (this.Alert.LocalizedArgs == null || this.Alert.LocalizedArgs.Count <= 0)
                && !this.HideActionButton)
            {
                aps["alert"] = new JValue(this.Alert.Body);
            }
            else
            {
                JObject jsonAlert = new JObject();

                if (!string.IsNullOrEmpty(this.Alert.LocalizedKey))
                    jsonAlert["loc-key"] = new JValue(this.Alert.LocalizedKey);

                if (this.Alert.LocalizedArgs != null && this.Alert.LocalizedArgs.Count > 0)
                    jsonAlert["loc-args"] = new JArray(this.Alert.LocalizedArgs.ToArray());

                if (!string.IsNullOrEmpty(this.Alert.Body))
                    jsonAlert["body"] = new JValue(this.Alert.Body);

                if (this.HideActionButton)
                    jsonAlert["action-loc-key"] = new JValue((string)null);
                else if (!string.IsNullOrEmpty(this.Alert.ActionLocalizedKey))
                    jsonAlert["action-loc-key"] = new JValue(this.Alert.ActionLocalizedKey);

                aps["alert"] = jsonAlert;
            }
        }

        if (this.Badge.HasValue)
            aps["badge"] = new JValue(this.Badge.Value);

        if (!string.IsNullOrEmpty(this.Sound))
            aps["sound"] = new JValue(this.Sound);

        if (this.ContentAvailable.HasValue)
            aps["content-available"] = new JValue(this.ContentAvailable.Value);

        //json["aps"] = aps;

        foreach (string key in this.CustomItems.Keys)
        {
            if (this.CustomItems[key].Length == 1)
                json[key] = new JValue(this.CustomItems[key][0]);
            else if (this.CustomItems[key].Length > 1)
                json[key] = new JArray(this.CustomItems[key]);
        }

        string rawString = json.ToString(Newtonsoft.Json.Formatting.None, null);

        StringBuilder encodedString = new StringBuilder();
        foreach (char c in rawString)
        {
            if ((int)c < 32 || (int)c > 127)
                encodedString.Append("\\u" + String.Format("{0:x4}", Convert.ToUInt32(c)));
            else
                encodedString.Append(c);
        }
        return rawString;// encodedString.ToString();
    }

关于带有 Apple 的 C# MDM 服务器,无法发送推送通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11542629/

有关带有 Apple 的 C# MDM 服务器,无法发送推送通知的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  3. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  4. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  5. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  6. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  7. ruby-on-rails - 无法在centos上安装therubyracer(V8和GCC出错) - 2

    我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e

  8. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  9. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  10. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

随机推荐