I'm a Web-Developer, App-Developer, Mobile-Developer, Java-Developer, node.js Newbie, Scala Newbie, very interested in NoSQL, Espresso-Junkie, an optimist.
Don't wanna be here? Send us removal request.
Photo

Frühjahrsputz bei meiner PS3, nach all den Jahren intensiven spielens hatte es der Controller mehr als nötig... #Playstation #frühjahrsputz #gaming #putzen (hier: Bochum, Germany) https://www.instagram.com/p/BPOBjTLhdZ8/?utm_source=ig_tumblr_share&igshid=1jqeklq6d741m
0 notes
Link
Gerade bei der Android Entwicklung kommt es häufiger vor, dass man bei der Implementierung einer Klasse leere Methodenrümpfe übrig bleiben.
Beispielsweise wenn wir einen SQLiteOpenHelper für eine neue App schreibt bleibt die onUpgrade Methode meistens erst einmal leer, bzw. wird mit einer Alibi-Log Meldung gefüllt.
public class DbHelper extends SQLiteOpenHelper { @Override public void onCreate(SQLiteDatabase db) { //Datenbank initialisieren [...] } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.d("DbHelper", "Hier ist nix zu sehen"); } }
Wenn wir nun unsere Tests schreiben, würden wir natürlich die onCreate Methode testen um sicherzustellen, dass unsere Datenbank-Initialisierung wie geplant funktioniert. Doch was machen wir mit der onUpgrade Methode? Einfach nicht testen weil ja (noch) kein Code zum Testen da ist? Oder einfach eine Testmethode schreiben die nichts testet, als Platzhalter für später?
Beide Varianten sind nicht ideal, denn in beiden bemerken wir (oder einer unserer Teamkollegen) nicht wenn Code in die Methode eingefügt, zumindest nicht in unseren Testfällen. Doch es gibt noch eine 3. Möglichkeit: Wir testen das eben nichts in der Methode passiert.
Mit Mockito rufen wir die Methode mit einem gemockten Datenbank auf und prüfen danach mit verifyZeroInteractions, dass die Methode wirklich nichts (relevantes) tut.
@Test public void testOnUpgrade() throws Exception { SQLiteDatabase db = mock(SQLiteDatabase.class); dbHelper.onUpgradedb; verifyZeroInteractions(db); }
Wenn wir oder ein Kollege nun die onUpgrade Methode ändern und Upgrade Logik implementieren wird der Test fehlschlagen und uns daran erinnern auch den Testfall anzupassen.
0 notes
Link
Gerade noch pünktlich, wie angekündigt, in KW 33 der erste Blogpost aus der Reihe “iOS Apps mit Maven bauen”
Generell gibt es bei Maven 2 Möglichkeiten ein neues Projekt zu erstellen: per Hand oder via archetype:generate. Das Maven Plugin für iOS bringt auch eigene (leicht angestaubte) Archetypes mit. Für die Arbeit in einem Unternehmen ist es immer sinnvoll Archetypes zu verwenden, um eine einheitliche Basis für alle Projekte zu haben. Trotzdem möchte ich hier einmal den manuellen Weg zeigen.
Wichtiger Hinweis: auch wenn Maven für alle Betriebssysteme verfügbar ist, läuft der iOS Build natürlich nur auf einem Mac, da nur hier die zusätzlich benötigen Commandline-Tools verfügbar sind.
Schritt 1: Xcode Commandline-Tools installieren
Für den Build mit Maven sind die Xcode Commandline Tools unbedingt erforderlich. Eine Anleitung für die Installation der Commandline Tools findet sich z.B. auf docwiki.embarcadero.com
Schritt 2: Projektordner erstellen
Der Aufbau des Projektordners ist sehr simpel: wir brauchen lediglich einen Unterordner für unser Xcode Projekt. Nach Maven Konvention liegen alle Dateien des Hauptprojektes unter “src/main”. Für unser iOS Projekt legen wir deshalb die Ordnerstruktur “src/main/ios” an.
Schritt 3: pom.xml erstellen
Nun kommt das Herzstück eine Maven Projektes: die pom.xml. In der pom.xml werden alle für das Build erforderlichen Konfigurationen zentral gepflegt. Die pom.xml muss im Root-Verzeichnis des Projektes liegen.
Die ersten Informationen, die wir in die pom.xml eintragen sind: groupId, artifactId und version.
Die groupId ist meistens die umgekehrte Domain, ähnlich wie bei einem Java Package. Je nach Vorliebe/Vorgabe noch ergänzt um weitere Elemente. Für thoughtsonmobile.com wäre die groupId also com.thoughtsonmobile
Ich ergänze generell noch gerne die Plattform in der groupId. Deshalb lautet die groupId: “com.thoughtsonmobile.ios”
Als nächstes die artifactId. Die artifactId ist der eigentliche Projektname. Hier stoßen das erste Mal Maven und Xcode/iOS Konventionen aufeinander: Während Maven auf lowercase und Bindestriche setzt, ist man bei Xcode eher CamelCase Projektnamen gewohnt. Für welche Konvention man sich am Ende entscheidet ist natürlich völlig egal. Ich persönlich habe mich für die Maven-Variante entschieden um auch in meinem Maven Repository einheitlich mit den anderen Projekten zu sein. Die artifactId und der spätere Projektname des Xcode Projekts müssen identisch sein. Für dieses Beispiel soll unsere artifactId “maven-test”
Die Version ist erst einmal völlig egal. Das einzig Wichtige ist, dass sie mit “-SNAPSHOT” endet. Dabei handelt es sich um ein Schlüsselwort von Maven, dass anzeigt, dass es sich bei der Version um eine Entwicklungsversion und nicht um eine Release-Version handelt. Detailliertere Informationen hierzu wird es in einem der nachfolgendes Blogposts geben.
Unsere pom.xml sieht nach den oben beschriebenen Punkten wie folgt aus:
<project xmlns="http://ift.tt/13J5Aq9; xmlns:xsi="http://ift.tt/Atvu06; xsi:schemaLocation="http://ift.tt/IH78KX http://ift.tt/19Bz6pF; <modelVersion>4.0.0</modelVersion> <groupId>com.thoughtsonmobile.ios</groupId> <artifactId>maven-test</artifactId> <version>1.0-SNAPSHOT</version> </project>
Nun müssen wir das iOS-Plugin ergänzen und konfigurieren. Außerdem müssen wir das “packaging” des Projektes, sprich die Auslieferungsform, auf “ipa” ändern.
Das Plugin ist derzeit nicht über Maven-Central erreichbar, deshalb müssen wir es von GitHub herunterladen (http://ift.tt/1A2Z12B) und anschließend mit mvn install in unser lokales Repository einspielen. Das Plugin wird gepflegt von LetsDev.
Danach können wir es einbinden und konfigurieren. Die fertige pom.xml sieht dann wie folgt aus:
<?xml version="1.0"?> <project xmlns="http://ift.tt/13J5Aq9; xmlns:xsi="http://ift.tt/Atvu06; xsi:schemaLocation="http://ift.tt/IH78KX http://ift.tt/19Bz6pF; <modelVersion>4.0.0</modelVersion> <groupId>com.thoughtsonmobile.ios</groupId> <artifactId>maven-test</artifactId> <version>1.0-SNAPSHOT</version> <name>Maven+iOS Example Project</name> <packaging>ipa</packaging> <build> <plugins> <plugin> <groupId>de.letsdev.maven.plugins</groupId> <artifactId>maven-ios-plugin</artifactId> <version>1.6-SNAPSHOT</version> <extensions>true</extensions> <configuration> <sourceDir>src/main/ios</sourceDir> <!-- replace with your own identity --> <codeSignIdentity>iPhone Developer: Leif Janzik</codeSignIdentity> <appName>${project.artifactId}</appName> <bundleIdentifier>com.thoughtsonmobile.${PRODUCT_NAME:rfc1034identifier}</bundleIdentifier> <displayName>TOM Maven</displayName> </configuration> </plugin> </plugins> </build> </project>
Wichtig ist natürlich die eigene Identity einzutragen.
Schritt 5: Xcode Projekt erstellen
Dieser Schritt ist mit der einfachste, einfach wie gewohnt ein Projekt in Xcode erstellen. Als Pfad wählen wir den Ordner iOS in unserem Testprojekt. Der Name des Projektes ist “maven-test”.
Schritt 6: Das Projekt bauen
Ist das Projekt erstellt, können wir ein erstes Build mit unserer Maven Konfiguration erstellen. Dazu einfach mvn package in der Kommandozeile aufrufen. Wenn alles richtig konfiguriert wurde, endet das Build nach einiger Zeit mit der Meldung: “[INFO] BUILD SUCCESS”. Danach finden wir in dem Ordner “target/” eine IPA Datei die wir auf unseren Testgeräten installieren können.
Parallel dazu können wir das Projekt natürlich noch uneingeschränkt mit Xcode bauen und debuggen.
Damit haben wir den ersten Teil abgeschlossen. Wir haben ein Xcode Projekt, dass wir mit Maven bauen können. Bisher stellt sich die Frage inwiefern das eine Verbesserung gegenüber dem Normalfall darstellt. Wie ich in meinem vorherigen Blogpost beschrieben habe, gibt es zu diesem Zeitpunkt noch keinen Vorteil. Die Vorteile von Maven werden erst in den nachfolgenden Artikeln deutlich, wenn es um die weiterführenden Möglichkeiten von Maven geht.
Der Sourcecode der gesamten Blogserie ist auf GitHub verfügbar: http://ift.tt/1A2YZrj
Teil 0: Muss das sein?
Teil 1: Aufsetzen eines iOS Projektes mit Maven
0 notes
Link
AspectJ führt seit Jahren ein Leben in der 2. Reihe. Viele Enterprise Frameworks wie z.B. das Spring Framework nutzen Aspekte bzw. Aspekt-Orientierte-Programmierung (AOP) exzessiv im Bereich Injection oder Transaktionen. Abseits von grossen Frameworks ist die Verwendung von Aspekten deutlich seltener zu finden.
In diesem Blogpost möchte ich aufzeigen wieviel einfacher AOP die Entwicklung für Android machen kann und welche Tücken und Fallstricke es gibt.
Was ist Aspektorientierte Programmierung?
In Frameworks wie Spring wird vor allem Load-Time-Weaving eingesetzt, d.h. die Aspekte werden zur Laufzeit bzw. beim Start der Applikation in die bestehenden Klassen “eingewebt”. Load-Time-Weaving kommt für Android Applikationen jedoch auf Grund der Dalvik VM nicht in Frage. Ausserdem würde diese Variante selbst wenn sie technisch möglich wäre die App deutlich verlangsamen. Doch AspectJ bringt noch eine weitere Weaving-Art aus seinen Anfangstagen mit: Build-Time-Weaving. Hier werden die Aspekte bereits vor dem Kompilieren (und dexen) mit den Klassen verwoben. Hier ist auch die Performance Problematik so gut wie nicht existent, da im Grunde Code eingewoben wird, den wir sonst per Hand eingebaut hätten.
Beispiel 1: Logging & Tracking
Das beliebteste Beispiel für den Einsatz von AspectJ ist “Logging” und “Tracking” im ersten Beispiel möchte ich also zeigen wie man mit einem 2 simplen PointCuts Activities automatisch loggen & tracken kann.
/** * log before an activity is created * * @param joinPoint aspectj JoinPoint */ @Before("execution(* android.app.Activity.onCreate())") public void logActivityCreated(final JoinPoint joinPoint) { Log.d(TAG, "Creating Activity: " + joinPoint.getTarget().getClass().getSimpleName()); } /** * track after an activity is created * * @param joinPoint aspectj JoinPoint */ @After("execution(* android.app.Activity.onCreate())") public void trackActivityCreated(final JoinPoint joinPoint) { Activity activity = (Activity) joinPoint.getTarget(); EasyTracker.getInstance(activity).activityStart(activity); }
Das Logging-Beispiel zeigt recht gut wie ApectJ funktioniert, aber gleichzeitig ist es eigentlich zu simpel um die vollen Möglichkeiten von AOP aufzuzeigen. Etwas interessanter wird es hoffentlich beim nächsten Beispiel:
Beispiel 2: Layout & View-Injection
Ein weiterer recht nützlicher Anwendungsfall für AOP ist das injizieren von Views und Layouts. Der Boilerplate-Code der anfällt wenn um Layout und Views mit einer Android Activity oder einem Fragment zu verknüpfen ist enorm. Eine nach “Clean Code” Gesichtspunkten entwickelte Activity ist (mit Bordmitteln) nahezu ein Ding der Unmöglichkeit. Unlängst bieten Frameworks wie Roboject oder Robojuice die Möglichkeit Views mit Hilfe von Annotations dem jeweiligen Framework zu injizieren. Dies geschiet jedoch zur Laufzeit und erfordert z.B. bei Roboject, dass alle Activities von einer Roboject Klasse erben müssen. Das ist nicht nur lästig sondern macht es auch nahezu unmöglich z.B. Frameworks wie ActionBarSherlock einzusetzen.
Mit AspectJ ist es sehr einfach z.B. das Layout einer Activity mit einer Annotation zu definieren:
Zuerst definieren wir das Layout mit der Annotation @Layout für unsere Activity
@Layout(R.layout.dashboard) public class DashboardActivity extends Activity { [..] }
und danach definieren wir einen PointCut für die onCreate Methode aller Klassen die von android.app.Activity abstammen und die mit @Layout annotiert wurden (Zeile 4). Im Advise schließlich müssen wir nur noch die setContentView-Methode mit dem Wert der Annotation aufrufen:
@Aspect public class ActivityInjectionAspect { @Before("execution(* android.app.Activity.onCreate(..)) && within(@com.thoughtsonmobile.example.aspectj.Layout *)") public void beforeOnCreate(JoinPoint joinPoint) { Activity activity = (Activity)joinPoint.getTarget(); Layout layout = activity.getClass().getAnnotation(Layout.class); activity.setContentView(layout.value()); } }
Dieses Beispiel zeigt schon etwas deutlicher wie sehr AspectJ unsere Art Android zu programmieren verändern könnte.
Fallstricke bei der Verwendung von AspectJ
Vererbung
Funktionen, die mit einem JoinPoint versehen werde müssen (auch) in der entsprechenden Klasse implementiert sein. Wenn die Methode von der Elternklasse geerbt wird, die aber z.B. eine Android Klasse ist, kann AspectJ (beim Build-Time-Weaving) die entsprechende Klasse nicht anpassen. Hier wäre wieder eine gemeinsame Elternklasse erforderlich, was aber auf der anderen Seite wieder zu Schwierigkeiten mit anderen Frameworks führen kann.
IDEs und Fehlersuche
Ein zu Recht angeführter Nachteil von AOP ist, dass der Sourcecode durch die größere Fragmentierung schwerer nach zu vollziehen ist. Dieser Nachteil wird durch eine gute Unterstützung seitens der IDE fast vollständig eliminiert. Für Eclipse gibt es ein sehr gutes kostenloses Plugin für IntelliJ ist das Plugin nur im Rahmen der kostenpflichtigen Version verfügbar. Für Android Studio gibt es also aktuell keine Unterstützung für AOP.
Zusammenfassung
Mit AspectJ und AOP können wir nicht nur für bessere Lesbarkeit unseres Codes und die Reduktion des Codes auf das wesentliche sorgen, wir können außerdem auch Dinge wie Injection ohne großen Performance-Verlust realisieren. AspectJ ist eine ausgereifte und erprobte Technologie, die ohne weiteres in unseren Android Applikationen zum Einsatz kommen kann.
Mini-Glossar
Aspect/Aspekt
Aspekte implementieren sogenannte Crosscutting Concerns, was übersetzt soviel wie Querschnittsfunktionalitäten heisst. Damit ist eine generelle Funktion wie Logging, Authentifizierung etc. gemeint.
Point Cut
Als Point Cut wird eine Menge von Join Points (deutsch: Verwebungspunkte) bezeichnet. Diese Menge kann leer sein oder einen, mehrere oder alle Join Points enthalten.
Join Point
Mit Join Point wird die Stelle innerhalb einer Software bezeichnet, an denen sich der AspectJ-Code in den Programmfluss einklinken soll. Join Points können Ausführungen von Methoden sein, die Ausführung sowie der Aufruf eines Konstruktors oder die Referenz auf Datenstrukturen (Variablen).
Advice
Dies ist ein spezifischer Begriff von AspectJ und definiert, was zu welchem Zeitpunkt an den Join Points eines Point Cuts umgesetzt wird. Advices bestehen aus ganz normalem Java Programmcode. Für den Zeitpunkt des Einfügens/Ausführens des AspectJ-Codes können festgelegt werden: before, after und around. Mit around kann die entsprechende Methode ggf. sogar komplett ersetzt werden.
Aspektorientierte Programmierung/AOP
Zurück nach oben
0 notes
Link
Der erste Gedanke als ich vor mehreren Monaten das erste Mal über das Maven Plugin für Xcode gestolpert bin war: “Oh mein Gott! Was für ein Mist! Warum muss man ein Tool aus der Java-Welt für iOS nehmen? ”
Im Bezug auf das reine Bauen von IPA Dateien hat sich meine Meinung auch nicht wirklich verändert. Es ist unnötig und es bietet keinen Mehrwert.
Auf der anderen Seite bin ich bei der Android-Entwicklung ein glühender Verfechter von Maven. Denn Maven ist kein reines Build-Tool sondern ein Build- und Konfigurations-MANAGEMENT-Tool. Neben dem reinen Bauen, ist da natürlich als erstes das Dependency-Management, dass jemandem in den Sinn kommt, der Maven kennt. Lösungen wie CocoaPods bieten zwar einen interessanten Ansatz um Abgängigkeiten in Xcode-Projekten zu verwalten und aufzulösen, aber es bleibt dabei nur ein weiteres Tool.
Ganz Mau sieht es aus wenn man nach automatisierbaren Reporting-Lösungen oder Release-Unterstützung schaut.
Bei unseren Android-Projekten werden alle Plugin- und Bibliotheksversionen und wiederkehrende Konfigurationen in einem gemeinsamen Elternprojekt gesammelt und verwaltet. Der Gesamte Build- und Release-Prozess kann so mit wenigen Ausnahmen komplett zentral verwaltet werden.
Das war der Punkt an dem ich wieder an das Xcode-Plugin für Maven denken musste. Die Idee auch bei iOS Maven einzusetzen wurde immer attraktiver. Denn eine eigene (automatisierbare) Build-Management-Lösung für iOS Applikationen die zum einen all das oben Beschriebene abdeckt und gleichzeitig mit Xcode zusammen funktioniert ist meines Wissens für iOS nicht in Sicht.
Daher starte ich hier nun die Serie “iOS Apps mit Maven bauen”:
Teil 0: Muss das sein?
Teil 1: Aufsetzen eines iOS Projektes mit Maven
Teil 2: Eine Library erstellen und einbinden (KW 34)
Teil 3: Konfigurieren eines Release-Prozesses (KW 35)
Teil 4: Reports für Dokumentation und Statische Code-Analyse (KW 36)
Teil 5: CocoaPods Libaries auf Maven migrieren (KW 37)
0 notes
Link
Es kommt sehr oft vor, dass wir für verschiedene Umgebungen z.B. unterschiedliche Backend-URLs konfigurieren möchten. Für diesen Zweck habe ich in meiner täglichen Arbeit diverse Lösungsansätze gesehen, die aber größtenteils entweder manuelle Änderungen am Sourcecode oder das Umkopieren von Konfigurationsdateien erforderten.
Die nächste Version des Maven Plugins für Maven bringt eine weitere (und wesentlich praktischere) Möglichkeit mit sich: eigene Konstanten in der BuildConfig Klasse definieren. Aktuell muss man allerdings wenn man diese neue Funktion nutzen will den aktuellen Snapshot (3.6.1-SNAPSHOT) verwenden.
Da die Konstanten nicht direkt im Sourcecode sondern in der pom.xml konfiguriert werden ist es möglich über verschiedene Profile die Werte neu zu definieren.
In unserem Beispiel wollen wir einfach die Backend URL für Development und Production unterschiedlich konfigurieren. Die meisten Builds werden wohl gegen das Development Backend gebaut werden, deshalb ist die Development URL der Default Wert. Für Production erstellen wir ein neues Profil: "Production". Außerdem sorgen wir dafür, dass bei einem Release ebenfalls das "Production" Profile verwendet wird.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://ift.tt/13J5Aq9; xmlns:xsi="http://ift.tt/Atvu06; xsi:schemaLocation="http://ift.tt/IH78KX http://ift.tt/19Bz6pF; [..] <build> <plugins> <plugin> <groupId>com.jayway.maven.plugins.android.generation2</groupId> <artifactId>android-maven-plugin</artifactId> <version>3.6.1-SNAPSHOT</version> <extensions>true</extensions> <configuration> <buildConfigConstants> <constant> <name>BACKEND_URL</name> <type>java.lang.String</type> <value>http://ift.tt/1m3YAB1; </constant> </buildConfigConstants> </configuration> </plugin> </plugins> </build> <profiles> <profile> <id>production</id> <build> <plugins> <plugin> <groupId>com.jayway.maven.plugins.android.generation2</groupId> <artifactId>android-maven-plugin</artifactId> <extensions>true</extensions> <configuration> <buildConfigConstants> <constant> <name>BACKEND_URL</name> <type>java.lang.String</type> <value>http://ift.tt/1m3YAB3; </constant> </buildConfigConstants> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project>
Wenn wir nun einfach mvn install aufrufen sieht die generierte BuildConfig wie folgt aus:
public final class BuildConfig { public final static boolean DEBUG = true; public final static String BACKEND_URL = "http://ift.tt/1m3YABe;; }
Wenn wir aber das Projekt mit dem "production" Profil bauen ändert sich die BuildConfig
public final class BuildConfig { public final static boolean DEBUG = true; public final static String BACKEND_URL = "http://ift.tt/1wM0fSq;; }
Das Plugin erlaubt natürlich auch eigene oder komplexe Klassen als Konstanten zu verwenden.
<buildConfigConstants> <constant> <name>CONFIGURATION_ENUM</name> <type>my.package.MyEnum</type> <value>my.package.MyEnum.CONFIG</value> </constant> </buildConfigConstants>
Und das war’s auch schon. Mit wenigen Aufwand können wir so sowohl manuelle Anpassungen überflüssig machen als auch alle Informationen an einer Stelle zusammenführen und verwalten.
0 notes
Link
In almost every project, we need to configure something for different environments, e.g. different backend URLs. To that problem, I have seen various attempts at a solution to this problem, which, however, primarily required manual changes to the source code or copying and renaming of configuration files.
The next version of the Maven plugin for Android is offering an additional (and much more practical) option: defining of own constants in the BuildConfig class. You have to use the current snapshot (3.6.1-SNAPSHOT) at the moment in order to use this new function.
Since these constants are not configured in the source code directly, but rather in pom.xml, it is possible to redefine the values through various build profiles.
In our example, we simply want to configure the backend URL for development and production differently. Most builds will be built against the development backend, therefore, the development URL is the default value. We create a new profile for production called “production”. In addition to that, we assure that the “production” profile is also used for a release.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://ift.tt/13J5Aq9; xmlns:xsi="http://ift.tt/Atvu06; xsi:schemaLocation="http://ift.tt/IH78KX http://ift.tt/19Bz6pF; [..] <build> <plugins> <plugin> <groupId>com.jayway.maven.plugins.android.generation2</groupId> <artifactId>android-maven-plugin</artifactId> <version>3.6.1-SNAPSHOT</version> <extensions>true</extensions> <configuration> <buildConfigConstants> <constant> <name>BACKEND_URL</name> <type>java.lang.String</type> <value>http://ift.tt/1m3YAB1; </constant> </buildConfigConstants> </configuration> </plugin> </plugins> </build> <profiles> <profile> <id>production</id> <build> <plugins> <plugin> <groupId>com.jayway.maven.plugins.android.generation2</groupId> <artifactId>android-maven-plugin</artifactId> <extensions>true</extensions> <configuration> <buildConfigConstants> <constant> <name>BACKEND_URL</name> <type>java.lang.String</type> <value>http://ift.tt/1m3YAB3; </constant> </buildConfigConstants> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project>
If we simply call “mvn install”, the generated BuildConfig looks as follows:
public final class BuildConfig { public final static boolean DEBUG = true; public final static String BACKEND_URL = "http://ift.tt/1m3YABe;; }
But if we build the project against the “production” profile, the BuildConfig changes
public final class BuildConfig { public final static boolean DEBUG = true; public final static String BACKEND_URL = "http://ift.tt/1wM0fSq;; }
Of course, the plugin also allows to use your own or complex classes as constants.
<buildConfigConstants> <constant> <name>CONFIGURATION_ENUM</name> <type>my.package.MyEnum</type> <value>my.package.MyEnum.CONFIG</value> </constant> </buildConfigConstants>
And that’s it! With only very little effort, we avoid manual changes in our sourcecode and we are able to manage all information in one single place.
0 notes
Link
Ready for Sale
Die App hat den Apple Review ohne Komplikationen passiert und ist nun in iTunes zum Download verfügbar. Die kleinen Änderungen haben also gereicht um den Review zu überstehen.
Zusammenfassung
Das Experiment eine iOS App für 5$ ist damit abgeschlossen. Das Resultat ist ok, aber weit davon entfernt zu sein von daher werde ich nach und nach die fehlenden Features (Offline-Fähigkeit, Sharing, Kommentare, etc.) nach und nach ergänzen.
Für einen Laien wäre die App allerdings nichts gewesen, denn die diversen Mängel hätten die App niemals den AppleReview passieren lassen. Von den “versteckte Features” wie dem fremden Google Analytics Account ganz zu schweigen. Es ist also nicht ohne weitere möglich eine App für 5$ zu erhalten die man ohne Programmierkenntnisse oder weitere Unterstützung in den AppStore stellen kann. Für mich als Entwickler war es aber ein interessantes Experiment und auch wenn ich die App lediglich als mögliche Grundlage für eine selbstentwickelte App nach meinen Vorstellungen betrachte, sind 5$ für das grundlegende Projekt auch ein interessantes Angebot.
Nachdem die iOS App nun also im AppStore ist werde ich mich Android und Windows Phone zuwenden. Für beide Plattformen habe ich inzwischen ein vergleichbares Angebot gefunden und warte aktuell auf die erste Lieferung des Quellendes. Es wird also demnächst Beiträge zu den Themen “Eine Android App für 5$” und “Eine Windows Phone App für 5$” geben.
weitere Teile
Teil 1: Das Experiment
Teil 2: Der gelieferte Sourcecode
Teil 3: Vorbereitungen für den AppStore
Teil 4: Der Apple Review
0 notes
Link
The app passed Apple review without any complications and is now available for download on iTunes. The small changes where thus enough to pass through the review.
Summary
The experiment for an iOS app for $5 is thus finished. The result is alright but far from perfect. Therefore, I will add the missing features (offline mode, sharing, comments, etc.) little by little.
However, the app would not have been successful for an amateur since all its shortcomings would’ve never let it pass Apple Review, not even to mention the “hidden features” such as a foreign Google Analytics account. It is thus not that simple to get an app for $5 which one can publish on the App Store without any programming knowledge or further support. As a developer, it was an interesting experiment for me, and even though I only look at the app as a possible basis for an app developed by myself and based on my own concepts, $5 still are an interesting offer for the base project.
Now that he iOS app is on the App Store, I will turn to Android and Windows phone. I have found a comparable offer for both platforms in the meantime, and I am currently waiting for the first delivery from the source. Therefore, there will be upcoming postings on the topics of “An Android App for $5” and “A Windows Phone App for $5”.
0 notes
Link
Im 2. Teil habe ich ja beschrieben, welche verschiedenen Bugs und Unvollständigkeiten den Release der gelieferten App in den AppStore de facto unmöglich machen.
In diesem Teil möchte ich kurz erläutern welche Teile ich geändert habe bevor ich die App in den AppStore eingestellt habe. Insgesamt habe ich nicht mehr als 2,5h damit verbracht.
Unerwünschtes löschen
Bei Kauf der App wusste ich nicht, dass z.B. mein privates Facebook-Profil Teil der App werden würde, da es mit meinem Blog nichts zu tun habe, habe ich die Tabbar mit den Socialmedia-Links (die eh einfach nur in einem WebView geöffnet wurden gelöscht.
Nötige Kosmetik
Da die App auch als Experiment natürlich irgendwie auf mich zurückfällt habe ich die App mit so wenig Aufwand wie möglich ein wenig aufgehübscht. Dank UIAppearance war das sehr schnell erledigt. Die App sieht nun so aus:
Nötige rechtliche Änderungen
Bei der App war natürlich kein Impressum vorgesehen, was man ja auch nicht erwarten kann, denn generell ist es doch eher ein recht deutsches Phänomen. Die Impressumseite musste ich also ebenfalls ergänzen.
Das Google Analytics Tracking habe ich natürlich auch nicht weiter auf den fremden Account weiterlaufen lassen sondern durch meinen Account ersetzt. In einem Update werde ich es vermutlich ganz entfernen. Erstmal wollte ich es aber drin lassen um die App so wenig wie möglich zu verändern.
Erste Tests mit Usern & fehlende Features
Vor dem Apple-Review habe ich die App einigen Nutzern gezeigt um ein paar Meinungen zu der App zu sammeln um zu sehen, welche Features die Leute eigentlich von einer “Blogreader”-App erwarten. Die Hauptkritikpunkte waren:
mangelnde Offlinefähigkeit
Gallerie oben ist nicht zu erkennen und auch nicht “klick”bar
Links innerhalb von Blogposts werden im WebView als Webseite geladen
Videos werden nicht sauber im Vollbild abgespielt
kein PullToRefresh für die Artikel/kein Nachladen der älteren Artikel beim scrollen nach unten
Danke an Carsten Pelka, Mirko Lemme (mileon.net) und Kevin Grahl(kevingrahl.de) für’s testen und Feedback schicken.
Und jetzt abwarten
Die App ist nun in den Apple Review eingereicht. Sobald die App abgelehnt oder im AppStore ist, werde ich den letzten Teil dieser Reihe schreiben.
Teil 1: Das Experiment
Teil 2: Der gelieferte Sourcecode
Teil 3: Vorbereitungen für den AppStore
Teil 4: Der Apple Review
0 notes
Link
As described in part II, there are different bugs and incompletions which render the release of the delivered app on the App Store practically impossible.
In this part, I want to briefly explain which parts I have made changes to before I published the app on the App Store. Overall, I didn’t spend more than 2.5h on this.
Delete unwanted content
When buying the app I didn’t know that, for example, my private Facebook profile would become part of the app, and since it has nothing to do with my blog, I simply deleted the tab bar with the social media links which only open in the web view anyway.
Necessary cosmetics
Being an experiment of mine, the app would of course also reflect on me in a way, so I prettified it with as little effort as possible. This was done pretty quickly, thanks to UIAppearance. Now the app looks like that:
Necessary legal changes
Of course the app didn’t have room for a publishing notice, which can hardly be expected since it’s a rather German phenomenon. Thus, I had to add the publishing notice as well.
The foreign account on the Google Analytics tracking was of course replaced with my own as well. I will probably remove it entirely on an update. For now, I wanted to leave it in there in order to change the app as little as possible.
First user tests and missing features
Prior to the Apple review, I showed the app to a few users in order to gather some opinions on it and to see, which features people expect from a blog reading app. The main points of criticism were:
lack of offline function
gallery on top is not recognizable and not clickable
links within the blog posts were opened in WebView as a website
videos were not played back clean in full screen
no pull-to-refresh for article/no loading of older articles when scrolling downwards
Thanks to Carsten Pelka, Mirko Lemme (mileon.net) and Kevin Grahl (kevingrahl.de) for testing the app and submitting feedback.
and now we wait..
The app has been submitted for Apple review. As soon as it has been rejected or published on the App Store, I will write the last part of this series.
0 notes
Link
Wie im 1. Teil angekündigt werde ich in diesem Teil genauer auf den Sourcecode der gelieferten App eingehen.
Experiment vorbei?
Direkt beim ersten Start/Blick auf den Sourcecode war klar, diese App wird es so nicht in den AppStore schaffen, denn Apps, die in den AppStore hochgeladen werden müssen u.a. 2 Bedingungen erfüllen:
Sie müssen mindestens iOS 4.3 als Target haben und einen iPhone5 Splashscreen anbieten, also das iPhone5 Display unterstützen.
Auf den ersten Blick war also klar: Diese App schafft es so nicht durch den Review. Streng genommen wäre das Experiment damit vorbei, denn Ziel war es ja die App auch im AppStore zu veröffentlichen. Aber da sich zumindest diese beiden Punkte mit wenigen Klicks beheben lassen, setzen wir das Experiment mal weiter fort.
Alter Code
Die oben genannten Probleme ließen schon vermuten, dass die App nicht unbedingt gestern, sondern vor einiger Zeit entstanden ist. Die Kommentare im Header deuten auf Ende 2011/Anfang 2012.
Das Alter stört aber eigentlich kaum, da die App ja trotzdem tut was sie soll man iOS Apps normalerweise das Alter des Sourcecodes nicht bzw. kaum ansieht. Für Nicht-Programmierer mag dieser Punkt also völlig irrelevant sein. Andererseits ist es für Nicht-Programmierer auch nicht gerade leicht die für den Review nötigen Änderungen durchzuführen, auch wenn sie wirklich gering sind.
Viel Framework, wenig selbstgeschrieben
Ein Punkt, der wirklich nicht verwerflich ist. Viele der Klassen stammen aus OpenSource Projekten. Das würde ich sogar als Pluspunkt verbuchen, da ich hier bei mit heißer Nadel gestrickten eigenem Lösungen wesentlich mehr Bauchschmerzen hätte. Die selbstgeschriebenen Bereiche beschränken sich wirklich auf die ViewController.
EDIT: Ärgerlich ist, dass auch Beschränkungen der verwendeten Frameworks nicht berücksichtigt wurden, so tauchen in der Liste HTML Tags auf, die aus dem RSS-Feed stammen und nicht entfernt werden.
Was ist Retina?
Ein Ärgernis ist, dass in einer 2012 geschriebenen App (da war das iPhone4 schon anderthalb Jahre alt) nicht alle Grafiken in Retina-Auflösung mitgeliefert werden. Das sieht nicht nur besch…en aus, es ist auch ebenfalls ein Ablehnungsgrund. Interessant ist auch, dass alle nachgeladenen Grafiken eine Breite von 480px haben und damit genau zwischen normal und Retina liegen. Vielleicht ein Kompromiss für die Ladezeiten, vielleicht auch einfach seltsam.
Kritisch: Nicht genannte Features
Über ein Feature bin ich beim Durchsehen eher zufällig gestolpert. Die App nutzt Google Analytics und zwar mit eingetragenem (fremden) Account! Das fand ich dann doch ein starkes Stück. Ein unbedarfter Blogger, der sich tatsächlich einfach nur eine App für seinem Blog kaufen will würde also die Tracking-Daten seiner Nutzer unwissend Dritten zur Verfügung stellen.
Fazit
Die App ist vom geschriebenen Code nicht schlecht, wirklich nicht. Aber da die App für Nicht-Entwickler niemals durch den Review gehen wird und außerdem ein fremdes Google Analytics Konto mit den Tracking-Daten versorgt wird, kann ich an dieser Stelle nur davon abraten solch ein Angebot zu erwägen.
Ich werde die App trotzdem nach so wenig Anpassungen wie möglich in den AppStore stellen um zu sehen ob die App es durch den Apple Review schafft.
Teil 1: Das Experiment
Teil 2: Der gelieferte Sourcecode
Teil 3: Vorbereitungen für den AppStore
Teil 4: Der Apple Review
0 notes
Link
As pointed out in Part I, I will further discuss the source code of the app delivered to me in this part.
Experiment over?
A quick start of/look at the source code already made it very clear that this app would not make it to the App Store like that because apps that are uploaded to the store have to meet two requirements, among other things:
They have to have at least iOS 4.3 as a target and offer an iPhone 5 splash screen, i.e. support the iPhone 5 display.
At first glance it was thus obvious: the app would not make it through the review. Strictly speaking, the experiment was over because the goal was to also publish the app in the App Store. But since those two flaws can be fixed with only a few clicks, the experiment can continue.
Older code
The problems addressed above already point to the fact that the app wasn’t created yesterday, but rather some time ago. The comments in the header point to late 2011/early 2012.
The age barely matters though, since the app does perform what it is supposed to do and normally, one cannot or only barely tell a source code’s age. For those unfamiliar with programming, this point might be completely irrelevant. At the same time, it’s also not easy for those unfamiliar with programming to make the necessary changes required for the review, even if they are small.
Lots of framework, little developed on their own
An approach that is not all that reprehensible. A lot of the classes come from OpenSource projects. I would even call that an advantage, since I’d be a lot more concerned with someone’s individual, half-baked solutions. The areas that were scripted by them are limited to the view controllers.
EDIT: It is also frustrating that the restrictions of the frameworks used were not kept in mind – thus, there are HTML tags showing up, which come from the RSS feed and were not removed.
What’s retina?
Another frustration is added by the fact that not all the graphics were delivered in retina resolution, on an app which was developed in 2012 when the iPhone 4 had been on the market for a year and a half already. Not only does this make it look crappy, but it is also a reason for refusal. What’s also interesting is that all graphics added afterwards have a width of 480px and are thus right in between a normal and a retina resolution. Maybe this is a compromise for the loading times; maybe it’s just really strange.
Critical: Features not mentioned
One feature I came across very accidentally when checking the app: It uses Google Analytics, but with an inscribed (foreign) account! I thought that was pretty steep. A clueless blogger, who really only wants to purchase an app for his or her blog, would thus make his or her users’ tracking data available to a third party without even knowing it.
Résumé
Regarding the written code, the app is really not that bad. But since the app would never pass the review for non-programmers and furthermore, a foreign Google Analytics account is being fed tracking data, I can only advise to refrain from purchasing such an offer.
Nevertheless, I will publish the app to the App Store (after making as little adjustments as possible) to see if the app would make it through the Apple review.
0 notes
Link
Was für Marketing Agenturen und andere Firmen, die Apps entwickeln lassen, wie die Erfüllung all ihrer Träume und Gebete klingt, wird bei Entwicklern sicherlich nur Kopfschütteln hervorrufen. 5$ (abzgl. der Gebühren der Plattform) für eine komplette App, das ist wirklich mickrig. Doch was bekommt man für seine 5$?
Das Angebot
Das Angebot lautete grob: Die eigene WordPress Seite als native App für 5$. Ok, dachte ich. Das kann man eigentlich für 5$ nur dann anbieten, wenn man eine Standart-Lösung hat, in die man einfach die URL einträgt und das Ganze ausliefert. Außerdem hatte ich ein wenig die Sorge lediglich die kompilierte App zu bekommen und für alle Anpassungen (wie z.B. ein Impressum) immer wieder zahlen zu müssen. Doch hier wurde ich überrascht. Für die 5$ sollte tatsächlich auch der komplette Sourcecode mit drin sein. Ok, damit war die Entscheidung gefallen und ich habe dieses Angebot bestellt.
Weitere 5$
Nachdem ich das Angebot gekauft hatte, sollte ich einige Grafiken bereitstellen, die ich aber gerade nicht zur Hand hatte, außerdem war ich ja neugierig auf den Sourcecode und zu ungeduldig um die 10 Grafiken eben zu erstellen, also habe ich darum gebeten einfach Platzhalter zu verwenden, ich würde die Grafiken dann später austauschen. Die Antwort kam zügig: Das ginge nicht, aber für weitere 5$ würde man mir “richtige” Grafiken (Splashscreen, App-Icon, etc) erstellen. Ok also weitere 5$ bezahlt, danach hieß es warten, denn die Auslieferung der App sollte ca. 7 Tage in Anspruch nehmen.
Die fertige App
Nach 5 Tagen konnte ich mir mein Projekt dann herunterladen und ausprobieren. Die Optik war eher enttäuschend. Aber die App lief solide, die Artikel wurden geladen und angezeigt. Die weiteren Tabs führten zu WebViews in denen dann jeweils mein Facebook Profil, mein Twitter Account oder mein GooglePlus Account (mit Video-Icon) angezeigt wurden.
Die Grafiken waren die größere Enttäuschung, aber fairer Weise muss man ja auch sagen, was will man für 5$ schon erwarten. Die App machte auf den ersten Blick genau was sie sollte und auch bei der Detailansicht wurde nicht einfach die Website in einem WebView geladen.
Wie es weiter geht
In weiteren Schritten werde ich den gelieferten Sourcecode noch ein wenig näher beleuchten und die App anschließend so vorbereiten, dass sie in den AppStore gestellt werden könnte (Impressum hinzufügen, die gröbsten Design-Schnitzer entfernen, etc). Ziel hierbei wird sein, den Sourcecode nicht bzw. nur minimal zu verändern und generell so wenig Aufwand wie möglich zu betreiben. Am Ende soll die App auch in den AppStore gestellt werden um zu sehen ob eine App für 5$ es denn auch durch den Apple Review schafft.
… und was ist mit Android?
Bei Android habe ich interessanterweise noch kein Angebot entdeckt bei dem eine native App inkl. Sourcecode angeboten wird. Sollte ich solch ein Angebot finden werde ich auch für Android mal eine App für 5$ entwickeln lassen.
weitere Teile
Teil 1: Das Experiment
Teil 2: Der gelieferte Sourcecode
Teil 3: Vorbereitungen für den AppStore
Teil 4: Der Apple Review
0 notes
Link
To marketing agencies and companies, who have apps developed for them, it might sound like a dream come true and like all their prayers have been answered, but with the developers it only causes a shake of the head: $5 (minus platform fees) for a complete app, that’s pretty puny. But what do you get for your $5?
The Offer
The offer went something like this: Your own WordPress page as a native app for $5. I thought ‘Okay, the only way to offer that for $5 is to have a standard solution, which allows you to paste the URL and delivers the final product. I was also concerned with only getting a compiled app and having to pay for every adjustment (such as publishing information) over and over again. But to my surprise, the complete source code was to be included for $5. This convinced me and I ordered this offer.
Another $5
After ordering the offer, I was asked to provide graphics which I did not have ready at this point, and since I was curious about the source code and too impatient to create ten graphics, I asked them to simply use placeholders and I would supply the graphics later. They responded quickly, telling me that this was not possible, but for another $5, “proper” graphics (splash screen, app icon, etc.) would be provided for me. Okay, so I paid another $5, and then I had to wait, since the app delivery was supposed to take up to seven days.
The finished App
I could download and try out my project after five days. The visual effects were rather disappointing. But the app was running smoothly, articles did load and displayed properly. The remaining tabs linked to WebViews which displayed my Facebook profile, my Twitter account and my Google + account (with video icon) respectively. The graphics were the biggest disappointment, but in all fairness, how much can you really expect for $5. At first glance, the app delivered exactly what it was supposed to, and the detailed view also didn’t simply show the website in a WebView either.
what happened next
I will now take a closer look at the source code that was provided, and then prepare the app so that it could be added to the app store (including publishing information, removing the biggest design flaws, etc.). The goal is not to change the source code (or at least only slightly), and in general put in as little effort as possible. Finally, the app is supposed to be offered in the App Store to see if an app for $5 will make it through the Apple review process.
…and what about Android?
Interestingly enough, I haven’t found an Android service that offers a native app with a source code. If I find an offer like that for Android, then I’m going to have an Android app developed for $5 as well.
0 notes
Link
Zugegeben, mir fällt kein Grund ein warum man AirPlay für ein Video deaktivieren sollte. Aber das heisst ja noch lange nicht, dass es keine Gründe gibt oder das niemand einen Kunden hat, der AirPlay für seine Videos nicht erlauben möchte.
Mit folgenden Attributen kann man AirPlay für ein Video deaktivieren:
<video src="video.mov" height="768" width="1024" x-webkit-airplay="deny" > </video> <!-- or --> <embed airplay="deny" src="movie.mov" width=320 height=240 mime-type="video/quicktime"> </embed>
0 notes
Link
Auf der DroidCon 2013, der größten Konferenz zum Thema Android in Deutschland, habe ich einen Vortrag zum Thema “Building High Quality Android Apps by using Jenkins and automated device tests” gehalten.
Die Folien dazu habe ich jetzt auch auf Slideshare hochgeladen.
Building High Quality Android Applications from Leif Janzik
Eine Rückmeldung via Twitter:
.@elliotmonster thanks for your great #droidcon talk on continuous integration and device testing.
— Andreas Jägle (@ajaegle) 9. April 2013
0 notes