# Tecnavia Newsmemory SDK Integration

This document describes how to integrate in your existing Xcode project the Tecnavia Newsmemory ePaper solution.

---

## Table of Contents

- [System requirements](#system)
- [Installation](#installation)
  - [Cocoapods](#cocoapods)
  - [Manual](#manual)
    - [Package contents](#contents)
- [Changes to the Info.plist](#changes)
- [Code integration](#integration)
  - [Delegate callbacks](#callbacks)
  - [Tracking](#tracking)
- [Troubleshooting](#troubleshooting)
- [Authors](#authors)

---

<a name="system"></a>

## System requirements

|                           | Version       |
| ------------------------- | ------------- |
| Xcode                     | 14.0 or above |
| Minimum deployment target | iOS 11        |

---

<a name="installation"></a>

## Installation

If you are not using Cocoapods in your project, follow the instruction of the section [`'Manual'`](#manual)

<a name="cocoapods"></a>

### Cocoapods

#### Get the SDK thru Xcode Cloud

1. Add the following lines inside your target declaration in your `Podfile`.

   Remember to:

   - add the source to our specs repo
   - replace `X.Y.Z` with the pod version provided (ex. 3.17.05)

```
...
source 'https://pubgit.newsmemory.com/tecnavia/newsmemory-ios-sdk-specs.git'
...

target '<YOUR_TARGET>' do

...

pod 'NewsmemorySDK', 'X.Y.Z'

...

end
```



#### Get the SDK thru GitHub

1. Create a new SSH key and name it `id_tecnavia_deploy_key`, put the key files in folder `~/.ssh/`(see this article for reference https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent). Then, in order to be able to download the software from Tecnavia repository, you should provide to Tecnavia your public key.

2. Edit your SSH config file `~/.ssh/config` and add the following lines:

```
#GitHub Tecnavia Repo
Host tecnavia-repo-sdk
    HostName github.com
    AddKeysToAgent yes
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/id_tecnavia_deploy_key
```

3. Add the following lines inside your target declaration in your `Podfile`.

   Remember to:

   - add the source to our specs repo
   - replace `X.Y.Z` with the pod version provided (ex. 3.17.05)

```
...
source 'https://github.com/tecnaviapress/Specs.git'
...

target '<YOUR_TARGET>' do

...

pod 'NewsmemorySDK', 'X.Y.Z'

...

end
```

4. Run `pod install`. If you upgrade from a previous version of NewsmemorySDK run `pod install --repo-update`

#### Get the SDK thru zip file

Tecnavia provides you a zip package named `ta-newsmemory-sdk_XYZ`, where XYZ stands for the package version (ex. 31705, means that the SDK version is 3.17.05).

1. Unzip the package and copy the `ta-newsmemory-sdk_XYZ` folder in the folder containing your project's `Podfile` file.

2. Add the following lines inside your target declaration in your `Podfile`.
   Notice that `XYZ` stands for the package version (ex. 31705)

```
...

target '<YOUR_TARGET>' do

...

pod 'NewsmemorySDK', path: 'ta-newsmemory-sdk_XYZ'

...

end
```

3. Run `pod install`.

<a name="manual"></a>

### Manual

<a name="contents"></a>

#### Package contents

Tecnavia provides you a zip package named `ta-newsmemory-sdk_XYZ`, where XYZ stands for the package version (ex. 31705, means that the SDK version is 3.17.05).

Unzip the package and copy the `ta-newsmemory-sdk_XYZ` folder in the folder containing your project's `.xcodeproj` file (i.e. the SDK folder must be at the same level of the project file).

The unzipped folder named `ta-newsmemory-sdk_XYZ` has the following subfolders structure:

```
  .
  ├── Headers                                 # headers files imported by the .xcconfig file
  ├── Libraries                               # libraries imported by the .xcconfig file
      ├── Device                              # arm64 libraries
      ├── Simulator                           # simulator x86_64 libraries
  ├── Other                                   # images and resources to manully import in the project
      ├── assets                              # set of default icons/images used by the ePaper
      ├── Resources
          ├── fonts                           # set of base fonts supported by the ePaper (*.otf, *.ttf files)
          ├── Newsmemory.js                   # the minified javascript bundle file, core of Tecnavia ePaper solution
          ├── AccessibilityResources.bundle   # a bundle required by React Native framework
  ├── ta-newsmemory-sdk.debug.xcconfig        # the .xcconfig file with debug settings
  ├── ta-newsmemory-sdk.release.xcconfig      # the .xcconfig file with release settings
  ├── LICENSE
  └── README.md
  └── img									  # set of images for the README file
```

---

1. Drag the `assets` inside `Other` folder and drop it in the project navigator.
2. Select `'Create folder references'` option

![Assets import](img/assets.gif)

3.  Drag the `Resources` inside `Other` folder and drop it in the project navigator.
4.  Select `'Create groups'` option

![Resources import](img/resources.gif)

5.  Drag and drop `ta-newsmemory-sdk.debug.xcconfig` and `ta-newsmemory-sdk.release.xcconfig` in the project navigator
6.  Select `'Create groups'` option
7.  Select your project in the project navigator and select `Info`
8.  Under `Configurations` expand the `Debug` line and select your Target
9.  Click on `None` and select `ta-newsmemory-sdk.debug.xcconfig`
10. Do the same for the `Release` configuration this time selecting the `ta-newsmemory-sdk.release.xcconfig` configuration file.

![xcconfig import](img/xcconfig.gif)

11. if your project already includes a `.xcconfig` file for your target configuration add this line at the end of the file

- your-debug-xconfig-file.xcconfig

```
...

#include "ta-newsmemory-sdk.debug.xcconfig"
```

- your-release-xconfig-file.xcconfig

```
...

#include "ta-newsmemory-sdk.release.xcconfig"
```

---

<a name="changes"></a>

## Changes to the Info.plist

### Fonts

In order to make ePaper fonts available inside your app you'll need to add the font file name lines to your app's `Info.plist`.
The key were to add the font names is `UIAppFonts`

```
 <key>UIAppFonts</key>
	<array>
		<string>Roboto_medium.ttf</string>
		<string>Roboto.ttf</string>
		<string>rubicon-icon-font.ttf</string>
		<string>Merriweather-Bold.otf</string>
		<string>Merriweather-Light.otf</string>
		<string>Merriweather-Regular.otf</string>
		<string>OpenSans-Bold.ttf</string>
		<string>OpenSans-Light.ttf</string>
		<string>OpenSans-Regular.ttf</string>
		<string>DroidKufi-Bold.ttf</string>
		<string>DroidKufi-Regular.ttf</string>
		<string>AntDesign.ttf</string>
		<string>Entypo.ttf</string>
		<string>EvilIcons.ttf</string>
		<string>Feather.ttf</string>
		<string>FontAwesome.ttf</string>
		<string>FontAwesome5_Brands.ttf</string>
		<string>FontAwesome5_Regular.ttf</string>
		<string>FontAwesome5_Solid.ttf</string>
		<string>Fontisto.ttf</string>
		<string>Foundation.ttf</string>
		<string>Ionicons.ttf</string>
		<string>MaterialCommunityIcons.ttf</string>
		<string>MaterialIcons.ttf</string>
		<string>Octicons.ttf</string>
		<string>SimpleLineIcons.ttf</string>
		<string>Zocial.ttf</string>
		<string>Nunito-Bold.ttf</string>
		<string>Nunito-Medium.ttf</string>
		<string>Nunito-Regular.ttf</string>
		<string>Nunito-Light.ttf</string>
	</array>
```

### Other Info.plist values

The ePaper usually works with the key `UIViewControllerBasedStatusBarAppearance` set to `NO`

```
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
```

If your app requires `UIViewControllerBasedStatusBarAppearance` to be `YES` ensure that your View Controller sets the Status bar style to `.lightContent`, as the default background color for the ePaper is `black`.

```
override var preferredStatusBarStyle: UIStatusBarStyle {
      return .lightContent
}
```

### HTTP support

If your ePaper app needs to load resources from non-HTTPS domains ensure that the Info.plist allows arbitrary loads:

```
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    ...
</dict>
```

---

<a name="integration"></a>

## Code integration

### Setup

Tecnavia provides also the couple "PAPER_SETUP" - "SERVER" which allows you to load the epaper for a specific publication.

Before displaying the ePaper View Controller (ex. during the your app setup), call the `Newsmemory` singleton to set the startup parameters.

1. Import the following header file

```
...
#import <Newsmemory/Newsmemory.h>
...
```

2. Make the class that will control the ePaper implement the `NewsmemoryDelegate` interface (the below code shows how you could do it in the `AppDelegate.h`).

   `IMPORTANT:` make sure that the class has a `window` property.

```
...
@interface AppDelegate : UIResponder <UIApplicationDelegate, NewsmemoryDelegate>
...
@property (nonatomic, strong) UIWindow *window;
...
```

3. Before loading the ePaper view (e.g. you could put in your `didFinishLaunchingWithOptions` method in your `AppDelegate.m`), set the publication parameters provided (i.e. PAPER_SETUP, SERVER and API_KEY) and set the delegate

```
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ...
    [Newsmemory setPSetup:@"PAPER_SETUP"];
    [Newsmemory setServer:@"SERVER"];
    [Newsmemory setDelegate:self];
    //if provided set also the API key
    [Newsmemory setAPIKey:@"API_KEY"];

    return YES;
}
...
```

4. Show the TANewsmemoryViewController

If you are using Storyboards you could simply create a `ViewController` element and set `TANewsmemoryViewController` as `'Class'`

![Storyboard setup](img/storyboard.png)

## Swift integration

If you are using Swift in your app and you are using the `use_frameworks!` attribute you need to take additional steps:

1. add the following lines to your `Podfile`:

```
...
### PODS ###
...

static_libraries = ['NewsmemorySDK'] # <- static libraries names
# Make frameworks in the list static frameworks by overriding the static_framework?function to return true
pre_install do |installer|
  installer.pod_targets.each do |pod|
    if static_libraries.include?(pod.name)
      puts "Overriding the static_framework? method for #{pod.name}"
      def pod.static_framework?;
        true
      end
      def pod.build_type;
        Pod::BuildType.static_library
      end
    end
  end
end

```

2. run again `pod install`

3. Add to you project a `-Bridging-Header.h` file and add there the import of the `Newsmemory` module:

```
#import <Newsmemory/Newsmemory.h>
```

4. Remove the import of the `Newsmemory` module from your `.swift` files

   ~~import Newsmemory~~

5. Go to `Project`-> `Build Settings`-> `Objective-C Bridging Header` and add the path to the bridging header file. The path should be relative to your project, similar to the way your Info.plist path is specified in Build Settings (see https://developer.apple.com/documentation/swift/importing-objective-c-into-swift for more details).

## Dependencies

This SDK has been tested with `Google-Mobile-Ads-SDK` versions >= `9.6` and < `12`.
Tecnavia does not guarantee that the SDK builds nor its stability if you use a higher version of the GMA SDK.

## Available Newsmemory methods

| Method name               | Type        | Default    | Description                                                                                                                        |
| ------------------------- | ----------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| setPSetup                  | NSString\* | (required) | the configuration to load for a publication                                                                                        |
| setServer                  | NSString\* | (required) | the Tecnavia endpoint for the publication                                                                                          |
| setAPIKey                  | NSString\* | none       | the API key to use the SDK at runtime                                                                                              |
| setToken                   | NSString\* | none       | the auto login token to pass the ePaper                                                                                            |
| setLockedOrientation       | NSString\* | none       | the orientation the SDK should support, possible values (`all`, `portrait`, `portrait_up`, `portrait_down`, `landscape`, `landscape_left`, `landscape_right`) |
| setLockedOrientationDevice | NSString\* | none       | the device type that should respect the locked orientation setting (see setLockedOrientation). Possible values (`phone`, `tablet`). If not set, locked orientation (if set) will be applied to both phones and tablets. |
| setDelegate                | delegate    | none       | pass the object that will implement the supported method [callbacks](#callbacks)                                                   |
| setNeedsCloseButton        | BOOL        | `NO`       | adds a button to the ePaper buttons bar to send to the enclosing app a message to close the ePaper                                 |
| setNeedsSafeArea           | BOOL        | `NO`       | delegates to the SDK the handling of the device safe area                                                                          |
| setDebugMode               | BOOL        | `NO`       | enables debug mode to increase logging and use development backend versions, it must be set to `NO` when building for Release      |
| enableDebugger             | BOOL        | `NO`       | enables a visual debugger to monitor performances and use development backend versions, it must be set to `NO` when building for Release      |

---

<a name="callbacks"></a>

## Delegate Callbacks

| Method name             | Params                | Return value | Is synchronous? | Description                                                                                                                                                                                                                                                                                                                                                                                                 |
| ----------------------- | --------------------- | ------------ | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| onNewsmemoryClose       | none                  | none         | `NO`            | Called when the user presses the button to close the ePaper see (`setNeedsCloseButton` method) |
| newsmemoryWillOpenURL   | (NSString\*)url      | BOOL         | `YES`           | This callback if called when the ePaper tries to open an URL, if this method returns `NO` the URL will be opened inside the Tecnavia ePaper solution, if the method returns `YES` the ePaper won't open the URL and the enclosing app should manage the opening itself. `IMPORTANT:` As this is a synchronous method if the decision can be made within 2 seconds the ePaper will open the URL internally. |
| onNewsmemoryTrackAction | (NSDictionary \*)data | none         | `NO`            | Each action/event in the app will cause this callback to be called. The data dictionary contains the info regarding the user action. This callback can be used to collect data and send it to the analytics platform your app uses. For more details about the data sent by the app see paragraph [Tracking](#tracking) |
| onNewsmemoryReload      | none                  | none         | `NO`            | This callback is invoked when a JS bundle update takes place in the SDK |
| onNewsmemoryTokenExpired| none                  | none         | `YES`           | This callback is invoked when the SDK login API call fails due to the expiration of the TOKEN. If this method returns `NO` the login process will be handled inside the Tecnavia ePaper solution, if the method returns `YES` the ePaper won't continue loading: the enclosing app should manage the login process itself and eventually relaunch the SDK. `IMPORTANT:` As this is a synchronous method if the decision can't be made within 2 seconds the ePaper will handle the login internally. |

Example:

```
- (void)onNewsmemoryClose {
    ...
}

- (BOOL)newsmemoryWillOpenURL:(NSString *)url {
    //TODO: handle the opening of the URL locally in your app
    return YES;
}

- (void)onNewsmemoryTrackAction:(NSDictionary *)data {
    ...
}

- (BOOL)onNewsmemoryTokenExpired {
    //TODO: handle the login process
    return YES;
}
```

---

<a name="tracking"></a>

## Tracking

By implementing the callback `onNewsmemoryTrackAction` your app will receive data about user actions and events occurring inside the ePaper.

In the following table we will describe the format of the data:

| Key       | Type            | Value                   |
| --------- | --------------- | ----------------------- |
| trackType | NSString \*     | `"screen"` or `"event"` |
| data      | NSDictionary \* | (see below)             |

### Common data

| Key     | Type        | Value                                             |
| ------- | ----------- | ------------------------------------------------- |
| paper   | NSString \* | the sanitized paper name, ex: `usatoday`          |
| edition | NSString \* | the edition currently open, ex: `USA Today`       |
| issue   | NSString \* | the issue currently open, ex: `20230218`          |
| page    | NSString \* | the page the user is currently on, ex: `A1`       |
| section | NSString \* | the section the user is currently on, ex: `World` |

When article mode is open there are other values available:

| Key   | Type        | Value                                                             |
| ----- | ----------- | ----------------------------------------------------------------- |
| title | NSString \* | the title of the article the user is currently on                 |
| type  | NSString \* | the type of the article the user is currently on, ex: `Editorial` |
| mode  | NSString \* | the mode the user is using to read an article, `text`/`graphic`   |

### Screen specific data

A `screen` represents something that is displayed on the screen, such as an ePaper page or article.

The `data` dictionary can contain the following values:

| Key    | Type        | Value                                                                                                                    |
| ------ | ----------- | ------------------------------------------------------------------------------------------------------------------------ |
| screen | NSString \* | an URL-like string containing all the info about what is shown onto screen. Ex: `/iPhone/20230218/USA Today/scrolled/A1` |
| action | NSString \* | the action associated to the screen, ex: `scrolled`                                                                      |

When article mode is open there are other values available:

| Key        | Type | Value                                   |
| ---------- | ---- | --------------------------------------- |
| article_id | int  | the Tecnavia id of the article, ex: `8` |

### Event specific data

An `event` represents an action performed by the user on the ePaper, such as the activation of the Text-to-speech feature or the sharing of an article on Facebook.

The `data` dictionary can contain the following values:

| Key      | Type        | Value                                    |
| -------- | ----------- | ---------------------------------------- |
| action   | NSString \* | the event name, ex: `tts_start`          |
| category | NSString \* | the event category, ex: `text_to_speech` |

---

<a name="troubleshooting"></a>

## Troubleshooting

#### - `error build: Library not found for -l<LIBRARY NAME>` at build stage

Check that you copied the SDK folder in the same folder of your `.xcodeproj` file.
Check that you imported the `.xcconfig` file in your project `Configurations` settings

#### - `[native] No bundle URL present. Make sure you're running a packager server or have included a .jsbundle file in your application bundle.` in the logs and crash at runtime

Ensure that the you imported the file `Newsmemory.js` within the SDK resources (see `Installation` step `4`).

#### - `rpath/libswiftCore.dylib not loaded` at runtime

This might mean that xCode is not including the required Swift packages.
To fix simply add a blank .swift file and let xCode generate the corresponding bridging header.

#### - `CocoaPods could not find compatible versions for pod "NewsmemorySDK"` when running `pod install`

```
[!] CocoaPods could not find compatible versions for pod "NewsmemorySDK":
  In Podfile:
    NewsmemorySDK (= 3.17.05)

None of your spec sources contain a spec satisfying the dependency: `NewsmemorySDK (= 3.17.05)`.

You have either:
 * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
 * mistyped the name or version.
 * not added the source repo that hosts the Podspec to your Podfile.
```

Simply run `pod install --repo-update`

---

<a name="authors"></a>

## Authors

- Nicolò Aquilini, iOS Software developer, Tecnavia
- Andrea Mauri, Android Software developer, Tecnavia
