<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
  <id>https://jumplink.eu/de/blog/tags/macos/feed.xml</id>
  <title>Pascal Garber – macOS</title>
  <updated>2026-11-01T00:00:00Z</updated>
  <link rel="self" type="application/atom+xml" href="https://jumplink.eu/de/blog/tags/macos/feed.xml"/>
  <link rel="alternate" type="text/html" href="https://jumplink.eu/de/blog/tags/macos/"/>
  <author>
    <name>Pascal Garber</name>
    <uri>https://jumplink.eu/</uri>
  </author>
  <entry>
    <id>https://jumplink.eu/de/blog/macos-signing/</id>
    <title>Mit gjsify GNOME-Apps für Linux, macOS und Windows ausliefern</title>
    <link rel="alternate" href="https://jumplink.eu/de/blog/macos-signing/"/>
    <published>2026-11-01T00:00:00Z</published>
    <updated>2026-11-01T00:00:00Z</updated>
    <summary>gjsify ship baut aus deiner App Pakete für Linux, macOS und Windows. Für den Mac signiert und notarisiert es jetzt auch, mit einem Befehl und ohne Packaging-Dateien im Repo.</summary>
    <content type="html">&lt;p&gt;Eine App zu schreiben ist die eine Hälfte, sie bei Leuten zum Laufen zu bringen die andere. Mit &lt;code&gt;gjsify ship&lt;/code&gt; baust du aus deinem Projekt installierbare Pakete, ohne Packaging-Dateien im Repo und ohne &lt;code&gt;dpkg-deb&lt;/code&gt;, &lt;code&gt;rpmbuild&lt;/code&gt; oder &lt;code&gt;hdiutil&lt;/code&gt; von Hand zu bedienen. Neu ist, dass &lt;code&gt;ship&lt;/code&gt; für macOS jetzt auch &lt;strong&gt;signiert und von Apple notarisieren lässt&lt;/strong&gt;. Das habe ich bei drei Apps benutzt: &lt;a href=&quot;https://jumplink.eu/Learn6502/&quot;&gt;Learn 6502 Assembly&lt;/a&gt;, &lt;a href=&quot;https://jumplink.eu/steuererklaerung/&quot;&gt;Steuererklärung&lt;/a&gt; und &lt;a href=&quot;https://jumplink.eu/beifahrer/&quot;&gt;Beifahrer&lt;/a&gt;. Alle drei gibt es jetzt als dmg für Apple Silicon und für Intel, und macOS öffnet sie ohne Warnung.&lt;/p&gt;
&lt;h3&gt;Ein Befehl pro Betriebssystem&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ship&lt;/code&gt; führt das &lt;code&gt;build&lt;/code&gt;-Skript deines Projekts aus, stellt eine Nutzlast zusammen und verpackt sie je Format. Welche Bibliotheken eine Linux-Distribution braucht, liest es aus deinem Bundle. Die Einstellungen stehen in einem &lt;code&gt;gjsify.ship&lt;/code&gt;-Block in der &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;gjsify&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; ship&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; linux&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --target&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; deb,rpm,appimage&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;gjsify&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; ship&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; darwin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --arch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; arm64&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --target&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; macos-app-zip,macos-app-dmg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linux bekommt &lt;code&gt;.deb&lt;/code&gt;, &lt;code&gt;.rpm&lt;/code&gt; und AppImage. Für den Mac entstehen eine &lt;code&gt;.app&lt;/code&gt; als &lt;code&gt;.zip&lt;/code&gt; und als &lt;code&gt;.dmg&lt;/code&gt;, eine Architektur pro Lauf. Die Apps tragen ihre Laufzeit selbst mit: Wer sie herunterlädt, braucht weder GJS noch GTK auf dem Rechner. Windows bekommt einen MSI-Installer. Den signiere ich noch nicht, dazu unten mehr.&lt;/p&gt;
&lt;h3&gt;Signieren und notarisieren&lt;/h3&gt;
&lt;p&gt;Ohne Signatur öffnet macOS eine heruntergeladene App nicht, das Quarantäne-Flag des Browsers lässt Gatekeeper sie ablehnen. Dafür brauchst du drei Dinge:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;eine Mitgliedschaft im Apple Developer Program,&lt;/li&gt;&lt;li&gt;ein Zertifikat vom Typ &lt;em&gt;Developer ID Application&lt;/em&gt; im Schlüsselbund,&lt;/li&gt;&lt;li&gt;einen Zugang für &lt;code&gt;notarytool&lt;/code&gt;, zum Beispiel einen App-Store-Connect-API-Schlüssel, abgelegt als Profil mit &lt;code&gt;xcrun notarytool store-credentials&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Dann kommen zwei Flags dazu:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;gjsify&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; ship&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; darwin&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --arch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; arm64&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --target&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; macos-app-dmg&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --sign&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;Developer ID Application: Dein Name (TEAMID)&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --notarize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; mein-notary-profil&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--sign&lt;/code&gt; signiert jedes ausführbare Bild in der App, das dmg-Image dazu. &lt;code&gt;--notarize&lt;/code&gt; schickt das Ergebnis an Apple, wartet auf die Freigabe und heftet das Ticket an die Datei. Fehlt die Identität, packt &lt;code&gt;ship&lt;/code&gt; ohne Signatur und sagt das laut. Ein stilles „signiert“ gibt es nicht.&lt;/p&gt;
&lt;p&gt;In CI läuft das auf einem Mac-Runner. Zertifikat und API-Schlüssel liegen als Secrets im Repository, der Job importiert sie in einen Wegwerf-Schlüsselbund. Bei mir hängen an jeder App fünf Secrets, und die Releases baut die CI. Danach prüft der Job pro Architektur &lt;code&gt;codesign --verify&lt;/code&gt;, &lt;code&gt;spctl&lt;/code&gt; mit gesetztem Quarantäne-Flag und &lt;code&gt;stapler validate&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Was ich unterwegs gelernt habe&lt;/h3&gt;
&lt;p&gt;Den Stolperstein habe ich bei Steuererklärung gefunden, und er lag im Werkzeug, nicht in der App: Der Umlaut im Namen machte die Signatur ungültig. &lt;code&gt;codesign&lt;/code&gt; leitet den Bezeichner des mitgelieferten Interpreters aus dem Dateinamen ab, und das dmg speichert Namen anders zerlegt als das Siegel sie berechnet hat. Das &lt;code&gt;.zip&lt;/code&gt; war in Ordnung, dieselbe App im eingehängten dmg nicht. Notarisierung und &lt;code&gt;stapler validate&lt;/code&gt; bestehen trotzdem, erst Gatekeeper lehnt die App beim Start ab. &lt;code&gt;ship&lt;/code&gt; behandelt beides inzwischen selbst (&lt;a href=&quot;https://github.com/gjsify/gjsify/pull/2466&quot;&gt;#2466&lt;/a&gt;, &lt;a href=&quot;https://github.com/gjsify/gjsify/pull/2480&quot;&gt;#2480&lt;/a&gt;, enthalten ab gjsify 0.64.14), und ein Test mountet ein dmg mit Umlaut in den Dateinamen und prüft die Signatur darin. Du musst dafür nichts tun, auch nicht bei einem Namen wie „Steuererklärung“.&lt;/p&gt;
&lt;p&gt;Die Lehre daraus gilt für jede Auslieferung: Prüfe das fertige dmg auf einem echten Mac. Ich nehme das MacBook für arm64 und eine macOS-VM für Intel. Beide bekommen das Quarantäne-Flag wie nach einem Browser-Download, dann &lt;code&gt;spctl&lt;/code&gt; und &lt;code&gt;codesign --verify --deep --strict&lt;/code&gt; auf der App im eingehängten Image. Eine grüne CI hätte den Fehler allein nicht gezeigt.&lt;/p&gt;
&lt;h3&gt;Und Windows?&lt;/h3&gt;
&lt;p&gt;Das MSI baut &lt;code&gt;ship&lt;/code&gt; schon, und die CI installiert und startet es testweise. Es ist aber unsigniert, und Windows warnt davor. Das Zertifikat von Microsoft steht noch aus, danach folgt die Anbindung an die CI.&lt;/p&gt;
&lt;p&gt;Mehr zu den Formaten steht in der Anleitung &lt;a href=&quot;https://gjsify.org/gjsify/ship/&quot;&gt;Ship your app&lt;/a&gt;.&lt;/p&gt;</content>
    <category term="gjsify"/>
    <category term="macOS"/>
  </entry>
</feed>