Skip to content

Commit 94ae18b

Browse files
feat(darwin): package macOS application as .app bundle to eliminate terminal launch
1 parent 8349d3c commit 94ae18b

3 files changed

Lines changed: 104 additions & 7 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ jobs:
3737
arch: arm64
3838
goarch: arm64
3939
binary_name: ipMonitorApp
40-
asset_name: ipMonitorApp-darwin-arm64.tar.gz
40+
asset_name: ipMonitorApp-darwin-arm64.zip
4141

4242
# macOS Intel (amd64) via compilação nativa no runner macOS
4343
- os: darwin
4444
runner: macos-latest
4545
arch: amd64
4646
goarch: amd64
4747
binary_name: ipMonitorApp
48-
asset_name: ipMonitorApp-darwin-amd64.tar.gz
48+
asset_name: ipMonitorApp-darwin-amd64.zip
4949

5050
steps:
5151
- name: Checkout repositório
@@ -74,8 +74,8 @@ jobs:
7474
go build -ldflags="-s -w -H=windowsgui" -o ${{ matrix.binary_name }} .
7575
Compress-Archive -Path ${{ matrix.binary_name }} -DestinationPath ${{ matrix.asset_name }}
7676
77-
- name: Compilar Binário (Linux / macOS)
78-
if: matrix.os != 'windows'
77+
- name: Compilar Binário (Linux)
78+
if: matrix.os == 'linux'
7979
env:
8080
CGO_ENABLED: '1'
8181
GOARCH: ${{ matrix.arch }}
@@ -84,6 +84,44 @@ jobs:
8484
chmod +x ${{ matrix.binary_name }}
8585
tar -czvf ${{ matrix.asset_name }} ${{ matrix.binary_name }}
8686
87+
- name: Compilar e Empacotar .app Bundle (macOS)
88+
if: matrix.os == 'darwin'
89+
env:
90+
CGO_ENABLED: '1'
91+
GOARCH: ${{ matrix.arch }}
92+
run: |
93+
# 1. Compila o binário Go nativo
94+
go build -ldflags="-s -w" -o ${{ matrix.binary_name }} .
95+
chmod +x ${{ matrix.binary_name }}
96+
97+
# 2. Converte ícone PNG para .icns nativo do macOS usando iconutil
98+
mkdir -p AppIcon.iconset
99+
sips -z 16 16 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_16x16.png
100+
sips -z 32 32 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_16x16@2x.png
101+
sips -z 32 32 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_32x32.png
102+
sips -z 64 64 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_32x32@2x.png
103+
sips -z 128 128 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_128x128.png
104+
sips -z 256 256 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_128x128@2x.png
105+
sips -z 256 256 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_256x256.png
106+
sips -z 512 512 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_256x256@2x.png
107+
sips -z 512 512 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_512x512.png
108+
sips -z 1024 1024 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_512x512@2x.png
109+
iconutil -c icns AppIcon.iconset -o AppIcon.icns
110+
rm -rf AppIcon.iconset
111+
112+
# 3. Monta a estrutura oficial do macOS .app
113+
APP_BUNDLE="IP Monitor.app"
114+
mkdir -p "$APP_BUNDLE/Contents/MacOS"
115+
mkdir -p "$APP_BUNDLE/Contents/Resources"
116+
117+
cp "${{ matrix.binary_name }}" "$APP_BUNDLE/Contents/MacOS/${{ matrix.binary_name }}"
118+
cp build/darwin/Info.plist "$APP_BUNDLE/Contents/Info.plist"
119+
cp AppIcon.icns "$APP_BUNDLE/Contents/Resources/AppIcon.icns"
120+
rm -f AppIcon.icns
121+
122+
# 4. Compacta o .app em ZIP preservando permissões de execução
123+
ditto -c -k --keepParent "$APP_BUNDLE" "${{ matrix.asset_name }}"
124+
87125
- name: Upload Artifact temporário
88126
uses: actions/upload-artifact@v4
89127
with:

‎Makefile‎

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ else
2121
UNAME_S := $(shell uname -s)
2222
ifeq ($(UNAME_S),Darwin)
2323
DETECTED_OS := macOS (Darwin)
24+
APP_BUNDLE := "IP Monitor.app"
2425
else
2526
DETECTED_OS := Linux
2627
endif
@@ -29,14 +30,14 @@ else
2930
LDFLAGS := -s -w
3031
export CGO_ENABLED := 1
3132

32-
RM_CMD = rm -f $(BINARY)
33+
RM_CMD = rm -rf $(BINARY) $(APP_BUNDLE)
3334
RUN_CMD = ./$(BINARY)
3435
endif
3536

3637
# ------------------------------------------------------------------------------
3738
# Alvos
3839
# ------------------------------------------------------------------------------
39-
.PHONY: all build run test clean info
40+
.PHONY: all build run test clean info bundle-mac
4041

4142
all: build
4243

@@ -50,17 +51,43 @@ info:
5051
build: info
5152
@echo Compilando executavel unico e portatil...
5253
go build -ldflags="$(LDFLAGS)" -o $(BINARY) $(SRC)
54+
ifeq ($(DETECTED_OS),macOS (Darwin))
55+
@echo Empacotando $(APP_BUNDLE)...
56+
@mkdir -p $(APP_BUNDLE)/Contents/MacOS $(APP_BUNDLE)/Contents/Resources
57+
@cp $(BINARY) $(APP_BUNDLE)/Contents/MacOS/$(BINARY)
58+
@cp build/darwin/Info.plist $(APP_BUNDLE)/Contents/Info.plist
59+
@if [ -f internal/assets/icons/app-icon.png ]; then \
60+
mkdir -p AppIcon.iconset; \
61+
sips -z 16 16 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_16x16.png >/dev/null 2>&1 || true; \
62+
sips -z 32 32 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_16x16@2x.png >/dev/null 2>&1 || true; \
63+
sips -z 32 32 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_32x32.png >/dev/null 2>&1 || true; \
64+
sips -z 64 64 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_32x32@2x.png >/dev/null 2>&1 || true; \
65+
sips -z 128 128 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_128x128.png >/dev/null 2>&1 || true; \
66+
sips -z 256 256 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_128x128@2x.png >/dev/null 2>&1 || true; \
67+
sips -z 256 256 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_256x256.png >/dev/null 2>&1 || true; \
68+
sips -z 512 512 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_256x256@2x.png >/dev/null 2>&1 || true; \
69+
sips -z 512 512 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_512x512.png >/dev/null 2>&1 || true; \
70+
sips -z 1024 1024 internal/assets/icons/app-icon.png --out AppIcon.iconset/icon_512x512@2x.png >/dev/null 2>&1 || true; \
71+
iconutil -c icns AppIcon.iconset -o $(APP_BUNDLE)/Contents/Resources/AppIcon.icns >/dev/null 2>&1 || true; \
72+
rm -rf AppIcon.iconset; \
73+
fi
74+
@echo Pacote $(APP_BUNDLE) criado com sucesso!
75+
endif
5376
@echo Build concluido com sucesso: $(BINARY)
5477

5578
run: build
5679
@echo Iniciando $(BINARY)...
80+
ifeq ($(DETECTED_OS),macOS (Darwin))
81+
open $(APP_BUNDLE)
82+
else
5783
$(RUN_CMD)
84+
endif
5885

5986
test:
6087
@echo Executando testes unitarios...
6188
go test -v ./...
6289

6390
clean:
64-
@echo Removendo binario $(BINARY)...
91+
@echo Removendo arquivos de build...
6592
$(RM_CMD)
6693
@echo Limpeza concluida.

‎build/darwin/Info.plist‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundlePackageType</key>
6+
<string>APPL</string>
7+
<key>CFBundleName</key>
8+
<string>IP Monitor</string>
9+
<key>CFBundleDisplayName</key>
10+
<string>IP Monitor</string>
11+
<key>CFBundleExecutable</key>
12+
<string>ipMonitorApp</string>
13+
<key>CFBundleIdentifier</key>
14+
<string>com.ademartellecher.ipmonitorapp</string>
15+
<key>CFBundleVersion</key>
16+
<string>2.3.2</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>2.3.2</string>
19+
<key>CFBundleIconFile</key>
20+
<string>AppIcon</string>
21+
<key>LSMinimumSystemVersion</key>
22+
<string>10.13.0</string>
23+
<key>NSHighResolutionCapable</key>
24+
<true/>
25+
<key>NSSupportsAutomaticGraphicsSwitching</key>
26+
<true/>
27+
<key>LSUIElement</key>
28+
<false/>
29+
<key>NSHumanReadableCopyright</key>
30+
<string>Copyright © 2026 Ademar Tellecher. All rights reserved.</string>
31+
</dict>
32+
</plist>

0 commit comments

Comments
 (0)