Auth API is available via account property of PressReader. Normally Host app performs PressReader authorization on start or before access to PressReader features is required.
let account = PressReader.instance().accounttry await account.authorize(token: String)try await account.authorize(externalToken: String, provider: String)Authorization by service name allows working with SDK based on service name only, without token. In order to achieve this behavior the next configuration has to be done:
In Info.plist of your app add PRConfig dictionary with SERVICE_NAME string type entry with your service name value.
Only account authorized with external auth token can be deauthorized.
try await account.deauthorize()To observer SDK's current state utilize the state property:
PressReader.instance().stateSDK state is described by the following options:
typedef NS_OPTIONS(NSUInteger, PRState) {
PRStateRunning = 1 << PRStateTypeRunning,
PRStateActivated = 1 << PRStateTypeActivated,
PRStateCatalogLoaded = 1 << PRStateTypeCatalogLoaded
};Each change in the state triggers the PressReaderStateDidChange notification. Alternatively, employ the PressReaderState class to manage state using the Combine API.
SDK state has to turn .activated to execute any operations and .catalogLoaded to be able to download issues.
After the instance of PressReader SDK is authorized, issues downloading becomes possible. The downloading process is manageable via catalog item's download property that conforms to Download interface described below.
Download {
var state: DownloadState
var progress: Int
var error: Error?
func start()
func pause()
func cancel()
}where DownloadState is
enum DownloadState {
stop, // the downloading wasn’t started or was stopped due to error
progress, // the downloading is in progress
pause, // the downloading is paused
ready // downloading was successfully completed
}You access specific download for a cid / date pair via corresponding item in catalog:
guard let download = PressReader.instance().catalog.item(cid, date)?.download else {
print("Item with given cid / date isn't found")
return
}download.start()download.pause()To resume download call download.start() method again.
download.cancel()Downloading state and progress can be accessed via state, progress and error properties.
Additionally download object conforms to observation interface that allows to attach handlers to follow download progress in real time.
Download {
/// when the returned DownloadObserver is deinited it will stop observing
func observe(_ callback: @escaping Callback) -> DownloadObserver?
}where Callback is
typealias Callback = (DownloadState, Progress, Error?) -> VoidAuthorizationError is returned when there’s a problem with authorization and re-authorization is required.
The management of downloaded catalog items can be done via downloaded property of catalog
let downloaded = PressReader.instance.catalog.downloadedwhere downloaded is
Downloaded {
// returns the list of downloaded items
var items: [Item]
// deletes downloaded item
func delete(_ item: Item)
func deleteAll()
}where Item is
Item {
var cid: String
var date: Date
var title: String
var size: Long?
var download: Download
}Please check Download section for the information how to access the item's download state and open it.
Downloaded object conforms to the observation interface and “calls back” on items deletion or insertion.
Downloaded {
/// when the returned Observer is deinited it will stop observing
func observe(_ callback: @escaping ()->()) -> Observer
}if let reader = ReadingVC(issue: issue) {
yourViewController.present(reader. animated: true, completion: nil)
}reader can be nil in case issue hasn't been previously ordered (dowload process not started)
let articleId = "281651080992599"
await PressReader.instance().openArticle(id: articleId)The getLogs asyncronous method is available to collect device logs and upload to server
func getLogs(completion: (Result<(linkToUploadedLogs: URL, additionalInfo: String), Error>) -> Void)completion is a callback executed after obtaining all required information including linkToUploadedLogs, additionalInfo - some textual information we usually provide along with logs inside feedback email, like OS version, device model, device id, some internal component versions (SDK version) and crash stack if available.
A list of tracker classes can be passed to PressReader SDK init method to track events happening when publication is viewed:
var trackerList: MutableList<AnalyticsTracker> = ArrayList()
trackerList.add(CustomTracker())
PressReader.init(Application.this, PressReader.Params(trackerList))where CustomTracker inherits from ReadingViewAnalyticsTracker and overrides the methods corresponding to the events to be logged.
| Event name | Event parameters | Description |
|---|---|---|
OpenIssueForReading |
issue |
Publication issue opened for reading |
IssuePage |
issue,pageNumber |
Issue page is changed (reading view) |
IssueTextFlow |
issue |
Issue article feed is presented (text view) |
ArticleView |
article |
Full Article Text view presented |
Translated |
fromLanguage,toLanguage |
Translated article presented |
ListenView |
issue |
text-to-speach view presented |
where fromLanguage, toLanguage are ISO language codes,
Any host app’s provided tracker should conform to abstract AnalyticsTracker protocol with no methods defined, but all protocol for different part of tracking functionality would include this protocol, for example the only currently defined RreadingViewAnalyticsTracker protocol:
public protocol ReadingViewAnalyticsTracker: AnalyticsTrackerProtocol {
/// publication opened for reading
func trackOpenIssueForReading(issue: TrackingIssue)
/// reading(replica) view switched to pageNumber [1...N]
func trackIssuePage(issue: TrackingIssue, pageNumber: Int)
/// reading view switched to text flow of article snippets (phone only)
func trackIssueTextFlow(issue: TrackingIssue)
/// reading view switched to detail article view
func trackArticleView(issue: TrackingIssue, article: TrackingArticle)
/// presenting "newspaper radio view" initiated from replica or article view
func trackListenView(issue: TrackingIssue)
/// presenting translated version of article, languages parameter are alpha-2 ISO codes
func trackTranlated(article: TrackingArticle, languageFrom: String, laguageTo: String)
/// specific page printed from replica view (full page or cropped to visible part)
func trackPrintedPages(issue: TrackingIssue, isFullPage: Bool, pageNumbers: [Int])
/// article printed as a formatted text or as it presented in replica view
func trackPrintedArticle(issue: TrackingIssue, article: TrackingArticle, inReplicaPresentation: Bool)
}Protocol methods are all have default implementation doing nothing, so host app implementation should only defined those methods in their classes which they want to track for example:
extension SomeTracker: ReadingViewAnalyticsTracker {
func trackOpenIssueForReading(issue: TrackingIssue) {
print ("Openin publication \(issue.slug) of \(issue.date) opened for reading")
}
}The following public API structures defined for host developer to be used inside ReadingViewAnalytics protocol methods as parameters:
public struct TrackingIssue {
public let cid: String
public let date: Date
public let isLatest: Bool
public let version: Int?
public let smartLayoutVersion: Int?
public let title: String
public let slug: String?
public let sourceType: String // currently "newspaper" or "magazine"
}
public struct TrackingArticle {
public let id: String
public let headline: String
public let language: String
}providing most of possibly used for analytics information from both replica and article view. In the future we’ll define more protocols for analytics in other parts of the tracked functionality.
Because PressReader class is a singleton, the host app should setup the list of analytics trackers via launchOptions class property before first use of PressReader:
private lazy var pressreader: PressReader = {
PressReader.launchOptions = [.prAnalyticsTrackers: [self]]
return PressReader.instance()
} ()