21

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 を作成しました
  • アプリ ID com.testapp.main.notificationextension のプッシュ通知を送信するための証明書とプロビジョニング プロファイルを作成しました
  • Xcode と Xamarin の証明書とプロビジョニングにインポート
  • Notification Extension リファレンスを参照してアプリをビルドします。
  • TestFlight にアップロードするアーカイブを作成しました
  • 配布証明書とプロビジョニング プロファイルを使用して署名されたアプリ
  • 配布証明書とプロビジョニング プロファイルを使用した署名付き拡張機能
  • TestFlight にアップロード
  • アプリのダウンロードと許可されたプッシュ通知
  • メッセージング用に Localytics ダッシュボードを使用してリッチ プッシュ通知を送信 - デバイスはプッシュ通知を受信しますが、Notification Service Extension の 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;
        }

    }
}
4

2 に答える 2

5

すべてを正しく行っています。これは、他の数人の xamarin 開発者によって提起された問題です。私が知る限り、何かをダウンロードするために NSURLSession を実行するとすぐに、それが非常に小さいものであっても、このタイプの拡張機能に許可されているメモリ制限を超えてしまいます。これはおそらく xamarin に固有のものです。Bugzilla へのリンクは次のとおりです。 https://bugzilla.xamarin.com/show_bug.cgi?id=43985

私が見つけた回避策/ハックは、理想とはほど遠いものです。このアプリの拡張機能を Xcode の Objective-C で書き直しました (Swift も使用できると思います)。これはかなり小さい (1 クラス) 拡張機能です。次に、同じコード署名証明書/プロビジョニング プロファイルを使用して xcode でビルドし、xcode の出力で .appex ファイルを見つけました。

それ以降は、「安価な方法」を取り、アプリを再署名して送信する直前に、.ipa フォルダー内のこの .appex ファイルを手動で交換できます。それで十分な場合は、ここで終了できます。

または、このプロセスを自動化して、appex ファイルを csproj の拡張子に配置し、ビルド アクションを「コンテンツ」として設定することもできます。次に、この 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 で条件付き calltargets を使用することをお勧めします。このような:

<Target Name="BeforeCodeSign">
    <CallTarget Targets="ImportExtension_Debug" Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' " />
    <CallTarget Targets="ImportExtension" Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' " />
 </Target>
于 2017-04-27T02:20:42.957 に答える