Μετάβαση στο κύριο περιεχόμενο

Ενσωμάτωση iOS SDK

Εγγενές iOS SDK για παρακολούθηση συμβάντων, διαχείριση συνεδριών χρηστών, αποστολή push notifications και εμφάνιση μηνυμάτων εντός εφαρμογής.

Δυνατότητες​

  • Ελαφρύ - Ελάχιστο αποτύπωμα
  • Γρήγορο - Βελτιστοποιημένο για απόδοση
  • Υποστήριξη εκτός σύνδεσης - Ουρά συμβάντων βασισμένη σε SQLite
  • Αυτόματη επανάληψη - Exponential backoff σε αποτυχίες
  • Ομαδοποίηση - Αποτελεσματική ομαδοποίηση συμβάντων (50 συμβάντα / 5 δευτ.)
  • Μηνύματα εντός εφαρμογής - native και HTML μηνύματα, 5 τύποι, με frequency capping
  • Push Notifications - Apple Push Notification Service (APNS)
  • Απόρρητο πρώτα - Συμβατό με GDPR, σέβεται τη συγκατάθεση χρήστη
  • iOS 14+ - Υποστήριξη σύγχρονων εκδόσεων iOS

Απαιτήσεις​

  • iOS 14.0+
  • Xcode 15.0+
  • Swift 5.9+
Κλήση από Objective-C

Το API του SDK είναι αποκλειστικά Swift, οπότε δεν μπορεί να κληθεί απευθείας από αρχείο .m ή .mm. Μια εφαρμογή Objective-C το ενσωματώνει προσθέτοντας ένα μόνο αρχείο Swift που κάνει import το Joryio και εκθέτει τις κλήσεις που χρειάζεται, και το καλεί από Objective-C ως συνήθως. Το Xcode ρυθμίζει το bridging header την πρώτη φορά που προσθέτετε αρχείο Swift σε στόχο Objective-C.

Εγκατάσταση​

Swift Package Manager (προτείνεται)​

Το SDK διανέμεται ως πακέτο Swift από το https://github.com/joryio/joryio-ios-sdk. Αυτός είναι ο προτεινόμενος τρόπος εγκατάστασης· το CocoaPods έχει καταργηθεί (δείτε CocoaPods). Προσθέστε το ακόλουθο στο Package.swift:

dependencies: [
.package(url: "https://github.com/joryio/joryio-ios-sdk.git", from: "1.3.3")
]

Το πακέτο παρέχει τρία products. Συνδέστε τα δύο πρώτα στην εφαρμογή σας ανάλογα με τις ανάγκες της· το τρίτο είναι μόνο για ένα Notification Service Extension (δείτε Εικόνες σε rich push):

.target(
name: "YourApp",
dependencies: [
.product(name: "Joryio", package: "joryio-ios-sdk"), // tracking, ταυτότητα, push
.product(name: "JoryioUI", package: "joryio-ios-sdk"), // + εμφάνιση in-app μηνυμάτων
]
)

Ή στο Xcode:

  1. File → Add Package Dependencies
  2. Εισαγάγετε: https://github.com/joryio/joryio-ios-sdk.git
  3. Επιλέξτε έκδοση και προσθέστε στον target

CocoaPods (καταργημένο)​

Καταργημένο - χρησιμοποιήστε Swift Package Manager

Το CocoaPods έχει καταργηθεί για το iOS SDK της Joryio υπέρ του Swift Package Manager. Το CocoaPods trunk, το αποθετήριο από το οποίο κατεβάζει ένα απλό pod 'Joryio', κλείνει (μόνο για ανάγνωση από τις 2 Δεκεμβρίου 2026), οπότε δεν είναι εγγυημένο ότι οι νέες εκδόσεις θα βρίσκονται εκεί. Αν η εφαρμογή σας πρέπει να μείνει στο CocoaPods, εγκαταστήστε από το git tag του SDK όπως παρακάτω: δεν χρησιμοποιεί το trunk, και το υποστηρίζει κάθε έκδοση από την 1.3.0 και μετά, μαζί με τις beta. Καθορίστε την έκδοση με :tag και αλλάξτε το tag για αναβάθμιση - το pod update δεν το μετακινεί.

Για να μεταβείτε στο Swift Package Manager: διαγράψτε τις γραμμές pod 'Joryio...' από το Podfile, τρέξτε pod install και προσθέστε το πακέτο όπως περιγράφεται παραπάνω. Τίποτα άλλο στον κώδικά σας δεν αλλάζει - εκτός από το ότι ένα Notification Service Extension γράφει import JoryioNotificationServiceExtension αντί για import Joryio.

pod 'Joryio/UI', :git => 'https://github.com/joryio/joryio-ios-sdk.git', :tag => '1.3.3' # τα πάντα, μαζί με την in-app εμφάνιση
# pod 'Joryio', :git => 'https://github.com/joryio/joryio-ios-sdk.git', :tag => '1.3.3' # μόνο tracking, ταυτότητα και push - χωρίς WebKit

# Μόνο σε target Notification Service Extension:
# pod 'Joryio/NotificationServiceExtension', :git => 'https://github.com/joryio/joryio-ios-sdk.git', :tag => '1.3.3'
Ποιο από τα δύο;

Το JoryioUI εξαρτάται από το Joryio, οπότε συνδέοντας το product UI τα παίρνετε και τα δύο.

Πάρτε μόνο το Joryio όταν η εφαρμογή δεν χρειάζεται in-app μηνύματα ή όταν ένας έλεγχος ασφαλείας αντιτίθεται στη σύνδεση web view. Προσοχή: η προεπιλογή στο CocoaPods είναι το Joryio χωρίς UI - το pod 'Joryio' δεν θα εμφανίζει in-app μηνύματα μέχρι να το αλλάξετε σε pod 'Joryio/UI'.

Privacy manifest​

Το SDK συνοδεύεται από το privacy manifest της Apple (PrivacyInfo.xcprivacy) τόσο στο Swift package όσο και στο pod του CocoaPods. Δηλώνει το μοναδικό required-reason API που χρησιμοποιεί το SDK - UserDefaults, λόγος CA92.1 - και τα δεδομένα που συλλέγει το SDK: user ID, device ID, αλληλεπίδραση με το προϊόν και ιστορικό αγορών, το καθένα συνδεδεμένο με τον χρήστη και χωρίς χρήση για tracking. Όλα δηλώνονται για τους σκοπούς App Functionality, Analytics και Developer's Advertising or Marketing, και όλα εκτός από το device ID επίσης για Product Personalization. Δεν δηλώνεται τοποθεσία: το SDK δεν διαβάζει ποτέ την τοποθεσία της συσκευής, και η χώρα που το backend της Joryio εξάγει από τη διεύθυνση IP δεν είναι δεδομένο που συλλέγει το SDK. Το Xcode το περιλαμβάνει στην αναφορά απορρήτου της εφαρμογής σας. Τα γνωρίσματα και τις ιδιότητες συμβάντων που επιλέγετε να στέλνετε τα δηλώνετε εσείς στο manifest της εφαρμογής σας.

Γρήγορη εκκίνηση​

1. Αρχικοποιήστε το SDK​

Στο AppDelegate.swift:

import Joryio

func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {

// Initialize with your SDK key
Joryio.shared.initialize(
sdkKey: "jry_sdk_ios_YOUR_SDK_KEY",
apiHost: "https://api-eu1.joryio.com/api"
)

return true
}
Εύρεση του κλειδιού SDK

Βρείτε το κλειδί SDK στο dashboard του Joryio στις Ρυθμίσεις → Εφαρμογές → [Η εφαρμογή σας] → SDK Keys.

Κάθε δημόσια μέθοδος μπορεί να κληθεί με ασφάλεια πριν από το initialize(). Οι optOut(), optIn(), wipeData(), updateConsent(_:), setSdkAuthenticationToken(_:), setSdkAuthenticationErrorHandler(_:) και setInAppMessageCallback(_:capabilities:) απομνημονεύονται και εφαρμόζονται όταν ξεκινήσει το SDK. Οι κλήσεις που συλλέγουν ή στέλνουν - track, identify, γνωρίσματα, addAlias, συνδρομές, reset, flush, οι κλήσεις push token, απόδειξης παράδοσης, κλικ και κατάργησης εγγραφής, και οι αναφορές in-app - μπαίνουν σε ουρά (έως 1000, η παλαιότερη απορρίπτεται πρώτη, το ίδιο όριο σε κάθε SDK του Joryio) και εκτελούνται με τη σειρά μόλις πετύχει το initialize(). Μέχρι τότε οι getters επιστρέφουν κενές τιμές. Μια κλήση που συλλέγει δεδομένα - συμβάν, γνώρισμα, alias, εγγραφή σε συνδρομή, απόδειξη ή κλικ push, αναφορά in-app - ενώ ο χρήστης έχει κάνει opt-out ή η συγκατάθεση έχει απορριφθεί, απορρίπτεται αμέσως: ένα μεταγενέστερο optIn() ή .granted δεν τη στέλνει ποτέ. Το identify εξακολουθεί να κρατιέται, ώστε οι ανακλήσεις να φέρουν τον σωστό χρήστη. Οι αποφάσεις που λαμβάνονται πριν από το initialize() - optOut(), optIn(), updateConsent(_:), wipeData() - ισχύουν πριν από οτιδήποτε κάνει το SDK κατά την εκκίνηση (Session Start, συγχρονισμός in-app, νέα καταχώριση push). Ένα optOut() / optIn() πριν από το initialize() υπερισχύει του optOut στις ρυθμίσεις. Τα isUserOptedOut() και getTrackingConsent() απαντούν από ό,τι είναι αποθηκευμένο ακόμη και πριν από το initialize(). Όταν δεν έχει αποφασιστεί ακόμη τίποτα, το getTrackingConsent() απαντά .granted - τη συγκατάθεση με την οποία ξεκινά μια εφαρμογή χωρίς banner συγκατάθεσης. Αν το initialize() απορρίψει το SDK key ή τον host, το registerPushToken(_:onResult:) απαντά αμέσως success: false αντί να περιμένει.

Εκκίνηση πριν από το πρώτο ξεκλείδωμα. Περιμένει μόνο μια εκκίνηση πριν η συσκευή ξεκλειδωθεί μία φορά μετά την ενεργοποίησή της (push στο παρασκήνιο ή αφύπνιση τοποθεσίας αμέσως μετά από επανεκκίνηση): μέχρι τότε ο χώρος αποθήκευσης του SDK δεν διαβάζεται. Το initialize() ολοκληρώνεται μόνο του σε εκείνο το πρώτο ξεκλείδωμα, οι κλήσεις στο μεταξύ παραμένουν στην ουρά, και το isInitializationPending είναι true όσο περιμένει - δεν είναι αποτυχία. Μια συσκευή που απλώς είναι κλειδωμένη, αφού ξεκλειδώθηκε μία φορά από την ενεργοποίησή της, ξεκινά αμέσως: ένα σιωπηλό push σε κλειδωμένο τηλέφωνο εξυπηρετείται κανονικά.

2. Παρακολουθήστε συμβάντα​

// Basic event
Joryio.shared.track("Button Tapped")

// Event with properties
Joryio.shared.track("Product Viewed", properties: [
"product_id": "abc123",
"product_name": "Wireless Headphones",
"price": 99.99,
"category": "Electronics"
])

// Screen view
Joryio.shared.trackScreen("ProductDetail", properties: [
"product_id": "abc123"
])

3. Αναγνωρίστε χρήστες​

Στείλτε τους αριθμούς τηλεφώνου με + και κωδικό χώρας

Στέλνετε πάντα τους αριθμούς τηλεφώνου σε πλήρη διεθνή μορφή (E.164): +, ο κωδικός χώρας και μετά ο αριθμός - για παράδειγμα +972501234567. Ένας αριθμός χωρίς + διαβάζεται με την προεπιλεγμένη χώρα για αριθμούς τηλεφώνου του χώρου εργασίας· αν δεν έχει οριστεί, ή αν τα ψηφία διαβάζονται με δύο τρόπους, αποθηκεύεται ως μη επαληθευμένος και δεν χρησιμοποιείται για μηνύματα. Πώς χειρίζονται οι αριθμοί τηλεφώνου

// Identify a user
Joryio.shared.identify("user-123")
Joryio.shared.setAttributes([
"email": "[email protected]",
"name": "John Doe",
"plan": "premium"
])

// Set attributes later
Joryio.shared.setAttribute("last_purchase", value: Date())
Joryio.shared.incrementAttribute("lifetime_value", by: 99.99)

// A second identifier for the same person - works before identify() too
Joryio.shared.addAlias("loyalty_id", name: "L-12345")

// On logout
Joryio.shared.reset()

Το identify συνδέει το ανώνυμο ιστορικό της συσκευής με τον χρήστη στον διακομιστή, καταχωρίζει ξανά το push token υπό αυτόν και συγχρονίζει ξανά τα in-app μηνύματα.

Η ταυτοποίηση ενός άλλου χρήστη χωρίς reset() ενδιάμεσα αντιμετωπίζεται σαν αποσύνδεση και σύνδεση για ό,τι άφησε πίσω ο προηγούμενος χρήστης: οι μη απεσταλμένες εγγραφές γνωρισμάτων του φεύγουν με τα δικά του IDs, ποτέ του νέου χρήστη, και με πιστοποίηση SDK το token του μένει δεμένο με τα στοιχεία του στην ουρά. Όσο το πρόσωπο έχει κάνει opt-out ή η συγκατάθεση είναι denied, το identify απλώς κρατά το user ID στη συσκευή, ώστε μια απεγγραφή, η καταγραφή opt-out ή μια κατάργηση push να αφορούν τον σωστό χρήστη - τίποτα δεν στέλνεται, δεν καταγράφεται ως συμβάν και δεν γράφεται σε προφίλ. Το κανονικό identify εκτελείται μόλις επιτραπεί ξανά η παρακολούθηση· τα reset() και wipeData() ξεχνούν το ID που κρατήθηκε.

Το reset ξεκινά αμέσως μια νέα ανώνυμη ταυτότητα: νέο anonymous ID, χωρίς user ID, χωρίς εκκρεμείς εγγραφές γνωρισμάτων και χωρίς κατάσταση in-app, και μια νέα συνεδρία που ανακοινώνεται με συμβάν Session Start. Ένα identify στην αμέσως επόμενη γραμμή χρησιμοποιεί ήδη τη νέα ταυτότητα. Το push token καταχωρίζεται ξανά υπό αυτήν και τα in-app μηνύματα συγχρονίζονται ξανά. Τα συμβάντα που μπήκαν στην ουρά πριν από το reset στέλνονται κανονικά, με τα IDs υπό τα οποία καταγράφηκαν.

Μια κλήση χωρίς υποχρεωτική τιμή - identify(""), track(""), κενό κλειδί γνωρίσματος - καταγράφει προειδοποίηση και δεν κάνει τίποτα. Ένας αριθμός που δεν είναι πεπερασμένος (NaN ή άπειρο) σε ιδιότητες συμβάντος ή τιμές γνωρισμάτων απορρίπτεται με προειδοποίηση στην καταγραφή, και η υπόλοιπη κλήση συνεχίζεται.

Οι ετικέτες του addAlias χρησιμοποιούν πεζά γράμματα, ψηφία και κάτω παύλες. Ένα alias που προστίθεται σε ανώνυμο επισκέπτη παραμένει στο προφίλ του όταν αυτός αναγνωριστεί.

Πού αποθηκεύονται τα αναγνωριστικά​

ΤιμήΑποθηκεύεται σεΜετά τη διαγραφή της εφαρμογής
Anonymous ID, device ID, συνεδρίαUserDefaultsΧάνεται
Opt-out, αποθηκευμένη άρνηση συγκατάθεσης, αποφάσεις πριν από το initialize, ιστορικό εμφάνισης in-appUserDefaultsΧάνεται
User ID, APNs device token, μη απεσταλμένες εγγραφές γνωρισμάτων, εκκρεμείς καταργήσεις push (φέρουν το token), user ID που κρατήθηκε κατά το opt-out, το token πιστοποίησης SDK ενός χρήστη που αποσυνδέθηκε (μέχρι να σταλούν ή να απορριφθούν τα στοιχεία του στην ουρά)Keychain (μόνο αυτή η συσκευή, μετά το πρώτο ξεκλείδωμα)Χάνεται - το SDK εντοπίζει την επανεγκατάσταση και διαγράφει τα στοιχεία του από το Keychain
Συμβάντα σε ουρά· εγγραφές identify, alias, συνδρομών και opt-out που περιμένουν τον διακομιστή· εγγραφές γνωρισμάτων που άφησε ένας προηγούμενος χρήστης όταν η εφαρμογή ταυτοποίησε κάποιον άλλο χωρίς reset()SQLite στο Application Support, εξαιρούνται από τα αντίγραφα ασφαλείαςΧάνεται

Κάθε κλειδί που γράφει το SDK στο UserDefaults ξεκινά με jry_ ή joryio_.

Αυτόματα δεδομένα συνεδρίας​

Το iOS SDK εμπλουτίζει τα συμβάντα Session Start με δεδομένα συσκευής και περιβάλλοντος:

  • $device_id
  • $platform (ios)
  • $model
  • $os_name / $os_version
  • $app_version / $build_number
  • $bundle_id
  • $screen_width / $screen_height
  • $locale
  • $language / $languages
  • $timezone
  • country (ISO-3166-1 alpha-2, προέρχεται από IP κατά την έναρξη συνεδρίας)

Push Notifications​

Πότε να ρωτήσετε

Ζητήστε την άδεια όταν ο χρήστης έχει λόγο να πει ναι. Μια προτροπή στα πρώτα δευτερόλεπτα μιας συνεδρίας είναι αυτή που απορρίπτεται συχνότερα, και μια άρνηση είναι πολύ δυσκολότερο να αντιστραφεί από μια καθυστέρηση - η προτροπή του συστήματος είναι εφάπαξ, οπότε ένα "όχι" εκεί είναι ουσιαστικά μόνιμο, ενώ μια μεταγενέστερη ερώτηση δεν σας κοστίζει τίποτα.

Το SDK δεν εμφανίζει ποτέ την προτροπή για λογαριασμό σας. Αν έχετε αποφασίσει ότι τη θέλετε στην εκκίνηση, ορίστε το requestPushPermissionAtLaunch - είναι απενεργοποιημένο εξ ορισμού, όχι μη διαθέσιμο.

Ενεργοποιήστε push notifications για αποστολή στοχευμένων μηνυμάτων μέσω Apple Push Notification Service (APNS).

1. Ρύθμιση στο AppDelegate​

import Joryio

class AppDelegate: UIResponder, UIApplicationDelegate {

func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Initialize SDK
Joryio.shared.initialize(
sdkKey: "jry_sdk_ios_YOUR_KEY",
apiHost: "https://api-eu1.joryio.com/api"
)

// Request push permissions
Task {
let granted = await Joryio.shared.requestPushPermission()
if granted {
print("Push notifications enabled")
}
}

return true
}

// Handle device token registration
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
Joryio.shared.didRegisterForRemoteNotifications(deviceToken: deviceToken)
}

// Handle registration failure
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
) {
Joryio.shared.didFailToRegisterForRemoteNotifications(error: error)
}

// Handle received push notification
func application(
_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
Joryio.shared.didReceiveRemoteNotification(userInfo, completionHandler: completionHandler)
}
}

Το SDK γίνεται ο delegate του UNUserNotificationCenter στο initialize() και διατηρεί τον delegate που είχε ορίσει η εφαρμογή σας πριν από αυτό. Ενεργεί μόνο σε ειδοποιήσεις Joryio (κλειδί payload joryio) - τις εμφανίζει στο προσκήνιο και χειρίζεται τα πατήματά τους - και προωθεί κάθε άλλη ειδοποίηση, καθώς και το callback ρυθμίσεων, στον delegate σας χωρίς αλλαγές. Αν ορίσετε δικό σας delegate μετά το initialize(), αναφέρετε μόνοι σας τα πατήματα ειδοποιήσεων Joryio με trackPushClick(trackingId:).

Το didRegisterForRemoteNotifications(deviceToken:) είναι επίσης το σημείο εισόδου για μια μηχανή που λαμβάνει η ίδια το APNs token - η γέφυρα Unity του περνά το token από το kUnityDidRegisterForRemoteNotificationsWithDeviceToken. Ένα token που φτάνει πριν από το initialize() διατηρείται και καταχωρίζεται όταν ξεκινήσει το SDK.

Το token καταχωρίζεται στο Joryio μόνο όσο ο χρήστης είναι opted in και η συγκατάθεση παρακολούθησης έχει δοθεί. Διαφορετικά παραμένει στη συσκευή και καταχωρίζεται όταν αυτό αλλάξει. Οι αποδείξεις παράδοσης και η παρακολούθηση κλικ ακολουθούν τον ίδιο κανόνα.

2. Ρύθμιση APNS στο dashboard​

Για να στείλετε push notifications, εισαγάγετε τα διαπιστευτήρια APNs στην iOS εφαρμογή στο Joryio:

  1. Μεταβείτε στις Ρυθμίσεις → Εφαρμογές και επιλέξτε το εικονίδιο Ειδοποιήσεις push (καμπανάκι) στη γραμμή της iOS εφαρμογής σας
  2. Επιλέξτε Environment - Ανάπτυξη (Sandbox) για builds που τρέχετε από το Xcode, Παραγωγή για builds App Store και TestFlight
  3. Επιλέξτε Με token (κλειδί .p8) και εισαγάγετε το Key ID, το Team ID και το περιεχόμενο του κλειδιού ελέγχου ταυτότητας .p8
  4. Επιλέξτε Αποθήκευση διαμόρφωσης

Για αναλυτικές οδηγίες δημιουργίας του κλειδιού στον λογαριασμό σας Apple Developer, δείτε Λήψη διαπιστευτηρίων APNs.

3. Δυνατότητες push​

// Check if push is enabled - true exactly when the status is "granted"
let isEnabled = await Joryio.shared.isPushEnabled()
let status = await Joryio.shared.getPushPermissionStatus() // "granted", "denied" or "notDetermined"

// Get device token
if let token = Joryio.shared.getDeviceToken() {
print("Device token: \(token)")
}

// Badge management
Joryio.shared.updateBadgeCount(5)
Joryio.shared.clearBadge()

// Unregister from push - removes the token on the Joryio server and with iOS.
// Holds across launches until registerPushToken(_:) or requestPushPermission().
Joryio.shared.unregisterPush()

// Your own push stack: hand the token over and report what happened
Joryio.shared.registerPushToken(hexToken) { result in
// result.success, result.message, result.isUnauthorized, result.isRetryable
}
Joryio.shared.reportPushDelivered(trackingId)
Joryio.shared.trackPushClick(trackingId: trackingId)

Η προσωρινή (provisional) και η εφήμερη (ephemeral) εξουσιοδότηση μετρούν ως "granted". Το γνώρισμα χρήστη push_permission χρησιμοποιεί τις ίδιες τιμές, με not_determined για το "notDetermined".

Το token πρέπει να είναι το APNs device token ως συμβολοσειρά hex. Οτιδήποτε άλλο - για παράδειγμα ένα registration token του Firebase (FCM) - απορρίπτεται: το onResult αναφέρει success: false και το SDK καταγράφει τον λόγο. Το unregisterPush() διατηρείται ανάμεσα στις εκκινήσεις: το token που δίνει το iOS σε μια επόμενη εκκίνηση κρατιέται στη συσκευή αλλά δεν καταχωρίζεται, μέχρι η εφαρμογή να καλέσει ξανά το registerPushToken(_:onResult:) ή το requestPushPermission(). Το registerPushToken(_:onResult:) καλεί το onResult μία φορά με το αποτέλεσμα· μια απάντηση 200 με success: false αναφέρεται ως αποτυχία, ποτέ ως επιτυχία. Τα reportPushDelivered(_:) και trackPushClick(trackingId:) είναι για εφαρμογή που χειρίζεται μόνη της τις ειδοποιήσεις, οπότε καμία δεν φτάνει στους handlers του SDK.

Εικόνες σε rich push​

Το APNs δεν μπορεί να επισυνάψει εικόνα από μόνο του· πρέπει να το κάνει ένα Notification Service Extension στην εφαρμογή σας. Προσθέστε ένα (File → New → Target → Notification Service Extension) και συνδέστε το product του extension μόνο σε εκείνο το target:

  • Swift Package Manager: JoryioNotificationServiceExtension
  • CocoaPods: pod 'Joryio/NotificationServiceExtension' στο μπλοκ target του extension

Μη συνδέσετε το Joryio στο extension: καλεί το UIApplication.shared, το οποίο τα app extensions δεν επιτρέπεται να χρησιμοποιούν, και φέρνει το SQLite σε μια διεργασία με όριο 24 MB. Το product του extension δεν έχει εξαρτήσεις. Αντικαταστήστε την κλάση που δημιουργήθηκε με:

import JoryioNotificationServiceExtension // CocoaPods: import Joryio

class NotificationService: JoryioNotificationService {}

Κατεβάζει το URL από το κλειδί jry_image_url (ή attachment-url) του payload και το επισυνάπτει.

Μηνύματα εντός εφαρμογής​

Εμφανίστε στοχευμένα μηνύματα εντός εφαρμογής σε χρήστες με βάση τη συμπεριφορά και τα γνωρίσματά τους.

Tokens παράδοσης (delivery tokens)​

Όταν ο διακομιστής σερβίρει μια επιλέξιμη καμπάνια, εκδίδει επίσης ένα υπογεγραμμένο token παράδοσης μικρής διάρκειας. Το SDK το επιστρέφει όταν αναφέρει εμφάνιση, κλικ ή απόρριψη, και ο διακομιστής επαληθεύει την υπογραφή πριν καταγράψει οτιδήποτε.

Δεν χρειάζεται να κάνετε τίποτα - το SDK το χειρίζεται για εσάς. Τεκμηριώνεται επειδή ο διακομιστής μπορεί να ρυθμιστεί ώστε να το απαιτεί. Από προεπιλογή, μια αναφορά χωρίς token γίνεται ακόμη δεκτή - ο διακομιστής την καταγράφει ως client παλαιότερης έκδοσης - και μόνο όταν το backend τρέχει με IN_APP_REQUIRE_DELIVERY_TOKEN=true απορρίπτεται η ίδια αναφορά:

POST /v1/in-app/track (no deliveryToken)
{ "success": false, "error": "A delivery token is required" }

Ένα token που υπάρχει αλλά δεν επαληθεύεται - πλαστό, αλλοιωμένο ή ληγμένο - απορρίπτεται πάντα, ανεξάρτητα από τη ρύθμιση.

Το token είναι αυτό που κάνει μια εμφάνιση αξιόπιστη: χωρίς αυτό, οποιοσδήποτε κατέχει το SDK key - το οποίο περιλαμβάνεται σε κάθε εφαρμογή και σελίδα - θα μπορούσε να αναφέρει εμφανίσεις και κλικ για μια καμπάνια που δεν εμφανίστηκε ποτέ, και τα δεδομένα σας θα τα μετρούσαν.

Αν οι εμφανίσεις in-app σταματήσουν να καταγράφονται σε backend που επιβάλλει tokens, ελέγξτε ότι η εφαρμογή έχει χτιστεί με τρέχουσα έκδοση του SDK: μια έκδοση από πριν υπάρξουν τα tokens παράδοσης δεν στέλνει token.

Αυτόματος συγχρονισμός καμπανιών​

Το SDK συγχρονίζει αυτόματα καμπάνιες από τον διακομιστή:

  • Κατά την εκκίνηση και όταν η εφαρμογή εισέρχεται στο προσκήνιο - το πολύ μία φορά ανά syncInterval (προεπιλογή 300 δευτερόλεπτα)
  • Αμέσως όταν ο χρήστης αναγνωρίζεται ή γίνεται reset, όταν πατηθεί ένα push, όταν φτάσει ένα σιωπηλό push συγχρονισμού και όταν αλλάξει ένα γνώρισμα που παρακολουθεί μια καμπάνια

Η syncInAppCampaigns() συγχρονίζει κατ' απαίτηση και δεν υπόκειται σε περιορισμό ρυθμού.

Τα μηνύματα που ενεργοποιούνται από ένα συμβάν, ένα πάτημα push ή ένα όριο γνωρίσματος περνούν από τα ίδια όρια συχνότητας και τον ίδιο κανόνα "ένα μήνυμα τη φορά" με κάθε άλλο μήνυμα.

Μη αυτόματος έλεγχος καμπάνιας​

// Manually sync campaigns from server
await Joryio.shared.syncInAppCampaigns()

// Manually trigger campaign evaluation
await Joryio.shared.evaluateInAppCampaigns()

// Reset displayed campaigns (for testing)
Joryio.shared.resetDisplayedCampaigns()
Οι κλήσεις δοκιμών απαιτούν enableDebug

Οι evaluateInAppCampaigns() και resetDisplayedCampaigns() αλλάζουν πραγματική κατάσταση - η μία μπορεί να εμφανίσει μήνυμα με το ζόρι, η άλλη σβήνει πραγματικά όρια συχνότητας - γι' αυτό ΑΓΝΟΟΥΝΤΑΙ εκτός αν το SDK αρχικοποιήθηκε με enableDebug: true· μια έκδοση release καταγράφει προειδοποίηση και δεν κάνει τίποτα. Τα διαγνωστικά μόνο για ανάγνωση (getQueueSize(), getSessionInfo(), getIdentity(), getDeviceToken()) δεν περιορίζονται. Η syncInAppCampaigns() είναι κανονικό API και εκτελείται πάντα.

Δύο είδη περιεχομένου​

Κάθε καμπάνια φτάνει σε μία από δύο μορφές περιεχομένου και το SDK αποδίδει την καθεμία διαφορετικά:

ΠεριεχόμενοΤι είναιΠώς αποδίδεται
NativeΔομημένα δεδομένα - τίτλος, κείμενο, εικόνα, κουμπιάΠραγματικά UIKit views, με το χρώμα τόνου, το Dynamic Type, τη σκοτεινή λειτουργία και το VoiceOver της εφαρμογής σας. Χωρίς web view.
HTMLΚώδικας HTML και CSS γραμμένος από τον συντάκτηΈνα WKWebView μέσα στο μήνυμα, υπό αυστηρή Content-Security-Policy.

Ενεργοποίηση μηνυμάτων HTML​

Τα μηνύματα HTML είναι απενεργοποιημένα από προεπιλογή. Ένα μήνυμα HTML αποδίδει κώδικα γραμμένο από τον συντάκτη σε ένα web view μέσα στην εφαρμογή σας, οπότε η ενεργοποίηση είναι απόφαση της ομάδας της εφαρμογής - όχι κάτι που ενεργοποιείται από μια πλατφόρμα μάρκετινγκ:

let config = JoryioConfig(
inApp: InAppConfig(allowHtmlJsInAppMessages: true) // προεπιλογή: false
)

Joryio.shared.initialize(
sdkKey: "jry_sdk_ios_YOUR_KEY",
apiHost: "https://api-eu1.joryio.com/api",
config: config
)

Αφήνοντάς το απενεργοποιημένο δεν απενεργοποιείτε τα in-app μηνύματα. Τα native μηνύματα συνεχίζουν να εμφανίζονται, επειδή είναι δεδομένα που αποδίδουν τα ίδια τα views του SDK - χωρίς κανέναν διερμηνέα. Οι καμπάνιες HTML παραλείπονται και καταγράφονται.

Αυτό αφορά τον renderer του ίδιου του SDK. Αν η εφαρμογή σας σχεδιάζει η ίδια τα in-app μηνύματα με setInAppMessageCallback(_:capabilities:), το web view του SDK δεν εκτελείται ποτέ, οπότε η ρύθμιση δεν ισχύει για αυτή τη διαδρομή - δηλώστε content.html στα capabilities και οι καμπάνιες HTML παραδίδονται στο callback σας είτε είναι ενεργοποιημένη είτε όχι. Δικός σας ο renderer, δική σας η απόφαση.

Το έγγραφο του μηνύματος εμφανίζεται υπό μια Content-Security-Policy που μπλοκάρει κάθε script, τα frames, την πρόσβαση στο δίκτυο και τις υποβολές φορμών - οι ίδιοι κανόνες με το web SDK. Εκτελείται μόνο το joryioBridge του ίδιου του SDK, οπότε οι σύνδεσμοι, τα κουμπιά, τα γνωρίσματα data-joryio-action, οι κλήσεις της γέφυρας και οι φόρμες data-jry-form λειτουργούν, αλλά τα δικά του <script> του συντάκτη, οι inline χειριστές on* και τα ενσωματωμένα <iframe> δεν εκτελούνται στο iOS (ούτε στο web).

Αν η πολιτική ασφαλείας σας απαγορεύει την απόδοση συντεταγμένου HTML εντός της διεργασίας, αφήστε το απενεργοποιημένο και συντάξτε τις καμπάνιες σας ως native μηνύματα.

Απόδοση των μηνυμάτων μόνοι σας​

Το SDK σχεδιάζει τα native μηνύματα για εσάς, αλλά μπορείτε να αναλάβετε πλήρως - η ίδια διέξοδος που άλλοι προμηθευτές ονομάζουν custom view factory. Υλοποιήστε το InAppMessagePresenter και αναθέστε το:

Joryio.shared.inAppPresenter = MyPresenter()

Η αυτόματη ανακάλυψη εκτελείται μόνο όταν το inAppPresenter είναι nil, οπότε ο δικός σας αντικαθιστά τον ενσωματωμένο renderer αντί να συγκρούεται μαζί του. Ορίστε τον πριν ή μετά το initialize.

Ο presenter λαμβάνει την καμπάνια με το content ήδη επιλυμένο - το Liquid αποδίδεται στον διακομιστή και τα native πεδία φτάνουν ως απλό κείμενο. Επιστρέψτε true από το present(campaign:in:delegate:) μόνο όταν το μήνυμα είναι στην οθόνη: τότε το SDK αναφέρει μόνο του "displayed" και μετρά την εμφάνιση στο όριο συχνότητας της καμπάνιας. Αναφέρετε τα πατήματα και το κλείσιμο μέσω του delegate που λαμβάνετε - messageViewClicked(_:action:url:) με το id του κουμπιού ή του συνδέσμου, και messageViewDidDismiss(_:) όταν το μήνυμα κλείνει. Μην καλείτε το trackInAppImpression από έναν presenter: το μήνυμα θα αναφερόταν δύο φορές.

Για απόδοση με δικό σας UI χωρίς presenter, χρησιμοποιήστε ένα callback:

Joryio.shared.setInAppMessageCallback({ campaign in
showMyMessage(campaign)
Joryio.shared.trackInAppImpression(campaignId: campaign.id, action: "displayed")
}, capabilities: ["content.native"])

// When a button is tapped, and when the message closes:
Joryio.shared.trackInAppImpression(campaignId: campaign.id, action: "clicked", elementId: "buy_now")
Joryio.shared.trackInAppImpression(campaignId: campaign.id, action: "dismissed")

// Hand display back to the SDK's own renderer:
Joryio.shared.clearInAppMessageCallback()

Το action είναι "displayed", "clicked", "dismissed" ή "converted"· οποιαδήποτε άλλη τιμή απορρίπτεται με μήνυμα καταγραφής. Το elementId ονομάζει προαιρετικά το κουμπί ή τον σύνδεσμο ενός κλικ. Η δική σας αναφορά "displayed" είναι η μόνη που στέλνεται για αυτό το μήνυμα, και αυτή μετρά το μήνυμα στο όριο συχνότητας της καμπάνιας - ένα μήνυμα που δόθηκε στο callback σας και δεν εμφανίστηκε ποτέ δεν καταναλώνει τίποτα. Το "dismissed" αφήνει το SDK να δώσει το επόμενο μήνυμα: ένα μήνυμα για το οποίο αναφέρατε "displayed" κρατά την οθόνη μέχρι να αναφέρετε "dismissed", ώστε να μη σχεδιαστεί τίποτα από πάνω του. Χωρίς καμία αναφορά, το SDK ελευθερώνεται μόνο του μετά από 30 δευτερόλεπτα· ένα μήνυμα που αναφέρθηκε "displayed" και ποτέ "dismissed" κρατά την οθόνη το πολύ 5 λεπτά. Αναφέρετε "dismissed" κάθε φορά που το μήνυμα φεύγει από την οθόνη, και μετά από κλικ. Ένα μήνυμα που περιμένει την καθυστέρηση εμφάνισής του δεν δίνεται αν ο χρήστης ταυτοποιηθεί ως άλλο πρόσωπο, κάνει opt-out ή αλλάξει η συγκατάθεση.

Από την έκδοση 1.3.2. Ένα callback που ορίζεται πριν από το initialize() εγκαθίσταται πριν από τον πρώτο συγχρονισμό. Αν το ορίσετε μετά το initialize(), ο πρώτος συγχρονισμός μπορεί να τελειώσει νωρίτερα και το SDK σχεδιάζει μόνο του εκείνο το μήνυμα· περάστε InAppConfig(holdInAppMessagesForHandler: true) για να το αποτρέψετε. Ένα μήνυμα που είναι έτοιμο πριν οριστεί το callback τότε κρατείται - δεν σχεδιάζεται, δεν αναφέρεται, δεν μετρά σε κανένα όριο συχνότητας - και δίνεται στο callback τη στιγμή που το ορίζετε. Αν αντί γι' αυτό καλέσετε clearInAppMessageCallback(), η αναμονή τελειώνει και το SDK σχεδιάζει το μήνυμα που κρατήθηκε.

Το όνομα της κλάσης διαφέρει ανά package manager

Δεν το ρυθμίζετε, αλλά αξίζει να το ξέρετε όταν κάτι δεν εμφανίζεται. Το SDK βρίσκει τον ενσωματωμένο renderer με το όνομά του κατά την εκτέλεση, και το module στο οποίο ζει αυτό το όνομα εξαρτάται από τον τρόπο ενσωμάτωσης:

πώς πακετάρεταικλάση που αναζητά το SDK
SwiftPMτο JoryioUI είναι δικό του targetJoryioUI.DefaultInAppMessagePresenter
CocoaPodsτο Joryio/UI είναι subspec, και τα subspecs μοιράζονται το module του podJoryio.DefaultInAppMessagePresenter

Δοκιμάζονται και τα δύο ονόματα. Αν δεν εμφανίζεται ποτέ μήνυμα, αναζητήστε την προειδοποίηση "No in-app presenter found" - σημαίνει ότι το προϊόν UI δεν είναι συνδεδεμένο (pod 'Joryio/UI' ή το προϊόν JoryioUI στο SwiftPM), όχι ότι η καμπάνια δεν έφτασε. Απ' έξω τα δύο μοιάζουν ίδια.

Ο δικός σας presenter δεν χρειάζεται τίποτα από αυτά: αναθέστε τον και η ανίχνευση δεν τρέχει καθόλου.

Τύποι μηνυμάτων​

Το SDK υποστηρίζει 5 τύπους μηνυμάτων:

  1. Modal - Στο κέντρο της οθόνης με σκίαση
  2. Banner - Στο επάνω μέρος της οθόνης
  3. Slide-Up - Μικρή ειδοποίηση από κάτω
  4. Full-Screen - Μήνυμα που καταλαμβάνει την οθόνη
  5. Custom - Η εφαρμογή σας αποφασίζει τη θέση

Τα banners και τα slide-ups δέχονται αγγίγματα μόνο μέσα στο μήνυμα, ώστε η υπόλοιπη εφαρμογή να παραμένει χρησιμοποιήσιμη πίσω τους. Τα μηνύματα modal και full-screen μπλοκάρουν την οθόνη.

Frequency Capping​

Τα μηνύματα τηρούν τους κανόνες επικοινωνίας σε επίπεδο workspace και τα όρια συχνότητας σε επίπεδο καμπάνιας:

  • Μέγιστες εμφανίσεις ανά χρονικό παράθυρο
  • Ελάχιστη καθυστέρηση μεταξύ μηνυμάτων
  • Όρια συχνότητας ανά καμπάνια

Πότε ένα μήνυμα μετρά ως εμφανισμένο​

Ένα μήνυμα μετρά ως εμφανισμένο - αναφέρεται το in_app.displayed και καταναλώνεται το όριο συχνότητας της καμπάνιας - μόνο όταν το άτομο μπορούσε πράγματι να το δει. Ο χρόνος που πρέπει να μείνει στην οθόνη είναι το IN_APP_DISPLAY_DWELL_MS (1000 ms), η ίδια σταθερά σε κάθε Joryio SDK.

  • Το SDK παρουσιάζει ένα μήνυμα μόνο όταν η εφαρμογή είναι ενεργή και ο ανώτερος view controller είναι σταθερός - όχι στη μέση παρουσίασης, κλεισίματος ή μετακίνησης. Διαφορετικά περιμένει και ξαναδοκιμάζει.
  • Το μήνυμα μετρά ως εμφανισμένο αφού μείνει στην οθόνη 1 δευτερόλεπτο ενώ η εφαρμογή παραμένει ενεργή. Αν η εφαρμογή περάσει στο παρασκήνιο νωρίτερα, το δευτερόλεπτο ξεκινά από την αρχή όταν επιστρέψει.
  • Αν το μήνυμα φύγει από την οθόνη νωρίτερα, δεν αναφέρεται τίποτα και το όριο δεν καταναλώνεται, οπότε παραμένει επιλέξιμο.
  • Ένα πάτημα ή κλείσιμο νωρίτερα μετρά ως προβολή: αναφέρεται πρώτα το displayed και μετά το κλικ ή η απόρριψη. Μια επαναφορά, αλλαγή χρήστη ή εξαίρεση (opt-out) νωρίτερα δεν αναφέρει τίποτα.
  • Αν αποδίδετε μόνοι σας τα μηνύματα: αναφέρετε το displayed με τον ίδιο κανόνα - αφού το μήνυμα είναι ορατό για InAppDisplay.IN_APP_DISPLAY_DWELL_MS, ή αμέσως πριν από ένα κλικ ή κλείσιμο που έρχεται νωρίτερα.

Επιλογές ρυθμίσεων​

Προσαρμόστε τη συμπεριφορά του SDK με JoryioConfig:

JoryioConfig(
// User Identification
userId: String?, // Initialize with known user ID
anonymousId: String?, // Custom anonymous ID

// Batching & Performance
batchSize: Int, // Default: 50 (at most 500 per request)
flushInterval: TimeInterval, // Default: 5.0 seconds (minimum 1.0)
sendImmediately: Bool, // Default: false
maxQueueSize: Int, // Default: 1000

// Session Management
sessionTimeout: TimeInterval, // Default: 1800 (30 minutes)
trackSessionStart: Bool, // Default: true

// Push
requestPushPermissionAtLaunch: Bool, // Default: false - prefer a primer

// In-App Messaging
inApp: InAppConfig, // Default: InAppConfig() - see below

// Network & Retry
maxRetries: Int, // Default: 3
retryBackoffMs: Double, // Default: 1000.0
requestTimeout: TimeInterval, // Default: 10.0

// SDK Authentication (opt-in)
enableSdkAuthentication: Bool, // Default: false
sdkAuthenticationToken: String?, // Default: nil

// Privacy & GDPR
optOut: Bool, // Default: false (optOut() persists regardless)
trackingConsent: TrackingConsent?, // Default: nil (unset) - see Tracking consent

// Debugging
enableDebug: Bool, // Default: false
logLevel: LogLevel? // Default: nil - .debug with enableDebug, otherwise .error
)
InAppConfig(
enabled: Bool, // Default: true - false turns in-app off
allowHtmlJsInAppMessages: Bool, // Default: false
syncInterval: TimeInterval, // Default: 300 - seconds between automatic syncs
onMessageDisplay: ((InAppMessage) -> Void)?, // after the SDK displays a message
onMessageClick: ((InAppMessage, String) -> Void)?, // with the tapped element's name
onMessageDismiss: ((InAppMessage) -> Void)?, // after a message is dismissed
holdInAppMessagesForHandler: Bool // Default: false - hold messages until setInAppMessageCallback (since 1.3.2)
)

Τα τρία callbacks εκτελούνται στο κύριο νήμα (main thread).

Προηγμένες δυνατότητες​

Διαχείριση γνωρισμάτων χρήστη​

// Set multiple attributes
Joryio.shared.setAttributes([
"age": 28,
"city": "San Francisco",
"premium": true
])

// Set single attribute
Joryio.shared.setAttribute("language", value: "en")

// Increment numeric attribute
Joryio.shared.incrementAttribute("page_views", by: 1)
Joryio.shared.incrementAttribute("total_spent", by: 29.99)

// Remove attribute
Joryio.shared.unsetAttribute("temporary_flag")

Έλεγχοι απορρήτου​

// Stop collecting. PERSISTED - survives an app restart.
Joryio.shared.optOut()

// Opt back in
Joryio.shared.optIn()

// Check opt-out status
if Joryio.shared.isUserOptedOut() {
print("User has opted out")
}

// Delete everything the SDK stored on this device.
// SEPARATE from optOut(): "stop collecting" and "delete what you have" are
// different requests. This is the one an erasure request needs. It does NOT
// opt the user out - call optOut() as well if that is also intended.
Joryio.shared.wipeData()

// Get identity info
let (userId, anonymousId) = Joryio.shared.getIdentity()
print("User: \(userId ?? "anonymous"), Anonymous ID: \(anonymousId)")

Τι ακριβώς κάνει το optOut():

σταματά τη συλλογήναι - κάθε διαδρομή εγγραφής: track, identify, γνωρίσματα (μαζί με αυξήσεις και unsets), aliases, εγγραφή σε συνδρομές, καταχώριση push και αποδείξεις παράδοσης, in-app impressions. Οι ανακλήσεις στέλνονται κανονικά: μια απεγγραφή, η καταγραφή opt-out και η κατάργηση του push
επιβιώνει σε επανεκκίνησηναι - η σημαία αποθηκεύεται στη συσκευή και διαβάζεται πριν συλλεχθεί οτιδήποτε. Δεν συνδέεται με το SDK key, οπότε επιβιώνει και σε αλλαγή κλειδιού. Το optOut: true στη ρύθμιση αποθηκεύεται με τον ίδιο τρόπο
απορρίπτει ό,τι είναι ήδη στην ουράναι - τα συμβάντα στην ουρά, οι μη επιβεβαιωμένες εγγραφές γνωρισμάτων και οι εγγραφές identify, alias και συνδρομών που περιμένουν απορρίπτονται, δεν παραδίδονται αργότερα. Οι ανακλήσεις που περιμένουν κρατούνται και παραδίδονται
ενημερώνει τον διακομιστήναι - το γνώρισμα προφίλ tracking_opted_out (true· το optIn() στέλνει false). Αποστέλλεται μόνο όταν αλλάζει το opt-out - και με optOut: true στις ρυθμίσεις ή με κλήση πριν από το initialize() - και ξαναστέλνεται μέχρι να το αποθηκεύσει ο διακομιστής. Στέλνεται όποια κι αν είναι η συγκατάθεση - και όταν εκκρεμεί ή έχει αρνηθεί
διαγράφει αποθηκευμένα δεδομέναόχι - χρησιμοποιήστε το wipeData()

Το γνώρισμα tracking_opted_out είναι καταγραφή, όχι επιβολή: αποθηκεύεται στο προφίλ ώστε οι καμπάνιες να μπορούν να το εξαιρούν. Η καταστολή στον διακομιστή είναι ξεχωριστή ρύθμιση.

Τι διαγράφει το wipeData(): το user ID και το anonymous ID, το device ID, τα συμβάντα στην ουρά, τις εγγραφές γνωρισμάτων που δεν στάλθηκαν, την κατάσταση in-app, τη συνεδρία και το push token - του οποίου καταργείται και η εγγραφή στον διακομιστή του Joryio, ώστε να μη στέλνεται τίποτα άλλο σε αυτή την εγκατάσταση. Το opt-out διατηρείται: η διαγραφή των δεδομένων κάποιου δεν τον επαναφέρει στην παρακολούθηση. Το επόμενο συμβάν (ή η επόμενη επιστροφή της εφαρμογής στο προσκήνιο) ξεκινά νέα συνεδρία, που ανακοινώνεται με ένα Session Start. Στη συνέχεια το push μένει ανενεργό μέχρι η εφαρμογή να καλέσει ξανά το registerPushToken ή να ζητήσει ξανά άδεια - ένα token που έρχεται σε επόμενη εκκίνηση δεν καταχωρίζεται αυτόματα. Η καταχώριση και η κατάργηση εκτελούνται μία κάθε φορά: μια νέα καταχώριση του ίδιου token ακυρώνει την κατάργησή του αν αυτή δεν έφτασε ακόμη στον διακομιστή, και μια ανεπιβεβαίωτη κατάργηση άλλου token στέλνεται πριν από κάθε νέα καταχώριση.

Περάστε τη συγκατάθεση που κατέχει ο consent manager σας κατά την εκκίνηση, και ενημερώστε την όταν αποφασίσει ο χρήστης:

Joryio.shared.initialize(
sdkKey: "jry_sdk_ios_YOUR_KEY",
apiHost: "https://api-eu1.joryio.com/api",
config: JoryioConfig(trackingConsent: .pending)
)

// Later, from your consent banner:
Joryio.shared.updateConsent(.granted) // or .denied
ΣυγκατάθεσηΣυμπεριφορά
.grantedΚανονική
.pendingΤα συμβάντα και οι εγγραφές γνωρισμάτων κρατούνται στη συσκευή (έως maxQueueSize) και δεν αποστέλλεται τίποτα - ούτε Session Start, ούτε συγχρονισμός in-app, ούτε καταχώριση push. Το .granted στέλνει ό,τι κρατήθηκε· το .denied το απορρίπτει
.deniedΔεν συλλέγεται τίποτα, και ό,τι έχει κρατηθεί διαγράφεται

Δύο ανεξάρτητοι διακόπτες καθορίζουν αν συλλέγεται κάτι: η συγκατάθεση που αναφέρει το banner σας και το opt-out του ίδιου του ατόμου. Συλλογή γίνεται μόνο όταν η συγκατάθεση είναι .granted ΚΑΙ το άτομο δεν έχει κάνει opt-out - οποιοδήποτε "όχι" υπερισχύει.

  • Το .denied αποθηκεύεται στη συσκευή και ισχύει και στις επόμενες εκκινήσεις. Το αίρει μόνο ένα ρητό updateConsent(.granted) ή ένα trackingConsent: .granted στις ρυθμίσεις.
  • Το trackingConsent είναι εξ ορισμού μη ορισμένο (nil). Μη ορισμένο χωρίς αποθηκευμένη τιμή συμπεριφέρεται ως .granted, ώστε μια εφαρμογή χωρίς banner συγκατάθεσης να λειτουργεί κανονικά· μη ορισμένο με αποθηκευμένο .denied παραμένει denied.
  • Το .pending δεν αποθηκεύεται: ισχύει μόνο για την τρέχουσα εκκίνηση και δεν υπερισχύει ποτέ ενός .denied, είτε αποθηκευμένου είτε δοσμένου νωρίτερα πριν από το initialize().
  • Η συγκατάθεση δεν αίρει ποτέ ένα opt-out. Μόνο το optIn() το κάνει, και το optOut() δεν αλλάζει ποτέ την αποθηκευμένη συγκατάθεση.
  • Το getTrackingConsent() επιστρέφει τη συγκατάθεση που ισχύει· το isUserOptedOut() αντανακλά μόνο το opt-out.
  • Μια συνεδρία που ξεκίνησε όσο η συλλογή δεν επιτρεπόταν ανακοινώνεται με συμβάν Session Start μόλις επιτραπεί - αργότερα στην ίδια εκκίνηση, ή σε επόμενη εκκίνηση ως νέα συνεδρία.

Μη αυτόματη αποστολή ουράς​

// Flush immediately (e.g., before app termination)
Joryio.shared.flush()

// Check queue size
let queueSize = Joryio.shared.getQueueSize()
print("Pending events: \(queueSize)")

Τα συμβάντα αποστέλλονται σε παρτίδες το πολύ 500 συμβάντων και περίπου 900 KB. Αν ο διακομιστής απορρίψει μια παρτίδα ως μη έγκυρη (HTTP 400, 413 ή 422), το SDK τη χωρίζει και ξαναστέλνει τα δύο μισά, ώστε ένα κακό συμβάν να μην μπορεί να καθυστερήσει τα υπόλοιπα· ένα συμβάν που απορρίπτεται όταν σταλεί μόνο του διαγράφεται και καταγράφεται. Τα συμβάντα που ο διακομιστής αναφέρει ως αποτυχημένα κρατούνται και ξαναστέλνονται. Με HTTP 429, 5xx και αποτυχίες δικτύου κρατούνται όλα και η αποστολή επαναλαμβάνεται με exponential backoff, τηρώντας το Retry-After. Το HTTP 402 ή 403 σταματά την αποστολή για το υπόλοιπο της συνεδρίας και κρατά τα συμβάντα. Οι αποτυχίες δεν διαγράφουν ποτέ συμβάντα· μόνο το maxQueueSize το κάνει, ξεκινώντας από τα παλαιότερα. Το SDK απορρίπτει ήδη στο track(), με μια γραμμή καταγραφής, ένα συμβάν που ξέρει ότι ο διακομιστής θα αρνηθεί - κενό όνομα ή μεγαλύτερο από 255 χαρακτήρες, ή ιδιότητες πάνω από 50 KB σειριοποιημένες (μετρημένες όπως τις μετρά ο διακομιστής), πάνω από 200 κλειδιά πρώτου επιπέδου ή με βάθος ένθεσης πάνω από 5 επίπεδα· και τα συμβάντα που ο διακομιστής αναφέρει στο rejectedIndices απορρίπτονται, δεν ξαναστέλνονται. Το flush() παρακάμπτει το backoff του ίδιου του SDK αλλά ποτέ το Retry-After του διακομιστή. Με πιστοποίηση SDK μια παρτίδα δεν αναμιγνύει ποτέ δύο χρήστες, και τα συμβάντα στην ουρά ενός χρήστη που αποσυνδέθηκε απορρίπτονται όταν ο διακομιστής τα αρνηθεί για οποιονδήποτε λόγο πιστοποίησης SDK, ώστε να μην μπλοκάρουν τα συμβάντα του επόμενου χρήστη.

Εγγραφές που πρέπει να φτάσουν στον διακομιστή​

Τα identify(_:), addAlias(_:name:), οι κλήσεις συνδρομών, η καταγραφή tracking_opted_out και το σκέλος του διακομιστή στα unregisterPush() / wipeData() κρατούνται στη συσκευή μέχρι να τα επιβεβαιώσει ο διακομιστής - μετά από επανεκκίνηση και μετά από reset() (το καθένα φέρει τα αναγνωριστικά με τα οποία έγινε). Αποστέλλονται με τη σειρά, ένα κάθε φορά, και μια νεότερη αλλαγή του ίδιου προσώπου για το ίδιο κανάλι ή την ίδια ομάδα αντικαθιστά αυτή που ακόμη περιμένει, ώστε μια παλαιότερη επανάληψη να μη φτάνει ποτέ μετά. Μια εγγραφή που έγινε ανώνυμα και στέλνεται μετά το identify(_:) φεύγει με το user ID, εφόσον το anonymous ID με το οποίο έγινε είναι ακόμη αυτό της συσκευής. Μια εγγραφή που ο διακομιστής απορρίπτει οριστικά (HTTP 400, 403, 409, 413, 422) διαγράφεται και καταγράφεται· μια αλλαγή συνδρομής που απαντάται με 404 (δεν υπάρχει ακόμη προφίλ) ξαναστέλνεται αφού σταλούν τα συμβάντα της ουράς, έως 5 φορές· τα success: false και ένα 401 πιστοποίησης SDK του τρέχοντος χρήστη ξαναστέλνονται με backoff, έως 10 φορές ανά εγγραφή. Η έλλειψη δικτύου, τα χρονικά όρια, τα HTTP 402, 429 και 5xx δεν μετρούν ποτέ εις βάρος μιας εγγραφής. Όσο η λήψη δεδομένων είναι σε παύση για το workspace σας (HTTP 402), οι ανακλήσεις φεύγουν κανονικά πριν από τις εγγραφές που πρέπει να περιμένουν. Όταν περιμένουν 1.000 εγγραφές, η παλαιότερη που δεν είναι ανάκληση κάνει χώρο. Τα optOut(), η συγκατάθεση .denied και το wipeData() απορρίπτουν τις εγγραφές identify, alias και συνδρομών που ακόμη περιμένουν· οι ανακλήσεις - μια απεγγραφή, η καταγραφή tracking_opted_out, μια κατάργηση push - κρατούνται και παραδίδονται.

Πιστοποίηση SDK​

Το token αποδεικνύει ποιος είναι ένας ταυτοποιημένος χρήστης: τα αιτήματα που αναφέρουν user ID πρέπει να φέρουν έγκυρο token. Οι ανώνυμοι επισκέπτες δεν έχουν token να δείξουν, οπότε τα αιτήματά τους γίνονται δεκτά χωρίς αυτό, εκτός αν το workspace ενεργοποιήσει και την αυστηρή ταυτότητα (strict identity).

Όταν η πιστοποίηση SDK είναι ενεργοποιημένη για το workspace σας, κάθε αίτημα ingest πρέπει να φέρει ένα JWT που εκδίδει το backend σας. Η παροχή token - στο sdkAuthenticationToken ή με setSdkAuthenticationToken(_:), πριν ή μετά το initialize() - ενεργοποιεί την κεφαλίδα, με ή χωρίς enableSdkAuthentication:

Joryio.shared.setSdkAuthenticationToken(tokenFromYourBackend)
Joryio.shared.setSdkAuthenticationErrorHandler { error in
fetchFreshToken { Joryio.shared.setSdkAuthenticationToken($0) }
}

Το reset() διαγράφει το token. Συμβάντα και εγγραφές που ο χρήστης που αποσυνδέεται είχε ήδη βάλει στην ουρά εξακολουθούν να στέλνονται με το δικό του token, οπότε μια κανονική αποσύνδεση δεν χάνει τίποτα - το token κρατιέται στο Keychain, δεμένο με αυτά τα στοιχεία, μέχρι να σταλούν ή να απορριφθούν, οπότε ούτε το κλείσιμο της εφαρμογής αμέσως μετά την αποσύνδεση χάνει κάτι. Η ταυτοποίηση άλλου χρήστη χωρίς reset() κάνει το ίδιο με το token του προηγούμενου χρήστη, και το ίδιο ισχύει όταν ορίζετε το token του επόμενου χρήστη με το setSdkAuthenticationToken(_:): είτε πριν είτε μετά το identify, ό,τι άφησε ο προηγούμενος χρήστης κρατά το δικό του token. Κάθε αίτημα φέρει το token του οποίου το sub είναι ο χρήστης του αιτήματος, ποτέ ένα που ονομάζει κάποιον άλλο· ένα token που ορίστηκε για τον επόμενο χρήστη πριν από το reset() - ακόμη κι όταν δεν είναι συνδεδεμένος κανείς - κρατιέται για εκείνον και χρησιμοποιείται ξανά στο δικό του identify, ενώ το wipeData() το διαγράφει - εκτός αν είναι το token του χρήστη που διαγράφεται (και ενός που ταυτοποιήθηκε όσο η παρακολούθηση είναι απενεργοποιημένη) ή το token που δόθηκε για αυτή την εκκίνηση, όταν εκτελείται ένα wipeData() που κλήθηκε πριν από το initialize(). Συμβάντα και εγγραφές που άφησε ένας χρήστης που δεν είναι πλέον ο τρέχων απορρίπτονται όταν η πιστοποίηση SDK τα αρνηθεί, για οποιονδήποτε λόγο (missing, sub_mismatch, expired, invalid), ώστε να μην μπλοκάρουν του επόμενου χρήστη. Ο χειριστής σφαλμάτων ενημερώνεται μόνο για τα αιτήματα του τρέχοντος χρήστη, ποτέ για ό,τι άφησε ένας προηγούμενος. Ακόμη κι όταν το πρόσωπο έχει κάνει opt-out ή η συγκατάθεση έχει αρνηθεί, ορίστε το token του χρήστη κατά τη σύνδεση: ο χρήστης που ταυτοποιήθηκε στο μεταξύ θεωρείται ο τρέχων για την απεγγραφή του, οπότε αν αυτή απορριφθεί ο χειριστής καλείται να δώσει το token του και η απεγγραφή διατηρείται.

Αναφορά API​

Κάθε δημόσιο μέλος του Joryio.shared, με το ακριβές όνομά του στη Swift.

ΜέθοδοςΤι κάνει
initialize(sdkKey:apiHost:config:)Ξεκινά το SDK με το SDK key, τον API host και προαιρετικό JoryioConfig. Μια δεύτερη κλήση αγνοείται
track(_:properties:)Καταγράφει ένα συμβάν με προαιρετικές ιδιότητες
trackScreen(_:properties:)Καταγράφει ένα συμβάν Screen Viewed με screen_name
identify(_:)Συνδέει τη συσκευή με ένα user ID· καταχωρίζει ξανά το push και συγχρονίζει τα in-app μηνύματα
addAlias(_:name:)Προσθέτει δεύτερο αναγνωριστικό με ετικέτα, και για ανώνυμους επισκέπτες
reset()Αποσύνδεση: νέα ανώνυμη ταυτότητα και συνεδρία
setAttributes(_:)Ορίζει πολλά γνωρίσματα· οι τιμές nil / NSNull τα αφαιρούν
setAttribute(_:value:)Ορίζει ένα γνώρισμα· το nil το αφαιρεί
incrementAttribute(_:by:)Ατομική αριθμητική αύξηση (προεπιλογή 1)
unsetAttribute(_:)Αφαιρεί ένα γνώρισμα
getUserId()Το τρέχον user ID, ή nil
getAnonymousId()Το τρέχον anonymous ID
getIdentity()(userId, anonymousId)
getSessionId()Το τρέχον ID συνεδρίας
getSessionInfo()(sessionId, sessionStart, duration)
optOut()Σταματά κάθε συλλογή και αποστολή· αποθηκεύεται
optIn()Συνέχεια μετά το optOut()
isUserOptedOut()Αν ο χρήστης έχει κάνει opt-out· πριν από το initialize(), από ό,τι είναι αποθηκευμένο
getTrackingConsent()Η συγκατάθεση παρακολούθησης που ισχύει: .granted, .denied ή .pending
updateConsent(_:)Ορίζει τη συγκατάθεση παρακολούθησης: .granted, .pending ή .denied
wipeData()Διαγράφει ό,τι αποθήκευσε το SDK στη συσκευή· κρατά το opt-out
setSubscription(channel:status:)Κατάσταση συνδρομής μάρκετινγκ για ένα κανάλι
addToSubscriptionGroup(_:channel:)Ένταξη σε ομάδα συνδρομής σε ένα κανάλι
removeFromSubscriptionGroup(_:channel:)Αποχώρηση από ομάδα συνδρομής σε ένα κανάλι
setSdkAuthenticationToken(_:)Δίνει ή αντικαθιστά το JWT πιστοποίησης SDK
setSdkAuthenticationErrorHandler(_:)Καλείται όταν ο διακομιστής απορρίπτει το JWT· απαντήστε με νέο token
clearSdkAuthenticationErrorHandler()Αφαιρεί αυτόν τον handler, π.χ. όταν κλείνει ένα bridge ή μια οθόνη
flush()Στέλνει τώρα τα συμβάντα της ουράς
getQueueSize()Συμβάντα που περιμένουν στη συσκευή
lastTransportErrorΗ πιο πρόσφατη αποτυχία αιτήματος (JoryioTransportError), ή nil μετά από επιτυχία
currentApiEndpointΗ βασική διεύθυνση API στην οποία στέλνει το SDK
isInitializationPendingtrue όσο το initialize() περιμένει το πρώτο ξεκλείδωμα μετά την ενεργοποίηση της συσκευής· δεν είναι αποτυχία
ecommerce(config:)Ο βοηθός e-commerce· δώστε ρύθμιση για να ορίσετε το νόμισμα
inAppPresenterΟ δικός σας InAppMessagePresenter, στη θέση του ενσωματωμένου renderer
setInAppMessageCallback(_:capabilities:)Λήψη in-app μηνυμάτων για να τα σχεδιάζετε μόνοι σας
clearInAppMessageCallback()Επιστροφή της σχεδίασης στο SDK
trackInAppImpression(campaignId:action:elementId:)Αναφορά του τι έκανε το δικό σας UI με ένα μήνυμα
submitInAppForm(campaignId:values:)Υποβολή φόρμας μέσα σε μήνυμα (async)· δεν πετάει ποτέ σφάλμα
syncInAppCampaigns()Λήψη in-app καμπανιών τώρα (async)
evaluateInAppCampaigns()Μόνο για δοκιμές, απαιτεί enableDebug: αξιολόγηση καμπανιών τώρα
resetDisplayedCampaigns()Μόνο για δοκιμές, απαιτεί enableDebug: ξεχνά ποια μηνύματα εμφανίστηκαν
requestPushPermission()Ζητά άδεια ειδοποιήσεων (async)· ακυρώνει το unregisterPush()
getPushPermissionStatus()"granted", "denied" ή "notDetermined" (async)
isPushEnabled()true ακριβώς όταν η κατάσταση είναι "granted" (async)
didRegisterForRemoteNotifications(deviceToken:)Προώθηση του APNs token από το AppDelegate
didFailToRegisterForRemoteNotifications(error:)Προώθηση αποτυχίας καταχώρισης APNs
didReceiveRemoteNotification(_:completionHandler:)Προώθηση απομακρυσμένης ειδοποίησης
registerPushToken(_:onResult:)Καταχώριση hex token από εσάς, με callback αποτελέσματος· ακυρώνει το unregisterPush()
getDeviceToken()Το αποθηκευμένο APNs token, ή nil
unregisterPush()Αφαιρεί το token στον διακομιστή και στο iOS· ισχύει ανάμεσα στις εκκινήσεις
reportPushDelivered(_:)Αναφέρει ότι έφτασε ένα push, με το trackingId του
trackPushClick(trackingId:)Αναφέρει πάτημα σε push, με το trackingId του
updateBadgeCount(_:)Ορίζει το badge της εφαρμογής
clearBadge()Καθαρίζει το badge της εφαρμογής
Joryio.pushPermissionAttributeΤο όνομα γνωρίσματος push_permission

Βέλτιστες πρακτικές​

1. Παρακολουθήστε ουσιαστικά συμβάντα​

Εστιάστε σε συμβάντα που είναι σημαντικά για την επιχείρησή σας:

// Good: Specific, actionable events
Joryio.shared.track("Trial Started", properties: ["plan": "premium"])
Joryio.shared.track("Feature Used", properties: ["feature": "export"])

// Avoid: Overly generic events
Joryio.shared.track("Button Tapped") // Too generic

2. Χειριστείτε τον κύκλο ζωής χρήστη​

// On login
func handleLogin(userId: String, userInfo: UserInfo) {
Joryio.shared.identify(userId)
Joryio.shared.setAttributes([
"email": userInfo.email,
"name": userInfo.name
])
}

// On logout
func handleLogout() {
Joryio.shared.reset()
}

// On signup - identify() joins the anonymous history to the new user
func handleSignup(userId: String, userInfo: UserInfo) {
Joryio.shared.identify(userId)
Joryio.shared.setAttributes(userInfo.attributes)
}

3. Αποστολή σε κρίσιμα συμβάντα​

override func applicationWillTerminate(_ application: UIApplication) {
Joryio.shared.flush()
}

Αντιμετώπιση προβλημάτων​

Τα συμβάντα δεν εμφανίζονται​

  1. Ελέγξτε ότι το κλειδί SDK είναι σωστό: jry_sdk_ios_*
  2. Ενεργοποιήστε debug logging: enableDebug: true (καταγράφει τα πάντα, εκτός αν ορίσετε και logLevel)
  3. Ελέγξτε τα logs της κονσόλας για σφάλματα
  4. Επαληθεύστε τη συνδεσιμότητα δικτύου
  5. Καλέστε flush() για άμεση αποστολή

Το push δεν λειτουργεί​

  1. Επαληθεύστε ότι τα διαπιστευτήρια APNs είναι αποθηκευμένα στην εφαρμογή στο dashboard
  2. Ελέγξτε ότι το device token έχει καταχωριστεί
  3. Βεβαιωθείτε για τα σωστά entitlements στο Xcode
  4. Δοκιμάστε στο σωστό περιβάλλον (development ή production)
  5. Αναζητήστε το σφάλμα της Αποστολή δοκιμαστικής push στο Λήψη διαπιστευτηρίων APNs

Σφάλματα build​

  1. Βεβαιωθείτε για target ανάπτυξης iOS 14.0+
  2. Εκκαθαρίστε τον φάκελο build: Cmd+Shift+K
  3. Ενημερώστε τις εξαρτήσεις Swift Package

Παρακολούθηση E-Commerce​

Το iOS SDK περιλαμβάνει ενσωματωμένο e-commerce tracker για συμβάντα προϊόντων, καλαθιού, checkout και παραγγελιών. Δείτε τον δια-SDK οδηγό E-Commerce Tracking για το πλήρες API με παραδείγματα Swift.

let ecommerce = Joryio.shared.ecommerce(config: EcommerceConfig(currency: "USD"))
ecommerce.purchase(order: EcommerceOrder(
orderId: "ORD-1001",
items: [EcommerceCartItem(productId: "SKU123", name: "Blue Shirt", price: 29.99, quantity: 2)],
value: 59.98
))

Μια κλήση χωρίς ό,τι δίνει νόημα στο συμβάν - ένα productId, ένα orderId, πεπερασμένη τιμή ή αξία, μια λίστα items σε μια αγορά (μπορεί να είναι κενή) - καταγράφει προειδοποίηση και δεν στέλνει τίποτα, ποτέ μια κενή ή μηδενική παραγγελία.

Το purchase στέλνει Order Completed με τα κλειδιά που διαβάζουν οι αναφορές εσόδων: orderId και total (συν currency και τα είδη). Αν καταγράφετε μόνοι σας μια αγορά με track(), χρησιμοποιήστε τα ίδια κλειδιά - τα order_id και value δεν διαβάζονται, και η παραγγελία μετρά ως μηδενικά έσοδα.

Επόμενα βήματα​

Παράδοση γνωρισμάτων​

Τα setAttributes, setAttribute, incrementAttribute και unsetAttribute είναι ανθεκτικά. Μια εγγραφή μένει στην ουρά μέχρι να την επιβεβαιώσει ο διακομιστής, οπότε ένα γνώρισμα που ορίστηκε ενώ η συσκευή ήταν εκτός σύνδεσης παραδίδεται όταν επιστρέψει η σύνδεση αντί να χαθεί. Μια αύξηση στέλνεται ως ατομική διαφορά, ποτέ ως σύνολο υπολογισμένο στη συσκευή.

  • Επανάληψη στην επόμενη εγγραφή γνωρίσματος, όταν η εφαρμογή επιστρέφει στο προσκήνιο και όταν συνεχίζεται η αποστολή (optIn(), παροχή συγκατάθεσης).
  • Ομαδοποίηση - μια ριπή κλήσεων γίνεται ένα αίτημα (παράθυρο 800ms). Μια μεμονωμένη εγγραφή φεύγει αμέσως. Μια εγγραφή που γίνεται ενώ ένα αίτημα είναι σε εξέλιξη το περιμένει και ακολουθεί· δεν το ακυρώνει ποτέ, οπότε μια αύξηση δεν μετριέται δύο φορές.
  • Επιβεβαιώνεται μόνο από τον διακομιστή - μια απάντηση 200 με success: false κρατά τις εγγραφές για την επόμενη προσπάθεια. Μια εγγραφή που ο διακομιστής απορρίπτει ως μη έγκυρη (HTTP 400, 413 ή 422) χωρίζεται και τα μισά στέλνονται ξανά, ώστε ένα λάθος κλειδί να μην κρατά πίσω τα υπόλοιπα· μια μεμονωμένη εγγραφή που απορρίπτεται ακόμη πετιέται και καταγράφεται. Έως 200 unsets ανά αίτημα, και τα υπόλοιπα ακολουθούν.
  • Το nil αφαιρεί - το setAttribute("nickname", value: nil), ή ένα NSNull από bridge, αφαιρεί το γνώρισμα όπως το unsetAttribute.
  • Διατηρείται στο iOS Keychain, ώστε μια εγγραφή να επιβιώνει αν τερματιστεί η διεργασία. Διαγράφεται μόλις επιβεβαιώσει ο διακομιστής, και καθαρίζεται από τα optOut(), reset() και wipeData(). Μια εγγραφή που ο διακομιστής απορρίπτει με HTTP 403 διαγράφεται και καταγράφεται, ώστε να μην μπορεί να καθυστερήσει τις επόμενες.

Τα γνωρίσματα χρησιμοποιούνται και για στόχευση in-app. Το προφίλ του διακομιστή είναι καθοριστικό: μόνο εγγραφές που ο διακομιστής δεν έχει ακόμη επιβεβαιώσει μπορούν να το παρακάμψουν, και αυτό εμποδίζει δύο συσκευές της ίδιας επαφής να διαφωνούν για το ποια είναι η επαφή.

Εγγραφή push και συγκατάθεση​

Το SDK εγγράφεται για απομακρυσμένες ειδοποιήσεις είτε ο χρήστης δώσει την άδεια ειδοποιήσεων είτε όχι. Στο iOS τα δύο είναι ξεχωριστά: η εγγραφή δίνει ένα device token χωρίς συγκατάθεση, και αυτό το token μπορεί να παραδώσει μόνο push παρασκηνίου (σιωπηλά) - δεν μπορεί να εμφανίσει τίποτα που ο χρήστης δεν έχει εγκρίνει.

Αυτό επιτρέπει σε ένα μήνυμα εντός εφαρμογής να φτάσει σε χρήστη που αρνήθηκε τις ειδοποιήσεις, και σημαίνει ότι υπάρχει ήδη token αν αργότερα ενεργοποιήσει τις ειδοποιήσεις από τις Ρυθμίσεις. Αναφέρετέ το στην πολιτική απορρήτου σας.

Μηνύματα εντός εφαρμογής​

Εμφανίστε στοχευμένα μηνύματα εντός εφαρμογής στους χρήστες με βάση τη συμπεριφορά και τα χαρακτηριστικά τους.

Συνδρομή μάρκετινγκ​

Αν επιτρέπεται να στέλνουμε μηνύματα σε αυτό το άτομο σε ένα κανάλι. Διαφορετική συναίνεση από το optOut(), που αφορά αν επιτρέπεται να το παρακολουθούμε - καμία δεν συνεπάγεται την άλλη.

Αυτό γράφει ένα κέντρο προτιμήσεων μέσα στην εφαρμογή.

Joryio.shared.setSubscription(channel: "email", status: "unsubscribed")
Joryio.shared.addToSubscriptionGroup("list_abc123", channel: "email")

Μια αλλαγή συνδρομής που γίνεται ενώ η συγκατάθεση παρακολούθησης εκκρεμεί περιμένει στη συσκευή και στέλνεται όταν δοθεί συγκατάθεση. Μια αλλαγή που αποτυγχάνει κρατείται, και μετά από επανεκκίνηση και reset(), και ξαναστέλνεται - δείτε Εγγραφές που πρέπει να φτάσουν στον διακομιστή.

Μια απεγγραφή - status: "unsubscribed", ή removeFromSubscriptionGroup - είναι ανάκληση: γίνεται δεκτή και παραδίδεται ακόμη κι αν το πρόσωπο έχει κάνει opt-out, η συγκατάθεση εκκρεμεί ή έχει αρνηθεί, ή μετά από wipeData(). Η εγγραφή σε κανάλι ή ομάδα όχι.

Κανάλια: email, sms, whatsapp, push, viber. Καταστάσεις: optedIn, subscribed, unsubscribed.

Απαιτείται αναγνωριστικό - η κλήση παραλείπεται, με καταγραφή σφάλματος, αν δεν υπάρχει ούτε user id ούτε anonymous id.