Appboy / appboy-ios-sdk

Public repo for the Braze iOS SDK
https://www.braze.com
Other
165 stars 142 forks source link

Sample Code in swift for Notification Extension #92

Closed ghost closed 7 years ago

ghost commented 7 years ago

Please update the sample code to include examples for swift iOS 10+ Notification or Provide better documentation for Notification Extensions

briancaw commented 7 years ago

Hi @mosn

Can you give us some more information about your use cases? e.g. if you're using Swift for your notification extension, are you doing something beyond our default handling? And regarding better documentation for Notification Extensions - are there particular pieces of information you would find high value to have more detail on?

We'll be updating our iOS 10 notification documentation in the near future and also refining that integration point, so any information you can provide to help us best do so would be much appreciated.

Thanks very much for the feedback, Brian

ghost commented 7 years ago

@briancaw Thanks for the quick response,

I'm trying to setup enahcne iOS10 notification (Notification Extensions) in swift and the documentation points out to see the sample code implenetation but that's written in Objective-C. Would be great to see that sample in swift too.

Also I think in general the documentation can improve a bit, an example would be SETP4:1 which uses UNUserNotificationCenter without pointing out to the reader that USERNOTIFICATION needs to be imported first.

or STEP4:3 which asks the user to implement delegate method didReceive response: UNNotificationResponse without mentioning the need to conform to UNUserNotificationCenterDelegate protocol beforehand

not to mention some of the code results in basic compiler warnings i.e STEP4:1 where immutable variable setting is declar with var

briancaw commented 7 years ago

Thanks very much for that feedback @mosn. We'll circle back and figure out best next steps here - I suspect we'll be able to get you some sample code in the not too distant future, though we'll have to solidify our next steps and timeline before committing to anything.

If you have any information regarding urgency on your end it'd be useful for us to consider in our planning.

Thanks, Brian

ghost commented 7 years ago

@briancaw unless you can provide the sample in next 48 hours, it has no use for me. I will see if I can convert the objc to swift and get it going.

Wenzhi commented 7 years ago

Hey @mosn,

I converted the Object-C sample code to Swift. Do you mind giving it a try?

import UserNotifications
import UIKit

let AppboyAPNSDictionaryKey = "ab"
let AppboyAPNSDictionaryAttachmentKey = "att"
let AppboyAPNSDictionaryAttachmentURLKey = "url"
let AppboyAPNSDictionaryAttachmentTypeKey = "type"

class NotificationService: UNNotificationServiceExtension {

  var contentHandler: ((UNNotificationContent) -> Void)?
  var bestAttemptContent: UNMutableNotificationContent?
  var originalContent: UNMutableNotificationContent?
  var abortOnAttachmentFailure: Bool = false

  override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
    self.contentHandler = contentHandler
    self.bestAttemptContent = (request.content.mutableCopy() as! UNMutableNotificationContent)
    self.originalContent = (request.content.mutableCopy() as! UNMutableNotificationContent)

    print("[APPBOY] Push with mutable content received.")

    var attachments : [UNNotificationAttachment] = []
    let userInfo: [AnyHashable : Any]! = request.content.userInfo

    // Check that the push is from Appboy
    if (userInfo![AppboyAPNSDictionaryKey] as Any? == nil) {
      // Note: if you have other push senders and want to handler here, fork your code here to handle
      self.displayOriginalContent("Push is not from Appboy.")
      return
    }

    let appboyPayload: [AnyHashable : Any]! = userInfo![AppboyAPNSDictionaryKey] as! [AnyHashable : Any]!
    // Check that the push has an attachment
    if (appboyPayload[AppboyAPNSDictionaryAttachmentKey] as Any? == nil) {
      self.displayOriginalContent("Push has no attachment.")
      return
    }

    let attachmentPayload: [AnyHashable : Any]! = appboyPayload[AppboyAPNSDictionaryAttachmentKey] as! [AnyHashable : Any]!
    // Check that the attachment has a URL
    if (attachmentPayload[AppboyAPNSDictionaryAttachmentURLKey] == nil ) {
      self.displayOriginalContent("Push attachment has no url.")
      return
    }

    let attachmentURLString: String! = attachmentPayload[AppboyAPNSDictionaryAttachmentURLKey] as! String
    print("[APPBOY] Attachment URL string is \(attachmentURLString)")
    // Get the type
    if(attachmentPayload[AppboyAPNSDictionaryAttachmentTypeKey] == nil) {
      self.displayOriginalContent("Push attachment has no type.")
      return
    }

    let attachmentType: String = attachmentPayload[AppboyAPNSDictionaryAttachmentTypeKey] as! String
    print("[APPBOY] Attachment type is \(attachmentType)")
    let fileSuffix: String = ".\(attachmentType)"

    // Download, store, and attach the content to the notification
    if (attachmentURLString != nil) {
      guard let attachmentURL = URL.init(string: attachmentURLString) else {
        self.displayOriginalContent("Cannot parse \(attachmentURLString) to URL.")
        return
      }
      let session = URLSession(configuration:URLSessionConfiguration.default)
      session.downloadTask(with: attachmentURL,
                           completionHandler: { (temporaryFileLocation, response, error) in
                            if (error != nil || temporaryFileLocation == nil) {
                              self.displayOriginalContent("Error fetching attachment, displaying content unaltered: \(error?.localizedDescription)")
                              return
                            } else {
                              print("[Appboy] Data fetched from server, processing with temporary file url \(temporaryFileLocation!.absoluteString)")

                              let fileManager = FileManager.default
                              let typedAttachmentURL = URL(fileURLWithPath:"\(temporaryFileLocation!.path)\(fileSuffix)")
                              do {
                                try fileManager.moveItem(at: temporaryFileLocation!, to: typedAttachmentURL)
                              } catch {
                                self.displayOriginalContent("Failed to move file path.")
                                return
                              }

                              let attachment: UNNotificationAttachment? = try? UNNotificationAttachment.init(identifier: "",
                                                                                  url: typedAttachmentURL,
                                                                                  options: nil)
                              if (attachment == nil) {
                                self.displayOriginalContent("Attachment returned error.")
                                return
                              }

                              attachments = [attachment!]
                              self.bestAttemptContent!.attachments = attachments;
                              self.contentHandler!(self.bestAttemptContent!);
                            }
      }).resume()
    }
  }

  func displayOriginalContent(_ extraLogging: String) {
    print("[APPBOY] \(extraLogging)")
    print("[APPBOY] Displaying original content.")
    self.contentHandler!(self.originalContent!)
  }

  override func serviceExtensionTimeWillExpire() {
    // 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.
    self.displayOriginalContent("Service extension called, displaying original content.")
  }
}

Thanks, Wenzhi

shuhrat10 commented 7 years ago

change line: (attachments array is empty by default, you can't replace value by index 0) attachments[0] = attachment! on attachments = [attachment!]

Wenzhi commented 7 years ago

Thanks, @shuhrat10! I updated the comment.