Проблема с расширением службы уведомлений Xamarin

У меня проблема с расширением службы уведомлений. Я следил за пошаговой документацией 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)
  • Создан идентификатор APPID com.testapp.main.notificationextension в членском центре Apple
  • Создан сертификат и профиль обеспечения для отправки push-уведомления для APP ID com.testapp.main.notificationextension
  • Импортировано в Xcode и Xamarin сертификат и подготовка
  • Создайте мое приложение со ссылкой на ссылку на расширение уведомлений.
  • Создан архив для загрузки в TestFlight
  • Подписанное приложение с его сертификатом распространения и профилем обеспечения
  • Подписанное расширение с его сертификатом распространения и профилем обеспечения
  • Загружено в TestFlight
  • Скачать и разрешить push-уведомление для моего приложения
  • Отправлено полнофункциональное push-уведомление с помощью панели мониторинга Localytics для обмена сообщениями - устройство получает push-уведомление , но не передает код 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;
        }

    }
}

person Luigi Saggese    schedule 02.01.2017    source источник
comment
Так в чем же проблема?   -  person Demitrian    schedule 02.01.2017
comment
Устройство получает push-уведомление, но не передает код NotificationService.cs расширения службы уведомлений!   -  person Luigi Saggese    schedule 02.01.2017
comment
Что значит не проходит? Вы имеете в виду, что DidReceiveNotificationRequest не выполняется?   -  person Demitrian    schedule 02.01.2017
comment
Точный. Я также попытался изменить только заголовок push внутри DidReceiveNotificationRequest, но он не вызывается.   -  person Luigi Saggese    schedule 02.01.2017
comment
Какая версия iOS у вас установлена? Расширения недоступны до iOS 10. Кроме того, я предполагаю, что вы включили расширение в качестве нового проекта в решение, в котором находится ваше приложение?   -  person Demitrian    schedule 02.01.2017
comment
Да, это новый проект (созданный как расширение службы уведомлений) с целью развертывания 10.0. Внутри проекта моего приложения я добавил ссылку на расширение проекта (внутри .csproj также автоматически установлен истинный тег xml ‹IsAppExtension› true ‹/IsAppExtension›, затем он распознается как расширение). Моя цель развертывания приложения начинается с версии 8.1. Я установил приложение на устройство с iOS 10.2.   -  person Luigi Saggese    schedule 02.01.2017
comment
Позвольте нам продолжить это обсуждение в чате.   -  person Luigi Saggese    schedule 02.01.2017
comment
Можете ли вы поделиться примером отправляемого сообщения? Я надеюсь подтвердить, что он содержит mutable-content: 1. Кроме того, при отладке проверьте журналы устройства и найдите любые очевидные ошибки, которые могут быть связаны.   -  person therealjohn    schedule 10.01.2017
comment
Мы отправили Rich Push через панель управления Localytics docs.localytics.com/dev/ios .html # rich-push-ios.   -  person Luigi Saggese    schedule 10.01.2017


Ответы (2)


Вы все делаете правильно, это проблема, поднятая несколькими другими разработчиками xamarin. Насколько я могу судить, как только вы запускаете NSURLSession для загрузки чего-либо, даже если оно очень маленькое, вы превысите лимит памяти, разрешенный для этого типа расширения. Скорее всего, это очень специфично для xamarin. Вот ссылка на bugzilla. https://bugzilla.xamarin.com/show_bug.cgi?id=43985

Обходной путь / хак, который я нашел, далек от идеала. Я переписал это расширение приложения в xcode в objective-c (полагаю, вы тоже можете использовать swift). Это довольно небольшое расширение (1 класс). Затем построил его в xcode, используя тот же профиль сертификата подписи кода / обеспечения, а затем нашел файл .appex в выводе xcode.

С этого момента вы можете выбрать «дешевый способ» и вручную заменить этот файл .appex в папку .ipa непосредственно перед уходом и отправкой приложения. Если вам этого достаточно, вы можете остановиться на этом.

Или вы можете автоматизировать этот процесс, чтобы поместить файл appex в расширение csproj и установить действие сборки как «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>

Это дает вам общее представление, но, очевидно, если вы хотите поддерживать специальную подпись распространения, подпись распространения магазина приложений 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>
person matfillion    schedule 27.04.2017
comment
Архив для публикации моего приложения - ›Подписание и распространение с тем же сертификатом, который использовался для подписи расширения Obj. Теперь разархивировал ipa и заменил appex. Сжат и заархивирован как ipa. Теперь я использовал этот инструмент, чтобы отказаться от заявки (github.com/maciekish/iReSign). Возможно, возникла проблема с отказом от расширения, потому что у меня эта ошибка при установке приложения [_validateSignatureAndCopyInfoForURL: withOptions: error:]: 147: Не удалось проверить подпись кода ... / extract / Payload / JRUITouch.app / PlugIns / NotificationServiceExtension.appex: 0xe8008001 ]. Вы знаете, какую команду выполнить, чтобы уволить приложение? - person Luigi Saggese; 27.04.2017
comment
Если вы используете iResign, он будет подписывать только весь ipa, но вам нужно подписать внутреннее приложение перед этим, а затем использовать iresign для подписи вашего полного пакета ipa. Вот пример команды, которую вы можете запустить перед повторным архивированием пакета ipa. codeign -f -s имя центра сертификации -i com.company.app.notifications --entitlements ../ExtensionEntitlements.plist Payload / MyApp.app / PlugIns / Notifications.appex - person matfillion; 27.04.2017
comment
У меня возникает эта проблема, когда я пытаюсь установить на устройстве после увольнения 28 апреля 09:41:16 Установка iPhone (MobileSystemServices) [3541] ‹Notice›: 0x16dfef000 + [MICodeSigningVerifier _validateSignatureAndCopyInfoForURL: withOptions: error:]: 147: Не удалось проверить код подпись /private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.QBb4HH/extracted/Payload/JRUITouch.app/PlugIns/NotificationServiceExtension.appex: 0xe8008001 (Произошла неизвестная ошибка.) - person Luigi Saggese; 28.04.2017
comment
Извините, это моя проблема из-за имени расширения, скомпилированного с помощью Xcode. С таким же именем отлично работает - person Luigi Saggese; 28.04.2017
comment
@LuigiSaggese Не могли бы вы подробнее рассказать о своем последнем комментарии к тому, что мы можем этого избежать? Похоже, что в этом имени есть что-то, на что могут натолкнуться другие. - person Philipp Sumi; 13.07.2017
comment
Имя расширения @PhilippSumi должно быть одинаковым, скомпилировано между Xamarin и Xcode - person Luigi Saggese; 13.07.2017

Если кто-то еще придет сюда, у меня работает код оригинального плаката, и упоминание об ошибке теперь помечено как исправленное. Если у меня есть один совет, не пытайтесь делать это в Windows. Вас ждет целый мир боли, и вы ничего не добьетесь (на самом деле, однажды это сработало для меня!). Также ожидайте, что Visual Studio на Mac выйдет из строя, если вы попытаетесь отладить!

person Si-N    schedule 21.05.2018
comment
что вы предлагаете тогда? Не могу ли я перехватить push-уведомление в службе расширений в Xamarin в Visual Studio в Windows? - person FreedomOfSpeech; 06.09.2018