C# Zweite Version einer App erstellen, Code-Reusing?

Physikbuddha

Lt. Commander
Registriert
Aug. 2014
Beiträge
1.051
Guten Morgen zusammen,

ich habe eine App in C# mit Xamarin (Native) erstellt. Die App steht seit ein paar Monaten sowohl im AppStore für iOS, als auch im Play Store für Android bereit.

Jetzt möchte ich eine alternative Enterprise-Version dieser App für B2B-Kunden erstellen. Sie soll, ich sag mal 90 % des Umfangs der Endkundenversion enthalten. Ein paar Sachen wie In-App-Käufe und Onboarding fliegen raus, dafür kommt zum Beispiel eine Loginfunktion herein, die die In-App-Käufe ersetzt (Profil des Nutzers bestimmt die freigeschalteten Funktionen).

Nun stellt sich die Frage, wie ich das technisch umsetze.
Die komplette Projektmappe enthält 9 Projekte, davon sind 2 die eigentlichen Android- und iOS-Projekte.
Die restlichen 7 sind geteilter Code wie ViewModels, Models, Services, Helpers, Datenhaltung (Repository), ... Um die mache ich mir gar keine Gedanken.

Es geht mir also um den Code der einzelnen Apps. Die Activities bzw. ViewController sind nicht gerade klein.
Spontan ging mir so durch den Kopf:
  • Sämtliche Dateien einfach kopieren. Wenn dann aber mal in Zukunft neue Funktionen hinzukommen sollen, muss ich sie in allen 4 Versionen nachrüsten, und dabei würde ich potentiell zu viel übersehen. Ich könnte immer WinMerge drüberjagen lassen, um mir die Unterschiede anzuzeigen, aber das klingt nicht wirklich praktikabel.
  • Komplette Ordner oder Dateien, die 1:1 übernommen werden können per Symlink/Junction rüberziehen. Hat wiederum den Nachteil, dass ich den Namespace nicht ändern kann. Außerdem hab ich da Probleme mit Git gehabt, aber das könnte man vielleicht lösen.
  • Irgendeine Art Shared-Android- oder -iOS-Projekt erstellen, und dort den doppelten Code reinhauen, aber das ist mir bislang nicht gelungen.
Ich habe erstmal mit der Symlink-Lösung angefangen und bin sofort auf das Problem gestoßen, dass ich auf Android in den Activities ja nicht mehr einfach FindViewById machen kann. Die IDs werden ja trotz identischem Namens auf jedem Projekt unterschiedlich ausgewürfelt und vergeben.
Unter iOS habe ich wiederum mein großes Storyboard als eine einzige Datei, die ich nicht einfach splitten kann, bzw. der Übersichtlichkeit halber nicht möchte.

Ich stehe jetzt also so ein bisschen auf dem Schlauch, wie ich an dieses Problem am besten herangehe.
Habt ihr Ideen oder Anregungen dafür? Kann ich weitere Informationen geben, die ich vergessen habe?

Gruß vom Physikbuddha
 
Einfach einen entsprechenden Branch im git machen? Du willst ja in Zukunft wenn du einen Patch Schreibst, diesen nicht 2x schreiben müssen.
 
Ich schlag mal vor den Preprocessor zu verwenden, dann kannst Du in der ersten Zeile:
#define FULLVERSION
Dann später wo sich der Code unterscheidet:
#if FULLVERSION ... #else ... #endif
schreiben ...
 
  • Gefällt mir
Reaktionen: herliTz_234
Du kannst eine Klasse bauen die deine Produktversionen enthält und die checkst einfach ob die installierte Version dieses Feature benutzen darf.
 
Noch ne weitere Idee. Du ziehst aus jeder Klasse, die du ändern willst, eine Abstraktion raus (falls es nicht schon ein passendes Interface/abstrakte Basisklasse gibt, was ja oftmals der Fall ist, wenn man ein Framework verwendet) und verwendest nur noch die Abtraktion anstatt die konkrete Klasse.
Jetzt brauchst du noch 2 Implementierungen, eine mit dem alten Verhalten und eine mit dem neuen.
Per Dependency Injection kannst du entscheiden, welches Verhalten du verwenden willst.
 
@lynxx @FroggieFrog Naja gut, das kenne ich ja und nutze ich auch. Aber, @herliTz_234, ich brauche trotzdem zwei Projekte, weil es im App Store später zwei separate Apps mit unterschiedlichen Metadaten geben soll. Dazu gehören neben BundleIdentifier auch Sachen wie App-Name, Icon, Versionsnummer. Die liegen bei iOS in der Info.plist, bei Android im Manifest.

Wie kann ich diese Dateien denn switchen? Präprozessor fällt flach, ist kein Code. Und per Buildconfig wüsste ich nicht, wie ich verschiedene Dateien einbinden kann. Ich darf auch die Dateien nicht umbenennen. Sie müssen(!) Info.plist und AndroidManifest.xml heißen und an ihrem festen Platz liegen.

@umask007 Habe ich auch schon dran gedacht, siehe mein Vorschlag Nummer 3. Dafür bräuchte ich aber ein Shared-Projekt, in dem ich die abstrakten Klassen ablege. Das muss dann aber ein Android- oder iOS-Projekt sein, weil ich auf die ganzen systemspezifischen Klassen zugreife.
Alles, was nicht systemspezifisch ist, liegt ja bereits in meinen ViewModels etc.
Allerdings habe ich es wie gesagt nicht hinbekommen, ein Projekt "Klassenbibliothek Android" oder "Klassenbibliothek iOS" anzulegen. Sowas gibts nicht. Jetzt könnte ich easy einfach eine leere App anlegen, aber du kannst nicht von einer App auf eine andere verweisen.

@Falc410 Ich muss zugeben, dass ich nicht der Git-Crack bin. Ich komme mit Commits, Brances etc recht gut klar, aber bin noch recht am Anfang. Von Patches habe ich mehr oder weniger gehört, aber noch nie eingesetzt. Cherry-Picks ebenfalls noch nicht.
Du meinst also, ich sollte mich da mal einlesen?
 
Na so wie ich das verstanden habe, bleibt vielleicht 90% von deinem Code gleich, dann wirst du ein paar zusäztliche Features ein- oder ausbauen.
Jetzt machst du aber eine Änderung in dem Code der beide Versionen betrifft. Wenn du eine Kopie von deinem Projektordner hast, dann musst du nun manuell die Änderung in die andere Version copy & pasten. git würde es dir eben erleichtern so etwas mehr oder weniger automatisch zu machen. Das nennt sich ja nicht umsonst ein Versionverwaltungstool (oder Versionierungstool?)

So läuft doch eigentlich jede Softwareentwicklung. Ich habe auch unterschiedliche Branches für verschiedene "Kunden" mit unterschiedlichen Features, aber der Core ist bei beiden identisch. Das will ich ja nicht 2x pflegen müssen.
 
Naja, das hab ich mich immer gefragt, wie man so einen Core vernünftig pflegt.
Wenn ich an so etwas wie Git-Rebase denke, geht mein Blutdruck direkt wieder hoch, weil ich mir da eigentlich so gut wie jedes Mal das Repo zerschieße.

Ja, ich nutze noch Tortoise Git, aber auch nur, weil ich auf der Kommandozeile komplett den Überblick verliere.

Und Patches, du schreibst "mehr oder weniger automatisch". Ich muss doch bestimmt trotzdem jeden Patch manuell erstellen und aus meinen Commits herauspflücken. Woher weiß Git denn, welche meiner neuen Funktionen jetzt beide Apps betreffen?
Vielleicht finde ich da mal ein brauchbares Tutorial. Danke für deine Anregungen! :)
 
Wir haben uns vor ein paar Jahren auf die git flow Konventionen geeinigt - das sieht im ersten Moment kompliziert aus, aber ich konnte das in weniger als 10 Minuten unseren ganzen Hiwis erkären und die haben es verstanden und sich daran gehalten.

https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow
https://datasift.github.io/gitflow/IntroducingGitFlow.html
https://danielkummer.github.io/git-flow-cheatsheet/

SourceTree unterstützt das auch direkt über Knöpfe und erstellt / schließt entsprechende Branches. Wenn du einen Patch machst, musst du den natürlich in deine anderen Branches mergen. Das kann man automatisieren (solange bis es zu einem merge conflict kommt den man manuell dann beheben muss).

Repo zerschiessen ist bei git eigentlich unmöglich - früher bei SVN hatte ich das oft zu meinen Studienzeiten.

Edit: Ich möchte dazu sagen - ich bin kein Software Engineer! Ich mache das nur Nebenbei und vielleicht gibt es schon modernere und bessere Workflows! Ich habe das in meiner Master Arbeit benützt und dann so beibehalten (also das Projekt wird seitdem ständig weiter entwickelt aber eben auch nicht von richtigen Software Engineers sondern hauptsächlich lasse ich Bachelor Studenten als Hiwis für mich Dinge implementieren).
 
  • Gefällt mir
Reaktionen: Physikbuddha
Ah cool, danke.
Mit zerschießen meine ich: Rebase von einem Zweig auf den anderen. Was ist jetzt mein "Branch", und was ist mein "Upstream"? Welchen Branch muss ich dafür gerade ausgecheckt haben?
Meistens immer genau das andere. So ist es halt passiert, dass ich meinen Core-Zweig auf den Featurezweig gerebrancht habe. Wie auch immer das geht. War dann halt Chaos.

Obwohl ich mit solch technischem Zeug eigentlich ganz fit bin, habe ich mich mit Git nie ganz vertragen. Mittlerweile überlege ich auch viermal, ob ich wirklich einen neuen Branch brauche, und lasse es meistens sein.

Ja, natürlich geht das komplett gegen die dahinterstehende Denkweise.
Aber von ständigen Konfliktproblemen hab ich irgendwie erstmal genug.
 
Git-flow is a merge based solution. It doesn't rebase feature branches.

Wahrscheinlich damit genau das was dir in der Vergangenheit passiert ist, nicht passiert :)

Git lädt zum brunchen...ah natürlich branchen ein.
 
Vorweg: Ich kenne mich nicht mit Xamarin aus.

bzgl Verschiedene Branches:
Wenn du in vielen Dateien immer 1-2 unterschiedliche Zeilen hast und an die rangehst (bzw in der Nähe reicht ja oft), dann bekommst du natürlich früher oder später immer Merge-Konflikte, auch wenn das allermeiste geshared wird, da hilfe nur eine bessere Isolierung, aber die ist eben nicht immer einfach so möglich..

Die pauschal beste Lösung gibt's da halt nicht, von den 4 genannten Lösungen (gleicher Code mit Feature-Weichen, verschiedene Branches mit Cherry-Picks, Rebases, etc, verschiedene Build-Configs, Copy & Paste) kann jede je nach Anforderung die Beste sein (wenns wenig shared code wäre auch copy & paste wenn man es so will..).

Ich hätte jetzt auch die Variante 1 empfohlen, wenn das aber keine Option ist, weil du partout 2 Apps willst, fällt das wohl weg.
Dann am Ehesten die Build-Configs, wo es ja scheinbar auch nicht möglich ist, zwei verschiedene Apps zu generieren.. Durch Googeln kommt man bei ganz komischen Forendiskussionen raus, wo anscheind jeder an jedem vorbeiredet.
Sollte das tatsächlich nicht funktionieren, kann man natürlich verschiedene Branches pflegen, mit der Gefahr zu Merge-Konflikten, ob Rebase oder nicht (beim Rebase ists halt verheerender, bzw man hat halt teils öfters welche an den gleichen Stellen, wenn man sie in mehreren Commits angefasst hat).
Und Copy & Paste ist natürlich übel, spätestens sobald man mehr als 1000 Zeilen Code shared, der sich auch mal weitereintwickeln soll..

In einem Thread den ich gefunden habe, wurde vorgeschlagen, zwei Startprojekte zu haben, zwischen denen man eben wechseln kann. Liegen denn die Info.plist und das Manifest nicht im Startprojekt, sondern in der großen Solution?
Sonst würde es so klingen als könnte man das analog zu dem Build-Vorschlag eben über verschiedene Startprojekte lösen, die dann eben den Core referenzieren..
 
Featuretoggle beim build die entsptechenden werte in eine config setzen.

Entsprechend den überflüssigen kram auslisten oder drin lassen.

Reicht eine Versionsverwaltung für beides. Super easy super effizient und vllt 3 Klassen für die featureverwaltung.

Die config ist das nix anderes als eine Lizenzdatei.

Was du da vorhast ist Wahnsinn. Sowas würde ich nicht pflegen wollen...
 
Zurück
Oben