# iOS

## Platform integration

#### Creating a Universal Push Notification Client SSL Certificate

You use Member Center to generate a push notification client SSL certificate that allows your notification server to connect to the APNs. Each App ID is required to have its own client SSL certificate. The client SSL certificate Member Center generates is a universal certificate that allows your app to connect to both the development and production environments.

{% hint style="info" %}
Only a team agent or admin can generate Apple Push Notification service SSL certificates.
{% endhint %}

To generate a universal client SSL certificate

1. In [Certificates, Identifiers & Profiles](http://developer.apple.com/account), select Certificates.
2. Click the Add button (+)<br>

   <figure><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2FAp9aATQVUmBP7JTxSzyg%2F%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA%20%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202022-06-06%20%D0%B2%2016.02.50.png?alt=media&#x26;token=a5d2e445-a861-4971-b6d9-2d4d909d0eaf" alt=""><figcaption></figcaption></figure>
3. Under Production, select the “Apple Push Notification service SSL (Sandbox & Production)” checkbox, and click Continue.<br>

   <figure><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2FtZvcwl7lU0lhtXMEgrIC%2F%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA%20%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202022-06-06%20%D0%B2%2016.04.47.png?alt=media&#x26;token=39b1eeb8-52d9-4363-956b-da1103c93864" alt=""><figcaption></figcaption></figure>
4. Choose an App ID from the App ID pop-up menu, and click Continue. Choose the explicit App ID that matches your bundle ID.
5. Create a certificate request on your Mac.
6. Click Choose File.
7. In the dialog that appears, select the certificate request file (with a .certSigningRequest extension), and click Choose File.
8. Click Generate.
9. Click Download.<br>

   <figure><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2F7l8VM2oNpa8besCPjLfb%2F%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA%20%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202022-06-06%20%D0%B2%2016.07.04.png?alt=media&#x26;token=4def9439-9403-404e-908d-f2f1903bd0b7" alt=""><figcaption></figcaption></figure>

#### **Follow these steps to export the certificate from Apple web-site to the P12-file:**

1. Open "Keychain access" application
2. If the certificate hasn't been added to keychain access yet, choose "File" →  "Import". Find the certificate file (CER-file) provided by Apple
3. Choose "Keys" section in "Keychain access" application
4. Choose a personal key associated with your iPhone developer certificate. Personal key is identified by open certificate associated with it "iPhone developer: ". Choose "File" → Export objects. Save key as .p12
5. You'll be suggested to create a password which is used when you need to import the key to another computer

#### Upload the certificate to the site

Upload the .p12-file into Integration section of application settings panel  (Settings -> Push Notifications):

![](https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2FJiPX25hOgHfRFXoPmaSB%2Fimage.png?alt=media\&token=3864303a-268f-429e-961e-814779e9e80a)

## Messaging Module Integration (CocoaPods)

[CocoaPods](http://cocoapods.org/) is the easiest way to add devtodev into your iOS project.

1\. Firstly, install CocoaPods using:

```bash
sudo gem install cocoapods
```

2\. In the project directory execute the command:

```bash
pod init
```

3\. In the created Podfile add the dependency:

```bash
platform :ios, '9.0'

target 'TargetName' do
  use_frameworks!
  pod 'DTDAnalytics', '~> 2.0.0'
  pod 'DTDMessaging', '~> 2.0.0'
end
```

4\. Finally, run the command in your Xcode project directory:

```bash
pod install
```

CocoaPods should download and install the devtodev library, and create a new Xcode workspace. Open this workspace in Xcode.

## Messaging Module Integration (Manual Installation) <a href="#messaging-module-integration-manual-installation" id="messaging-module-integration-manual-installation"></a>

To connect the module for processing push notifications, you need to:

1. [Download the latest devtodev SDK from the repository](https://github.com/devtodev-analytics/ios-sdk-2.0).
2. Add **`DTDAnalytics.xcframework`** to the project (check Do Not Embed).

{% hint style="info" %}
The DTDMessaging plugin will not work without the DTDAnalytics main analytics plugin.
{% endhint %}

3. Add DTDMessaging.xcframework to the project (check Do Not Embed)

![](https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LnGcP_ZeRJ1ipj9O8dF%2F-MgQTpc8ZGD6DQ_pLKom%2F-MgQXvnqMCh2mAaDFPq5%2Fimage.png?alt=media\&token=c7861577-caf4-4e48-bdab-ab8b2db5c62c)

4. In the Xcode project settings, open the tab, and add: "Push Notifications" and "Background Modes" respectively.

<div align="left"><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LnGcP_ZeRJ1ipj9O8dF%2F-MgQTpc8ZGD6DQ_pLKom%2F-MgQY2khXyJOV5Qp4GUY%2Fimage.png?alt=media&#x26;token=dfc33f13-a148-4797-aeb7-b7e389370781" alt=""></div>

<div align="left"><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LnGcP_ZeRJ1ipj9O8dF%2F-MgQTpc8ZGD6DQ_pLKom%2F-MgQYAnJJ-kWXw_hT5Uq%2Fimage.png?alt=media&#x26;token=6c6c808f-7524-4b9d-a752-69463f90814a" alt=""></div>

5. In the "Background Modes" section, enable "Remote notifications".

![](https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LnGcP_ZeRJ1ipj9O8dF%2F-MgQTpc8ZGD6DQ_pLKom%2F-MgQYTYlJo8Rc9oWkzfF%2Fimage.png?alt=media\&token=b061d5ee-3a21-4922-8869-a3385bb9be3f)

6. Add initialization to **`didFinishLaunchingWithOptions`** method:

{% tabs %}
{% tab title="Swift" %}

```swift
let config = DTDAnalyticsConfiguration()
config.logLevel = .error
DTDAnalytics.initialize(applicationKey: "App ID", configuration: config)

DTDMessaging.delegate = self
DTDMessaging.pushNotificationsOptions = [.DTDNotificationOptionAlert,
                                         .DTDNotificationOptionSound,
                                         .DTDNotificationOptionBadge]
DTDMessaging.startPushService()
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
DTDNotificationOptions *options = [[DTDNotificationOptions alloc] initWithRawValue:
                                  [DTDNotificationOptions.DTDNotificationOptionAlert rawValue] |
                                  [DTDNotificationOptions.DTDNotificationOptionSound rawValue] |
                                  [DTDNotificationOptions.DTDNotificationOptionBadge rawValue]];
[DTDMessaging setPushNotificationsOptions:options];
[DTDMessaging startPushService];
```

{% endtab %}
{% endtabs %}

7. To handle SDK delegate methods, you need to add the implementation of the **`DTDMessagingDelegate`** protocol.

{% tabs %}
{% tab title="Swift" %}

```swift
extension AppDelegate: DTDMessagingDelegate {
    func didRegisterForRemoteNotifications(with deviceToken: Data) {
        // your code
    }

    func didFailToRegisterForRemoteNotifications(with error: Error) {
        // your code
    }

    func didReceiveInvisibleNotification(with message: DTDMessage) {
        // your code
    }

    func didReceiveForegroundNotification(with message: DTDMessage) {
        // your code
    }

    func didOpenRemoteNotification(with message: DTDMessage, and buttonClicked: DTDActionButton?) {
        // your code
    }
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
@interface AppDelegate () <DTDMessagingDelegate>

- (void)didRegisterForRemoteNotificationsWith:(NSData *)deviceToken {
    // your code
}

- (void)didFailToRegisterForRemoteNotificationsWith:(NSError *)error {
    // your code
}

-(void)didReceiveInvisibleNotificationWith:(DTDMessage *)message {
    // your code
}

- (void)didReceiveForegroundNotificationWith:(DTDMessage *)message {
    // your code
}

-(void)didOpenRemoteNotificationWith:(DTDMessage *)message and:(DTDActionButton *)buttonClicked {
    // your code
}
```

{% endtab %}
{% endtabs %}

The **`DTDMessaging`** module provides support for notifications with attachments. These notifications are available since iOS 10. Attachments support images, animated gifs and videos. To use this function, you will need to create a “**Notification Service Extension**“, for this create a new target in your application settings:

* Open Xcode (File -> New -> Target).\
  Select ***Notification Service Extension***.

![](https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LnGcP_ZeRJ1ipj9O8dF%2F-MgQTpc8ZGD6DQ_pLKom%2F-MgQZPRZ-Bq5mrs35P1G%2Fimage.png?alt=media\&token=b7601e58-cd50-4208-9d7c-d44f6a01284d)

The next step is to modify the **`Notification Extension`** class as follows:

* Delete all auto-generated code.
* Inherit **`Notification Extension`** class from **`DTDMediaAttachmentExtension`**

Example:

```swift
import UserNotifications
import DTDMessaging

class NotificationService: DTDMediaAttachmentExtension {

}
```

### External interface of the `DTDMessaging` module <a href="#external-interface-of-the-dtdmessaging-module" id="external-interface-of-the-dtdmessaging-module"></a>

<table data-header-hidden><thead><tr><th width="237.21311475409834">Object</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><strong>Object</strong></td><td>Type</td><td><strong>Description</strong></td></tr><tr><td><strong><code>startPushService</code></strong></td><td></td><td><p>Method responsible for activating push notifications:</p><ul><li>Requests permission from the user to receive Push Notifications</li><li>Sends a pushToken and the current state <em><strong><code>isAllowed</code></strong></em></li></ul></td></tr><tr><td><strong><code>apnsToken</code></strong><br></td><td>Data?</td><td>Getter giving the current pushToken, represented by a Data </td></tr><tr><td><strong><code>apnsTokenString</code></strong></td><td>String?</td><td>Getter giving the current pushToken,  represented by a String </td></tr><tr><td><strong><code>delegate</code></strong></td><td>DTDMessagingDelegate?</td><td>Property for assigning a delegate to handle events from the SDK </td></tr><tr><td><strong><code>pushNotificationsOptions</code></strong></td><td>DTDNotificationOptions</td><td><p>Configuring the display of Push Notifications, is an <strong><code>OptionSet</code></strong>, is set by the developer to select the method for notifying the user. May be changed by the end user.</p><p>By default it has the following value:  <em><strong><code>[.DTDNotificationOptionBadge, .DTDNotificationOptionSound, .DTDNotificationOptionAlert]</code></strong></em> </p></td></tr></tbody></table>

### Optional `DTDMessagingDelegate` methods <a href="#optional-dtdmessagingdelegate-methods" id="optional-dtdmessagingdelegate-methods"></a>

| **Delegate method**                                                                                                  | **Description**                                                                                                                                                   |
| -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`didFailToRegisterForRemoteNotifications`**`(with error:`` `**`Error`**`)`                                         | The method is called when an error occurs at the time of receiving a pushToken, represented by the **`Error`** base class.                                        |
| **`didOpenRemoteNotification`**`(with message:`` `**`DTDMessage`**`, and buttonClicked:`` `**`DTDActionButton?`**`)` | The method is called when a remote push notification is opened by an end user. A **`DTDMessage`** object and an optional **`DTDActionButton`** object are passed. |
| **`didReceiveForegroundNotification`**`(with message:`` `**`DTDMessage`**`)`                                         | The method is called when a remote push notification is received when the application is in the ***Foreground*** state. The **`DTDMessage`** object is passed.    |
| **`didReceiveInvisibleNotification`**`(with message:`` `**`DTDMessage`**`)`                                          | The method is called when an invisible remote push notification is received. The **`DTDMessage`** object is passed.                                               |
| **`didRegisterForRemoteNotifications`**`(with deviceToken:`` `**`Data`**`)`                                          | The method is called in case the **`pushToken`** successfully arrives; represented by a Data.                                                                     |

### Class for receiving Notification data (**DTDMessage**)  <a href="#class-for-receiving-notification-data-dtdmessage" id="class-for-receiving-notification-data-dtdmessage"></a>

| **Property**       | Type               | **Description**                                                                                                                                                                                                                                                                                                                                                                                                     |
| ------------------ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`payload`**      | \[AnyHashable:Any] | Full information sent using remote push notification.                                                                                                                                                                                                                                                                                                                                                               |
| **`actionType`**   | DTDActionType      | <p>Property returning the enum <strong>DTDActionType</strong> value. Possible values:</p><ul><li><em><strong><code>App</code></strong></em> - default value</li><li><em><strong><code>Url</code></strong></em> - open an external link</li><li><em><strong><code>Share</code></strong></em> - share content</li><li><em><strong><code>Deeplink</code></strong></em> - open a link inside the application </li></ul> |
| **`actionString`** | String?            | Property returning an optional action identifier.                                                                                                                                                                                                                                                                                                                                                                   |
| **`badge`**        | Int                | The value that is passed to display a *badge* on the application icon.                                                                                                                                                                                                                                                                                                                                              |
| **`category`**     | String?            | Property returning an optional identifier of a push notification category                                                                                                                                                                                                                                                                                                                                           |

### Class for handling pressed buttons on a notification (**DTDActionButton**) <a href="#class-for-handling-pressed-buttons-on-a-notification-dtdactionbutton" id="class-for-handling-pressed-buttons-on-a-notification-dtdactionbutton"></a>

| **Property**       | Type          | **Description**                                                                                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`actionType`**   | DTDActionType | <p>Property returning the enum <strong>DTDActionType</strong> value. Possible values:</p><ul><li><em><strong><code>App</code></strong></em> - default value</li><li><em><strong><code>Url</code></strong></em> - open an external link</li><li><em><strong><code>Share</code></strong></em> - share content</li><li><em><strong><code>Deeplink</code></strong></em> - open a link inside the application</li></ul> |
| **`actionString`** | String?       | Property returning an optional action identifier.                                                                                                                                                                                                                                                                                                                                                                  |
| **`buttonId`**     | String        | Property returning the identifier of the pressed button.                                                                                                                                                                                                                                                                                                                                                           |
| **`text`**         | String        | Property returning the text of the pressed button.                                                                                                                                                                                                                                                                                                                                                                 |

## Notes <a href="#notes" id="notes"></a>

### Foreground Notification <a href="#foreground-notification" id="foreground-notification"></a>

Displaying push notifications in **Foreground** state is available since iOS 10.0.

By default, according to Apple Push Notification Guidelines, the display of push notification in the **Foreground** state is disabled. In order to set the display method, you must:

* Assign delegate for **`UNUserNotificationCenter`**
* Or pass a parameter in the push notification constructor (***`_fg = 1`***). In this case, the display method will be formed from the Notification settings.
* Or delegate the system method **`userNotificationCenter willPresent notification`**. In this case, the display properties will be taken from the developer.

An example of a delegated method implementation:&#x20;

```swift
func userNotificationCenter(_ center: UNUserNotificationCenter, 
                            willPresent notification: UNNotification, 
                            withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
  completionHandler([.alert, .sound])
}
```

### DTDNotificationOptions <a href="#dtdnotificationoptions" id="dtdnotificationoptions"></a>

It is an **`OptionSet`** that is used to pass push notification authorization and set up interactions with users.

{% hint style="info" %}
The user can change the allowed parameters at any time in the notification settings.
{% endhint %}

Possible values:

| **Value**                                     | Description                                                                                                                                                            |
| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ***`DTDNotificationOptionBadge`***            | display a badge on the application icon                                                                                                                                |
| ***`DTDNotificationOptionSound`***            | play sound                                                                                                                                                             |
| ***`DTDNotificationOptionAlert`***            | display an alert                                                                                                                                                       |
| ***`DTDNotificationOptionCarPlay`***          | display push notification in CarPlay                                                                                                                                   |
| ***`DTDNotificationOptionCriticalAlert`***    | play sound for critical notifications regardless of the “Do Not Disturb” setting (*Critical alerts require special permission from Apple*.) *Available since iOS 12.0* |
| ***`DTDNotificationOptionProvidesSettings`*** | an option specifying that the system should display a button for notification settings in the application. *Available since iOS 12.0*                                  |
| ***`DTDNotificationOptionProvisional`***      | pre-send notifications to the Action Center without interrupting work. *Available since iOS 12.0*                                                                      |
| ***`DTDNotificationOptionAnnouncement`***     | for Siri to automatically read messages through AirPods. *Available since iOS 13.0*                                                                                    |

{% hint style="info" %}
***`DTDNotificationOptionProvisional`*** - Provisional push notifications appear in the user's Notification Center, but not on the lock screen. This type of push notification does not have to be explicitly allowed by the user. Start submitting them as soon as the user installs and runs your application. However, the user can also opt in/opt out of notifications, but they will need to do it explicitly.

This setting is used to prevent receiving push notification permission requests at the start, which is intrusive and most users refuse to receive them.

It is also important that when using the ***`DTDNotificationOptionProvisional`*** setting, the user will be able to subscribe to explicit notifications only from the notification center settings.
{% endhint %}

### **`DTDMediaAttachmentExtension`** <a href="#dtdmediaattachmentextension" id="dtdmediaattachmentextension"></a>

To handle the application attitude to displaying push notifications, you need to add a Notifications service Extension. And inherit **`NotificationService`** from **`DTDMediaAttachmentExtension`**

```kotlin
@available(iOSApplicationExtension 10.0, *)
class NotificationService: DTDMediaAttachmentExtension {
  // nothing
}
```

### Custom sounds

To use custom sounds for push notifications, you need to copy the necessary sound files to the Libraries folder of your Xcode project. You can read more about supported formats [here](https://developer.apple.com/documentation/usernotifications/unnotificationsound#2943048).

<figure><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2FrNzmhaNdclsWtlwv1Z4j%2FAddSound.png?alt=media&#x26;token=81553d21-0336-4125-ae28-a2925eae4e36" alt=""><figcaption></figcaption></figure>

When creating a push company, it is important to specify the full name of the sound with file extension (for example, sound.wav).

### DTDMessaging integration with swizzling disabled

DTDMessaging automatically swizzles notification tracking and APNS-token usage methods by default. If you want to disable the function, add the flag **`DTDMessagingSwizzlingEnabled`** (boolean) in the app’s **`Info.plist`** file and set it to ***NO (0)***. However, if you disable notification swizzling, you will need additional integration for accurate analytics:

For sending APNS-token to DTDMessaging:

{% tabs %}
{% tab title="Swift" %}

```swift
func application(_ application: UIApplication, 
                didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
  DTDMessaging.apnsToken = deviceToken
}i
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    [DTDMessaging setApnsToken:deviceToken];
}
```

{% endtab %}
{% endtabs %}

For sending information about the application:

{% tabs %}
{% tab title="Swift" %}

```swift
func application(_ application: UIApplication,
                didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
  DTDMessaging.didReceiveMessage(userInfo: userInfo, actionIdentifier: nil)
}

@available(iOS 10.0, *)
extension AppDelegate: UNUserNotificationCenterDelegate {
  func userNotificationCenter(_ center: UNUserNotificationCenter, 
                              didReceive response: UNNotificationResponse, 
                              withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo
    let actionIdentifier = response.actionIdentifier
    DTDMessaging.didReceiveMessage(userInfo: userInfo, actionIdentifier: actionIdentifier)
  }

  func userNotificationCenter(_ center: UNUserNotificationCenter, 
                              willPresent notification: UNNotification, 
                              withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    let userInfo = notification.request.content.userInfo
    DTDMessaging.willPresentMessage(userInfo: userInfo)
  }
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    [DTDMessaging didReceiveMessageWithUserInfo:userInfo actionIdentifier:nil];
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    NSDictionary *userInfo = notification.request.content.userInfo;
    [DTDMessaging willPresentMessageWithUserInfo:userInfo];
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    NSString *actionIdentifier = response.actionIdentifier;

    [DTDMessaging didReceiveMessageWithUserInfo:userInfo actionIdentifier:actionIdentifier];
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Note: If you disable automatic notification swizzling, **`DTDMessagingDelegate`** methods will not be called.
{% endhint %}
