2017-01-02 21 views
13

Mam problem z rozszerzeniem usługi powiadomień. Podążyłem za dokumentacją krok po kroku: https://developer.xamarin.com/guides/ios/platform_features/introduction-to-ios10/user-notifications/enhanced-user-notifications/#Working_with_Service_ExtensionsXamarin Notification Service Extension issue

Aby zaimplementować, zrobiłem to w ten sposób.

  • Dodany Usługa powiadamiania Przedłużacz z samego prefiksu mojej aplikacji (dodanie przyrostka, np: app: com.testapp.main - EXT: com.testapp.main.notificationextension)
  • Utworzono AppID identyfikator com.testapp .main.notificationextension w państwach Center Apple
  • Utworzono certyfikatu i zastrzegania profil wysyłać powiadomienia push o identyfikator aplikacji com.testapp.main.notificationextension
  • importowane do świadectwa Xcode i Xamarin i zaopatrzenie
  • zbudować mojej aplikacji z odniesieniem do powiadomienia Exte referencja nsion.
  • utworzono archiwum przesłać do TestFlight
  • Signed aplikacja ze swojego certyfikatu Distribution i profilu Provisioning
  • Signed rozszerzenie z Certyfikatem dystrybucja i Provisioning Profile
  • przesłany do TestFlight
  • pobierania i pozwolił powiadomienia Push dla mojej aplikacji
  • Wysyłanie bogatych powiadomień push za pomocą Localytics Dashboard do przesyłania wiadomości - Urządzenie odbiera powiadomienia push , ale nie przekazuje do usługi NotificationService.cs c przedłużenie usługi powiadomień!

To jest mój kod 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; 
     } 

    } 
} 
+0

Jaki jest problem? – Demitrian

+0

Urządzenie odbiera powiadomienia push, ale nie przekazuje kodu usługi NotificationService.cs rozszerzenia usługi powiadomień! –

+0

Co masz na myśli mówiąc "nie przechodzi"? Czy masz na myśli, że 'DidReceiveNotificationRequest' nie jest wykonywane? – Demitrian

Odpowiedz

5

Robicie wszystko poprawnie, jest to kwestia podniesiona przez kilku innych twórców Xamarin. Z tego co wiem, gdy tylko uruchomisz NSURLSession, by pobrać coś, nawet jeśli jest super super małe, przekraczasz limit pamięci dozwolony dla tego typu rozszerzenia. Jest to prawdopodobnie bardzo specyficzne dla xamarin. Oto link do bugzilli. https://bugzilla.xamarin.com/show_bug.cgi?id=43985

Obejście/włamanie, które znalazłem, jest dalekie od ideału. Przepisałem to rozszerzenie aplikacji w kodzie xc w celu-c (można by też użyć szybkiego, jak przypuszczam). To dość małe (1 klasa) rozszerzenie. Następnie zbuduj go w Xcode, używając tego samego certyfikowanego/opatrzonego profilu podpisu kodu, a następnie znajdź plik .appex w danych wyjściowych xcode.

Od tego momentu możesz zrobić "tanią drogę" i zamieniać ten plik .appex w folderze .ipa tuż przed rezygnacją i przesłaniem aplikacji. Jeśli to ci wystarczy, możesz na tym poprzestać.

Albo możesz zautomatyzować ten proces, tak aby umieścić plik appex w rozszerzeniu csproj i ustawić build-action jako "treść". Następnie w tym pliku csproj (musisz edytować bezpośrednio) możesz dodać coś takiego. (W takim przypadku plik nazywa się Powiadomienia.appex i jest umieszczony w folderze o nazwie 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> 

Daje to ogólne pojęcie, ale oczywiście jeśli chcesz wesprzeć-ad hoc podpis dystrybucji, iOS podpis dystrybucja app-store trzeba będzie dodać trochę więcej kodu do tego (i ewentualnie dodać csproj natywny plik appex dla każdego innego podpisu), sugerowałbym umieszczenie takiego kodu XML w oddzielnym pliku ".targets" i użycie warunkowego calltargets w csproj. W ten sposób:

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

Archiwum dla Opublikuj moją aplikację -> Podpisywanie i rozpowszechnianie za pomocą tego samego certyfikatu, który został użyty do podpisania rozszerzenia Obj. Teraz rozpakowałem ipa i zastąpiłem appex. Skompresowany i skompresowany jako ipa. Teraz użyłem tego narzędzia, aby zrezygnować z aplikacji (https://github.com/maciekish/iReSign). Być może jest problem z rezygnacją z przedłużenia, ponieważ mam ten błąd podczas instalowania aplikacji [_validateSignatureAndCopyInfoForURL: withOptions: error:]: 147: Nie można zweryfikować podpisu kodu .../extract/Payload/JRUITouch.app/PlugIns/NotificationServiceExtension.appex: 0xe8008001 ]. Czy wiesz, które polecenie wykonać, aby zrezygnować z aplikacji? –

+0

Jeśli używasz iResign, podpisuje on tylko całe oprogramowanie ipa, ale musisz wcześniej podpisać wewnętrzną appex, a następnie użyć iresign do podpisania pełnego pakietu ipa. Oto przykład polecenia, które można uruchomić przed zreinstalowaniem pakietu ipa. kod -f -s "nazwa urzędu certyfikacji" -i "com.company.app.notifications" --entitlements "../ExtensionEntitlements.plist" "Payload/MyApp.app/PlugIns/Notifications.appex" – oXeNoN

+0

I Mam ten problem, gdy próbuję zainstalować na urządzeniu po rezygnacji 28 kwietnia 09:41:16 iPhone installd (MobileSystemServices) [3541] : 0x16dfef000 + [MICodeSigningVerifier _validateSignatureAndCopyInfoForURL: withOptions: error:]: 147: Nie można zweryfikować podpisu kodu/private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.QBb4HH/extract/Payload/JRUITouch.app/PlugIns/NotificationServiceExtension.appex: 0xe8008001 (Wystąpił nieznany błąd.) –