diff --git a/mac/package.sh b/mac/package.sh index 88c409c..af1f44b 100644 --- a/mac/package.sh +++ b/mac/package.sh @@ -25,8 +25,8 @@ cp "$BUILD_DIR/SonioxVoice" "$APP_BUNDLE/Contents/MacOS/SonioxVoice" cp "$PROJECT_DIR/Info.plist" "$APP_BUNDLE/Contents/Info.plist" cp "$PROJECT_DIR/resources/AppIcon.icns" "$APP_BUNDLE/Contents/Resources/AppIcon.icns" -# 3. Ad-hoc Codesign -codesign --force --deep --sign - "$APP_BUNDLE" +# 3. Stable Codesign with explicit identifier +codesign --force --deep --sign - --identifier "com.soniox.voice" "$APP_BUNDLE" echo "✅ App bundle assembled at $APP_BUNDLE" @@ -52,4 +52,3 @@ rm -rf "/Applications/$APP_NAME.app" cp -R "$APP_BUNDLE" "/Applications/$APP_NAME.app" echo "🎉 All Done Successfully!" -ls -lh "$BUILD_DIR" diff --git a/mac/src/AppDelegate.swift b/mac/src/AppDelegate.swift index 95bc189..f01a141 100644 --- a/mac/src/AppDelegate.swift +++ b/mac/src/AppDelegate.swift @@ -10,6 +10,7 @@ public final class AppDelegate: NSObject, NSApplicationDelegate { private var isBusyFinalizing = false private var currentAudioLevel: Float = 0.0 private var latestPartialText: String? = nil + private var permissionPollTimer: Timer? // Remote Android Phone Local Receiver (Port 8999) private var remoteListener: NWListener? @@ -135,6 +136,34 @@ public final class AppDelegate: NSObject, NSApplicationDelegate { } private func checkInitialPermissions() { + // 1. Force macOS to trigger the system Accessibility prompt dialog! + let axOptions = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true] as CFDictionary + let axTrusted = AXIsProcessTrustedWithOptions(axOptions) + print("AppDelegate: 🔒 Accessibility Permission Status (trusted: \(axTrusted))") + + if !axTrusted { + print("AppDelegate: ⚠️ Accessibility not yet granted! Prompting user and monitoring...") + // Open Accessibility pane directly + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + if let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility") { + NSWorkspace.shared.open(url) + } + } + + // Poll every 1.5 seconds until user toggles the switch + permissionPollTimer = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: true) { [weak self] timer in + let nowTrusted = AXIsProcessTrusted() + if nowTrusted { + print("AppDelegate: 🟢 Accessibility Permission GRANTED by user!") + timer.invalidate() + self?.permissionPollTimer = nil + HotkeyManager.shared.registerHotkeys() + HUDOverlayController.shared.show(state: .success(text: "دسترسی Accessibility تایید شد ✅")) + } + } + } + + // 2. Microphone permission audioRecorder.requestMicrophonePermission { granted in if !granted { print("Warning: Microphone permission not granted.")