Apfel-Appstore-Reader - Update 2.0

Wie im Artikel - Apfel-Appstore-Reader - beschrieben, hält sich Apple bezüglich der App-Rankings (Positionierung im Appstore) sehr gedeckt. Auch im Report-Tool (ITC / iTunes-Connect -> Sales & Trends) keinerlei Informationen auftauchen, an welcher Position man sich mit der jeweiligen App in z.B. einer Kategorie wie “Produktivität” befindet, habe ich vor längerer Zeit ein kleines Java-Tool (mit dem einfallsreichen Namen Appstore-Reader) geschrieben.

Die nakten Zahlen des Tools sind ganz nett, aber leider wenig aussagekräftig... Zum Einen variiert das App-Ranking über den Tag teils erheblich, zum Anderen hat man wohl kaum lust das Tool ständig aufzurufen, um sich die Werte dann irgendwo aufzuschreiben. Eine Datenbank-Anbindung an MySQL sowie lokal an eine SQLite-DB hatte ich zwar realisiert, um mal eine Durchschnittsposition über den Monat hinweg zu errechnen, aber optimal und zufriedenstellend war das Ganze immer noch nicht.

Überlegungen zur Optimierung des Store-Readers

  • Auslagerung des Java-Tools vom lokalen Heim-Rechner auf einen Server im Internet.
  • Das Tool sollte selbstständig z.B. einmal pro Stunde gesteuert über einen Cron-Job alle Kategorien des Appstores durchsuchen und die Rankings der gewünschten Apps speichern.
  • Es muss eine Schnittstelle her, um aus den erfassten Daten eine grafische Übersicht zu zaubern. Tages- und Monatsübersicht -> zu welchen Zeiten finden die meisten Verkäufe/Downloads statt bzw. ist das App-Ranking am höchsten?!

Die Umsetzung - Java, PHP und JPGraph

appstore_reader_2_previewAusgangssituation ist der Apfel-Appstore-Reader. Lediglich die statischen Arrays wie die Länderkürzel, Appstore-Genres und die Links zum Appstore-RSS-Generator habe ich in die neue MySQL-Datenbank ausgelagert um etwas flexibler zusein, grade was das spätere Auswerten der Daten angeht. Aus dem Java-Code braucht man dann nurnoch ein Jar-File erstellen, auf den Server laden und einen Cron einrichten. Ich habe mich für einen stündlichen Cronjob entschieden, so soll man später Stundenweise sehen wie sich das App-Ranking verhält.

Auszug aus der Crontab - 10 Minuten nach jeder vollen Stunde von 9 bis 23 Uhr:
10 9-23 * * * root java -jar /var/www/myweb/httpdocs/java/sync.jar > /dev/null

Die Software speichert nun stündlich anhand der App-ID den aktuellen App-Rang und folgende Informationen. Felder: app_id, datum, uhrzeit, kategorie_id (ID des Appstore-Genres, z.B. 6002 für Dienstprogramme), store_kategorie_id (eindeutige Kennung, z.B. 1 = Top Apps Kostenlos, 2 = Top Apps iPad, 3 = Top Apps Umsatzstark, usw....), rank (Position der App im Store), store_lang (Appstore, z.B. de für Deutschland).

Jetzt wird es Zeit die Daten in Form zubringen. :) Ich habe mich für die OpenSource-Lösung JPGraph entschieden, um die erfassten App-Ranking-Daten visuell aufzubereiten. Mit diesem PHP-Framework kann man schnell tolle Grafiken erstellen. JPGraph ist sehr mächtig und verfügt über unzählige Anpassungsmöglichkeiten, daher gehe ich hier nur auf einige Basics ein. ;-)

Zunächst holt man sich die Library per include bzw. require in seine PHP-Funktion.
require_once ($jpgraph_path.'/src/jpgraph.php');
require_once ($jpgraph_path.'/src/jpgraph_line.php');

Jetzt erstellt man den Graphen, im Beispiel soll die Grafik 800x500 Pixel groß werden, und anhand einer Kurve den Ranking-Verlauf über den Tag hinweg zeigen. Eine Legende unter der Grafik soll helfen das gezeigte auch zu verstehen.

$graph = new Graph(800,500);
$graph->legend->Pos(0.00,0.5,"center","bottom");
$graph->legend->SetLayout(LEGEND_HOR);
$graph->legend->SetFont(FF_FONT1, FS_NORMAL);
$graph->SetScale("textlin");
$graph->SetAxisStyle(AXSTYLE_BOXOUT);

Nun fügen wir ein bischen Margin, also freie Fläche rund um die Grafik ein, damit das Ganze nicht ganz so gedrückt aussieht. Dann fügen wir eine Überschrift (Ranking + App-Name) über das Diagramm ein, und etwas kleiner darunter das Datum der gezeigten Daten inkl. Appstore-Kategorie und Land/Sprache des Stores. Dann noch die Beschriftung für die X- und Y-Achse.

$graph->img->SetMargin(70,70,80,30);

$graph->title->Set("Ranking - ".$app_name);
$graph->title->SetFont(FF_FONT1,FS_BOLD);
       
$graph->subtitle->Set($this->getDateLongFromSqlDate($sqldate)." - ".$kategorie_name." / ".$lang);
$graph->subtitle->SetFont(FF_FONT1,FS_NORMAL);

$graph->yaxis->SetTitle("Rang");
$graph->xaxis->SetTitle("Uhrzeit");

An dieser Stelle laden wir die erfassten Daten in ein Array, woraus dann die entsprechenden Kurven erstellt werden. $dataLabels enthält die Punkte auf der X-Achse (Uhrzeiten: 8 bis 22 Uhr). $datay ist ein mehrdimensionales Array und behinhaltet alle Y-Daten (App-Store-Positionen zur entsprechenden Uhrzeit). Da in meinem Fall bis zu 6 Store-Sektionen angezeigt werden sollen (Top-Apps, Top-Apps iPad, usw...) speichere ich die IDs und Namen in separaten Arrays ($stores und $store_kategorie_ids). Die Daten aus Sektion 0 (z.B. Top-Apps mit ID 1) werden dann in $datay[0] gespeichert, Sektion 1 in $datay[1] etc... Auf den ersten Blick etwas wirsch, auf den Zweiten sehr logisch und schön wie ich finde. ;-)

$dataLabels = array();
$count = 0;
       
for ($i=8; $i<=22; $i++)
{
               for ($s=0; $s<$store_count; $s++)
               {
                   $q = "SELECT rank FROM ".TABLE_APPS_RANKING." WHERE app_id='".$id."'"
                    ." AND store_kategorie_id='".$store_kategorie_ids[$s]."' AND store_lang='".$lang."'"
                       ." AND kategorie_id='".$kategorie_id."'"
                       ." AND datum='".$sqldate." ".$i.":00:00'";
                   $res = $this->query($q);
                                                                       
                   if ($data = mysql_fetch_assoc($res))
                   {
                       if (!$has_data)
                           $has_data = true;
                   }
                   else
                   {
                       $data = array();
                       $data['rank'] = '';
                   }
                   $datay[$s][$count] = $data['rank'];
               }
       
               $dataLabels[$count] = $i.":00";
               $count++;
}
$graph->xaxis->SetTickLabels($dataLabels);

Damit der bessere Rang oben steht und nicht unten müssen wir noch die Y-Achse spiegeln. Das funktioniert ganz einfach indem wir die Y-Werte ins Negative bringen.

for ($s=0; $s<$store_count; $s++)
{
    $n = count($datay[$s]);
    for($i=0; $i<$n; ++$i)
    {
         if ($datay[$s][$i]!="")
                $datay[$s][$i] = round(-$datay[$s][$i]);
    }
}

if (!function_exists("_cb_negate"))
{
     function _cb_negate($aVal)
    {  return round(-$aVal);  }
}

$graph->yaxis->SetLabelFormatCallback("_cb_negate");

Abschließend werden noch die entsprechenden Kurven (LinePlot) mit Hilfe der Y-Daten erstellt und in den Graphen geladen. Ein kleines Array namens $colors mit Farbwerten hilft, die einzelnen Linien zu unterscheiden. ->setLegend(titel) darf nicht fehlen, um die Beschreibung dieser der Legende hinzuzufügen. Alle anderen Aufrufe wurden aufs wesentliche runtergebrochen und sollten selbsterklärend sein. :-)

$colors = array("#00FF00", "#0000FF", "#FF0000", "#00FFFF", "#FFFF00", "#FF00FF");
for ($i=0; $i<$store_count; $i++)
{
               $p1 = new LinePlot($datay[$i]);
               $graph->Add($p1);
                                                       
               $p1->SetLegend($stores[$i]);
                                                       
               $p1->mark->SetType(MARK_SQUARE, 1.0);
               $p1->mark->SetWidth(3);
               $p1->mark->SetFillColor($colors[$i]);
                                                  
               $p1->SetColor($colors[$i]);
               $p1->SetWeight(2);                                                                             
               $p1->SetStepStyle(true);
}

Jetzt noch $graph->Stroke() aufrufen, um die Grafik zu erstellen. Als Parameter wird der Pfad übergeben, wohin die Datei gespeichert werden soll. Alternativ kann man die Funktion Stroke() auch ohne Parameter aufrufen, was zur Folge hat, dass die Grafik direkt zurückgeben wird. Funktioniert auch wenn man das PHP-Script einzig zum Generieren nutzt und die Grafik mit z.B.  <img src="meinscript.php"> aufrufen will.

Grafik als Datei speichern: $saveas z.B. ./images/grafik.png
$graph->Stroke($saveas);

Das Resultat - Apfel-Appstore-Reader 2.0

Das Resultat ist eine kleine ansehnliche Grafik des App-Rankings der jeweiligen App.

appstore_reader_2_screen

Passt man das Script hier und da etwas an, kann man ganz einfach auch mehrere Apps mit einander vergleichen, oder Monats- und Jahresübersichten visualisieren.

Grafiken / Reports automatisiert per E-Mail verschicken

Kaum jemand hat lust sich jeden Tag in sein Backoffice einzuloggen um einzelnt die Reports durchzuklicken. Daher hier noch kurz ein Beispiel für den Mailversand der Grafiken bzw. Berichte. Mit Hilfe von PHP und eines Crons am morgen kein Problem! Alles was wir brauchen ist eine Funktion der wir die E-Mail-Adresse des Empfängers, einen Betreff, eine Nachricht und ein Array mit den Pfaden zu den erstellten Reports (PNG-Files). Das Script sollte selbsterklärend sein.:)

function sendMailWithAttachment($email, $subject, $msg, $files=array())
   {
           $nl = "\r\n";
           
           $header = "From: ".ADMIN_EMAIL;
           $boundary = strtoupper(md5(uniqid(time())));
       
           $header .= "\nMIME-Version: 1.0";
           $header .= "\nContent-type: multipart/mixed; boundary=".$boundary;
           $header .= "\n\nThis is a multi-part message in MIME format  --  Dies ist eine mehrteilige Nachricht im MIME-Format";
       
           /* mail-inhalt */
           $header .= $nl."--".$boundary;
           $header .= $nl."Content-type: text/html";
           $header .= $nl."Content-Transfer-Encoding: 8bit";
           $header .= $nl.$nl.$msg;
       
           /* anhänge anfügen */
           for ($i=0; $i<count($files); $i++)
           {
               $file = $files[$i];
           
               if (file_exists($file))
               {
                   $inhalt = $this->read_file($file);
                   
                   //nur png-files unterstützt; ggf. noch content-types einfügen; jpg, gif, pdf, etc...
                   $filename = "anhang".($i+1).".png";
                   
                   $header .= $nl."--".$boundary;
                   $header .= $nl."Content-type: images/png; name=\"".$filename."\"";
                   $header .= $nl."Content-Transfer-Encoding: base64";
                   $header .= $nl."Content-Disposition: attachment; filename=\"".$filename."\"";
                   $header .= $nl.$nl.$inhalt;
               }
           }
           
//ende der mail
$header .= $nl."--".$boundary."--";
           
//senden
mail($email, $subject, "", $header);

Schlusswort

Interessant was man so über die eigene App und Zielgruppe erfährt. Eine der Überlegungen wäre, wenn die meisten Downloads der App z.B. zwischen 19 und 21 Uhr gefahren werden, könnte man seine Facebook-Werbekampagnen genau auf diese Stoßzeiten legen, um das Ranking noch weiter in die Höhe zu treiben, anstatt plätscherweise sein Budget über den Tag zu verschleudern. ;-) *Nur ein Gedanke*

Hoffe das Lesen hat Spaß gemacht, Feedback und Anregungen erwünscht! :-)

Zuletzt bearbeitet: 19. April, 2016
Tags: , , , , , , , , ,

Verwandte Beiträge

Streams und Apps um Radio zu hören

Der Empfang von deutschen oder auch ausländischen Rundfunkstationen ist kein Problem mit der passenden App. Auch Empfangsprobleme gehören so der Vergangenheit an. Inzwischen werden die meisten Sender auch über das Internet digital ausgestrahlt, sodass man nicht zwangsläufig auf ein Radio als Empfangsgerät angewiesen ist. Wer dennoch auf sein herkömmliches Radio nicht verzichten möchte, für den [...] Weiterlesen »


Kleine Helfer für den erfolgreichen Börsenhandel

BÖRSE ONLINE ist das etablierteste unabhängige Anlegermagazin in Deutschland. Seit mehr als 25 Jahren hilft es Anlegern Woche für Woche bei ihren Anlageentscheidungen. BÖRSE ONLINE richtet sich gleichermaßen an institutionelle Leser in Banken, Versicherungen, Vermögensverwaltungen und Kapitalanlagegesellschaften sowie an selbstentscheidende, kapitalmarktaffine Privatanleger. • Informiert schwerpunktmäßig über deutsche und internationale Aktien. • Fokussiert die Berichterstattung auf [...] Weiterlesen »


Safari Abenteuer: Wir entdecken Afrika - Brettspiel für Kinder

Safari Abenteuer: Wir entdecken Afrika - Brettspiel für Kinder, Schüler, Familie - von Kindermatica Ltd. Bring Familie und Freunde mit dem Safari-Rätselspiel zusammen! In diesem kinderfreundlichen Brettspiel für mehrere Spieler wirst du die Bewohner der heißen Savanne kennen lernen und erstaunliche Abenteuer in Afrika erleben! Du könntest einen Löwen treffen, dich Regenschauern schützen, eine Brücke [...] Weiterlesen »


Der Apfel-Appstore-Reader

Aufgrund der Tatsache das Apple sich bezüglich der App-Rankings (Positionierung im Appstore) sehr gedeckt hält, und auch im Report-Tool (ITC / iTunes-Connect -> Sales & Trends) keinerlei Informationen auftauchen, an welcher Position man sich mit der jeweiligen App in z.B. einer Kategorie wie "Dienstprogramme" befindet, habe ich ein kleines Java-Tool (mit dem einfallsreichen Name Appstore-Reader) [...] Weiterlesen »


KING OF KARTS 3D

Mach dich bereit, auf die Plätze, LOS! King of Karts ist ein faszinierendes 3D-Rennspiel! Besiege deine Freunde auf 8 Strecken. 3 unterschiedliche Spielmodi warten auf dich, wobei auch Mehrspieler-Partien mit bis zu 6 Geräten möglich sind. Sammle Power-Up-Items, entdecke Abkürzungen und verborgene Wege, benutze Boostfelder und Sprungschanzen und wage riskante Stunts und Drifts. King of [...] Weiterlesen »