Muenchen.de

Seit diesem Jahr arbeite ich als regelmäßiger Freelancer bei der „Portal München Betriebs-GmbH“ – oder besser bekannt einfach als „muenchen.de“, also dem offiziellen Münchner Stadtportal.

Nikolaus Gradl, den ich schon seit seiner Stadtratszeit kenne, hatte mich als einer der Projektleiter dort eingeladen und mit einem Projekt geködert, bei dem ich nach München Transparent wohl ein recht naheliegender Kandidat war: der Web-Umsetzung der Münchner Rathaus Umschau, einer werktäglich erscheinenden „Zeitschrift“ der Stadtverwaltung, die neben einer Printversion bisher nur im PDF-Format erschienen ist. Die Herausforderung dabei war, das so in den bisherigen Prozess der Rathaus Umschau zu integrieren, dass dieser erst einmal weit gehend unverändert weiter laufen kann und das PDF auch weiterhin die „Referenzfassung“ bleibt. In der Praxis heißt das, dass die Web-Version hauptsächlich durch ein automatisiertes Parsen des PDFs erstellt wird. Das PDF wird dabei in die einzelnen Meldungen, Terminhinweise, Anträge usw. zerlegt, analysiert und dann veröffentlicht. Das ist sicher nicht die eleganteste Lösung (PDFs wieder zurück in Text umzuwandeln ist leider nicht ganz so komplikationsfrei wie man annehmen könnte), aber hier erst einmal das zweckmäßigste.

Da die PHP-Anwendungen im muenchen.de-Umfeld (der Kern von muenchen.de selbst läuft nicht unter PHP) hauptsächlich auf Laravel basieren, war das außerdem einmal eine gute Gelegenheit, mich damit intensiver zu beschäftigen – sonst hatte ich ja hauptsächlich mit Yii und früher noch mit Zend gearbeitet. Mein persönlicher Favorit bleibt aber bis auf weiteres Yii2. 😀

Ansonsten geht es technisch recht bislang recht abwechslungsreich zu: ein automatischer Konverter von HTML nach AMP war dabei, mit München 360° die Web-Umsetzung einer VR-App auf Basis des Tools krpano, und aktuell ein Projekt, bei dem ich einmal mit Angular2 und Typescript auf Tuchfühlung gehen kann. Typescript finde ich sehr cool, da ich inzwischen ein recht großer Freund statischer Typisierung bin. Mit Angular 2… komme ich auch langsam zurecht, auch wenn ich das 1er darin eigentlich gar nicht mehr wiedererkenne. Wahrscheinlich wäre es sinnvoller, darin gleich ein komplett unabhängiges, neues Framework zu sehen, und weniger einen Nachfolger von Angular 1. Für größere Projekte sehe ich auf alle Fälle die Vorteile gegenüber dem 1er, auch wenn es um einiges komplizierter erscheint.

OpenSlides 2.1

Bei der demnächst neu erschienen Version 2.1 von OpenSlides hatte ich die Gelegenheit, auch ein paar wichtigere neue Funktionen beizutragen: die Zeilennummerierung, das Inline-Bearbeiten von Anträgen sowie die Verwaltung von Änderungswünschen inkl. Änderungsansicht. Alles sind natürlich Funktionen, von der Art, mit der ich bei Antragsgrün bereits Erfahrung gesammelt habe, auch wenn sich die konkrete Implementierung schon allein deshalb maßgeblich unterscheidet, dass sie bei Antragsgrün hauptsächlich serverseitig in PHP implementiert, während OpenSlides hauptsächlich AngularJS-basiert (mit minimalem Python-Backend) ist. Das hat Vor- und Nachteile: grundsätzlich ist das Interface von OpenSlides dadurch natürlich deutlich responsiver. Gerade bei den aufwändigeren Algorithmen (Zeilennummern und Änderungsansichten sind komplizierter, als man anfangs oft meint) und bei längeren Texten stellt das aber auch höhere Ansprüche an die Leistungsfähigkeit des Client-Rechners, und mindestens an einer Stelle konnten wir aus diesem Grund auch nicht die beste Implementierung wählen.

Spannend war auch das Erzeugen des PDFs auf Basis der JavaScript-Bibliothek PDFMake. Es ist einerseits cool, dass es überhaupt funktioniert, PDFs rein clientseitig im Browser zu erzeugen – andererseits sind wir auch an einige problematische Einschränkungen gestoßen. Wobei der Antragsgrün-Ansatz, auf LaTeX bzw. XeTeX als Backend fürs PDF-Rendering zu setzen, auch nicht unproblematisch ist.

Ich bin auf alle Fälle gespannt, wie es sich weiter entwickelt – und wie sich das Zusammenspiel zwischen OpenSlides und Antragsgrün weiterentwickelt. Anders als einige andere sehe ich die zwei Tools ja auch immer noch als eher komplementär zueinander, und weniger als Konkurrenz. Auf alle Fälle wird ein weiteres Betätigungsfeld sein, die Schnittstellen zwischen den beiden Tools weiter zu verbessern.

München und Hamburg

Anfang April hat sich bei mir beruflich nun wieder einiges geändert. Die Zeit des ununterbrochenen Pendelns zwischen München und Hamburg ist nun vorbei und ich werde endlich wieder deutlich mehr Zeit in meiner selbstgewählten Heimatstadt verbringen können. Hamburg hat es mir aber durchaus auch angetan, ich mag die Stadt und werde auch weiterhin ein bis zweimal im Monat dort sein: seit diesem Monat bin ich auf Teilzeitbasis bei web care LBJ / pflege.de als „Head of Development“ angestellt, statt wie bisher nur als Freelancer.

Meine selbstständige Tätigkeit behalte ich aber bei, und hatte da auch gleich wieder Glück: auch jetzt seit Anfang April arbeite ich an einem Projekt beim offiziellen Münchner Stadtportal muenchen.de. Da ich mit München Transparent ja auch schon in ähnlichen Gebieten unterwegs war, liegt mir das natürlich thematisch auch sehr.

pflege.de

Seit Ende Oktober bin ich nun selbstständig, und nach zwei Weiterentwicklungs-Sprints für Antragsgrün im Auftrag vom Grünen-Bundesverband einerseits und dem Deutschen Bundesjugendring andererseits bin ich nun im ersten größeren Projekt: bei der Seite pflege.de, die im hübschen Hamburg sitzt.

Moment, Hamburg?

Ja, die Situation ist tatsächlich: ich wohne weiterhin in München, arbeite unter der Woche aber in Hamburg. Mein erster Gedanke bei der Idee war, einmal die Woche mit dem Zug zwischen München und Hamburg pendeln geht gar nicht. Andererseits: vor wenigen Monaten bin ich erst über 15.000km mit dem Zug von München nach Saigon gefahren und habe das als erholsamen Urlaub empfunden, da können mich ein paar Stunden im ICE nun auch nicht mehr schocken.

Nach einer anfänglichen Überraschung – als PHP-/JavaScript-/HTML-Entwickler angeheuert, durfte ich stattdessen erst mal hauptsächlich auf Ruby on Rails, CoffeeScript und HAML programmieren – hab ich mich inzwischen recht gut eingelebt. Und das das eigentliche Projekt, für das ich ins Boot geholt wurde, hat nun auch den ersten großen Meilenstein erreicht: den Relaunch des Content-Management-Systems. Zum Glück auf PHP-Basis. 🙂

Screenshot von pflege.de (nach dem Relaunch)

Converting HTML to OpenDocument Text and Spreadsheet

I moved one of the components of Antragsgrün into a separate library, as it might be useful for other projects: HTML2OpenDocument converts formatted HTML content to OpenDocument Text- and Spreadsheet-Files (ODT / ODS). It can handle basic formattings like bold, italic, underlined, strike-through, inserted and deleted text. Lists are supported in Text-Files. The library is licenced under the MIT licence and is available on GitHub and on Packagist / Composer.

Codeception: HTML and Accessibility Validation

For my latest web project, Antragsgrün 3, I’m heavily using Codeception for acceptance testing. As I want to ensure that the system validates against the HTML5 standard and is accessible, I’ve written two helpers for Codeception that I want to share: one Helper that validates the current site using the Nu Html Checker (http://validator.github.io/validator/), and one that validates it against WCAG2.0 (A, AA or AAA) or Section 508 using Pa11y.

Both helpers are using the command line tools, so they do not rely on an online web service and can be used offline. While the accessibility validator works with both the PhpBrowser and the Webdriver module of Codeception, the Html Validators needs Webdriver (which, while a bit more difficult to set up, is superior anyway).

Validating the current site is as easy as:

$I->validateHTML();
$I->validatePa11y();

(There are also some parameters for choosing the accessibility standard and to ignore certain errors).

The code and installation instructions are on these two gists:
HTML Validator
Accessibility Validator

Bezirksausschuss Laim: Website

Vor wenigen Tagen ging nach langer Vorbereitungszeit endlich die neue Website des Laimer Bezirksausschuss online:

Screenshot der Website des Bezirksausschuss Laim (Internale)

Die lange Vorbereitungszeit lag dabei nicht an der eigentlichen Gestaltung – technisch ist die Seite eher trivial, wie man denke ich recht schnell sieht. Ungewohnt war für mich nur, einmal komplett ohne serverseitigen Skriptsprachen zu arbeiten und stattdessen nur auf statische HTML-Seiten zu setzen – aber dank Jekyll & co ist das ja inzwischen auch kein Problem mehr. Die rechtliche Klärung dauerte dafür aus nicht ganz nachvollziehbaren Gründen locker fünfmal so lang wie die eigentliche Programmierung. Na ja, Ende gut, alles gut – jetzt ist sie endlich da und alle sind glücklich. 🙂

Vortrag: München Transparent

Dank der Einladung des SIN – Studio im Netz e.V. habe ich kommenden Donnerstag, den 18. Juni um 19:00 Uhr die Gelegenheit, im Rahmen der Münchner Webwoche das Projekt München Transparent vorzustellen. Den Vortrag halte ich zusammen mit Marcus M. Dapp, der über Open Data und Open Government im größeren Kontext sprechen wird. Wer Lust hat, sich es anzuhören: der Vortrag ist kostenlos, nur eine Voranmeldung ist nötig.

Nachtrag: die Folien des Vortrags sind nun online.

Antragsgrün 3 – Aktuelle Planung

In den letzten Wochen und Monaten kam wieder einiges an Schwung in die Weiterentwicklung von Antragsgrün. Da sich momentan eine komplette Überarbeitung des Antragstools abzeichnet, will ich hier die aktuellen Planungen kurz umreißen.

Rückblick

Die erste Version von Antragsgrün hatte ich 2012 für den Landesverband Bayern von Bündnis 90 / Die Grünen geschrieben, um die Antragsverwaltung auf den Landesdelegiertenkonferenzen sowohl für Delegierte als auch die Geschäftsstelle zu vereinfachen. Es unterstützte damals unter anderem schon Anträge, Änderungsanträge, Kommentare und automatisch generierte PDFs. Es war relativ schnell klar, dass auch andere grüne Verbände Interesse daran haben, und dass das anfängliche Modell, für jeden Verband eine neue Instanz zu installieren, nicht wirklich skalierte. Daher folgte schnell Antragsgrün 2, dessen wichtigste Neuerung die Mandantenfähigkeit war – also dass eine zentrale Installation beliebig viele Verbände bedienen kann. Antragsgrün ist damit einerseits Open-Source-Software, die frei auf eigenen Servern installiert werden kann – andererseits aber auch ein zentrales Portal www.antragsgruen.de, über das sich alle grünen Verbände kostenlos ohne technische Kenntnisse eigene Programmdiskussionen einrichten können.

Neue Anforderungen

Nun zeigt sich aber, dass Antragsgrün auch für deutlich mehr als nur reine Antragsarbeit verwendet wird und damit auch ein großer Bedarf für neue Anwendungsszenarien besteht, die momentan nicht oder nur auf Umwegen abgedeckt werden. Beispiele dafür sind Bewerbungen und strukturierte Programmarbeit, was beispielsweise einen Bilder-Upload und deutlich flexiblere Formulare benötigt als Antragsgrün mit seiner momentan noch recht starren Fixierung auf das „Antragstext + Begründung“-Schema liefern kann. Oft gewünscht wird auch eine Tagesordnungsfunktion, bessere Anpassbarkeit in so ziemlich allen denkbaren Gebieten (Wording, Layout, verschiedene Antragsschlüsse, …) und eine bessere Kompatibilität mit verwandten Tools wie OpenSlides und cvtx. Um diese Funktionen einzubauen, müssen einige grundlegende Strukturen von Antragsgrün überarbeitet werden.

Nicht zuletzt gibt es auch einige rein technische Gründe, die für eine größere Überarbeitung sprechen: von den meisten verwendeten Software-Bibliotheken gibt es nach vier Jahren nun große neue Versionen, insbesondere vom zugrunde liegenden PHP-Framework Yii. Und, um ehrlich zu sein: einige grundlegende Design-Entscheidungen beim bisherigen Antragsgrün waren rückblickend schlicht falsch und warten auf Korrektur. Eine Überarbeitung ist außerdem ein guter Anlass, auch endlich automatisierte Tests mit einzubauen, die die allgemeine Softwarequalität langfristig deutlich erhöhen sollte. Zumindest hatten sich zuletzt häufig Fehler eingeschlichen, die beim konsequenten Einsatz von Unit- und Acceptance-Tests vermieden hätten werden können.

Antragsgrün 3 soll mit den eben genannten Punkten und Verbesserungen noch im diesen Sommer erscheinen. Zeitlich ist das zwar ambitioniert, nach meiner aktuellen Einschätzung und mit der bisherigen Vorarbeit und Unterstützung aber realistisch.

Aktuelle Entwicklung

Die konkreten Arbeiten an Antragsgrün 3 begannen schon im Februar diesen Jahres, als sich abzeichnete, dass sowohl ein Grüner Landesverband Interesse an den Bewerbungen und der Tagesordnungsfunktion hat, als auch der Bundesverband Interesse bekundete, Antragsgrün verstärkt einzusetzen. In einem neuen Github-Branch liegt demnach auch schon einiges an Code – natürlich noch in einem recht frühen Zustand, da es bislang nur in meiner Freizeit entwickelt ist. Allerdings sind bereits alle wichtigen Kerntechniken grundlegend implementiert – von der neuen Datenstruktur über einen neu geschriebenen Diff-Algorithmus bis hin zu den Unit- und Acceptance-Tests.

Ein Großteil der Entwicklungsarbeit wird im Juli stattfinden. Im Juli werde ich, dank der Unterstützung durch den Grünen-Bundesverband sowie einiger -Landesverbände, in Vollzeit an Antragsgrün arbeiten können und in dieser Zeit hoffentlich einen Großteil der oben genannten Punkte umsetzen können. Es wird demnach wohl Ende Juli eine erste Beta-Version geben, die erste stabile Version ist für August geplant. Natürlich ist damit dann nicht die Entwicklung ein für alle mal abgeschlossen – nur wird das Tempo wieder stärker davon abhängen, wie viel Freizeit ich habe bzw. ob sich für bestimmte Neuerungen „Sponsoren“ finden.

Technischer Überblick

Achtung: hier folgt viel Technik-Fachsimpelei, das man auch einfach überspringen kann. Ab dem nächsten Abschnitt wird es wieder verständlicher. 🙂

Frameworks

Antragsgrün 3 wird technisch auf das Yii2-Framework aufsetzen, benötigt mindestens PHP 5.5, wird in der Produktivversion aber entweder auf PHP7 oder HHVM laufen.

Als CSS-Framework kommt Bootstrap 3 in der SASS-Variante, oder, falls bis dahin verfügbar, Bootstrap 4.

Für die Unit- und Acceptance-Tests setze ich Codeception ein, plus diverse Tools zur statischen Code-Analyse (PHP Mess Detector, PHP Code Sniffer). Als Coding-Standard verwende ich PSR-2. Noch unschlüssig bin ich bei der Wahl des Continuous-Integration-Tools; aktuell verwende ich noch PHPCI, bin allerdings nicht so ganz zufrieden und möchte daher auch mindestens noch Jenkins und Travis testen.

Es gibt auch schon ein prototypisches Docker-Image; eine Vagrant-basierte Umgebung ist angedacht.

Datenstrukturen und Features

Das große Motto von Antragsgrün 3 ist „Flexibilisierung“ (mit sinnvollen Voreinstellungen):

  • Es wird nicht mehr vorgegeben, aus welchen Bestandteilen ein Antrag, eine Bewerbung etc. genau besteht. Diskussionsvorschläge können beispielsweise nur ein Textfeld haben, Anträge dagegen zwei, und Bewerbungen noch ein Bild und tabellarische Angaben wie Geburtsjahr, KV usw. Zwar gibt es Voreinstellungen, die für die üblichen Verwendungszwecke (Parteitag mit Anträgen und Bewerbungen, Programmdiskussion, …) maßgeschneidert sind, die Strukturen werden aber nicht mehr fest einprogrammiert sein wie das bisherige Antragstext+Begründungs-Schema.
  • Es kann mehrere Dokumententypen pro Veranstaltung / Diskussion geben, die einerseits unterschiedlich strukturiert sind, andererseits aber auch unterschiedliche „Regeln“ haben. Damit ist es beispielsweise möglich, unterschiedliche Antragsschlüsse für Anträge, Satzungsänderungsanträge, Eilanträge und Bewerbungen festzulegen, oder unterschiedliche Voraussetzungen (ein Antrag, der z.B. 5 UnterstützerInnen benötigt, während es für Bewerbungen keine benötigt).
  • Möglichst alle Textbausteine auf einer Seite sollen auf Wunsch anpassbar sein.
  • Es wird die Möglichkeit geben, aus mehreren PDF-Vorlagen für Anträge, Änderungsanträge, Bewerbungen etc. zu wählen.

Weitere Änderungen sind unter anderem:

  • Verbessert werden soll auch die BenutzerInnenverwaltung. Beispielsweise fehlen aktuell noch grundlegende Funktionen wie eine Passwort-Zurücksetzen-Funktion, die nachgerüstet wird.
  • Texte werden nun intern nicht mehr als BBCode, sondern direkt als (normalisiertes) HTML gespeichert. Die Entscheidung für BBCode war indirekt für viele kleinere Probleme verantwortlich, die es bei Antragsgrün momentan noch gibt – auch scheinbar unzusammenhängende Probleme wie die unzulängliche Absatzerkennung bei der Eingabe von Texten.
  • Ein Betrieb auf eigenen Servern soll vereinfacht werden; beispielsweise soll kein eigener E-Mail-Server mehr vorausgesetzt werden.
  • Neben MySQL soll auch SQLite als Datenbank unterstützt werden.
  • Die Liste von AntragstellererInnen und UnterstützerInnen eines Antrags werden sauberer von der User-Tabelle getrennt sein. Die aktuelle Verschränkung dieser beiden Tabellen hatte häufiger für unerwartete Seiteneffekte gesorgt.
  • Die Funktion zur Anzeige von Änderungen wird nun direkt in Antragsgrün implementiert, nicht mehr über eine externe Bibliothek. Dadurch können Probleme hier leichter behoben werden, wie zum Beispiel die oft sehr unvorteilhafte Anzeige, wenn größere Textblöcke als ganzes durch Neue ersetzt werden.

Antragsgrün 4, 5, …

Bei den internen Treffen mit VertreterInnen anderer Landesverbände zeigte sich schon, dass es auch weit über die hier vorgestellten Funktionen noch größere Visionen gibt, die allerdings zeitlich dieses Jahr noch nicht umgesetzt werden können.

Das langfristige Ziel sollte bei Antragsgrün sein, die Arbeit der Antragskommission komplett ohne Medienbrüche abbilden zu können – was schon alleine deshalb herausfordernd ist, da die verschiedenen Antragskommissionen der Verbände teils grundlegend unterschiedlich arbeiten. Solche Medienbrüche, die derzeit noch üblich sind, sind das Ausdrucken von Spreadsheets/Excel-Tabellen, Google Speadsheets, oder die Verwendung anderer Tools für einzelne Aspekte der Antragsbearbeitung.

Auch eine Offline-Variante von Antragsgrün wird immer wieder gewünscht, was aber mit PHP gerade auf Windows leider doch komplizierter ist als beispielsweise mit Python. Ansatzpunkte könnten PHP Desktop oder PHPWebkit sein – allerdings habe ich hier noch keine Praxiserfahrung und wäre auch über sachdienliche Hinweise dankbar. 🙂

Ein weiterer Nachteil von Antragsgrün, auch der kommenden 3er-Version ist, dass es sich nicht in andere Content-Management-Systeme integrieren lässt. Für WordPress punktet hier das cvtx-Plugin von Alexander Fecke, für Typo3 ist mir keines bekannt. Ob eine WordPress- und/oder Typo3-Variante von Antragsgrün realistisch ist, müsste genauer evaluiert werden.

Da auch international keine wirklich mit Antragsgrün vergleichbare (Open-Source-)Software gibt, bietet sich eine Internationalisierung auch geradezu an. Da schon Antragsgrün 3 Mechanismen vorhält, Textbausteine auf der Seite flexibel zu ersetzen, ist auch schon ein erster Schritt in diese Richtung getan.

Choosing Android’s System Sounds for Cordova Push Notifications, using Native Configuration Screens

One of the features most wished for in one of my Cordova-based android apps was to let the users choose another sound for push notifications, or to disable sound altogether (without having to mute the whole smart phone and still keeping vibration). The Push Plugin supports custom sounds, however all sound resources have to be embedded in the app. In my case, I wanted to let the users choose among the system sounds provided by Android itself, which apparently isn’t possible without some major changes to the plugin.

Here, I’m going to outline the changes necessary to integrate Android’s native RingtonePreference dialog into a Cordova-based app to let the users choose another notification sound. I’ve published the modified plugin that should work on android projects on Github.

Screenshot_2015-04-29-18-13-18Screenshot_2015-04-29-18-13-23

Configuration Dialog

Choosing the preferences for push notifications is done in a native android PreferenceScreen that is opened from within the app using a new javascript-method on the pushNotification-Object. The configuration screen is defined by a xml file stored at platforms/android/res/xml/pushsettings.xml:



    

        

        

        

        

    

The referenced strings are stored in platforms/android/res/values/strings-gcm.xml:



    Notifications
    Light
    Light is switched on
    Light is switched off
    Vibration
    Vibration is switched on
    Vibration is switched off
    Sound
    Sound is switched on
    Sound is switched off
    Ring tone
    Choose a ring tone

Translated versions can be stored in files like platforms/android/res/values-de/strings-gcm.xml

Opening the dialog
First of all, a new activity has to be defined in the platforms/android/AndroidManifest.xml:


The Activity itself is pretty simple, just remember to replace the „CORDOVA_PACKAGE_ID“ by the id of your app (necessary to access the R.xml.pushsettings-resource):

package com.plugin.gcm;

import CORDOVA_PACKAGE_ID.R;
import android.os.Bundle;
import android.preference.PreferenceActivity;

public class PushSettingsActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.pushsettings);
    }
}

This activity is called from PushPlugin.java’s execute-method, something like:

if ('showPushSettings'.equals(action)) {
    Intent i = new Intent(this.cordova.getActivity(), PushSettingsActivity.class);
    this.cordova.getActivity().startActivityForResult(i, RESULT_PUSH_SETTINGS);
    callbackContext.success();
}

The JavaScript-method to call this in PushNotification.js is:

PushNotification.prototype.showPushSettings = function (successCallback, errorCallback) {
    if (errorCallback == null) {
        errorCallback = function () {}
    }
    if (successCallback == null) {
        successCallback = function () {}
    }

    if (typeof errorCallback != "function") {
        console.log("PushNotification.showPushSettings failure: failure parameter not a function");
        return;
    }

    if (typeof successCallback != "function") {
        console.log("PushNotification.showPushSettings failure: success callback parameter must be a function");
        return;
    }

    cordova.exec(successCallback, errorCallback, "PushPlugin", "showPushSettings", []);
};

With all these changes applied, a call to plugins.pushNotification.showPushSettings() should open the configuration dialog and let the user apply her desired notification sound. The settings are stored automatically in android’s SharedPreferences. In the source code of the plugin, I also added a getPushSettings()-method that returns the settings into JavaScript, if you ever need to query these settings.

Using the settings for the notification
The actual notification sound is triggered in GCMIntentService.java’s onMessage-method. The new code reads the settings from the SharedPreferences and acts accordingly:

SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean vibration = app_preferences.getBoolean("com.plugin.gcm.vibration", true);
boolean sound = app_preferences.getBoolean("com.plugin.gcm.sound", true);
boolean light = app_preferences.getBoolean("com.plugin.gcm.light", true);
String ringtonePath = app_preferences.getString("com.plugin.gcm.ringtone", "defValue");
int defaults = 0;
if (vibration) defaults = defaults | Notification.DEFAULT_VIBRATE;
if (light) defaults = defaults | Notification.DEFAULT_LIGHTS;
		
NotificationCompat.Builder mBuilder =
    new NotificationCompat.Builder(context)
        .setDefaults(defaults)
        .setSmallIcon(context.getApplicationInfo().icon)
        .setWhen(System.currentTimeMillis())
        .setContentTitle(extras.getString("title"))
        .setTicker(extras.getString("title"))
        .setContentIntent(contentIntent)
        .setAutoCancel(true);

if (!ringtonePath.equals("") && sound) {
    Uri uri = Uri.parse(ringtonePath);
    Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), uri);
    r.play();

    mBuilder.setSound(null);
}

I’m using the Ringtone.play() instead of the setSound()-method of NotificationCompat.Builder, as the latter one somehow didn’t actually change the sound, even with the URL of the sound provided. I haven’t yet figured out why, but there probably is a solution that’s more elegant than the one showed above.
That’s it. Have fun! 🙂