Xamarin通知服务扩展问题

时间:2017-01-02 13:59:40

标签: ios push-notification notifications xamarin.ios localytics

我的Notification Service Extension存在问题。 我已经按照一步一步的文档 https://developer.xamarin.com/guides/ios/platform_features/introduction-to-ios10/user-notifications/enhanced-user-notifications/#Working_with_Service_Extensions

要实施,我已经这样做了。

  • 添加了与我的应用相同前缀的通知服务扩展(添加后缀,例如:APP:com.testapp.main - EXT:com.testapp.main.notificationextension)
  • 在Apple的会员中心创建APPID标识符com.testapp.main.notificationextension
  • 创建证书和配置文件以发送APP ID的推送通知com.testapp.main.notificationextension
  • 导入Xcode和Xamarin证书和配置
  • 参考通知扩展参考构建我的应用程序。
  • 创建存档以上传到TestFlight
  • 使用其分发证书和配置文件签名的应用程序
  • 带有分发证书和配置文件的签名扩展
  • 上传到TestFlight
  • 下载并允许我的应用推送通知
  • 使用Localytics Dashboard发送富推送通知以进行消息传递 - 设备接收推送通知但未通过NotificationService.cs通知服务扩展代码!

这是我的NotificationService代码:

using System;
using Foundation;
using UserNotifications;

namespace NotificationServiceExtension
{
    [Register("NotificationService")]
    public class NotificationService : UNNotificationServiceExtension
    {
        Action<UNNotificationContent> ContentHandler { get; set; }
        UNMutableNotificationContent BestAttemptContent { get; set; }
        const string ATTACHMENT_IMAGE_KEY = "ll_attachment_url";
        const string ATTACHMENT_TYPE_KEY = "ll_attachment_type";
        const string ATTACHMENT_FILE_NAME = "-localytics-rich-push-attachment.";

        protected NotificationService(IntPtr handle) : base(handle)
        {
            // Note: this .ctor should not contain any initialization logic.
        }

        public override void DidReceiveNotificationRequest(UNNotificationRequest request, Action<UNNotificationContent> contentHandler)
        {
            System.Diagnostics.Debug.WriteLine("Notification Service DidReceiveNotificationRequest");
            ContentHandler = contentHandler;
            BestAttemptContent = (UNMutableNotificationContent)request.Content.MutableCopy();
            if (BestAttemptContent != null)
            {
                string imageURL = null;
                string imageType = null;
                if (BestAttemptContent.UserInfo.ContainsKey(new NSString(ATTACHMENT_IMAGE_KEY)))
                {
                    imageURL = BestAttemptContent.UserInfo.ValueForKey(new NSString(ATTACHMENT_IMAGE_KEY)).ToString();
                }
                if (BestAttemptContent.UserInfo.ContainsKey(new NSString(ATTACHMENT_TYPE_KEY)))
                {
                    imageType = BestAttemptContent.UserInfo.ValueForKey(new NSString(ATTACHMENT_TYPE_KEY)).ToString();
                }

                if (imageURL == null || imageType == null)
                {
                    ContentHandler(BestAttemptContent);
                    return;
                }
                var url = NSUrl.FromString(imageURL);
                var task = NSUrlSession.SharedSession.CreateDownloadTask(url, (tempFile, response, error) =>
                {
                    if (error != null)
                    {
                        ContentHandler(BestAttemptContent);
                        return;
                    }
                    if (tempFile == null)
                    {
                        ContentHandler(BestAttemptContent);
                        return;
                    }
                    var cache = NSSearchPath.GetDirectories(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomain.User, true);
                    var cachesFolder = cache[0];
                    var guid = NSProcessInfo.ProcessInfo.GloballyUniqueString;
                    var fileName = guid + ATTACHMENT_FILE_NAME + imageType;
                    var cacheFile = cachesFolder + fileName;
                    var attachmentURL = NSUrl.CreateFileUrl(cacheFile, false, null);
                    NSError err = null;
                    NSFileManager.DefaultManager.Move(tempFile, attachmentURL, out err);
                    if (err != null)
                    {
                        ContentHandler(BestAttemptContent);
                        return;
                    }
                    UNNotificationAttachmentOptions options = null;
                    var attachment = UNNotificationAttachment.FromIdentifier("localytics-rich-push-attachment", attachmentURL, options, out err);
                    if (attachment != null)
                    {
                        BestAttemptContent.Attachments = new UNNotificationAttachment[] { attachment };
                    }
                    ContentHandler(BestAttemptContent);
                    return;
                });
                task.Resume();
            }
            else {
                ContentHandler(BestAttemptContent);
            }
        }

        public override void TimeWillExpire()
        {
            // Called just before the extension will be terminated by the system.
            // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
            ContentHandler(BestAttemptContent);
            return;
        }

    }
}

2 个答案:

答案 0 :(得分:5)

你正在做的一切正确,这是一些其他xamarin开发人员提出的问题。据我所知,只要你运行NSURLSession下载一些东西,即使它超级超级小,你也要超过这种类型扩展所允许的内存限制。这很可能是非常特殊的xamarin。 这是bugzilla的链接。 https://bugzilla.xamarin.com/show_bug.cgi?id=43985

我发现的解决方法/黑客远非理想。我在objective-c中重写了xcode中的这个app扩展(你也可以使用swift)。这是一个相当小(1级)的扩展。然后使用相同的代码签名证书/配置文件在xcode中构建它,然后在xcode的输出中找到.appex文件。

从那时起,您可以采取“便宜的方式”,并在辞职和提交应用程序之前手动将此.appex文件交换到.ipa文件夹中。如果这对你来说足够好,你就可以到此为止。

或者您可以自动执行此过程,为此,将appex文件放在csproj的扩展中,并将build-action设置为“content”。然后在这个csproj的文件中(你需要直接编辑)你可以添加这样的东西。 (在这种情况下,该文件名为Notifications.appex,并放在名为NativeExtension的文件夹中)

<Target Name="BeforeCodeSign">
    <ItemGroup>
        <NativeExtensionDirectory Include="NativeExtension\Debug\**\*.*" />
    </ItemGroup>

    <!-- cleanup the application extension built with Xamarin (too heavy in memory)-->
    <RemoveDir SessionId="$(BuildSessionId)"
               Directories="bin\iPhone\Debug\Notifications.appex"/>

    <!-- copy the native one, built in obj-c -->
    <Copy
            SessionId="$(BuildSessionId)"
            SourceFiles="@(NativeExtensionDirectory)"
            DestinationFolder="bin\iPhone\Debug\Notifications.appex"
            SkipUnchangedFiles="true"
            OverwriteReadOnlyFiles="true"
            Retries="3"
            RetryDelayMilliseconds="300"/>
</Target>

这为您提供了一般性的想法,但显然如果您想支持ad-hoc分发签名,iOS应用商店分发签名,您需要在此添加更多代码(并且可能在csproj中添加本机appex每个不同签名的文件),我建议将这些xml代码放在单独的“.targets”文件中,并在csproj中使用条件调用目标。像这样:

<Target Name="BeforeCodeSign">
    <CallTarget Targets="ImportExtension_Debug" Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' " />
    <CallTarget Targets="ImportExtension" Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' " />
 </Target>

答案 1 :(得分:0)

如果有其他人来到这里,原始海报的代码对我有效,现在标记为已修复。如果我有一个提示,请不要尝试在Windows上执行此操作。你将陷入痛苦的整个世界,并且无处可去(实际上,它曾经为我工作过一次!)。如果您尝试调试,还期望Mac上的Visual Studio崩溃!