HowTo: iFrame öffne dich! App Integration ab DSM 7.2

Tommes

Benutzer
Sehr erfahren
Maintainer
Mitglied seit
26. Okt 2009
Beiträge
9.151
Punkte für Reaktionen
1.115
Punkte
314
Bis zur DSM Version 7.1.x konnte man in der Datei config, durch einfaches Ändern des key-Wertes "type" festlegen, ob eine App in einem iFrame oder in einem neuen Pop-up-Fenster ausgeführt werden soll. Das ist ab DSM 7.2 so nicht mehr möglich. Daher beschreibt dieses Tutorial, wie man ab DSM 7.2 weiterhin eine "inoffizielle" 3rdParty App in einem iFrame betreiben kann.

Ich möchte an dieser Stelle eingehend darauf hinweisen, das ich meine gesammelten Erkenntnisse rein durch das Try and Error Prinzip erworben habe. Ich kann daher nur vermuten, das die nachfolgenden Anpassungen im Großen und Ganzen dem entsprechen, was Synology hier voraussetzt. Von daher nehmt ihr das - wie immer - auf eure eigene Kappe, sollte es im Nachgang zu Problemen bzw. Unstimmigkeiten kommen.

Los gehts!


Änder in deiner INFO Datei den Value-Wert von dsmappname so ab, das dieser dem nachfolgenden Muster entspricht. Wobei [APPLICATION_NAME] nur als Platzhalter für den Namen deiner App dient. Achte im folgenden darauf, das dieser Wert an jeder Stelle dieses Tutorials gleich lautet. Ebenfalls musst du alle, in deinem Projekt vorkommenden Value-Werte für dsmappname entsprechend anpassen.

Syntax:
dsmappname="SYNO.SDS.[APPLICATION_NAME].Application"

Beispiel:
dsmappname="SYNO.SDS.LogAnalysis.Application"
Diese Schreibweise ist wichtig und vermutlich ausschlaggebend für den späteren Erfolg.

Änder deine config Datei (liegt i.d.R. im Ordner /ui) so ab, das sie dem nachfolgendem Muster entspricht. Solltest du hier abweichende oder weitere key/value Werte aufgeführt haben, teste im späteren Verlauf, ob diese noch greifen. Passe auch hier die entsprechenden Platzhalter für [APPLICATION_NAME], [APPLICATION_DESCRIPTION] sowie [APPLICATION_ICON] deinen Bedürfnissen an. Bitte beachte, das in den nachfolgenden Code-Blöcken die Platzhalter nicht grün, sondern in rot, blau oder schwarz eingefärbt sind. ;)

JSON:
{
    "[APPLICATION_NAME].js": {
        "SYNO.SDS.[APPLICATION_NAME].Application": {
            "type": "app",
            "title": "[APPLICATION_NAME]",
            "appWindow": "SYNO.SDS.[APPLICATION_NAME].MainWindow",
            "desc": "[APPLICATION_DESCRIPTION]",
            "icon": "[APPLICATION_ICON]",
            "allowMultiInstance": false,
            "allowStandalone": true,
            "allowSharing": true,
            "allUsers": true,
            "grantPrivilege": "all",
            "advanceGrantPrivilege": true,
            "texts": "texts",
            "depend": ["SYNO.SDS.[APPLICATION_NAME].MainWindow"]
        },
        "SYNO.SDS.[APPLICATION_NAME].MainWindow": {
            "type": "lib",
            "title": "[APPLICATION_NAME]",
            "icon": "[APPLICATION_ICON]",
            "texts": "texts",
            "depend": ["SYNO.SDS.[APPLICATION_NAME].Utils"]
        },
        "SYNO.SDS.[APPLICATION_NAME].Utils": []
    }
}


Erstelle im Ordner /ui eine neue Datei, die als Dateinamen den Namen deiner App trägt und als Erweiterung ein .js erhält. Editier die grad erstellte Datei und füge den nachfolgenden Inhalt ein.

Syntax:
[APPLICATION_NAME].js

Beispiel:

Javascript:
Ext.namespace("SYNO.SDS.[APPLICATION_NAME].Utils");

Ext.apply(SYNO.SDS.[APPLICATION_NAME].Utils, function(){
    return{
        getMainHtml: function(){
            // Timestamp must be inserted here to prevent caching of iFrame
            return '<iframe src="webman/3rdparty/[APPLICATION_NAME]/index.cgi?_ts=' + new Date().getTime() + '" title="react-app" style="width: 100%; height: 100%; border: none; margin: 0"/>';
        },
    }
}());

Ext.define("SYNO.SDS.[APPLICATION_NAME].Application", {
    extend: "SYNO.SDS.AppInstance",
    appWindowName: "SYNO.SDS.[APPLICATION_NAME].MainWindow",
    constructor: function(){
        this.callParent(arguments);
    }
});
 
Ext.define("SYNO.SDS.[APPLICATION_NAME].MainWindow", {
    extend: "SYNO.SDS.AppWindow",
    constructor : function(a){
        var MY = SYNO.SDS.[APPLICATION_NAME];
        this.appInstance = a.appInstance;
        MY.MainWindow.superclass.constructor.call(this, Ext.apply({
            layout : "fit",
            resizable : true,
            cls: "syno-my-win",
            maximizable : true,
            minimizable : true,
            width : 1024,
            height : 768,
            html: MY.Utils.getMainHtml()
        }, a));
        MY.Utils.ApplicationWindow = this;
    },

    onOpen : function(){
        SYNO.SDS.[APPLICATION_NAME].MainWindow.superclass.onOpen.apply(this, arguments);
    },

    onRequest : function(a){
        SYNO.SDS.[APPLICATION_NAME].MainWindow.superclass.onRequest.call(this, a);
    },

    onClose : function(){
        clearTimeout(SYNO.SDS.[APPLICATION_NAME].TimeOutID);
        SYNO.SDS.[APPLICATION_NAME].TimeOutID = undefined;
        SYNO.SDS.[APPLICATION_NAME].MainWindow.superclass.onClose.apply(this, arguments);
        this.doClose();
        return true;
    }
});


Das sollte es gewesen sein. Ich hoffe, ich habe nichts vergessen.

Tommes
 
Zuletzt bearbeitet:

BigRonin

Benutzer
Mitglied seit
08. Mai 2015
Beiträge
1.156
Punkte für Reaktionen
130
Punkte
89
Wow ... einfach klasse !!!

Ein Problem hab ich mit der Umsetzung, ist es normal das ich in die Kopfleiste des Fensters klicken muss um es in den Vordergrund zu bringen? ... oder hab ich was übersehen?
 

Tommes

Benutzer
Sehr erfahren
Maintainer
Mitglied seit
26. Okt 2009
Beiträge
9.151
Punkte für Reaktionen
1.115
Punkte
314
Ich kann dieses Verhalten bei mir nicht feststellen. Wenn du magst, kannst du dir LogAnalysis zum Vergleich installieren um zu schauen, ob auch hier das gleiche Verhalten auftritt. Falls nicht, dann vergleich beide Pakete mal miteinander und versuch Unterschiede zu erkennen. Mehr kann ich grad auch nicht dazu sagen.
 

BigRonin

Benutzer
Mitglied seit
08. Mai 2015
Beiträge
1.156
Punkte für Reaktionen
130
Punkte
89
LogAnalysis hab ich auf meiner DS118 installiert … hier das selbe verhalten … ob es an der DS118 liegt ? …. ich forsche weiter :)
 

Tommes

Benutzer
Sehr erfahren
Maintainer
Mitglied seit
26. Okt 2009
Beiträge
9.151
Punkte für Reaktionen
1.115
Punkte
314
Ich werd mir das am WE auch noch mal genauer anschauen, für den Moment bin ich aber überfragt. Einzig das Ab- und wieder Anmelden am DSM, das löschen des Browser Caches, oder auch, es mit einem anderen Browser zu probieren, würde mir dabei einfallen.
 

Tommes

Benutzer
Sehr erfahren
Maintainer
Mitglied seit
26. Okt 2009
Beiträge
9.151
Punkte für Reaktionen
1.115
Punkte
314
Ach ich Seppel. Jetzt habe ich erst verstanden, was du mir mit...

ist es normal das ich in die Kopfleiste des Fensters klicken muss um es in den Vordergrund zu bringen?
... sagen willst. Und ja, ich habe hier bei mir das gleiche Verhalten, auch wenn mir dieses, ehrlich gesagt, noch nie wirklich aufgefallen ist :ROFLMAO:

Ich könnte mir durchaus vorstellen, das es key/value Werte gibt, die ich nicht kenne, da ich keine Doku darüber habe. Auch könnte es für z.B. den key/value Wert layout : "fit" in der .js Datei weitere Value Werte geben, die ich aber ebenfalls nicht kenne. Sowas lässt sich nur nach dem Try and Error Prinzip herausfinden, oder indem man sich die .js Datei in anderen Paketen anschaut. Diese können mitunter aber ziemlich vollgestopft mit Informationen sein, was das Suchen und Finden nicht grade erleichtert.

Tommes
 

Tommes

Benutzer
Sehr erfahren
Maintainer
Mitglied seit
26. Okt 2009
Beiträge
9.151
Punkte für Reaktionen
1.115
Punkte
314
Ich hab nochmal ein wenig herumprobiert bezüglich deiner Frage...
ist es normal das ich in die Kopfleiste des Fensters klicken muss um es in den Vordergrund zu bringen?

... und festgestellt, das es an dem eingebetteten iFrame in der [APPLICATION_NAME].js liegt. Also dieser Abschnitt...
Javascript:
Ext.apply(SYNO.SDS.[APPLICATION_NAME].Utils, function(){
    return{
        getMainHtml: function(){
            // Timestamp must be inserted here to prevent caching of iFrame
            return '<iframe src="webman/3rdparty/[APPLICATION_NAME]/index.cgi?_ts=' + new Date().getTime() + '" title="react-app" style="width: 100%; height: 100%; border: none; margin: 0"/>';
        },
    }
}());

Wenn man jetzt hingeht, und hängt dem Inline CSS-Style ein pointer-events: none; an, dann kannst du zwar ins komplette Fenster hineinklicken, um es in den Vordergrund zu holen, jedoch kannst du dann keine click-, scroll– und/oder hover-Events im darin liegenden HTML-Dokument mehr ansteuern. Sprich, dein im iFrame laufendes HTML-Dokument ist nur noch lesbar, kannst aber nichts mehr damit machen. Kannst das gerne mal ausprobieren, indem du die o.a. Zeile wie folgt abänderst...
Javascript:
return '<iframe src="webman/3rdparty/[APPLICATION_NAME]//index.cgi?_ts=' + new Date().getTime() + '" title="react-app" style="pointer-events: none; width: 100%; height: 100%; border: none; margin: 0"/>';

Du kannst auch ganz einfach mal die CSS-Style Werte für width: 100%; height: 100%; mal auf 90% oder so stellen, dann kannst du außerhalb des iFrames auf dessen Rand klicken, um das Fenster in den Vordergrund zu holen. Innerhalb des iFrames klappt das dann nicht mehr.

Eine Lösung für dieses Problem habe ich leider nicht. Bin also für jeden Vorschlag offen...

Tommes
 

Tommes

Benutzer
Sehr erfahren
Maintainer
Mitglied seit
26. Okt 2009
Beiträge
9.151
Punkte für Reaktionen
1.115
Punkte
314

inkaman

Benutzer
Mitglied seit
20. Apr 2009
Beiträge
200
Punkte für Reaktionen
12
Punkte
18
Hallo zusammen, hoffe gut gefeiert zu haben ;)


Aus Interesse, wie genau rufe ich jetzt eine z.B. index.html Seite auf die ich mit ins ui Verzeichnis lege?
Einfach hinter dem Pfad < ..index.cgi?_ts=index.html' + new Date().getTime() + '" ..> hinter schreiben?

Gruß - inkaman
 

Tommes

Benutzer
Sehr erfahren
Maintainer
Mitglied seit
26. Okt 2009
Beiträge
9.151
Punkte für Reaktionen
1.115
Punkte
314
Hi!
Die hier vorgestellte Möglichkeit bezieht sich einzig und allein darauf, eine 3rdParty App in einem Fenster des DSM, also einem iFrame laufen zu lassen. Das hat mit der internen Verarbeitung, wie du innerhalb deiner App auf Seiten weiterleitest, erstmal wenig zu tun. Ich versuch’ das kurz zu erklären ... und das gilt zunächst auch nur für meine Apps, da man das auf unterschiedliche Weise lösen kann. Synology schreibt Apps (bzw. baut der DSM komplett darauf auf) soweit ich weiß nur noch in Ext JS, darauf baut auch diese Anleitung auf. Ich persönlich habe von Ext JS jedoch absolut keine Ahnung. Betrachte nachfolgende Erläuterungen daher nur als Beispiel.

Bis DSM 7.1 konnte man eine 3rdParty App einfach in einem iFrame laufen lassen. Würde man die App z.B. per Rechtsklick in einem neuen Fenster bzw. Browser-Tab öffnen, könnte die Adressleiste vielleicht sowas hier erhalten...
https://[IP-DEINER-DS]:5001/webman/3rdparty/[NAME-DER-APP]/index.cgi?page=main&section=start

Je nachdem würde zusätzlich noch einen angehängter SynoToken folgen. Innerhalb deiner App würdest du einen Link aber nur z.B. mit einem...
<a href="index.cgi?page=main&section=start">Link</a>
... ausführen, wobei die angehängten key/value Werte zusammen mit dem Link per GET-Request an das aufzurufende Script übergeben werden. Hier siehst du schon, das es etwas knifflig wird. Ich rufe bei meiner Vorgehensweise demnach keine HTML Seiten auf, sondern Shell-Scriptdateien, die einen Mix aus HTML und BASH-Code enthalten. Das ist in etwas so, als würdest du mit php deine Websites erstellen. Dann enden deine aufzurufen Dateien i.d.R. mit .php und darin ist ein Mix aus HTML und php-Code enthalten. Mann könnte das alles auch z.B. mit Python lösen.

Seit DSM 7.2 funktioniert der Aufruf in einem iFrame jedoch nicht mehr. Ich kann die App zwar immer noch in einem neuen Fenster bzw. Browser-Tab öffen und mir wird auch weiterhin die o.a. Adresse ausgespuckt, innerhalb eines iFrames wird solch eine Adresse aber nicht mehr akzeptiert.

Änder ich meine App aber nach der hier vorgestellten Möglichkeit ab, dann wird der eigentliche Aufruf einer Seite mit Ext JS maskiert. Das sieht dann in etwa so aus...
https://[IP-DEINER-DS]:5001/?launchApp=SYNO.SDS.[NAME-DER-APP].Application&SynoToken=TTHXeWt0YGluY

Erst du diese Maskierung lässt sich eine 3rdParty App ab DSM 7.2 in einem iFrame ausführen. Der Seitenaufruf innerhalb der App hat sich dabei jedoch nicht geändert.

Wie gesagt... ich spreche hier nur von meinen Apps und meiner Vorgehensweise, wie ich Seiten verarbeite.

Ich hoffe, das hilft dir weiter, ansonsten frag gerne weiter.

Tommes
 
Zuletzt bearbeitet:

inkaman

Benutzer
Mitglied seit
20. Apr 2009
Beiträge
200
Punkte für Reaktionen
12
Punkte
18
Hi Tommes erst mal danke für die vielen Infos.

Ich habe mir mal schnell ne index.html Seite im *.spk erstellt und in Deinem Script hinterlegt.
Erster Testaufruf .. die Seite ist über den direkten LINK im Browser ohne Probleme zu erreichen.

Wenn ich das jetzt bei Deinem Aufruf hinterlege .. ist es das leider nicht mehr der Fall.
return '<iframe src="webman/3rdparty/JDownloader/index.html' + new Date().getTime() + '" title="react-app" style="width: 100%; height: 100%; border: none; margin: 0"/>';

Jetzt hast du ja geschrieben das es bei der 7.2 Version nur noch so gehen soll ..
https://[IP-DEINER-DS]:5001/?launchApp=SYNO.SDS.[NAME-DER-APP].Application&SynoToken=TTHXeWt0YGluY

1. Woher weiß ich wie der Token lautet?
2. Wenn die App jemand anderes nutzt der natürlich eine andere IP hat wie muss der Aufruf dann lauten?

https://??????:5001/?launchApp=SYNO.SDS.JDownloader.Application&SynoToken=??????

Ich hatte mir vorgestellt das man einfach die lokale ip oder name nutzt also so ..

https://127.0.0.1:5001/?launchApp=SYNO.SDS.JDownloader.Application&SynoToken=????????
https://localhost:5001/?launchApp=SYNO.SDS.JDownloader.Application&SynoToken=????????

Geht das überhaupt?
 

Tommes

Benutzer
Sehr erfahren
Maintainer
Mitglied seit
26. Okt 2009
Beiträge
9.151
Punkte für Reaktionen
1.115
Punkte
314
Stopp mal kurz… du willst die offizielle JDownloader App so umbauen, das diese in einem iFrame läuft? Falls dem so ist, dann wird das alleine noch nicht zum Erfolg führen, da du hier noch an ein paar anderen Schrauben drehen müsstest. Welche genau das sind kann ich dir aus der hohlen Hand nicht sagen, dazu müsste ich mir den Aufbau der App zunächst selbst anschauen.

Woher weiß ich wie der Token lautet?
Man kann den SynoToken einerseits auslesen, wozu ich dir mal diesen Link an die Hand gebe. Durch die eingangs beschriebene Vorgehensweise wird der SynoToken automatisch an die URL gehangen. Man muss den Token also nicht selbst an die URL hängen. 3rdParty Apps laufen auch ohne den Token, unter DSM 7.2 dann halt aber nicht mehr im iFrame. Ich selbst lese den Token in meinen Apps auch schon länger nicht mehr aus.

Wenn die App jemand anderes nutzt der natürlich eine andere IP hat wie muss der Aufruf dann lauten?
Naja, die Apps sind ja so gebaut, das sie von jedem installiert und verwendet werden können, unabhängig von der IP oder sonst was. Der Teil https://??????:5001 wird in der App selbst demnach garnicht definiert. Ist schwer zu erklären…

Schau dir vielleicht mein DSM7DemoSPK In meiner Signatur an und spiel damit ein wenig rum wenn du magst.
 

inkaman

Benutzer
Mitglied seit
20. Apr 2009
Beiträge
200
Punkte für Reaktionen
12
Punkte
18
Hi, nein ich möchte einfach nur eine kleine index Seite basteln in html/htm oder php Format,
wo ich 2-3 Seiten im iFrame anzeigen lassen kann. Mehr nicht. :unsure:

JDownloader.spk ohne JAVA_HOME Variable und ohne root Rechte hab ich ja schon gebaut und funktioniert ja auch schon. ;)

Ich wollte nur eine Erweiterung mit rein bringen wo man z.B. kleine Anleitungshilfen aufführt oder um vielleicht Ordner umzubenennen etc.
Ist nur ne Idee von mir aber das sich der Aufruf einer Seite so schwirig gestaltet finde ich echt kontraprodukitiv.

Ich spiel noch was rum damit. Geht nicht .. gibt es meiner Meinung nach nicht.
Ist allerdings blöd sich alles so zusammensuchen und reimen zu müssen.

Eine Lösung für synodsmnotify habe ich leider auch noch nicht gefunden.
Bis 7.1.x geht alles und ab 7.2.x nicht mehr nur noch als root über die Konsole.
Aber das Paket ist so ja nicht mehr installierbar als 3rd Party App.

Weder als ein User in der @administrators Gruppe noch die Umstellung beim Aufruf auf @users helfen hier weiter.
 

Tommes

Benutzer
Sehr erfahren
Maintainer
Mitglied seit
26. Okt 2009
Beiträge
9.151
Punkte für Reaktionen
1.115
Punkte
314
Ist allerdings blöd sich alles so zusammensuchen und reimen zu müssen.
Willkommen in meiner Welt!
Synology gibt uns mit dem Developer Guide zwar grundlegende Informationen für den Paketaufbau an die Hand. Auch kann man mit dem darin beschriebenen Toolkit seine Pakete auch komfortabel packen. Im Zusammenspiel mit git macht das dann auch durchaus Laune. Leider hält Synology uns inoffiziellen 3rdParty Entwicklern aber auch jede Menge Informationen vor. Daher ist der Weg leider ziemlich steinig und mit jedem DSM Update wird es eher schlimmer als besser.

Was ich trotzdem noch nicht ganz verstanden habe ist, ob du nun ein eigenständiges Paket entwickeln möchtes, so wie du hier schreibst...
ich möchte einfach nur eine kleine index Seite basteln in html/htm oder php Format,
wo ich 2-3 Seiten im iFrame anzeigen lassen kann. Mehr nicht.

... oder möchtest du den JDownloader erweitern, so wie du hier schreibst....
Ich wollte nur eine Erweiterung mit rein bringen wo man z.B. kleine Anleitungshilfen aufführt oder um vielleicht Ordner umzubenennen etc.

Falls du ersters meinst, dann kann ich dir meine Demo App empfehlen, falls du letzters meinst, kann ich dir bedauerlicherweise nicht groß helfen. Dafür müsste ich mir JDownlaoder selber anschauen um zu verstehen, wie das umgesetzt ist.

Eine Lösung für synodsmnotify habe ich leider auch noch nicht gefunden.
Der Befehl wird bei meinen Apps auch nur dann ausgelöst, wenn man das Script als root ausführt. Man muss halt eigene Wege finden, wie man sowas löst. Da gibt es keine Patentlösung für. Du kannst dich auch als offizeller Developer bei Synology bewerben, dann erhält du sicherlich auch root Rechte für deine Apps ;)

Ist halt alles nicht so einfach

Tommes
 

inkaman

Benutzer
Mitglied seit
20. Apr 2009
Beiträge
200
Punkte für Reaktionen
12
Punkte
18
Hi, ich habe mich mit der Thematik jetzt ein bischen auseinander gesetzt..

und siehe da, der iFrame startet eine über das Paket mitgelieferten index.html Seite die man in den ui Ordner legt .. wenn man den iframe Link in der JDownloader.js Datei richtig baut.

Der originale Code mit meinem Link .. (es wird eine Fehlerseite von Synology angezeigt)

Code:
..
// Timestamp must be inserted here to prevent caching of iFrame
return '<iframe src="webman/3rdparty/JDownloader/index.html' + new Date().getTime() + '" title="react-app" style="width: 100%; height: 100%; border: none; margin: 0"/>';
..

Meine abgeänderte Version mit meinem Link .. (der Inhalt der index.html Seite wird angezeigt)

Code:
..       
// Timestamp must be inserted here to prevent caching of iFrame
return '<iframe src="webman/3rdparty/JDownloader/index.html?'+new Date().getTime()+'" title="react-app" style="border:0px #ffffff none;" scrolling="no" frameborder="1" marginheight="0px" marginwidth="0px" height="100%" width="100%" allowfullscreen></iframe>';
..

Demnach ist der Aufruf über
https://[IP-DEINER-DS]:5001/?launchApp=SYNO.SDS.[NAME-DER-APP].Application&SynoToken=IRGenDwaS
doch nicht erforderlich so wie es aktuell aussieht.

Jetzt kann ich mir ne Webseite zusammenbauen die über den iFrame zusätzlich Inhalte veranschaulicht.

Gruß - inkaman
 
Zuletzt bearbeitet:


 

Kaffeautomat

Wenn du das Forum hilfreich findest oder uns unterstützen möchtest, dann gib uns doch einfach einen Kaffee aus.

Als Dankeschön schalten wir deinen Account werbefrei.

:coffee:

Hier gehts zum Kaffeeautomat