FirstMRRCentre d'aide
Développeurs

Apps mobiles (iOS et Android)

Un module d'un fichier, en Swift ou en Kotlin, qui envoie les ouvertures et les conversions sans identifiant publicitaire.

1 min de lecture

La requête

POSThttps://firstmrr.app/app/api/collectClé publique dans le corps (k)
ChampTypeRequisDescription
kstringObligatoireTa clé publique.
estringObligatoireL'événement : open ou screen (compté comme une visite), signup, activation, trial, payment, cancel, source, ab:exposure, ou un nom à toi.
astringObligatoireL'identifiant d'installation : un UUID aléatoire créé au premier lancement.
pstringOptionnelL'écran affiché (/home).
wnumberOptionnelLa largeur de l'écran en points (tablette à partir de 600).
v / c / inumber / string / stringOptionnelPaiement : montant, devise, identifiant de la transaction.
s / dstring / stringOptionnelRéponse d'origine et compte cité.
abobject[]OptionnelLes affectations A/B, [{ "test": "pricing_page", "variant": "b" }], 4 au plus.

La réponse est toujours 204, sans corps : ne la lis pas et ne réessaie pas. Envoie sans bloquer l'interface, 5 secondes au plus.

Le module

import UIKit

enum FirstMRR {
    private static let endpoint = URL(string: "https://firstmrr.app/app/api/collect")!
    private static let key = "pk_0123456789abcdef01234567" // your public key
    private static let defaults = UserDefaults.standard

    /// A random id created at the first launch: never the IDFA or identifierForVendor.
    static var installId: String {
        if let id = defaults.string(forKey: "firstmrr.installId") { return id }
        let id = UUID().uuidString
        defaults.set(id, forKey: "firstmrr.installId")
        return id
    }

    /// The "Audience measurement" setting of your app.
    static var enabled: Bool {
        get { !defaults.bool(forKey: "firstmrr.optOut") }
        set { defaults.set(!newValue, forKey: "firstmrr.optOut") }
    }

    static func track(_ event: String, screen: String = "/", extra: [String: Any] = [:]) {
        guard enabled else { return }
        var body: [String: Any] = ["k": key, "e": event, "a": installId, "p": screen, "w": Int(UIScreen.main.bounds.width)]
        body.merge(extra) { _, new in new }
        guard let data = try? JSONSerialization.data(withJSONObject: body) else { return }
        var request = URLRequest(url: endpoint, timeoutInterval: 5)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = data
        URLSession.shared.dataTask(with: request).resume() // fire and forget: no retry, no queue
    }
}

// FirstMRR.track("open", screen: "/home")
// FirstMRR.track("payment", extra: ["v": 9.99, "c": "USD", "i": transaction.id])

Appelle track("open") à chaque ouverture et retour au premier plan, signup, activation, trial, puis payment dans le rappel de succès de StoreKit, Google Play Billing, RevenueCat ou Superwall.

Validation Apple et Google

  • Pas d'IDFA, d'AAID, d'identifierForVendor ni d'empreinte de l'appareil : pas de fenêtre App Tracking Transparency.
  • Un réglage « Mesure d'audience », activé par défaut, qui coupe tout envoi.
  • PrivacyInfo.xcprivacy : Product Interaction et Device ID, non liés à l'identité, sans suivi, finalité Analytics ; Purchase History si tu envoies les paiements ; UserDefaults avec la raison CA92.1.

L'installation assistée de Distribution → Tracking écrit ce module pour toi et te dit quoi déclarer dans App Store Connect et Google Play.