2. MAC App-Store, Delphi und die Sandbox

Sandbox-Pflicht
Mehrmals hat Apple die Sandbox-Pflicht für Programme im App-Store verschoben, aber seit dem 01. Juli 2012 gilt sie. Ihre Anwendung muss daher jetzt die Sandbox-Funktionalität unterstützen. Man kann sich die Sandbox als eine Art Container vorstellen, in dem die Anwendung werkelt. Es gibt denn im Datei-System auch tatsächlich einen Ordner Namens "Containers", in dem die Umgebung des Systems in Teilen quasi virtuell nachgebildet ist.

Containers
Schauen Sie selber unter /Users/IHRNAME/Library/Containers einmal nach, wenn Sie eine Sandbox-App auf Ihrem System laufen haben und Ihr OS System mindestens 10.7.x oder neuer lautet (also Lion). Die Sandbox-Anwendung selber wird übrigens nach wie vor im "/Applications" Ordner installiert.

Delphis Sandbox-Funktionalität
Delphi unterstützt schon vom Stand heraus das Sandboxing. Das ist allerdings nur aktiv, wenn Sie die Einstellung "App Store" in der Projektverwaltung, in der Zielplattform OS X aktiviert haben.  Als weitere Voraussetzung ist erforderlich, dass Sie unter Projekt, Optionen, Bereitstellung, bei den Entwicklerprofilen Ihre 3rd Party MAC Entwicklerzertifikate ausgewählt haben. Damit wird Ihre Anwendung nämlich  signiert, wenn das Application-Bundle auf den MAC übertragen wird. Diese Signatur ist sozusagen ein wichtiges Verbindungselement, welches das Sandboxing erst im System für Ihre Anwendung aktiviert. Ach ja, das passende  OS System natürlich vorausgesetzt. Unter Snow Leopard wird das Sandboxing noch nicht unterstützt, unter Lion noch nicht perfekt. Sie müssen daher Ihr Programm unter Mountain Lion entwickeln, zumindest aber testen, wenn Sie die Sandbox-Funktionalität überprüfen wollen.

Mir ist das leider auch erst später bewusst geworden und die Apple-Reviewer sehen eben doch nicht alles. Meine Programme "CopyBackup" und "TEditor" unterstützen daher die volle Sandbox-Funktionalität jeweils erst ab der Version 3.01 bzw. 1.01.

Berechtigungen (Entitlements)
In Delphi XE3 können Sie unter Projekt, Optionen, Berechtigungsliste einstellen, welche weitergehenden Rechte Ihre Anwendung haben darf. In der Regel ist es kein Problem, wenn Sie das Lese- und Schreibrecht für Ordner und Dateien aktivieren, die über die Öffnen und Sichern-Dialoge auswählbar sind.

Powerbox
Die Öffnen und Sichern-Dialoge haben übrigens eine ganz wichtige Funktion. Denn damit erhält Ihre Anwendung während der Laufzeit Zugriff auf Dateien und Ordner, die außerhalb der Sandbox liegen. Wenn Sie z.B. den Datei Öffnen-Dialog aufrufen, wird die Funktion, die Apple als "Powerbox" bezeichnet aktiv und gewährt der Anwendung Zugriff auf die Datei. Zur Laufzeit des Programms können Sie denn auch Änderungen an der Datei vornehmen und diese Änderungen zurückspeichern.

Wenn Sie das Programm beenden und es dann erneut starten, ist dieses Recht aber verwirkt, Sie müssten erneut den Öffnen-Dialog bemühen, um wieder Zugriff auf die Datei oder einen Ordner außerhalb der Sandbox zu erhalten. Hatten Sie die Datei innerhalb Ihrer Sandbox gespeichert, geht das allerdings auch so, Sie können in diesem Fall eine solche Datei direkt mit typischen ".Loadfromfile" Funktionen öffnen und laden. 

Sie werden aber oft die Situation haben, dass Sie Dateien bearbeiten, die in Ordnern liegen, die auch für andere Anwendungen zugänglich sein müssen, z.B. im Ordner Dokumente. Und dann wäre es schon praktisch, wenn Sie mit einer "Zuletzt bearbeitet" - Liste direkt auf eine Datei zugreifen können, ohne wieder den Datei Öffnen Dialog benutzen zu müssen.

Persistenter Zugriff auf Dateien und Ordner mit Bookmarks
Wenn Sie in Ihre Entitlements-Datei den Schlüssel "com.apple.security.files.bookmarks.app-scope" aufnehmen (manuell, Delphi bietet es nicht an), können Sie sog. Bookmarks, also Lesezeichen, anlegen, mit deren Hilfe Sie später wieder auf Dateien und Ordner außerhalb der Sandbox zugreifen können, ohne die Öffnen und Sichern -Dialoge bemühen zu müssen.

Allerdings ist dies leider gar nicht so einfach und bedauerlicherweise auch nicht mit den Komponenten TOpenDialog und TSaveDialog zu bewirken, die Delphi mitliefert. 

Denn man kann diese "Security Scoped Bookmarks" leider nur zu einem ganz bestimmten Zeitpunkt anlegen und das ist während der Lebensdauer eines Original MAC NSOpenPanels bzw. NSSavePanels. Zwar kapseln die Delphi-Komponenten die NSPanel-Objekte. Da aber nach der Rückkehr von den Execute-Funktionen im TOpenDialog bzw. TSaveDialog die NSPanels wieder zerstört sind, besteht hier leider keine Möglichkeit mehr, solche Bookmarks anzulegen.

Man muss daher diese beiden Dialoge selber noch mal neu implementieren und dabei an der entscheidenden Stelle einen Aufruf der NSURL-Funktion "bookmarkDataWithOptions" vornehmen. Hier liegt der Zeitpunkt genau zwischen der Erzeugung des NSOpenPanels, der Auswahl der Datei und vor der Freigabe des Dialogs. Dann ist sozusagen die Tür einen Spalt offen und nur dann kann man die Bookmark anlegen. 

Diese Beschränkungen ergeben sich aus Überlegungen zur Sicherheit. Denn falls Ihre MAC-Anwendung mal von einem Virus befallen werden sollte, hat dieser selber keinen Zugriff auf Ressourcen außerhalb der Sandbox und kann dort keinen Schaden anstellen.

Bei dem NSSavePanel wird es leider noch komplizierter. Denn die Bookmarks werden an tatsächlich bestehende Ordner oder Dateien gebunden. Was also machen, wenn Sie eine Textliste erst nur im Arbeitsspeicher haben und eine Bookmark anfordern wollen für eine Datei, die noch nicht existiert? 

Man muss - wieder an der entscheidenden Stelle - während der Lebenszeit des NSSavePanels eine Datei mit dem gewünschten Namen temporär erzeugen (das kann auch eine leere Datei sein) und dann dafür die Bookmark anlegen. Nach Rückkehr vom NSSavePanel-Dialog können Sie dann die Datei mit den von Ihnen gewünschten Inhalten füllen.

Der Aufruf der Funktion zur Erzeugung der Bookmark sieht so aus:

function CreateAppScopedBookMark (var data: NSDATA; URL: 
MacApi.Foundation.NSURL): Boolean;
var
  err2: NSError;
  includingResourceValuesForKeys: NSArray;
  relativeToURL: MacApi.Foundation.NSURL;
begin
  //.. notwendige Vorbelegungen
  Data := URL.bookmarkDataWithOptions(NSURLBookmarkCreationWithSecurityScope,
  includingResourceValuesForKeys, 
  relativeToURL, // NIL = App-Scope
  @Err2);
  // Prüfen, ob OK, oder Fehler aufgetreten
end;

Data, ein NSData-Objekt enthält dann die Bookmark, die man dann z.B. in einer Datei speichern und später wieder laden kann, um die Sandbox damit wieder zu öffnen.

Dieses spätere Öffnen erfolgt im ersten Schritt mit der NSURL-CLASS Funktion "URLByResolvingBookmarkData". NSURL und NSURLCLASS sind übrigens in der Unit MACApi.Foundation.pas implementiert, diese Unit müssen Sie also in Ihr Projekt einbinden. 

Damit ist es aber noch nicht getan. Sie müssen zunächst

startAccessingSecurityScopedResource aufrufen

dann die Datei oder den Ordner verwenden und danach mit

stopAccessingSecurityScopedResource

die Nutzung der Ressource wieder beenden. Die Start und Stop-Aufrufe müssen ausbalanciert sein, wenn nicht, verliert Ihre Anwendung während der weiteren Laufzeit die Fähigkeit mit Bookmarks auf Ressourcen außerhalb der Sandbox zuzugreifen. Es funktioniert dann erst wieder nach dem nächsten Programmstart.

Zu allem Übel der sich hier andeutenden Komplexität wurden im NSURL-Interface, das in der MACApi.Foundation.pas implementiert ist, leider nicht die beiden zuletzt genannten Funktionen integriert. Man muss diese also selber in einer eigenen Interface-Implementation integrieren. Ich habe mit der Quality-Central Meldung Report #: 113852 darauf hingewiesen und gebeten, dass dies in einem der nächsten Updates nachgeholt wird. Denn nicht jeder weiß wie man das macht und selbst dann verkompliziert es die Programmlogik nur unnötig.

Die HSW.FMXSandbox.pas unit
Mit den vorstehenden Erläuterungen ist im groben geschildert, wie Ihre Sandbox-Anwendung persistenten Zugriff auf Dateien und Ordner außerhalb der Sandbox erhalten kann.

Im aktuellen e-Book existiert bereits ein allgemeiner Abschnitt zum Sandboxing, wo unter anderem noch eine andere Möglichkeit zum Zugriff auf Ressourcen außerhalb der Sandbox beschrieben wird.

In der 16. Auflage des e-Books, das am 22.03.2013 erscheinen wird, ist der Inhalt dieses Blogs sehr viel ausführlicher geschildert und vor allem ist im Anhang meine HSW.FMXSandbox.pas unit abgedruckt, die Sie als Leser des e-Books frei verwenden können. Dort sind nicht nur die ganzen MACApi.Foundation Funktionen in die Delphi Notation umgesetzt, sondern es werden auch fehlende Integerkonstanten (z.B. NSURLBookmarkCreationWithSecurityScope) ergänzt und auch die Implementierung der fehlenden start und stop NSURL-Funktionen wird nachgeholt. Schließlich wurde die ganze Verwaltung des Anlegens, Speicherns und Wiederaufrufen der Bookmarks integriert und automatisiert, so dass nur noch 2 kurze Funktionsaufrufe erforderlich sind, um die Ressourcen anzufordern und wieder freizugeben. Und zu guter letzt haben Sie Zugriff auf meine Implementierung der erweiterten Öffnen und Sichern-Dialoge, die es Ihnen überhaupt erst ermöglichen, die Bookmarks anzulegen.

Also, was ist Ihre Meinung zum Sandboxing mit Delphi, wie sind Ihre eigenen  Erfahrungen? Wenn Sie Anregungen zu Themen haben, lassen Sie es mich gerne wissen. Meine Mailadresse finden Sie oben auf der Seite unter dem Link "Anbieterkennzeichnung & Kontakt". Über meinen Hastasoft-Twitter Account werde ich posten, wenn neue Blogbeiträge zur Verfügung stehen. Wenn Sie wollen, klinken Sie sich dort ein (siehe meine Hastasoft-Seite).

Der nächste Blogbeitrag wird sich mit Objective C und Cocoa befassen und grob erläutern, was da eigentlich hinter steckt und wie Sie die dahinter stehende Funktionalität in Ihre Delphi-Programme holen.

Viel Erfolg mit Delphi und FireMonkey!

Harry Stahl, 20.03.2013