Statistiques de ventes des Applications AppStore et
MacAppStore
Frank Lefebvre & Jacques Foucry
Cocoaheads Paris 14/03/2013
L’existantiTunesConnect : site web et application iOS
Données agrégées après 15 jours
C’est beau mais bon...
Les applications dans le cloud
Obligation de laisser un login/mot de passe
Non sérieux, le cloud...
Récupération des données
Solution fournie par Apple (même s’ils ne sont pas au courant)
Autoingestion.class
C’est une classe Java fournie par Apple
Documentation
iTunes Connect Sales and Trends Guide
Limitations
... Et si on refaisait le truc ?
Reverse engineering...
String body = "USERNAME=" + URLEncoder.encode(paramArrayOfString[0], "UTF-8");body = body + "&PASSWORD=" + URLEncoder.encode(paramArrayOfString[1], "UTF-8");body = body + "&VNDNUMBER=" + URLEncoder.encode(paramArrayOfString[2], "UTF-8");body = body + "&TYPEOFREPORT=" + URLEncoder.encode(paramArrayOfString[3], "UTF-8");body = body + "&DATETYPE=" + URLEncoder.encode(paramArrayOfString[4], "UTF-8");body = body + "&REPORTTYPE=" + URLEncoder.encode(paramArrayOfString[5], "UTF-8");body = body + "&REPORTDATE=" + URLEncoder.encode(str1, "UTF-8");
URL url = new URL("https://reportingitc.apple.com/autoingestion.tft?");HttpsURLConnection connection = url.openConnection();connection.setRequestMethod("POST");connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");connection.setDoOutput(true);OutputStreamWriter localOutputStreamWriter = new OutputStreamWriter(connection.getOutputStream());localOutputStreamWriter.write(body);localOutputStreamWriter.flush();localOutputStreamWriter.close();
...
Que nous envoie Apple ?
Daily summary avec différenciation des ventes, des mises à jour, des in-app purchases
NewsStand : abonnements et données personnelles
Données iOS et MacAppStore
Apple ne fournit que deux semaines de données
Obligation de récupérer tous les jours et de stocker localement (+backup)
Format du fichier
C’est du texte Gzippé
Tab delimited
Avec les entêtes
Attention, les dates sont au format US (mm/dd/yyyy)
Un compte spécifique
Dans iTunesConnect, il est possible de créer des comptes avec des droits restreints
Cela va faciliter l’automatisation
Et surtout sécuriser l’accès au compte
Connexion à iTC / Manage Users
Choisir le type de compte
Résumé des utilisateurs existants
Nommer l’utilisateur
Droits d’accès de l’utilisateur
Territoires d’intervention
Et boum...
Stockage
Archivage (et backup) des fichier txt.gz
une base données sqlite3
Disponible directement sous OSX
Facile à installer sur d’autres environnements
Schéma de la base
product_idapple_product_idproduct_skuiap_parent_skuproduct_namedeveloper
productdate
report_dateproduct_versiontransaction_typeunitscustomer_countrycustomer_currencypayment_currencycustomer_pricepayment_pricepromo_codesubscription_typesubscription_period
daily_summary
Le script Python
Pourquoi Python ?
Parce que pas perl !
Simple à mettre en œuvre, présent sur toutes les plateformes
Intégration sqlite3
Dépendances
Python 2.7
Dispo sans problème sur OSX, ça peut être amusant sur d’autres OS (par exemple CentOS)
Mako, pour les gabarits
Flotr2, pour le rendu
Architecture de l’application
iTunesStats
its_download.py its_import.py its_report.py
its_database.py its_format.py
Ligne de commande
iTunesStats
--download config_file [--date yyyy-mm-dd]
--download-import config_file [--date yyyy-mm-dd]
--import config_file path
--report config_file
Fichier de configuration
Trois sections :
[iTunes] : les informations nécessaires à la connection à iTunesConnect
[data] : les informations de stockage (fichiers tgz et base de données)
[report] : l’emplacement des templates et le répertoire où son stockés les rapports
Fichier de configuration, un exemple
[iTunes]username = [email protected] = Tucroyaisquejelaisseraismonmotdepassevendor = 12345678
[data]archive = /Users/jacques/its/saleshistory = /Users/jacques/its/itc-historydatabase = /Users/jacques/its/sales/itunes-stats.db
[report]templates = /Users/jacques/its/templatesoutput = /Users/jacques/its/output
Automatisation
Quelle est la meilleure heure pour lancer la récupération des stats ?
La plupart du temps, c’est 14h30 UTC
Parfois il y a des ratés (serveurs surchargés par exemple)
Et pourquoi pas toutes les heures ?
S’il n’y a rien à récupérer, on ne fait rien
Sur OSX
launchd
une plist qui décrit au daemon launchd comment lancer le script et quand
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0">! <dict>! ! <key>Label</key>! ! <string>net.correze-software.its</string>! ! <key>ProgramArguments</key>! ! <array>! ! ! <string>/usr/local/scripts/iTunesStats</string>! ! ! <string>--download-import</string>! ! ! <string>/etc/its/its-param</string>! ! </array>! ! <key>StandardOutPath</key>! ! <string>/var/log/its_download.log</string>! ! <key>StartInterval</key>! ! <integer>3600</integer>! </dict></plist>
Emplacement des fichiersFichier Launchd
à mettre dans /Library/LaunchDaemons
Fichier de paramètres
par exemple dans /etc/itc (ou /Library/Application Support/its)
Les scripts
j’aime bien mettre mes scripts dans /usr/local/scripts
Prise en compte par launchd et vérification
sudo launchctl load -w /Library/LaunchDaemons/net.correze-software.its.plist
sudo launchctl list
Sur un autre unix like (linux, *BSD, Aix, Solaris, sco...)
cron/crontab
Deux posibilités :
éditer la crontab
utiliser le répertoire /etc/cron.hourly
Éditer la crontab
$ crontab -e
25!*! *! *! *! /usr/local/scripts/iTunesStats --download-import /home/jacques/its-param 1> /dev/null 2> /var/log/its_download.log
(Lancement toutes les heures de tous les jours, tous les mois... à 25 minutes)
Utiliser /etc/cron.hourlyIl suffit de déposer dans ce répertoire un petit script shell qui lancera notre script avec les paramètres nécessaires
#!/bin/sh
if [ -x /usr/local/scripts/iTunesStats]then! /usr/local/scripts/iTunesStats --download-import /home/jacques/its-param 1> /dev/null 2>/var/log/its_download.logfi
Le rendu
Assuré par Flotr2 <http://humblesoftware.com/flotr2/>
du json
un template mako
le json
Généré par le script its_report.py (requête sur la base et écriture du résultat sous forme de json)
Le template Mako
Pour intégrer le json à du HTML++ (avec des boucles, des variables, etc)
Génére le fichier HTML
template-stats.html<html lang="fr"><head> <meta charset="utf-8" /> <title>iTunesStats</title> <script type="text/javascript" src="Flotr2/flotr2.min.js"></script> <script type="text/javascript" src="charts.js"></script> <link rel="stylesheet" type="text/css" href="style.css" media="screen"/></head><body> % for product in products: <p> <details open> <summary class="gradient-background">${product[1]}</summary> <div class="container"> <div id="piechart_${product[0]}" class="country"></div> <script type="text/javascript"> displayPieChart("piechart_${product[0]}", "country-${product[0]}.json"); </script> </div> <div class="container"> <div id="bargraph_${product[0]}" class="date"></div> <script type="text/javascript"> displayBarGraph("bargraph_${product[0]}", "date-${product[0]}.json"); </script> </div> <div class="container"> <div id="version_${product[0]}" class="version"></div> <script type="text/javascript"> displayPieChart("version_${product[0]}", "version-${product[0]}.json"); </script> </div> </details> </p> % endfor</body></html>
Flotr2
Un framework HTML
Inclure le javascript du framework
include notre propre définition des graphs que nous voulons et
HOP !
Disponible sur GitHub
https://github.com/franklefebvre/iTunesStats.git