Compare commits

...
Author SHA1 Message Date
forge-recoveryandClaude Sonnet 5.5 d748647e9b ci: build the unit-test target on Xcode 27 and baseline approved historical secret findings
KofTwentyTwo/ci-policy: ci / fork-guard (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / go-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / go-nix-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / gradle-2 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / gradle-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / java-docker-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / java-maven-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / manifests-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / nix-7 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / node-8 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / python-9 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-10 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-11 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-12 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-2 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-7 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / not-enrolled (pull_request) Skipped
KofTwentyTwo/ci-policy: native / fork-deny (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: Shared source and config CI / verify (pull_request) Failing after 17s
KofTwentyTwo/ci-policy: Shared Swift CI / verify (pull_request) Failing after 18s
KofTwentyTwo/ci-policy: Shared source and config CI / secrets (pull_request) Successful in 45s
KofTwentyTwo/ci-policy: Shared Swift CI / secrets (pull_request) Successful in 46s
KofTwentyTwo/ci-policy: Shared source and config CI / gate (pull_request) Failing after 11s
KofTwentyTwo/ci-policy: ci / source-config-13 (pull_request) Failing after 58s
KofTwentyTwo/ci-policy: Shared Swift CI / gate (pull_request) Failing after 12s
KofTwentyTwo/ci-policy: native / swift-2 (pull_request) Failing after 59s
KofTwentyTwo/ci-policy: ci / ci-result (pull_request) Failing after 8s
KofTwentyTwo/ci-policy: native / native-result (pull_request) Failing after 8s
- config/test-base.xcconfig (unit-tests target only): MACOSX_DEPLOYMENT_TARGET 10.13 -> 12.0, the lowest Xcode 27.2 supports. The shipping app keeps 10.13 in config/base.xcconfig (also read by scripts/update_appcast.sh).
- Same file: deprecation warnings (APIs deprecated in macOS 11/12 and used by the 10.13 app code) are downgraded for the test build only, via -warnings-as-errors followed by -Wwarning DeprecatedDeclaration; every other warning stays an error.
- .gitleaksignore: the six exact historical fingerprints from the central scan, no patterns.

Guards A (Test scheme), B (LicenseManager depaywall markers) and C (conflict markers) are unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-01 22:11:41 +00:00
semantic-release-bot dc40fa43bc chore(release): 100.2.1 [skip ci]
## [100.2.1](https://github.com/KofTwentyTwo/CommandTabFree/compare/v100.2.0...v100.2.1) (2026-06-16)
2026-06-16 21:21:18 +00:00
james.maes 2ae7ded357 docs: record auto-update live, cask v100.2.0, release-gate decouple
Reflect v100.2.0 (auto-update via the GitHub Pages feed), the Homebrew cask bump, and the will-release gating that lets non-release pushes build and test without cutting a release.
2026-06-16 16:16:42 -05:00
james.maes dd15f22031 ci: gate release apparatus on semantic-release will-release decision
determine_next_version.sh writes an empty VERSION.txt when no commit since the last tag is release-worthy; gate cert-import/sign-build/notarize/appcast/release (and version injection) on that, so non-release pushes build+test without cutting a release or needing [skip ci].
2026-06-16 16:11:32 -05:00
semantic-release-bot 4ecfc4606f chore(release): 100.2.0 [skip ci]
# [100.2.0](https://github.com/KofTwentyTwo/CommandTabFree/compare/v100.1.0...v100.2.0) (2026-06-16)

### Features

* **updates:** enable Sparkle auto-update via GitHub Pages appcast ([45457cb](https://github.com/KofTwentyTwo/CommandTabFree/commit/45457cb))
2026-06-16 21:05:45 +00:00
james.maes 45457cb313 feat(updates): enable Sparkle auto-update via GitHub Pages appcast
Point DOMAIN at the repo's GitHub Pages site (serves the gh-pages appcast.xml), enable SUEnableAutomaticChecks, and remove the in-tree appcast skeleton (feed is published out-of-tree). Ships an auto-updating build.
2026-06-16 16:02:04 -05:00
james.maes 62e0226f01 ci: stop release tail clobbering .fork-sync-state cursor [skip ci]
Reset .fork-sync-state to v11.3.0 (last-synced upstream tag) and remove the release-tail step that overwrote it with the fork release tag, which would stall upstream-sync. Update SESSION-STATE/TODO/CICD-STATUS/README for the live signed+notarized v100.1.0 release.
2026-06-16 15:32:55 -05:00
github-actions[bot] 92254c021f chore(sync-state): advance to v100.1.0 [skip ci] 2026-06-16 19:48:28 +00:00
semantic-release-bot 0aca4d9400 chore(release): 100.1.0 [skip ci]
# [100.1.0](https://github.com/KofTwentyTwo/CommandTabFree/compare/v100.0.3...v100.1.0) (2026-06-16)

### Bug Fixes

* **ci:** build ad-hoc until Apple cert provisioned ([6070f0c](https://github.com/KofTwentyTwo/CommandTabFree/commit/6070f0c))
* **l10n:** regenerate base Localizable.strings from source ([d1e1b29](https://github.com/KofTwentyTwo/CommandTabFree/commit/d1e1b29))

### Features

* **release:** sign + notarize with fork Developer ID ([2f9fac1](https://github.com/KofTwentyTwo/CommandTabFree/commit/2f9fac1))
2026-06-16 19:48:19 +00:00
james.maes 2f9fac17b7 feat(release): sign + notarize with fork Developer ID
Set the fork Developer ID in config/local.xcconfig (Manual style + team), re-sign the vendored Sparkle helpers under it, and import the cert with an optional APPLE_P12_PASSWORD. Built, signed, and notarized (Accepted) locally before cutting.
2026-06-16 14:42:45 -05:00
james.maes 4a007e88c9 docs: add owner-gated TODO; tidy SESSION-STATE
Capture the owner-gated remaining work (publishing pipeline blockers) in docs/TODO.md; make SESSION-STATE HEAD reference hash-stable.
2026-06-16 12:55:22 -05:00
james.maes 885c52567d docs: record CI green + ad-hoc build fix + sync labels
Push CI is fully green (run 27634828800). NEXT SESSION blocker resolved; remaining work is owner-gated only.
2026-06-16 12:16:12 -05:00
james.maes 6070f0cbb9 fix(ci): build ad-hoc until Apple cert provisioned
Release build inherited upstream's Developer ID and failed on CI (exit 65, no cert). Build ad-hoc when the release gate is not signing-ready; build_app.sh now forwards xcodebuild overrides. Auto-switches to signed when the owner adds the cert.
2026-06-16 12:08:05 -05:00
james.maes d1e1b29623 fix(l10n): regenerate base Localizable.strings from source
Base strings drifted from source after the About redesign and brand sweep; regenerating via genstrings unblocks the generated-files CI gate. Dead paywall strings stay upstream-branded to keep merge surface minimal.
2026-06-15 15:22:49 -05:00
james.maes 2588101096 docs: correct CI/CD status + add NEXT SESSION handoff 2026-06-15 15:07:12 -05:00
james.maes 6313c295f3 docs: record CI/CD wiring + Guard B fix (green on unblocked) 2026-06-15 14:55:24 -05:00
james.maes d3e7529d91 ci: fix Guard B to match shipped de-paywall patch (guard-false-else + depaywall marker) 2026-06-15 14:52:09 -05:00
james.maes 287c4a07c4 ci: gate release tail on owner secrets (push CI green until then); sign_update --ed-key-file; commitlint sync-merge ignores; drop upstream-only scripts 2026-06-15 14:45:14 -05:00
james.maes eb95ad2d52 docs(readme): note .dmg/.zip direct-download install option 2026-06-15 14:31:18 -05:00
james.maes b9e871f176 chore: repo renamed alt-tab-free → CommandTabFree (update URLs); drop JetBrains sponsor from README 2026-06-15 14:13:53 -05:00
james.maes 39f10cfba3 docs: mark ⌘⇥ app icon as final (owner-approved), drop real-artwork TODO 2026-06-15 14:05:16 -05:00
james.maes 5b590bd6e5 docs: README install section + mark §3.1 brand/l10n/icon items done 2026-06-15 14:00:35 -05:00
james.maes 0b6d389842 docs: bump SESSION-STATE to v100.0.3 (full l10n rebrand) 2026-06-15 13:44:18 -05:00
james.maes adcd7c5f93 l10n: rebrand AltTab→CommandTabFree across all language tables (attribution kept) 2026-06-15 13:13:16 -05:00
james.maes b2cad34a6a docs: bump SESSION-STATE to v100.0.2 (menu icon, About redesign, l10n tidy) 2026-06-15 13:08:42 -05:00
james.maes 76ef4e49a5 l10n: rebrand AltTab→CommandTabFree in base+en strings (attribution kept) 2026-06-15 12:52:50 -05:00
james.maes acef128bbd feat(about): KofTwentyTwo identity + AltTab attribution links; drop Support button 2026-06-15 12:43:11 -05:00
james.maes 7f2a483ad2 brand: menu bar icons → command-tab (⌘⇥) glyph, matching app icon 2026-06-15 12:16:32 -05:00
james.maes 0b021beda7 chore: gitignore vendor/*/build (Xcode per-package output) 2026-06-15 11:58:47 -05:00
james.maes 4c169ef3d7 docs: record v100.0.1 release, brew tap, Sparkle key wiring + build gotcha 2026-06-15 11:57:32 -05:00
james.maes c7d2d9681e feat(sparkle): wire fork EdDSA public key; disable auto-checks 2026-06-15 11:42:28 -05:00
james.maes edf499d19e docs: session-state handoff (depaywall-free) 2026-06-15 09:53:20 -05:00
james.maes 98a023aa03 brand: placeholder app icon (command-tab glyph) + fix scheme product name to CommandTabFree.app 2026-06-15 08:57:37 -05:00
james.maesandClaude Opus 4.8 f5f9034d41 brand: rename user-facing AltTab → CommandTabFree, update About dialog (upstream attribution preserved)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 08:55:39 -05:00
james.maes e2429096d7 build: default CURRENT_PROJECT_VERSION=0.0.0 for local builds (App.version crash) 2026-06-15 08:51:15 -05:00
james.maes 4d82a684f3 chore: set fork identity — CommandTabFree / com.koftwentytwo.commandtabfree (frozen) 2026-06-10 17:03:12 -05:00
james.maes 6795ff43fb docs: mark Test scheme GREEN — 16 legacy paywall tests resolved (1a914c88) 2026-06-10 13:57:20 -05:00
james.maes 1a914c88f5 test: skip legacy paywall-behaviour tests (depaywall) — Test scheme green, anti-relock guards still active 2026-06-10 13:55:21 -05:00
james.maes 5c57cc738b docs: execution status + owner publish checklist (Test scheme RED on 16 legacy paywall tests — flagged BLOCKING) 2026-06-10 13:43:53 -05:00
james.maes 3dde8a91b6 chore: identity overlay + sync/guard/release CI scaffolding (placeholders flagged for owner) 2026-06-10 13:38:09 -05:00
james.maesandClaude Opus 4.8 4506c53958 test: anti-relock guards (pro never locked, incl. post-trial-expiry)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 13:32:00 -05:00
james.maes f3d7685984 depaywall: neutralize license gate, cookie, telemetry, and activate handler (src/pro left intact) 2026-06-10 13:29:52 -05:00
james.maes e243fb4bff docs: audit + republish/maintained-fork plans 2026-06-10 13:27:36 -05:00
semantic-release-bot 9fadf36bf8 chore(release): 11.3.0 [skip ci]
# [11.3.0](https://github.com/lwouis/alt-tab-macos/compare/v11.2.0...v11.3.0) (2026-06-04)

### Features

* better support adobe apps (closes [#5707](https://github.com/lwouis/alt-tab-macos/issues/5707)) ([f3fe535](https://github.com/lwouis/alt-tab-macos/commit/f3fe535))
2026-06-04 20:33:23 +00:00
lwouis f3fe535acb feat: better support adobe apps (closes #5707) 2026-06-04 21:56:59 +02:00
semantic-release-bot 8124cf5496 chore(release): 11.2.0 [skip ci]
# [11.2.0](https://github.com/lwouis/alt-tab-macos/compare/v11.1.0...v11.2.0) (2026-06-04)

### Bug Fixes

* always persist menubar icon removal from dragging ([#5654](https://github.com/lwouis/alt-tab-macos/issues/5654)) ([a354fde](https://github.com/lwouis/alt-tab-macos/commit/a354fde))
* better handle some shortcut conflicts (related to 3059dc23) ([cddc89d](https://github.com/lwouis/alt-tab-macos/commit/cddc89d))
* command+tab would sometimes not bind correctly (closes [#5653](https://github.com/lwouis/alt-tab-macos/issues/5653)) ([c75aac5](https://github.com/lwouis/alt-tab-macos/commit/c75aac5))
* focus issues with show-main-window setting (closes [#5684](https://github.com/lwouis/alt-tab-macos/issues/5684)) ([0899f61](https://github.com/lwouis/alt-tab-macos/commit/0899f61))
* improve processing of accessibility events (closes [#5665](https://github.com/lwouis/alt-tab-macos/issues/5665)) ([e0b1778](https://github.com/lwouis/alt-tab-macos/commit/e0b1778))
* only show screen recording callout when it's needed (closes [#5623](https://github.com/lwouis/alt-tab-macos/issues/5623)) ([9a9994b](https://github.com/lwouis/alt-tab-macos/commit/9a9994b))
* preserve switcher selection across reorders (closes [#5665](https://github.com/lwouis/alt-tab-macos/issues/5665)) ([5bd746d](https://github.com/lwouis/alt-tab-macos/commit/5bd746d))
* settings window search and controls editor edge-cases ([c143ec2](https://github.com/lwouis/alt-tab-macos/commit/c143ec2))
* text shortcuts like cmd+a work in search mode (closes [#5675](https://github.com/lwouis/alt-tab-macos/issues/5675)) ([d483c5a](https://github.com/lwouis/alt-tab-macos/commit/d483c5a))
* very minor memory leak ([7d60d55](https://github.com/lwouis/alt-tab-macos/commit/7d60d55))

### Features

* do not repeat title if window title is app name (closes [#5672](https://github.com/lwouis/alt-tab-macos/issues/5672)) ([30eb5f2](https://github.com/lwouis/alt-tab-macos/commit/30eb5f2))

### Performance Improvements

* carry (pid, wid) in AX subscription refcon to skip identity calls ([a39816e](https://github.com/lwouis/alt-tab-macos/commit/a39816e))
* improve performance of the settings window ([3059dc2](https://github.com/lwouis/alt-tab-macos/commit/3059dc2))
2026-06-04 11:59:20 +00:00
lwouis cddc89dd21 fix: better handle some shortcut conflicts (related to 3059dc23) 2026-06-04 13:55:22 +02:00
lwouis 83b5ddc091 refactor: move debug-menu into qa-menu, and update it 2026-06-03 21:18:31 +02:00
lwouis 7d60d55395 fix: very minor memory leak 2026-06-03 21:17:45 +02:00
lwouis e0b1778db7 fix: improve processing of accessibility events (closes #5665) 2026-06-01 08:34:12 +02:00
lwouis 9a9994bf28 fix: only show screen recording callout when it's needed (closes #5623) 2026-06-01 08:34:12 +02:00
lwouis a39816e303 perf: carry (pid, wid) in AX subscription refcon to skip identity calls
AXObserverAddNotification's refcon was always nil. Bake the owning identity into it at subscribe time so the AX callback gets (pid, wid) for free, instead of an element.pid()/cgWindowId() round-trip per event. Window-level subscriptions carry a real wid; app-level subscriptions carry wid 0, so focus/main/created still resolve their per-event subject window from the element. Notably this gives a reliable wid for kAXUIElementDestroyed, which previously had to query an already-dead element.
2026-05-30 21:51:13 +02:00
lwouis c143ec2f0c fix: settings window search and controls editor edge-cases 2026-05-30 19:38:20 +02:00
lwouis 83f8ae18fa refactor: remove very minor leak or flagged-as-leak 2026-05-28 21:04:48 +02:00
lwouis f006b26931 refactor: improve specs/tests coverage 2026-05-28 19:28:49 +02:00
lwouis e4a306dc8c refactor: prevent appkit rare crashes due to in-flight tooltips 2026-05-28 14:11:14 +02:00
lwouis c75aac585a fix: command+tab would sometimes not bind correctly (closes #5653) 2026-05-28 14:00:57 +02:00
lwouis 60cca89bb8 refactor: add specs and coverage; move tests close to files 2026-05-28 14:00:57 +02:00
lwouis 0899f61654 fix: focus issues with show-main-window setting (closes #5684) 2026-05-28 13:56:51 +02:00
lwouis 3059dc2356 perf: improve performance of the settings window 2026-05-28 13:56:50 +02:00
lwouis 5bd746d342 fix: preserve switcher selection across reorders (closes #5665)
Async AX events (focused-window changed, app activated) can fire during
the switcher's show path and reorder Windows.list under the panel. The
old updateSelectedWindow short-circuited to the initial-pick path
whenever the lowest-lastFocusOrder window changed mid-show, throwing
away the user's selectedTarget and re-picking the default. Visible slot
swap plus highlight jump; if the user released keys early they landed
on the wrong window.

Extract a pure-function kernel (SelectionResolver) covering the full
selection state machine and replace updateSelectedWindow with a thin
snapshot/decide/apply wrapper. The actual fix is dropping the
focusedWindowChangedWhileShowing arm of shouldSelectFromScratch: the
list still reorders (Photoshop finishing launch is fresh state the
user wants reflected), but the existing target-by-id lookup re-resolves
the user's pick at its new index instead of being skipped.

28 new SelectionResolverTests lock down every selection path: initial
pick rules, target preservation across reorders (#5665 regressions),
target removal, search-mode flags, edge cases.

Also adds minimal Appearance and SettingsSearchIndex stubs to Mocks.swift
so the unit-test target builds. ProBadgeView and LightLabel referenced
those types without the underlying source being in the test target.
2026-05-28 13:56:50 +02:00
lwouis 9a47672920 refactor: log results of carbon shortcut apis (#5653) 2026-05-28 13:56:49 +02:00
lwouis a354fdecc8 fix: always persist menubar icon removal from dragging (#5654) 2026-05-28 13:56:49 +02:00
lwouis d483c5aa88 fix: text shortcuts like cmd+a work in search mode (closes #5675) 2026-05-28 13:56:48 +02:00
lwouis 30eb5f2116 feat: do not repeat title if window title is app name (closes #5672) 2026-05-28 13:56:48 +02:00
semantic-release-bot 14acc0ce7d chore(release): 11.1.0 [skip ci]
# [11.1.0](https://github.com/lwouis/alt-tab-macos/compare/v11.0.1...v11.1.0) (2026-05-25)

### Bug Fixes

* better handle electron apps hidden windows (closes [#5449](https://github.com/lwouis/alt-tab-macos/issues/5449)) ([0434679](https://github.com/lwouis/alt-tab-macos/commit/0434679))
* improve tab detection (closes [#5618](https://github.com/lwouis/alt-tab-macos/issues/5618)) ([a8098c3](https://github.com/lwouis/alt-tab-macos/commit/a8098c3))
* rare crash when assigning shortcuts with arrow keys ([4977808](https://github.com/lwouis/alt-tab-macos/commit/4977808))
* rare crash when capturing window thumbnails ([f4a54c8](https://github.com/lwouis/alt-tab-macos/commit/f4a54c8))
* very rare crash on quit ([007edc6](https://github.com/lwouis/alt-tab-macos/commit/007edc6))

### Features

* support setups with non latin keyboard layouts (closes [#5607](https://github.com/lwouis/alt-tab-macos/issues/5607)) ([f0e195d](https://github.com/lwouis/alt-tab-macos/commit/f0e195d))
2026-05-25 11:42:42 +00:00
lwouis 04346790b8 fix: better handle electron apps hidden windows (closes #5449) 2026-05-25 11:37:54 +02:00
lwouis f49250aa45 refactor: silence swiftui logs when debugging 2026-05-25 10:53:39 +02:00
lwouis a8098c39db fix: improve tab detection (closes #5618) 2026-05-25 10:36:56 +02:00
lwouis f0e195d0de feat: support setups with non latin keyboard layouts (closes #5607) 2026-05-25 09:41:46 +02:00
lwouis 49778089ea fix: rare crash when assigning shortcuts with arrow keys 2026-05-25 09:35:27 +02:00
lwouis f4a54c8f1b fix: rare crash when capturing window thumbnails 2026-05-24 22:00:29 +02:00
lwouis 007edc624e fix: very rare crash on quit 2026-05-24 21:14:39 +02:00
lwouis b6af54425e refactor: remove references to poeditor files we removed 2026-05-24 17:41:34 +02:00
semantic-release-bot 146e2aec46 chore(release): 11.0.1 [skip ci]
## [11.0.1](https://github.com/lwouis/alt-tab-macos/compare/v11.0.0...v11.0.1) (2026-05-22)

### Bug Fixes

* cmd key could be stuck after switching (closes [#5650](https://github.com/lwouis/alt-tab-macos/issues/5650)) ([3a48a13](https://github.com/lwouis/alt-tab-macos/commit/3a48a13))
2026-05-22 17:12:59 +00:00
lwouis 3a48a13cb5 fix: cmd key could be stuck after switching (closes #5650) 2026-05-22 18:53:59 +02:00
lwouis 910288d149 ci: update github actions versions 2026-05-21 10:44:20 +02:00
semantic-release-bot 1f2b5a513e chore(release): 11.0.0 [skip ci]
# [11.0.0](https://github.com/lwouis/alt-tab-macos/compare/v10.12.0...v11.0.0) (2026-05-21)

### Features

* introducing alt-tab pro! ([9147a4a](https://github.com/lwouis/alt-tab-macos/commit/9147a4a)), closes [#5450](https://github.com/lwouis/alt-tab-macos/issues/5450) [#5539](https://github.com/lwouis/alt-tab-macos/issues/5539) [#5627](https://github.com/lwouis/alt-tab-macos/issues/5627) [#5509](https://github.com/lwouis/alt-tab-macos/issues/5509) [#5492](https://github.com/lwouis/alt-tab-macos/issues/5492) [#5585](https://github.com/lwouis/alt-tab-macos/issues/5585) [#5488](https://github.com/lwouis/alt-tab-macos/issues/5488) [#5583](https://github.com/lwouis/alt-tab-macos/issues/5583) [#5482](https://github.com/lwouis/alt-tab-macos/issues/5482) [#5313](https://github.com/lwouis/alt-tab-macos/issues/5313)

### BREAKING CHANGES

* announcement: https://github.com/lwouis/alt-tab-macos/discussions/5533

* improved performance, especially switcher responsiveness
* reduced battery usage even more
2026-05-21 08:28:52 +00:00
lwouis 9147a4a864 feat: introducing alt-tab pro!
BREAKING CHANGE: announcement: https://github.com/lwouis/alt-tab-macos/discussions/5533

* improved performance, especially switcher responsiveness
* reduced battery usage even more
* reduced ram usage (closes #5450, closes #5539, closes #5627)
* reduced app size even more
* polished many aspects of the ui; align more with liquid glass
* better handle "ghost" windows (closes #5509)
* fix issue with wrong window order (closes #5492)
* escape closes the switcher on tahoe (closes #5585)
* improve search matches (closes #5488)
* localizations trimmed and reviewed entirely (closes #5583)
* highlight matching app icons when searching, in addition to text
* better settings import/export
* reworked "send feedback" experience
* reworked exceptions ui (closes #5482)
* per-shortcut settings (closes #5313)
* rework about window
2026-05-21 10:21:25 +02:00
semantic-release-bot 317a485bcb chore(release): 10.12.0 [skip ci]
# [10.12.0](https://github.com/lwouis/alt-tab-macos/compare/v10.11.0...v10.12.0) (2026-04-13)

### Features

* remove the need to add email in feedback form ([da9a46b](https://github.com/lwouis/alt-tab-macos/commit/da9a46b))
* show usage stats in the about-window ([9c5b963](https://github.com/lwouis/alt-tab-macos/commit/9c5b963))
2026-04-13 09:03:24 +00:00
lwouis 20caf75096 ci: move appcast from github raw to website 2026-04-13 10:57:52 +02:00
lwouis 873aabec72 docs: add terms and privacy policies on website 2026-04-13 10:53:25 +02:00
lwouis da9a46bf49 feat: remove the need to add email in feedback form 2026-04-13 10:53:25 +02:00
lwouis 9c5b9630e8 feat: show usage stats in the about-window 2026-04-13 10:31:08 +02:00
semantic-release-bot 49a41bd66d chore(release): 10.11.0 [skip ci]
# [10.11.0](https://github.com/lwouis/alt-tab-macos/compare/v10.10.1...v10.11.0) (2026-04-08)

### Features

* add local usage stats for curious users ([8e07d26](https://github.com/lwouis/alt-tab-macos/commit/8e07d26))
2026-04-08 20:11:45 +00:00
lwouis 8e07d261b9 feat: add local usage stats for curious users 2026-04-08 22:02:28 +02:00
semantic-release-bot d222dbbb10 chore(release): 10.10.1 [skip ci]
## [10.10.1](https://github.com/lwouis/alt-tab-macos/compare/v10.10.0...v10.10.1) (2026-04-05)

### Bug Fixes

* about-alttab window would crash when opened (closes [#5491](https://github.com/lwouis/alt-tab-macos/issues/5491)) ([d5152fb](https://github.com/lwouis/alt-tab-macos/commit/d5152fb))
* rare crash sometimes when opening the app twice quickly ([47e6cbd](https://github.com/lwouis/alt-tab-macos/commit/47e6cbd))
* rare crash when scrolling some settings window views ([317d2ff](https://github.com/lwouis/alt-tab-macos/commit/317d2ff))
2026-04-05 15:40:34 +00:00
lwouis 47e6cbd987 fix: rare crash sometimes when opening the app twice quickly 2026-04-05 17:33:12 +02:00
lwouis 317d2ff78a fix: rare crash when scrolling some settings window views 2026-04-05 17:22:40 +02:00
lwouis d5152fba44 fix: about-alttab window would crash when opened (closes #5491) 2026-04-05 08:49:28 +02:00
lwouis 90cdd3544a ci: fix changelog broken by sitemap 2026-04-04 21:42:38 +02:00
lwouis 13340d82f6 ci: remove _redirects on cloudflare 2026-04-04 21:38:11 +02:00
semantic-release-bot 69f67ffeeb chore(release): 10.10.0 [skip ci]
# [10.10.0](https://github.com/lwouis/alt-tab-macos/compare/v10.9.0...v10.10.0) (2026-04-04)

### Bug Fixes

* better handle bugged apps with hidden windows (closes [#5296](https://github.com/lwouis/alt-tab-macos/issues/5296)) ([ff1e923](https://github.com/lwouis/alt-tab-macos/commit/ff1e923))
* improve reliability after sleep/wake ([1ab419d](https://github.com/lwouis/alt-tab-macos/commit/1ab419d))
* show more apps when adding an exception (closes [#5463](https://github.com/lwouis/alt-tab-macos/issues/5463)) ([41d608e](https://github.com/lwouis/alt-tab-macos/commit/41d608e))

### Features

* better recognizes tabbed windows ([170bd67](https://github.com/lwouis/alt-tab-macos/commit/170bd67))
* improve localizations ([fe6e52d](https://github.com/lwouis/alt-tab-macos/commit/fe6e52d))
* improved detection of windows and apps ([7a2a548](https://github.com/lwouis/alt-tab-macos/commit/7a2a548))
* update localizations ([ecafbe7](https://github.com/lwouis/alt-tab-macos/commit/ecafbe7))

### Performance Improvements

* improve badges retrieval ([edbbf20](https://github.com/lwouis/alt-tab-macos/commit/edbbf20))
2026-04-04 19:30:53 +00:00
lwouis fe6e52d691 feat: improve localizations 2026-04-04 21:26:45 +02:00
lwouis 6c35e10a66 ci: generate sitemap 2026-04-04 16:22:47 +02:00
lwouis 18b523e458 ci: migrate from netlify to cloudflare 2026-04-04 15:36:46 +02:00
lwouis 41d608efda fix: show more apps when adding an exception (closes #5463) 2026-03-29 18:22:52 +02:00
lwouis f1c59a2748 refactor: small improvements to concurrency 2026-03-28 17:21:10 +01:00
lwouis 0e897b0678 refactor: program main-menu instead of .xib
avoids SDK logs
not sure if easier to maintain though
2026-03-28 12:07:17 +01:00
lwouis 7a2a5482ae feat: improved detection of windows and apps
* find more windows and apps (e.g. apps that take 30s to launch)
* keep windows and apps more up-to-date
* more efficient, uses fewer resources
2026-03-28 11:57:48 +01:00
lwouis 170bd673e0 feat: better recognizes tabbed windows 2026-03-28 11:57:48 +01:00
lwouis ff1e92303a fix: better handle bugged apps with hidden windows (closes #5296) 2026-03-28 11:57:48 +01:00
lwouis edbbf2082c perf: improve badges retrieval 2026-03-28 11:57:48 +01:00
lwouis 1ab419dd09 fix: improve reliability after sleep/wake 2026-03-28 11:57:48 +01:00
lwouis 6bd5f26e1c refactor: improve logs for application discrimination 2026-03-24 11:35:05 +01:00
lwouis ecafbe7212 feat: update localizations 2026-03-22 18:51:57 +01:00
semantic-release-bot 173950af08 chore(release): 10.9.0 [skip ci]
# [10.9.0](https://github.com/lwouis/alt-tab-macos/compare/v10.8.0...v10.9.0) (2026-03-22)

### Bug Fixes

* panel may re-center when searching ([a1f8b18](https://github.com/lwouis/alt-tab-macos/commit/a1f8b18))

### Features

* new setting to not capture windows in background (closes [#5337](https://github.com/lwouis/alt-tab-macos/issues/5337)) ([5ed6c1d](https://github.com/lwouis/alt-tab-macos/commit/5ed6c1d)), closes [#5371](https://github.com/lwouis/alt-tab-macos/issues/5371)
* show better ui when there are no window (closes [#283](https://github.com/lwouis/alt-tab-macos/issues/283)) ([9f3e20a](https://github.com/lwouis/alt-tab-macos/commit/9f3e20a))
* update fr/en localizations ([630527e](https://github.com/lwouis/alt-tab-macos/commit/630527e))
2026-03-22 16:29:10 +00:00
lwouis 5ed6c1d9ce feat: new setting to not capture windows in background (closes #5337)
Also closes #5371
2026-03-22 17:19:19 +01:00
lwouis 630527e0b7 feat: update fr/en localizations 2026-03-22 17:19:19 +01:00
lwouis a1f8b18888 fix: panel may re-center when searching 2026-03-22 17:19:18 +01:00
lwouis 9f3e20a826 feat: show better ui when there are no window (closes #283) 2026-03-22 17:19:18 +01:00
lwouis dbc77fe214 ci: release notes should interpret markdown (closes #597) 2026-03-22 17:19:17 +01:00
semantic-release-bot be2de1ab83 chore(release): 10.8.0 [skip ci]
# [10.8.0](https://github.com/lwouis/alt-tab-macos/compare/v10.7.0...v10.8.0) (2026-03-20)

### Bug Fixes

* allow quitting multiple apps in a row (follow-up on [#5421](https://github.com/lwouis/alt-tab-macos/issues/5421)) ([56c1927](https://github.com/lwouis/alt-tab-macos/commit/56c1927))
* apps with no open window might not show up (closes [#5424](https://github.com/lwouis/alt-tab-macos/issues/5424)) ([8962ad1](https://github.com/lwouis/alt-tab-macos/commit/8962ad1))
* avoid repeating shortcut that was released (closes [#5429](https://github.com/lwouis/alt-tab-macos/issues/5429)) ([3b1c7c7](https://github.com/lwouis/alt-tab-macos/commit/3b1c7c7))
* switcher might show empty on rare occasions (closes [#5432](https://github.com/lwouis/alt-tab-macos/issues/5432)) ([6105bb3](https://github.com/lwouis/alt-tab-macos/commit/6105bb3))
* window order in the switcher might be incorrect ([#5346](https://github.com/lwouis/alt-tab-macos/issues/5346)) ([545d81d](https://github.com/lwouis/alt-tab-macos/commit/545d81d))

### Features

* allow next-window shortcut without modifiers (closes [#5433](https://github.com/lwouis/alt-tab-macos/issues/5433)) ([15ede93](https://github.com/lwouis/alt-tab-macos/commit/15ede93))
* stabilize ui during search (closes [#5431](https://github.com/lwouis/alt-tab-macos/issues/5431)) ([7dd11cf](https://github.com/lwouis/alt-tab-macos/commit/7dd11cf))
2026-03-20 20:57:34 +00:00
lwouis 56c1927584 fix: allow quitting multiple apps in a row (follow-up on #5421) 2026-03-20 21:52:24 +01:00
lwouis 7dd11cff01 feat: stabilize ui during search (closes #5431) 2026-03-20 21:52:24 +01:00
lwouis 15ede93868 feat: allow next-window shortcut without modifiers (closes #5433) 2026-03-20 21:52:23 +01:00
lwouis 4502e8bd15 refactor: improve logging of window discriminator logic 2026-03-20 21:52:23 +01:00
lwouis 6105bb30ad fix: switcher might show empty on rare occasions (closes #5432) 2026-03-20 21:52:22 +01:00
lwouis 545d81d872 fix: window order in the switcher might be incorrect (#5346) 2026-03-20 21:52:22 +01:00
lwouis 3b1c7c76a9 fix: avoid repeating shortcut that was released (closes #5429) 2026-03-19 21:11:06 +01:00
lwouis 8962ad1a54 fix: apps with no open window might not show up (closes #5424) 2026-03-16 19:44:17 +01:00
semantic-release-bot 39b818de11 chore(release): 10.7.0 [skip ci]
# [10.7.0](https://github.com/lwouis/alt-tab-macos/compare/v10.6.0...v10.7.0) (2026-03-15)

### Bug Fixes

* allow quitting multiple apps in a row (closes [#5421](https://github.com/lwouis/alt-tab-macos/issues/5421)) ([de9aaa1](https://github.com/lwouis/alt-tab-macos/commit/de9aaa1))
* avoid memory usage growth over time (closes [#5138](https://github.com/lwouis/alt-tab-macos/issues/5138)) ([739649a](https://github.com/lwouis/alt-tab-macos/commit/739649a))
* edit shortcuts in settings window search bar on first launch ([2adf741](https://github.com/lwouis/alt-tab-macos/commit/2adf741))
* prevent sheets from messing up thumbnails order ([#5346](https://github.com/lwouis/alt-tab-macos/issues/5346)) ([b008d63](https://github.com/lwouis/alt-tab-macos/commit/b008d63))
* thumbnails might be shown too small ([57c95a6](https://github.com/lwouis/alt-tab-macos/commit/57c95a6))

### Features

* reduce memory usage by storing fewer app icons ([b21168a](https://github.com/lwouis/alt-tab-macos/commit/b21168a))
2026-03-15 14:29:13 +00:00
lwouis b008d63928 fix: prevent sheets from messing up thumbnails order (#5346) 2026-03-15 15:19:38 +01:00
lwouis de9aaa1fc1 fix: allow quitting multiple apps in a row (closes #5421) 2026-03-15 15:15:07 +01:00
lwouis 739649a749 fix: avoid memory usage growth over time (closes #5138) 2026-03-14 18:44:57 +01:00
lwouis 2adf741355 fix: edit shortcuts in settings window search bar on first launch 2026-03-13 10:46:37 +01:00
lwouis ec763814a9 refactor: reduce ram usage by early returning when not visible 2026-03-13 10:27:00 +01:00
lwouis b21168a033 feat: reduce memory usage by storing fewer app icons 2026-03-13 10:22:04 +01:00
lwouis cf8a41528d refactor: throttling was not actually working 2026-03-12 17:15:24 +01:00
lwouis 57c95a6e35 fix: thumbnails might be shown too small 2026-03-12 11:24:47 +01:00
semantic-release-bot 17615d00a9 chore(release): 10.6.0 [skip ci]
# [10.6.0](https://github.com/lwouis/alt-tab-macos/compare/v10.5.0...v10.6.0) (2026-03-10)

### Bug Fixes

* allow edit shortcuts in the search bar (closes [#5308](https://github.com/lwouis/alt-tab-macos/issues/5308)) ([35ddbe7](https://github.com/lwouis/alt-tab-macos/commit/35ddbe7))
* better handle context menu in search bar ([9aea8f6](https://github.com/lwouis/alt-tab-macos/commit/9aea8f6))
* key repeat in search mode ([fd4e373](https://github.com/lwouis/alt-tab-macos/commit/fd4e373))
* preview may not update its position (closes [#5396](https://github.com/lwouis/alt-tab-macos/issues/5396)) ([dbadb2b](https://github.com/lwouis/alt-tab-macos/commit/dbadb2b))
* right-click and middle-click outside panel ([9969a07](https://github.com/lwouis/alt-tab-macos/commit/9969a07))
* show preview window on first shortcut press (closes [#5385](https://github.com/lwouis/alt-tab-macos/issues/5385)) ([106f7c9](https://github.com/lwouis/alt-tab-macos/commit/106f7c9))
* trackpad scrolling shouldn't also scroll on background apps ([cacb789](https://github.com/lwouis/alt-tab-macos/commit/cacb789))

### Features

* scrolling the settings update the sidebar (closes [#5400](https://github.com/lwouis/alt-tab-macos/issues/5400)) ([3b831d4](https://github.com/lwouis/alt-tab-macos/commit/3b831d4))
2026-03-10 20:49:15 +00:00
lwouis 35ddbe72ed fix: allow edit shortcuts in the search bar (closes #5308) 2026-03-10 21:33:46 +01:00
lwouis fd4e3734e8 fix: key repeat in search mode 2026-03-10 21:33:46 +01:00
lwouis cacb7891e7 fix: trackpad scrolling shouldn't also scroll on background apps 2026-03-10 21:33:44 +01:00
lwouis 9969a07b22 fix: right-click and middle-click outside panel 2026-03-10 21:33:25 +01:00
lwouis 9aea8f62c9 fix: better handle context menu in search bar 2026-03-10 21:33:00 +01:00
lwouis 106f7c90f9 fix: show preview window on first shortcut press (closes #5385) 2026-03-09 23:14:38 +01:00
lwouis 3b831d4e59 feat: scrolling the settings update the sidebar (closes #5400) 2026-03-09 23:09:46 +01:00
lwouis dbadb2b4e5 fix: preview may not update its position (closes #5396) 2026-03-09 16:34:17 +01:00
semantic-release-bot 7d0eb278bf chore(release): 10.5.0 [skip ci]
# [10.5.0](https://github.com/lwouis/alt-tab-macos/compare/v10.4.0...v10.5.0) (2026-03-08)

### Bug Fixes

* input with ime better interacts with search (closes [#5377](https://github.com/lwouis/alt-tab-macos/issues/5377)) ([15caa33](https://github.com/lwouis/alt-tab-macos/commit/15caa33))

### Features

* improved search results ([0f8d6f1](https://github.com/lwouis/alt-tab-macos/commit/0f8d6f1))
* refinements on mouse hover and dragging ([#5350](https://github.com/lwouis/alt-tab-macos/issues/5350)) ([643cc80](https://github.com/lwouis/alt-tab-macos/commit/643cc80))
2026-03-08 17:56:44 +00:00
lwouis 0f8d6f140a feat: improved search results 2026-03-08 18:49:58 +01:00
lwouis 15caa33a60 fix: input with ime better interacts with search (closes #5377) 2026-03-08 18:49:57 +01:00
lwouis d905617248 refactor: add log for menubar visibility change 2026-03-05 15:25:01 +01:00
lwouis 643cc80ae0 feat: refinements on mouse hover and dragging (#5350) 2026-03-05 15:25:00 +01:00
semantic-release-bot a867171a45 chore(release): 10.4.0 [skip ci]
# [10.4.0](https://github.com/lwouis/alt-tab-macos/compare/v10.3.0...v10.4.0) (2026-03-04)

### Bug Fixes

* clicking tiles required to release precisely (closes [#5373](https://github.com/lwouis/alt-tab-macos/issues/5373)) ([2c6c9fb](https://github.com/lwouis/alt-tab-macos/commit/2c6c9fb))
* issues when using multiple keyboard languages (closes [#2125](https://github.com/lwouis/alt-tab-macos/issues/2125)) ([ea7284b](https://github.com/lwouis/alt-tab-macos/commit/ea7284b))
* switcher may show windows in the wrong order (closes [#5346](https://github.com/lwouis/alt-tab-macos/issues/5346)) ([a632e42](https://github.com/lwouis/alt-tab-macos/commit/a632e42))

### Features

* add kazakh and improve all localizations ([0ad389a](https://github.com/lwouis/alt-tab-macos/commit/0ad389a))
* improve drag-and-drop over alttab (closes [#5350](https://github.com/lwouis/alt-tab-macos/issues/5350)) ([a809ffa](https://github.com/lwouis/alt-tab-macos/commit/a809ffa))
2026-03-04 18:43:30 +00:00
lwouis 2c6c9fb2cc fix: clicking tiles required to release precisely (closes #5373) 2026-03-04 19:37:39 +01:00
lwouis 0ad389aa6f feat: add kazakh and improve all localizations 2026-03-04 19:01:28 +01:00
lwouis a632e42fbc fix: switcher may show windows in the wrong order (closes #5346) 2026-03-04 11:45:58 +01:00
lwouis a809ffad61 feat: improve drag-and-drop over alttab (closes #5350) 2026-03-01 19:26:28 +01:00
lwouis ea7284b387 fix: issues when using multiple keyboard languages (closes #2125) 2026-03-01 16:45:30 +01:00
lwouis 37ba9662f1 docs: simplify website introduction page 2026-02-24 21:26:27 +01:00
lwouis 1f340a3590 ci: netlify deploy broke after they updated their ubuntu vm
make jekyll build use ruby 3 and more recent bundler, so it works on more recent VMs
2026-02-24 21:21:56 +01:00
semantic-release-bot f7368f0dfe chore(release): 10.3.0 [skip ci]
# [10.3.0](https://github.com/lwouis/alt-tab-macos/compare/v10.2.0...v10.3.0) (2026-02-24)

### Bug Fixes

* avoid clipping long settings window buttons (closes [#5320](https://github.com/lwouis/alt-tab-macos/issues/5320)) ([402b6f6](https://github.com/lwouis/alt-tab-macos/commit/402b6f6))
* closing a window would remove the thumbnail (closes [#5324](https://github.com/lwouis/alt-tab-macos/issues/5324)) ([451bbbe](https://github.com/lwouis/alt-tab-macos/commit/451bbbe))
* fade-out speed could show wrong value in rare cases ([f5e81fe](https://github.com/lwouis/alt-tab-macos/commit/f5e81fe))
* improve settings window on macos 10.13 ([5ce48c1](https://github.com/lwouis/alt-tab-macos/commit/5ce48c1))
* mouse hover would sometimes disappear ([8c7263e](https://github.com/lwouis/alt-tab-macos/commit/8c7263e))

### Features

* add ur/mr localizations + update all localizations ([dc538dc](https://github.com/lwouis/alt-tab-macos/commit/dc538dc))
* consolidate settings (closes [#1732](https://github.com/lwouis/alt-tab-macos/issues/1732)) ([219098d](https://github.com/lwouis/alt-tab-macos/commit/219098d))
* reduce app disk size ([3c95c6c](https://github.com/lwouis/alt-tab-macos/commit/3c95c6c))
2026-02-24 19:55:27 +00:00
lwouis dc538dc994 feat: add ur/mr localizations + update all localizations 2026-02-24 20:48:29 +01:00
lwouis 9f563bcec2 docs: release notes had bright titles in dark mode 2026-02-24 20:48:29 +01:00
lwouis 1ff8c9c19a docs: migrate faq to github discussions
also closes #5339
2026-02-24 20:48:28 +01:00
lwouis 810b7116cd chore: refresh controls ui on dark/light mode change 2026-02-24 20:48:28 +01:00
lwouis 3fb66d412a chore: derisk event handling (#5336)
* .listenOnly means we don't block event processing
* using CGEvent directly means we don't need main-thread to convert to NSEvent
2026-02-24 20:48:27 +01:00
lwouis 741b074134 chore: multiple shortcuts could be selected if scrolling 2026-02-24 20:48:27 +01:00
lwouis c3ef4bc87c chore: logs in the debug tools were hard to read in dark mode 2026-02-24 20:48:26 +01:00
lwouis f5e81fe8cd fix: fade-out speed could show wrong value in rare cases 2026-02-24 20:48:26 +01:00
lwouis 3c95c6c276 feat: reduce app disk size 2026-02-24 20:48:26 +01:00
lwouis f54aca3fd9 refactor: reuse nested-scrolling logic across controls and blacklist 2026-02-24 20:48:25 +01:00
lwouis 7220643c82 refactor: make migration code simpler 2026-02-24 20:48:25 +01:00
lwouis ede879f3d6 refactor: make language preferences drier 2026-02-24 20:48:24 +01:00
lwouis 8c7263e8f1 fix: mouse hover would sometimes disappear 2026-02-24 20:48:24 +01:00
lwouis 402b6f6ff1 fix: avoid clipping long settings window buttons (closes #5320) 2026-02-24 20:48:23 +01:00
lwouis 451bbbe035 fix: closing a window would remove the thumbnail (closes #5324) 2026-02-24 20:48:23 +01:00
lwouis db34a7eb8f refactor: use static vars/funcs as much as possible 2026-02-24 20:48:22 +01:00
lwouis 5ce48c18e6 fix: improve settings window on macos 10.13 2026-02-24 18:42:22 +01:00
lwouis 219098d6a3 feat: consolidate settings (closes #1732) 2026-02-24 18:42:21 +01:00
semantic-release-bot 5f87336f3f chore(release): 10.2.0 [skip ci]
# [10.2.0](https://github.com/lwouis/alt-tab-macos/compare/v10.1.0...v10.2.0) (2026-02-19)

### Bug Fixes

* improve settings ui on macos 10.13 ([#5255](https://github.com/lwouis/alt-tab-macos/issues/5255)) ([75347ad](https://github.com/lwouis/alt-tab-macos/commit/75347ad))
* rare crash when a window was opened ([28c4b12](https://github.com/lwouis/alt-tab-macos/commit/28c4b12))
* small issues when mouse hover is set to select (closes [#5292](https://github.com/lwouis/alt-tab-macos/issues/5292)) ([b9e0344](https://github.com/lwouis/alt-tab-macos/commit/b9e0344))
* sometimes the active app was not up-to-date (closes [#5291](https://github.com/lwouis/alt-tab-macos/issues/5291)) ([ea51d57](https://github.com/lwouis/alt-tab-macos/commit/ea51d57))

### Features

* add burmese + update all localizations ([f5e1014](https://github.com/lwouis/alt-tab-macos/commit/f5e1014))
* add new setting for auto size (closes [#3669](https://github.com/lwouis/alt-tab-macos/issues/3669)) ([c51376f](https://github.com/lwouis/alt-tab-macos/commit/c51376f))
* add setting to blacklist window by title (closes [#5299](https://github.com/lwouis/alt-tab-macos/issues/5299)) ([35eae11](https://github.com/lwouis/alt-tab-macos/commit/35eae11))
* can add running apps into blacklist (closes [#5268](https://github.com/lwouis/alt-tab-macos/issues/5268)) ([d5d6996](https://github.com/lwouis/alt-tab-macos/commit/d5d6996))
* remember position/size of secondary windows (closes [#5305](https://github.com/lwouis/alt-tab-macos/issues/5305)) ([4b85fb8](https://github.com/lwouis/alt-tab-macos/commit/4b85fb8))
2026-02-19 22:42:05 +00:00
lwouis f5e1014bce feat: add burmese + update all localizations 2026-02-19 23:34:57 +01:00
lwouis 75347adc8d fix: improve settings ui on macos 10.13 (#5255) 2026-02-19 23:34:56 +01:00
lwouis 35eae11389 feat: add setting to blacklist window by title (closes #5299) 2026-02-19 23:34:55 +01:00
lwouis 28c4b121ca fix: rare crash when a window was opened 2026-02-19 23:20:15 +01:00
lwouis d5d699659c feat: can add running apps into blacklist (closes #5268) 2026-02-19 23:20:14 +01:00
lwouis 4b85fb8cf7 feat: remember position/size of secondary windows (closes #5305) 2026-02-19 23:20:14 +01:00
lwouis c51376fd26 feat: add new setting for auto size (closes #3669) 2026-02-19 23:20:13 +01:00
lwouis b9e0344da4 fix: small issues when mouse hover is set to select (closes #5292) 2026-02-19 23:20:12 +01:00
lwouis ea51d57d3d fix: sometimes the active app was not up-to-date (closes #5291) 2026-02-19 23:20:12 +01:00
semantic-release-bot a7b7a79ece chore(release): 10.1.0 [skip ci]
# [10.1.0](https://github.com/lwouis/alt-tab-macos/compare/v10.0.0...v10.1.0) (2026-02-17)

### Bug Fixes

* better flow when last 2 windows are minimized (closes [#2159](https://github.com/lwouis/alt-tab-macos/issues/2159)) ([da6be20](https://github.com/lwouis/alt-tab-macos/commit/da6be20))
* issue with link drag-and-drop over the switcher (closes [#5292](https://github.com/lwouis/alt-tab-macos/issues/5292)) ([4e6361f](https://github.com/lwouis/alt-tab-macos/commit/4e6361f))
* trackpad gesture active when disabled (closes [#5301](https://github.com/lwouis/alt-tab-macos/issues/5301)) ([d074faa](https://github.com/lwouis/alt-tab-macos/commit/d074faa))

### Features

* allow settings export/import (closes [#4514](https://github.com/lwouis/alt-tab-macos/issues/4514)) ([69a9dfa](https://github.com/lwouis/alt-tab-macos/commit/69a9dfa))
2026-02-17 18:30:07 +00:00
lwouis 09789e297d refactor: remove unnecessary string 2026-02-17 18:24:48 +01:00
lwouis 69a9dfa41b feat: allow settings export/import (closes #4514) 2026-02-17 18:01:26 +01:00
lwouis 4e6361ff7b fix: issue with link drag-and-drop over the switcher (closes #5292) 2026-02-17 17:42:20 +01:00
lwouis 91d4a7781e refactor: update settings sidebar to liquid glass visuals 2026-02-17 17:42:18 +01:00
lwouis da6be203f0 fix: better flow when last 2 windows are minimized (closes #2159) 2026-02-17 11:45:55 +01:00
lwouis d074faafd1 fix: trackpad gesture active when disabled (closes #5301) 2026-02-17 10:38:08 +01:00
semantic-release-bot 39d7af8483 chore(release): 10.0.0 [skip ci]
# [10.0.0](https://github.com/lwouis/alt-tab-macos/compare/v9.0.0...v10.0.0) (2026-02-16)

### Bug Fixes

* app could crash in rare scenarios ([3de0276](https://github.com/lwouis/alt-tab-macos/commit/3de0276))
* launched app may not be seen as active (closes [#5291](https://github.com/lwouis/alt-tab-macos/issues/5291)) ([3e47ebe](https://github.com/lwouis/alt-tab-macos/commit/3e47ebe))
* quick switches could sometimes do nothing (closes [#5289](https://github.com/lwouis/alt-tab-macos/issues/5289)) ([82795d8](https://github.com/lwouis/alt-tab-macos/commit/82795d8))

### Features

* add debug tools ([07e4024](https://github.com/lwouis/alt-tab-macos/commit/07e4024))
* add fuzzy search mode (closes [#590](https://github.com/lwouis/alt-tab-macos/issues/590)) ([4e986f3](https://github.com/lwouis/alt-tab-macos/commit/4e986f3))
* allow up to 9 shortcuts ([#3882](https://github.com/lwouis/alt-tab-macos/issues/3882)) ([8cab3e1](https://github.com/lwouis/alt-tab-macos/commit/8cab3e1))
* new settings experience (closes [#5287](https://github.com/lwouis/alt-tab-macos/issues/5287)) ([3890beb](https://github.com/lwouis/alt-tab-macos/commit/3890beb))
* support app-icon badges with large numbers ([ceed334](https://github.com/lwouis/alt-tab-macos/commit/ceed334))
* support showing only non-visible spaces (closes [#1274](https://github.com/lwouis/alt-tab-macos/issues/1274)) ([51db0cb](https://github.com/lwouis/alt-tab-macos/commit/51db0cb))
* update bn localization ([3f1617c](https://github.com/lwouis/alt-tab-macos/commit/3f1617c))

### BREAKING CHANGES

* a whole new alt-tab experience by pressing "s". You can also set search as the default style in the settings
2026-02-16 23:04:53 +00:00
lwouis 2ee406c909 refactor: fix tests 2026-02-16 23:56:14 +01:00
lwouis 66db895dd3 refactor: missed some renames 2026-02-16 23:56:13 +01:00
lwouis 07e4024a9c feat: add debug tools 2026-02-16 23:56:13 +01:00
lwouis 8cab3e1f8b feat: allow up to 9 shortcuts (#3882) 2026-02-16 22:53:01 +01:00
lwouis 3f1617cba0 feat: update bn localization 2026-02-16 22:53:01 +01:00
lwouis 82795d845c fix: quick switches could sometimes do nothing (closes #5289) 2026-02-16 22:53:01 +01:00
lwouis 99201191f4 refactor: prevent ambiguous ids between apps and windows 2026-02-16 22:53:00 +01:00
lwouis 3de027644c fix: app could crash in rare scenarios
concurrency issues on preferences
2026-02-16 22:53:00 +01:00
lwouis 3e47ebec8e fix: launched app may not be seen as active (closes #5291) 2026-02-16 22:52:59 +01:00
lwouis 3890beb9d3 feat: new settings experience (closes #5287) 2026-02-16 22:52:58 +01:00
lwouis 93e2b35dc7 refactor: permissions window is lazily initialized 2026-02-16 22:52:57 +01:00
lwouis da21cb8e21 refactor: feedback window is lazily initialized 2026-02-16 22:52:57 +01:00
lwouis 14a0b716b6 refactor: preferences window is lazily initialized 2026-02-16 22:52:56 +01:00
Jakku Sakura 4e986f37a0 feat: add fuzzy search mode (closes #590)
BREAKING CHANGE: a whole new alt-tab experience by pressing "s". You can also set search as the default style in the settings
2026-02-16 22:52:56 +01:00
lwouis e3092b4299 chore: remove complex ai rules 2026-02-16 13:33:19 +01:00
lwouis ceed334b06 feat: support app-icon badges with large numbers 2026-02-16 13:33:18 +01:00
lwouis 51db0cb8e4 feat: support showing only non-visible spaces (closes #1274) 2026-02-16 13:33:18 +01:00
semantic-release-bot 3961f2a888 chore(release): 9.0.0 [skip ci]
# [9.0.0](https://github.com/lwouis/alt-tab-macos/compare/v8.3.4...v9.0.0) (2026-02-11)

### Bug Fixes

* missing thumbnails in rare cases ([3142590](https://github.com/lwouis/alt-tab-macos/commit/3142590))
* preserve scroll position in switcher if windows change ([fa9e4d0](https://github.com/lwouis/alt-tab-macos/commit/fa9e4d0))
* prevent macos 10.13 crash (closes [#5255](https://github.com/lwouis/alt-tab-macos/issues/5255)) ([d525d35](https://github.com/lwouis/alt-tab-macos/commit/d525d35))

### Features

* improve performance when many windows are open (closes [#5177](https://github.com/lwouis/alt-tab-macos/issues/5177)) ([5d0a92f](https://github.com/lwouis/alt-tab-macos/commit/5d0a92f))
* new thumbnails shadows in macos 26 style ([26d46e3](https://github.com/lwouis/alt-tab-macos/commit/26d46e3))
* update cs/el/fr/ru localizations ([2681218](https://github.com/lwouis/alt-tab-macos/commit/2681218))

### Performance Improvements

* better caanimation batching ([016052c](https://github.com/lwouis/alt-tab-macos/commit/016052c))
* cache expensive layout values ([904bd17](https://github.com/lwouis/alt-tab-macos/commit/904bd17))
* cache expensive layout values 2 ([13ed78b](https://github.com/lwouis/alt-tab-macos/commit/13ed78b))
* cache font from appearance ([305870b](https://github.com/lwouis/alt-tab-macos/commit/305870b))
* cache screen uuids and frontmost app ([a5135c5](https://github.com/lwouis/alt-tab-macos/commit/a5135c5))
* capture samplebuffer directly ([2bce0d2](https://github.com/lwouis/alt-tab-macos/commit/2bce0d2))
* create overlay view to optimize view count ([ec5802a](https://github.com/lwouis/alt-tab-macos/commit/ec5802a))
* do all mouse interactions globally instead of local tracking ([d89bc29](https://github.com/lwouis/alt-tab-macos/commit/d89bc29))
* have views under and over the thumbnailview ([b9637e5](https://github.com/lwouis/alt-tab-macos/commit/b9637e5))
* improve hiding the ui ([4f5e325](https://github.com/lwouis/alt-tab-macos/commit/4f5e325))
* merge mouseevents into cursorevents ([9edf312](https://github.com/lwouis/alt-tab-macos/commit/9edf312))
* move app icon capture to background queue ([5a35aa9](https://github.com/lwouis/alt-tab-macos/commit/5a35aa9))
* optim hangs from DebugMenu ([4b830e6](https://github.com/lwouis/alt-tab-macos/commit/4b830e6))
* prevent appkit work ([fefc491](https://github.com/lwouis/alt-tab-macos/commit/fefc491))
* prevent costly window recursive views update ([41e0e7c](https://github.com/lwouis/alt-tab-macos/commit/41e0e7c))
* prevent possible frequent permissions check ([216563b](https://github.com/lwouis/alt-tab-macos/commit/216563b))
* remove normalize-subview to avoid appkit work ([ce2dfc1](https://github.com/lwouis/alt-tab-macos/commit/ce2dfc1))
* simplify and combine views for better perf ([3a8c0f3](https://github.com/lwouis/alt-tab-macos/commit/3a8c0f3))
* small optimizations from profiling ([db314c9](https://github.com/lwouis/alt-tab-macos/commit/db314c9))
* throttle all window/app ax calls ([337e2fb](https://github.com/lwouis/alt-tab-macos/commit/337e2fb))
* update windows manually after 250s ([52530b2](https://github.com/lwouis/alt-tab-macos/commit/52530b2))
* use calayer instead of nsview for lightimageview ([7dec9da](https://github.com/lwouis/alt-tab-macos/commit/7dec9da))

### BREAKING CHANGES

* major performance improvements
2026-02-11 20:50:23 +00:00
lwouis 91d44e72df ci: workaround github actions bug by checking out more commits 2026-02-11 21:42:44 +01:00
lwouis 314259032d fix: missing thumbnails in rare cases 2026-02-11 21:35:41 +01:00
lwouis fa9e4d0ee1 fix: preserve scroll position in switcher if windows change 2026-02-11 21:35:41 +01:00
lwouis 6de7fee90c refactor: add bottom padding when scrolling in appicons appearance 2026-02-11 21:35:40 +01:00
lwouis f7226f681a refactor: fix windowless indicator position 2026-02-11 21:35:39 +01:00
lwouis 26d46e3768 feat: new thumbnails shadows in macos 26 style 2026-02-11 21:35:39 +01:00
lwouis 216563b635 perf: prevent possible frequent permissions check 2026-02-11 21:35:38 +01:00
lwouis 3f2f391c93 refactor: extract statusiconsview 2026-02-11 21:35:38 +01:00
lwouis 9edf31244a perf: merge mouseevents into cursorevents 2026-02-11 21:35:37 +01:00
lwouis d89bc29425 perf: do all mouse interactions globally instead of local tracking 2026-02-11 21:35:36 +01:00
lwouis d525d350fc fix: prevent macos 10.13 crash (closes #5255) 2026-02-11 21:35:36 +01:00
lwouis d1ba6bd333 chore: update periphery + remove dead code 2026-02-11 21:35:35 +01:00
lwouis 6695e9be9c refactor: rename to tiles 2026-02-11 21:35:35 +01:00
lwouis 396ef6f0b0 refactor: fix mouse hover right after switching space 2026-02-11 21:35:34 +01:00
lwouis b9637e5802 perf: have views under and over the thumbnailview 2026-02-11 21:35:34 +01:00
lwouis fe52511885 refactor: space indicator always rightmost 2026-02-11 21:35:33 +01:00
lwouis 337e2fbfec perf: throttle all window/app ax calls 2026-02-11 21:35:32 +01:00
lwouis 4f5e32593b perf: improve hiding the ui 2026-02-11 21:35:32 +01:00
lwouis db314c9948 perf: small optimizations from profiling 2026-02-11 21:35:31 +01:00
lwouis 7dec9da401 perf: use calayer instead of nsview for lightimageview 2026-02-11 21:35:31 +01:00
lwouis 3a8c0f3bee perf: simplify and combine views for better perf 2026-02-11 21:35:30 +01:00
lwouis ec5802a487 perf: create overlay view to optimize view count 2026-02-11 21:35:29 +01:00
lwouis fefc491ce5 perf: prevent appkit work 2026-02-11 21:35:29 +01:00
lwouis 41e0e7c688 perf: prevent costly window recursive views update 2026-02-11 21:35:28 +01:00
lwouis ce2dfc1f19 perf: remove normalize-subview to avoid appkit work 2026-02-11 21:35:28 +01:00
lwouis 13ed78bc23 perf: cache expensive layout values 2 2026-02-11 21:35:27 +01:00
lwouis 904bd17c53 perf: cache expensive layout values 2026-02-11 21:35:27 +01:00
lwouis 1f3a653faa refactor: add benchmarker 2026-02-11 21:35:26 +01:00
lwouis cd1d6574f7 chore: remove dead code 2026-02-11 21:35:26 +01:00
lwouis a5135c5560 perf: cache screen uuids and frontmost app 2026-02-11 21:35:25 +01:00
lwouis 2bce0d2d40 perf: capture samplebuffer directly 2026-02-11 21:35:24 +01:00
lwouis 016052ca14 perf: better caanimation batching 2026-02-11 21:35:24 +01:00
lwouis 305870b3ee perf: cache font from appearance 2026-02-11 21:35:23 +01:00
lwouis 52530b2d5c perf: update windows manually after 250s 2026-02-11 21:35:23 +01:00
lwouis 5a35aa95bc perf: move app icon capture to background queue 2026-02-11 21:35:22 +01:00
lwouis 53da0344bf refactor: avoid checking transparency on some images 2026-02-11 21:35:22 +01:00
lwouis f30d3760a1 refactor: codex perf improvements 2026-02-11 21:35:21 +01:00
lwouis fbcc3f5f02 refactor: improve manual window discovery 2026-02-11 21:35:21 +01:00
Christian Battaglia 5d0a92f3f7 feat: improve performance when many windows are open (closes #5177)
BREAKING CHANGE: major performance improvements
2026-02-11 21:35:18 +01:00
lwouis 4b830e6ba7 perf: optim hangs from DebugMenu 2026-02-08 10:30:48 +01:00
lwouis 698e5e8e0c chore: update periphery config 2026-02-08 10:30:47 +01:00
lwouis a4f5a23846 docs: add ai agents rules 2026-02-08 10:30:44 +01:00
lwouis 268121850d feat: update cs/el/fr/ru localizations 2026-02-08 10:23:16 +01:00
semantic-release-bot aeaf782feb chore(release): 8.3.4 [skip ci]
## [8.3.4](https://github.com/lwouis/alt-tab-macos/compare/v8.3.3...v8.3.4) (2026-01-31)

### Bug Fixes

* app could sometimes crash in the background ([ab704dc](https://github.com/lwouis/alt-tab-macos/commit/ab704dc)), closes [#5260](https://github.com/lwouis/alt-tab-macos/issues/5260)
* quitting apps by pressing q multiple times (closes [#5247](https://github.com/lwouis/alt-tab-macos/issues/5247)) ([21aeafd](https://github.com/lwouis/alt-tab-macos/commit/21aeafd))
2026-01-31 18:18:25 +00:00
1981 changed files with 99897 additions and 58869 deletions

No files matched your search

+193
View File
@@ -0,0 +1,193 @@
---
name: assets-optimization
description: Audit and optimize every image asset shipped with AltTab. Apply the right format per asset class (PDF for vectors, HEIC for raster) and the right post-processing (strip Figma cruft from PDFs, extract SF Symbols as minimal vector PDFs, encode raster sources to HEIC at q50 with visual review). Use whenever new assets are added, when the bundle size needs shrinking, or whenever you want a full assets audit.
---
# /assets-optimization — AltTab asset audit and optimization
## Goal
Every byte that ships in `AltTab.app/Contents/Resources/` should justify itself. Vectors stay vector, rasters compress to HEIC, and neither carries metadata, color profiles, accessibility tags, or producer signatures that AppKit doesn't use.
This skill applies a known-good pipeline to each asset class. It is opinionated about the right format and the right encoder for each kind of content.
## When to use
- A designer drops new exports into `~/Desktop/` or `resources/`.
- Someone asks "why is the bundle so big?".
- After adding a new icon, illustration, app icon variant, or menubar variant.
- Periodic audit when nothing else is broken.
## Step 1: Inventory
Run a one-shot enumeration so you know what you're working with:
```sh
find resources -type f \( -iname '*.pdf' -o -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.heic' -o -iname '*.svg' -o -iname '*.icns' \) \
-exec ls -la {} \; | awk '{printf "%8d %s\n", $5, $9}' | sort -k2
```
Group what you see by directory. For AltTab the relevant buckets are:
- `resources/icons/menubar/` — small template icons shown in the macOS menubar.
- `resources/icons/tabs/` — Preferences sidebar icons (template, sized ~13pt).
- `resources/icons/permission-window/` — first-launch permission window icons (~32pt).
- `resources/icons/app/` — the macOS app icon (`.icns` + `.iconset/`). **Don't touch** — `.icns` is required by the bundle and Apple's tooling produces near-optimal output already.
- `resources/illustrations/` — the appearance-tab preview thumbnails. Raster (screenshots inside).
For each asset, decide what category it falls into:
| Source content | Right format | Why |
|---|---|---|
| Custom vector design (Figma/Sketch/Illustrator) | **PDF** | macOS 10.13 doesn't accept SVG; PDF is the universal vector container AppKit reads natively. |
| SF Symbol (Apple system glyph) | **Font glyph** in the bundled `SF-Pro-Text-Regular.otf` subset | Render via `NSImage.fromSymbol(.foo, pointSize:)` (or as text via the `Symbols` enum). Smaller than per-icon PDFs, picks up Apple's latest glyph refinements automatically when the developer updates SF Symbols.app. |
| Photographic / screenshot-heavy | **HEIC** | HEIC at q50 beats JPEG by ~30% at the same perceptual quality. |
| Tiny pixel-precise UI sprite | **PNG @2x** | Below ~40×40px the PDF overhead exceeds the bitmap savings. PNG wins. |
| App icon (the macOS bundle one) | **`.icns`** | Required by `CFBundleIconFile`. |
If an asset is in the wrong format, flag it. If it's in the right format but unoptimized, run the matching pipeline below.
## Step 2: Vector PDFs — Figma exports
Figma's "Export → PDF" output is bloated. For each menubar/illustration/icon vector PDF that came from Figma, you can strip ~50–75% of the bytes without losing a single rendered pixel.
What Figma adds that AppKit doesn't need:
1. **Embedded ICC color profile** (`/ICCBased ...`, ~3.2 KB compressed). Replace every `[/ICCBased N R]` reference with `/DeviceRGB` (or `/DeviceGray` for monochrome). Patches needed in:
- the page `Resources/ColorSpace` dict
- every Form XObject's `Resources/ColorSpace` dict (these are streams, not plain dicts — pikepdf's `pdf.objects` will only catch them if you accept both `Dictionary` and `Stream`)
- every Image XObject's direct `/ColorSpace` key
- every Shading dict inside `Pattern` entries (Figma's color icons use 8+ patterns, each with its own `/ColorSpace N R` reference)
2. **`/Metadata`** XMP packet (~830 B) — Figma's XML manifest.
3. **`/StructTreeRoot`, `/ParentTree`, `/StructElem`** — accessibility tags ("Document" / "Part" structural roles). AppKit's PDF renderer ignores them.
4. **`/Info` dict** — `Producer="Figma"`, `Title="Menubar 22x22@1x white"`. In Figma's exports the Info dict sometimes lives **inline inside the Catalog** rather than at the trailer level, so deleting `pdf.docinfo` isn't enough — also `del root[Name('/Info')]`.
5. **`/Lang`, `/MarkInfo`, `/Annots`, `/StructParents`, `/Tabs`** — empty or trivial page-level entries.
6. **`/ProcSet [/PDF]`** — deprecated since PDF 1.4.
Use the script:
```sh
python3 scripts/assets/optimize_figma_pdf.py resources/icons/menubar/*.pdf
```
It edits in place and prints the savings per file. After running, also pipe through `mutool clean -ggg -z` and `qpdf --object-streams=generate --recompress-flate --compression-level=9` for the final 1–2% squeeze.
Verify each file still renders by sips'ing it back to PNG and eyeballing:
```sh
for f in resources/icons/menubar/*.pdf; do
sips -s format png "$f" --out "/tmp/$(basename $f .pdf).png" -Z 300 >/dev/null 2>&1
done
```
Open the PNGs in Preview to confirm nothing visual changed.
## Step 3: SF Symbols via font subset
Every SF Symbol shipped in AltTab — switcher status icons, sidebar tab icons, button icons, permission/feedback icons — is rendered as a text glyph from a subsetted SF Pro Text font. There are no SF-Symbol PDFs in the bundle.
How it works: SF Symbols are glyphs in the Private Use Area of SF Pro Text. Apple's `SF-Pro-Text-Regular.otf` contains every symbol they've ever shipped. We subset it down to just the codepoints AltTab needs (currently ~36 glyphs, ~17 KB) into `resources/SF-Pro-Text-Regular.otf`, and register it via `Info.plist:ATSApplicationFontsPath = ""`. At runtime, `NSFont(name: "SF Pro Text", size:)` resolves to the bundled subset on macOS <11 (where the system font isn't installed) and to the system font on macOS 11+, with identical glyph appearance either way.
To add a new SF Symbol:
1. Open [SF Symbols.app](https://developer.apple.com/sf-symbols/), search for the symbol, press **Cmd-C** to copy the symbol character to the clipboard. (Apple's name→codepoint mapping is not exposed via public API, and the SF Pro Text font's cmap uses `uniXXXXXX.medium`-style names rather than semantic ones, so this manual lookup is the authoritative path.)
2. Paste the character into a new case on the `Symbols` enum in [src/switcher/main-window/TileFontIconView.swift](src/switcher/main-window/TileFontIconView.swift) — e.g., `case foo = "􀝥" // SF Symbol name`.
3. Paste the same character at the end of the `--text=` argument in [scripts/assets/subset_font.sh](scripts/assets/subset_font.sh).
4. Run `bash scripts/assets/subset_font.sh`. It reads `/Library/Fonts/SF-Pro-Text-Regular.otf` (installed by SF Symbols.app — a standard developer prerequisite) and writes the regenerated subset to `resources/SF-Pro-Text-Regular.otf`. Picks up Apple's latest glyph refinements automatically.
5. Use it in code: `NSImage.fromSymbol(.foo, pointSize: 14)` returns a template `NSImage`; or `TileFontIconView(symbol: .foo, ...)` for the cached-attributed-string path in the switcher hot loop.
The script runs `pyftsubset` via the project's pipenv environment. Warnings about `MERG`/`meta`/`trak` tables being dropped are normal — those tables aren't relevant to glyph rendering.
### Historical note: SF Symbols via PDF (deprecated, scripts removed)
A previous pipeline shipped each SF Symbol as a per-glyph PDF in `resources/icons/`. The pipeline lives only in git history now (`scripts/assets/export_sf_symbol_pdf.swift` was deleted alongside the migrated PDFs). The technique is worth knowing in case a future need arises (e.g., a multi-color symbol that fonts can't represent):
- The naive route — `NSImage(systemSymbolName:).draw(in:)` against a PDF `CGContext` — produces a **black rectangle**, because Quartz emits `image-mask + fill-rectangle` operators where the rectangle paints over the mask. AppKit bug at the PDF emission level; `paletteColors` config does not fix it.
- The working route was to extract the symbol's vector path directly via private selectors that have been stable across macOS 11–15:
`NSImage(systemSymbolName:).representations[0] (NSSymbolImageRep) → .perform("vectorGlyph") (CUINamedVectorGlyph) → .perform("CGPath") (real CGPath)`.
- The CGPath lives in CUI's internal coordinate space (~2× display points, Y-down) — scale to fit the canvas and flip Y. Walk the path via `CGPath.applyWithBlock` and emit raw PDF operators (`m`, `l`, `c`, `h`, `f`). Non-zero winding fill. Fill with DeviceGray (`0 g`), **not** `NSColor.black.cgColor`, which drags in a ~3.4 KB ICC color profile.
- Final PDF wrapper: 4 objects (Catalog, Pages, Page, Content), no `/Info`, no `/Metadata`, no `/Resources/ColorSpace`. ~750–1800 bytes per icon.
Git: see commit `990c1e79` ("feat: pro improve assets") for the PDF pipeline as-it-was; subsequent commit migrated the SF-Symbol PDFs back to font glyphs.
## Step 4: Raster → HEIC at q50
For anything raster (illustration thumbnails, screenshots inside an icon, anything photographic), HEIC at quality 50 is the baseline. q50 is roughly 50% smaller than JPEG at perceptually-equivalent quality, and at the small display sizes used in this app the artifacts are invisible.
Pipeline (built-in to macOS via `sips`):
```sh
sips -Z 1000 -s format heic -s formatOptions 50 input.png --out output.heic
```
- `-Z 1000` resizes the longest edge to 1000px **preserving aspect ratio**. AltTab's illustration display is 500pt wide, so 1000px is the correct @2x ship size. Anything larger wastes bytes; anything smaller looks soft on Retina.
- `formatOptions 50` is the quality. q50 was chosen after a side-by-side comparison at q20/q35/q50/q65/q80 — q50 was the lowest setting where text in screenshots stayed legible and gradient backgrounds didn't band.
Use the script for batch conversion:
```sh
bash scripts/assets/encode_heic.sh ~/Desktop 1000 50
```
That walks all PNG/JPEG files in the source directory, resizes to longest-edge 1000px at q50 HEIC, writes outputs to `/tmp/heic-out/`.
### Visual review (mandatory)
Before swapping the new HEICs into `resources/`, **always** decode a representative sample back to PNG and visually compare against the source:
```sh
sips -s format png /tmp/heic-out/sample.heic --out /tmp/sample-decoded.png >/dev/null 2>&1
open /tmp/sample-decoded.png /Users/you/Desktop/sample.png
```
Pick the visually most demanding file from the batch — usually one with the most text or the strongest gradients. Confirm:
- No banding in flat color regions
- Text edges still crisp at native display size
- No haloing around anti-aliased edges
- Color rendition matches
If anything looks degraded, bump quality to q60 or q65 and re-batch. The user, not the script, is the final arbiter — show them the sample with sizes before committing.
### Bumping quality
If q50 isn't acceptable, the next quality steps are q60 and q65 — beyond that, returns diminish quickly. q80 is the previous default in this repo and roughly 2× the bytes of q50 for no visible improvement on AltTab's content.
## Step 5: pbxproj registration
Whenever you change the file extension of a resource (.jpg → .heic, .png → .pdf, etc.), update [alt-tab-macos.xcodeproj/project.pbxproj](alt-tab-macos.xcodeproj/project.pbxproj). The places that need patching:
1. **PBXBuildFile section** — comment + the comment inside `fileRef = ... /* name.ext */`.
2. **PBXFileReference section** — comment, `lastKnownFileType` (e.g. `image.pdf`, `image.heic`, `image.png`), and `path = "name.ext"`.
3. **PBXGroup section** — the file's entry inside its parent group's `children`.
4. **PBXResourcesBuildPhase section** — the entry in the main app target's `files`.
For pure extension swaps (no new files), `sed -i '' 's|old\.ext|new.ext|g'` plus a `lastKnownFileType` substitution covers it. For new files, generate new 24-char uppercase-hex object IDs (`python3 -c "import secrets; print(secrets.token_hex(12).upper())"`) and insert in all four places.
If you removed an asset entirely (file deleted from disk), delete its 4 entries from pbxproj — otherwise the build fails with "missing file" or ships dangling references.
## Step 6: Verify
```sh
bash ai/build.sh # must show ** BUILD SUCCEEDED **
bash ai/run.sh # launch the app and visually inspect every asset
```
Walk through every UI surface that loads an asset:
- Menubar icon (default + the two alternates from Preferences → General → Menubar icon)
- Preferences sidebar — 4 tab icons (SF Symbol on macOS 11+, bundled PDF below)
- Permissions window — open by revoking a permission
- Preferences → Appearance — illustration thumbnails change per show/hide row
Compare `git diff --stat` before committing. Asset replacements should net negative on bundle size.
## Reporting
After the run, report:
- File-by-file before/after sizes for everything that changed.
- Total bundle delta in KB.
- Any files left untouched and why (e.g., `app.icns` — bundle-required format).
- The encoder settings used (especially HEIC quality if not q50, so the next person knows).
- Anything the visual review revealed (e.g., "had to bump to q60 for `thumbnails_dark` because gradient banding at q50").
+65
View File
@@ -0,0 +1,65 @@
---
name: audit-specs-tests
description: Audit the AltTab test suite for spec/test/code consistency. For every co-located triad in `src/` (`Foo.swift` + `FooSpecs.md` + `FooTests.swift`), it cross-checks that each XCTest method has a matching scenario line in the spec and vice-versa, flags drift between a scenario's description and the test's doc-comment, and reports orphan tests, orphan scenarios, and unpaired files. Use after adding or editing any `*Tests.swift` / `*Specs.md`, before committing a test change, or to get an overall health check of the suite.
---
# /audit-specs-tests
## Project context
AltTab co-locates tests and a living spec next to the source they cover. The convention (see the plan in `.claude/plans/` and `src/pro/license/` as a worked example) is a **triad** per concept:
```
src/<feature>/
├── Foo.swift # production / kernel (app target, or app+test for kernels)
├── FooSpecs.md # the living spec (not compiled)
└── FooTests.swift # XCTest (unit-tests target only)
```
The spec is **documentation tied 1:1 to the test methods**. Its `## Test scenarios` section lists every test, grouped, as:
```markdown
### A. <Group name>
- **testAFooDoesBar** — one-line description of what it pins.
```
This skill's job is to keep the three in sync: every `func test…` ⇔ exactly one `- **test…** —` spec line, descriptions roughly agree, and no triad is missing a leg.
## What counts as a triad
Pair by base name in the **same folder**: `<Base>Tests.swift` ⇔ `<Base>Specs.md`. A `<Base>.swift` (or a kernel like `SelectionResolver.swift`, `SearchTestable.swift`) in the folder is the code under test, but a spec may legitimately cover several classes (e.g. `LicenseManagerSpecs.md` documents `Clock`/`Keychain`/`LicenseAPI` too) — so a missing same-name `.swift` is a note, not an error.
## Workflow
1. **Enumerate.** Find all test and spec files:
```sh
find src -name '*Tests.swift' | sort
find src -name '*Specs.md' | sort
```
Also list any test files still under `unit-tests/` and flag them as **not yet migrated** (the target end-state is zero test files outside `src/`).
2. **For each `*Tests.swift`, extract the test methods and their doc-comments.** Test names:
```sh
grep -nE '^\s*func test[A-Za-z0-9_]+\(' src/<path>/FooTests.swift
```
For each, capture the immediately-preceding `///` or `//` comment lines (the test's intent) and the enclosing `// MARK: -` group. Note methods wrapped in `#if DEBUG`.
3. **For each `*Specs.md`, parse the scenario index.** In the `## Test scenarios` section, collect every `### <Group>` heading and every `- **testName** — description` bullet. Build the set of spec-listed test names and their descriptions.
4. **Cross-check each triad and classify findings:**
- **Orphan test** — `func testX` exists but no `- **testX** —` line in the spec. (Most common drift; spec is stale.)
- **Orphan scenario** — spec lists `testX` but no `func testX` in the suite. (Test deleted/renamed; spec stale.)
- **Group mismatch** — a test's `// MARK:` group and its spec `###` group disagree (readability drift, not fatal).
- **Description drift** — the spec bullet and the test's doc-comment describe materially different behavior. Judge semantically, don't string-match; only flag real divergence.
- **Unpaired file** — a `*Tests.swift` with no `*Specs.md` (or vice-versa).
5. **Lighter code check (kernels only).** For decision-kernel files (`*Testable.swift`, `*Resolver.swift`), list `public`/`static` entry-point functions and `enum … Decision` cases, and flag any with no scenario referencing them — a hint that a branch is undocumented/untested. Skip this for AppKit-coupled production files (intentionally not unit-tested here).
6. **Optionally repair.** If asked, regenerate a spec's `## Test scenarios` section from the live test methods + their doc-comments (preserving the existing `### Group` order where it matches `// MARK:` sections). Never invent behavior — only restate what the test asserts. Do not edit `*Tests.swift` from this skill.
## Reporting
- A per-triad status table: `folder/Base` · #tests · #scenarios · status (✅ in sync / ⚠️ drift / ❌ unpaired).
- A punch list grouped by finding type (orphan tests, orphan scenarios, description drift, unpaired, undocumented kernel branches), each with the file + line.
- The count of test files still outside `src/` (migration progress).
- If nothing is wrong, say so plainly. Then offer to fix the drift (regenerate stale spec scenario indexes) and list exactly which files would change.
+63
View File
@@ -0,0 +1,63 @@
---
name: coverage-explore
description: Measure AltTab test coverage and record it as documentation. Runs the Test scheme with coverage into a throwaway result bundle, parses the per-file/region report, refreshes the per-feature badge atop each `*Specs.md` and the root `src/coverage.md` table, then suggests the highest-value missing tests. These two markdown outputs are the ONLY stored coverage — no lcov/html/xcresult is kept, and routine test runs don't gather coverage. Use to refresh coverage docs, find untested kernel branches, or decide what to test next.
---
# /coverage-explore
## Project context
AltTab follows the **Humble Object** pattern: logic lives in dependency-free **decision kernels**
(`SelectionResolver.swift`, `SearchModeResolver.swift`, the `*Testable.swift` files) compiled into the
`unit-tests` target and tested in isolation; the AppKit layer (windows, views, event taps) is kept thin
and is deliberately *not* unit-tested. So coverage is meaningful **per kernel / per feature-source** —
those should trend to ~100%, every decision branch exercised — and an aggregate app-wide % is not a
goal.
**Coverage is documentation here, not a build artifact.** The only stored coverage is:
1. the per-feature badge (`> **Line coverage:** …`) atop each `*Specs.md`, and
2. the root **`src/coverage.md`** table.
There is intentionally **nothing else**: no lcov, no HTML, no committed `.xcresult`, and coverage is
**not** gathered on routine runs (`scripts/run_tests.sh`, CI, or Xcode) — only when this skill runs it.
(Coverage isn't usefully viewable in IntelliJ, so there's no IDE-integration artifact to maintain.)
## Workflow
1. **Measure into a throwaway bundle** (then delete it — store nothing technical):
```sh
rm -rf /tmp/altcov.xcresult
set -o pipefail && xcodebuild test \
-project alt-tab-macos.xcodeproj -scheme Test -configuration Release \
-enableCodeCoverage YES -resultBundlePath /tmp/altcov.xcresult | scripts/xcbeautify
```
If the build is red, stop and report — coverage on a failing suite is meaningless.
2. **Parse** `xcrun xccov view --report --json /tmp/altcov.xcresult`. Each `targets[].files[]` has
`path`, `lineCoverage`, `coveredLines`, `executableLines`, `functions[]`. For line-by-line counts of
one file while investigating a gap: `xcrun xccov view --file <abs-path> /tmp/altcov.xcresult`.
3. **Refresh `src/coverage.md`.** Rewrite the table with every `src/` file (excluding `*Tests.swift`)
that the test target compiles, sorted worst-coverage-first, as `| NN% (cov/exec) | \`path\` |`.
Keep the header note explaining the Humble-Object scope and that this + the badges are the only
stored coverage. Update the "updated" date.
4. **Offer to refresh the per-spec badges.** For each `<Base>Specs.md` whose `<Base>.swift` (or kernel)
is in the report, propose updating its `> **Line coverage:** …` line with the new % + today's date.
Ask first; only apply the ones the user accepts. Keep honest notes where a file is intentionally
partial (e.g. `PreferencesMigrations.swift`).
5. **Rank gaps & suggest tests.** For kernels below 100%, list the uncovered functions/regions, map each
to the behavior it represents (read the source), and write ready-to-paste additions: a
`- **testGroupScenario** — …` spec line + a short XCTest stub in that suite's builder style. Don't add
tests automatically unless asked.
6. **Clean up:** `rm -rf /tmp/altcov.xcresult`. Leave no technical coverage files in the tree.
## Reporting
- Headline: a small ascending table of kernel `lineCoverage`, and the delta vs the previous `src/coverage.md`.
- Ranked gap list: file → uncovered function/branch → the behavior it represents.
- Suggested scenarios (spec lines + test stubs) for the top gaps.
- State exactly what was rewritten (`src/coverage.md`, which badges). Flag files that are partial *by
design* (AppKit glue, excluded migrations) so a low number isn't mistaken for a problem.
@@ -0,0 +1,75 @@
---
name: translate-missing-l10n
description: Translate missing l10n strings for AltTab using Claude's multilingual ability. Refreshes the source `Localizable.strings` from current Swift code, finds keys missing in each `<lang>.lproj/Localizable.strings`, translates them, then writes them back via `scripts/l10n/apply_translations.ts`.
---
# /translate-missing-l10n
## Project context
AltTab is a macOS app that helps switch between windows, similar to the Windows alt-tab experience. The strings to translate are mostly Settings UI — some tooltips, dialogs, and general user guidance.
## Target languages (20)
`de, ja, fr, es, zh-CN, pt-BR, nl, ko, it, pl, ar, zh-HK, vi, tr, sv, th, zh-TW, he, id, ru`
(`en` is the source — handled automatically by the apply step.)
## Translation guidelines
- **Format specifiers must be preserved exactly**: `%@`, `%d`, `%1$@`, `%2$@`, `\n`, `\t`. The number and order of specifiers in the translation must match the source. Positional and unindexed forms are interchangeable (`%@ %@` ≡ `%1$@ %2$@`), but the count must match.
- **Do not translate proper nouns**: "AltTab", "macOS", "Mission Control", "Spaces", "Dock".
- **Do not translate modifier key names**: "Cmd", "Option", "Alt", "Shift", "Ctrl", "Control", "Fn", "Command".
- **Use Apple's official platform terminology** for the target locale where one exists. For example, prefer the term Apple uses in macOS System Settings for that locale ("Réglages" vs "Préférences" in French) over a literal translation.
- **Match the source brevity**. Settings strings are short; the translation should be short too. Prefer concise, idiomatic phrasing over literal grammatical completeness.
- **Match macOS tone**: neutral, direct, no exclamation marks unless the source has them.
- **Comments in the source file are engineer guidance, not user-visible text**. Use them to disambiguate meaning, but never include them in the translation.
## Workflow
1. **Refresh the source.** Run:
```sh
bash scripts/l10n/extract_l10n_strings.sh
```
This regenerates `resources/l10n/Localizable.strings` from the current Swift code via `genstrings`.
2. **Parse the source.** Read `resources/l10n/Localizable.strings`. Each entry has the shape:
```
/* engineer comment */
"key" = "value";
```
Build the ordered list of `(comment, key, value)` triples. The `value` for the source is usually identical to `key`, but may include positional indices (`%1$@`, `%2$@`) when there are multiple specifiers.
3. **Compute missing keys per language.** For each of the 20 target languages, read `resources/l10n/<lang>.lproj/Localizable.strings`. Each line is `"key" = "translation";`. A key is **missing** if it's present in the source but either (a) absent from the target file, or (b) present with an empty or whitespace-only value. Treat (b) the same as (a) — produce a real translation.
4. **Stop if nothing is missing.** Report and exit.
5. **Translate.** For each language, produce a translation for each missing key, applying the guidelines above. Do not invent keys; only translate keys that appear in the source. Group your work into batches of 5–10 languages per call to keep individual outputs manageable.
6. **Apply each batch.** Write the batch to a fresh file under `/tmp` (not committed) with this shape:
```json
{
"fr": { "About %@": "À propos de %@", "Quit": "Quitter" },
"ja": { "About %@": "%@について" }
}
```
Then run:
```sh
npx ts-node scripts/l10n/apply_translations.ts /tmp/batch-NN.json
```
The helper:
- Validates format specifiers — translations whose specifier set doesn't match the source value are rejected with a clear error and **not merged**.
- Always rewrites `en.lproj/Localizable.strings` from source **keys** (each entry written as `"key" = "key";` for symmetry) — no need to include `en` in your batch. This avoids leaking genstrings-rewritten values like `%1$@` into the English file when the original source key uses plain `%@`.
- Rewrites each `<lang>.lproj/Localizable.strings` using source order: existing translations are preserved, new translations merged in, and keys no longer in the source are pruned.
- Exits with code `2` if any entries were rejected.
7. **Handle rejections.** If `apply_translations.ts` reports format-specifier mismatches, fix those translations and re-run only the affected language(s) in a follow-up batch. Do not move on while rejections are outstanding.
## Reporting
After the run, report:
- Number of languages processed.
- Total translations produced and merged.
- Any entries you intentionally left untranslated (e.g., the source was already a proper noun) — list them so the user can decide.
- Any format-specifier rejections that required manual fixes.
+1
View File
@@ -0,0 +1 @@
v11.3.0
+9 -3
View File
@@ -1,3 +1,9 @@
github: lwouis
patreon: alt_tab_macos
custom: ["paypal.com/donate/?hosted_button_id=ACYAC3UYCM7CN", "donate.stripe.com/4gw9D7bA3g3O0ikaEF"]
# alt-tab-free [depaywall]: upstream's FUNDING.yml routed the GitHub "Sponsor" button on the fork's
# repo to lwouis (github: lwouis / patreon: alt_tab_macos / ko_fi: alt_tab / a lwouis PayPal button) —
# i.e. every donation would have gone to the author the fork just de-paywalled (PLAN §3.5). It has
# been emptied so NO sponsor button renders and no donation routes to the upstream author.
#
# OWNER-OVERRIDABLE-BEFORE-PUBLISH: to accept sponsorships for THIS fork, uncomment and fill in your
# own handles (do NOT re-add lwouis's). Otherwise leave this file empty / delete it.
# github: <fork-owner-handle>
# custom: ["https://<fork-domain>/donate"]
+173 -15
View File
@@ -1,7 +1,27 @@
# alt-tab-free: fork-owned CI/CD workflow (diverged from upstream lwouis/alt-tab-macos).
# Upstream's ci_cd.yml fires `on: push: branches: [master]` ONLY and is the sole workflow,
# so this fork ADDS a `pull_request:` trigger to gate the sync PR pre-merge (see PLAN §4.2),
# gates every release/push-only step under `if: github.event_name == 'push'`, and wires the
# anti-relock + conflict-marker greps as the FIRST push-job steps so a relocked or conflicted
# tree aborts BEFORE update_appcast.sh (Sparkle sign), semantic-release (tag push), and the
# gh-release. This file is in the §6.2 "keep ours" recurring-conflict set — on an upstream
# ci_cd.yml change, reconcile manually and re-confirm the `pull_request:` trigger survives.
on:
push:
branches:
- master
# alt-tab-free [depaywall]: PR trigger so the sync PR runs the guards pre-merge (PLAN §4.2).
# A separate fork-owned .github/workflows/guard.yml ALSO runs the guards on pull_request, so a
# careless upstream-conflict resolution that strips this trigger cannot silently disarm the gate.
pull_request:
branches:
- master
# alt-tab-free [depaywall]: GitHub defaults GITHUB_TOKEN to read-only since 2023; semantic-release
# (@semantic-release/git) pushes commits+tags to master and softprops/action-gh-release creates the
# release — both need contents:write, else they 403 and the appcast enclosure 404s for auto-update
# (PLAN §4.3).
permissions:
contents: write
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
APPCENTER_SECRET: ${{ secrets.APPCENTER_SECRET }}
@@ -10,15 +30,18 @@ env:
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_P12_CERTIFICATE: ${{ secrets.APPLE_P12_CERTIFICATE }}
FEEDBACK_TOKEN: ${{ secrets.FEEDBACK_TOKEN }}
NETLIFY_WEBHOOK: ${{ secrets.NETLIFY_WEBHOOK }}
# alt-tab-free [depaywall]: optional .p12 export password (empty if exported password-less).
# Not part of the release-gate AND — the cert import tolerates an empty password.
APPLE_P12_PASSWORD: ${{ secrets.APPLE_P12_PASSWORD }}
SPARKLE_ED_PRIVATE_KEY: ${{ secrets.SPARKLE_ED_PRIVATE_KEY }}
GITHUB_EVENT_BEFORE: ${{ github.event.before }}
GITHUB_EVENT_AFTER: ${{ github.event.after }}
BUILD_DIR: ${{ github.workspace }}
XCODE_BUILD_PATH: DerivedData/Build/Products/Release
VERSION_FILE: VERSION.txt
APP_NAME: AltTab
# alt-tab-free [depaywall]: must equal PRODUCT_NAME in config/local.xcconfig
# (PLAN §3.1/§4.3) or the build/package/appcast scripts mismatch the artifact.
APP_NAME: CommandTabFree
jobs:
build:
runs-on: macos-15 # all options: https://github.com/actions/runner-images/tree/main
@@ -32,37 +55,172 @@ jobs:
COMMITS: ${{ toJson(github.event.commits) }}
run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
COUNT=$(( $(echo "$COMMITS" | jq length) + 5 ))
COUNT=$(( $(echo "$COMMITS" | jq length) + 30 ))
else
COUNT=1
fi
echo "fetch-depth=$COUNT" >> "$GITHUB_OUTPUT"
- uses: actions/checkout@v3
- uses: actions/checkout@v6
with:
fetch-depth: ${{ steps.pre-checkout.outputs.fetch-depth }}
- uses: actions/setup-node@v3
# alt-tab-free [depaywall]: Guard B + Guard C run FIRST on the push job (before run_tests.sh,
# and therefore before update_appcast.sh's Sparkle sign + semantic-release's tag push) so a
# relock or a still-conflicted tree aborts the job BEFORE any irreversible side-effect (PLAN
# §4.4 "Where the guards run"). They are near-instant target-independent greps, so running them
# first is free. They also run on the PR path for the fastest red signal. A second copy sits
# just before action-gh-release as belt-and-suspenders.
- name: anti-relock — verify de-paywall marker present (Guard B)
run: |
grep -q 'depaywall' src/pro/license/LicenseManager.swift \
|| { echo "PAYWALL RELOCKED: depaywall marker missing from computeState()"; exit 1; }
# The marker proves the patch is present; pair with the if-false wrap the patch introduces.
# A bare `return .pro` grep is NOT load-bearing (it matches the unpatched line 187 too).
grep -Eq 'guard[[:space:]]+false[[:space:]]+else' src/pro/license/LicenseManager.swift \
|| { echo "PAYWALL RELOCKED: 'guard false else' (forced .pro) missing from computeState()"; exit 1; }
- name: anti-conflict — no unresolved merge markers (Guard C)
run: |
if git -c grep.lineNumber=false grep -nE '^(<<<<<<<|=======|>>>>>>>)' -- . ':(exclude)docs/'; then
echo "UNRESOLVED CONFLICT MARKERS present — resolve before merge/release"; exit 1
fi
# alt-tab-free [depaywall]: release-readiness gate (PLAN §3.3/§4.3 owner-secret checklist).
# The fork ships unsigned/ad-hoc until the OWNER provisions the Apple Developer ID cert and the
# Sparkle key. We do NOT hard-fail when those secrets are absent — that would make every push
# RED on a fork that is correctly built but not yet signing-provisioned. Instead we compute a
# boolean from secret presence and SKIP the sign/notarize/appcast/release tail cleanly when it
# is false. The build + Guard A (run_tests.sh) still run on push, so push CI is GREEN today and
# the release tail FLIPS ON automatically the moment the owner adds the secrets. Secrets are not
# available in step-level `if:` directly, so map them to env and emit an output here.
- name: release-gate — are signing/notarization secrets present?
id: release-gate
env:
HAS_P12: ${{ secrets.APPLE_P12_CERTIFICATE != '' }}
HAS_APPLE_ID: ${{ secrets.APPLE_ID != '' }}
HAS_APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD != '' }}
HAS_APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID != '' }}
HAS_SPARKLE_KEY: ${{ secrets.SPARKLE_ED_PRIVATE_KEY != '' }}
run: |
set -euo pipefail
if [ "$HAS_P12" = "true" ] && [ "$HAS_APPLE_ID" = "true" ] \
&& [ "$HAS_APPLE_PASSWORD" = "true" ] && [ "$HAS_APPLE_TEAM_ID" = "true" ] \
&& [ "$HAS_SPARKLE_KEY" = "true" ]; then
echo "signing-ready=true" >> "$GITHUB_OUTPUT"
echo "All signing/notarization/Sparkle secrets present — release tail WILL run on push."
else
echo "signing-ready=false" >> "$GITHUB_OUTPUT"
echo "::warning::Signing/notarization/Sparkle secrets absent — release tail (codesign/notarize/appcast/semantic-release/gh-release) is SKIPPED. Build + Guard A still run. Provision APPLE_P12_CERTIFICATE / APPLE_ID / APPLE_PASSWORD / APPLE_TEAM_ID / SPARKLE_ED_PRIVATE_KEY in the 'production' Environment to enable releases (PLAN §3.3/§3.4)."
fi
- uses: actions/setup-node@v6
with:
node-version: 16
node-version: 16 # PLAN §4.3: keep node-16; the package.json engines mismatch only warns
cache: 'npm'
- run: sudo xcode-select -s /Applications/Xcode_26.0.1.app/Contents/Developer
- run: scripts/print_env.sh
- run: npm ci
# alt-tab-free [depaywall]: commitlint is gated to the push path. On push it lints the whole
# pushed range, which drags in upstream's non-conforming messages on a `chore(sync)` merge —
# this is handled by an `ignores` predicate in commitlint.config.js (PLAN §4.3) that drops the
# synthetic merge commit and upstream's own messages; do NOT break commitlint on --no-ff merges.
# $GITHUB_EVENT_BEFORE/AFTER are push-context (empty on pull_request), so a PR-safe variant runs
# below on the PR path instead.
- run: npx commitlint --from "$GITHUB_EVENT_BEFORE" --to "$GITHUB_EVENT_AFTER" --verbose
if: github.event_name == 'push'
# alt-tab-free [depaywall]: PR-safe commitlint — lints base..head (valid on pull_request),
# paired with the commitlint.config.js `ignores` predicate (PLAN §4.2/§4.3).
- run: npx commitlint --from "${{ github.event.pull_request.base.sha }}" --to "${{ github.sha }}" --verbose
if: github.event_name == 'pull_request'
# Runs on both push and PR: catches an un-regenerated l10n/generated-file diff (PLAN §4.2/§4.5).
- run: scripts/ensure_generated_files_are_up_to_date.sh
# alt-tab-free [depaywall]: release-path — a semantic-release dry-run against a PR head is
# meaningless and can mis-bump, so gate to push (PLAN §4.2).
- run: scripts/determine_next_version.sh
if: github.event_name == 'push'
# alt-tab-free [depaywall]: decouple the release apparatus from "every signing-ready push".
# determine_next_version.sh writes an EMPTY VERSION.txt when no commit since the last tag is
# release-worthy (semantic-release dry-run finds no bump). Gate the sign/notarize/release steps
# on this so a docs/ci/chore push still runs guards + commitlint + run_tests (Release-config
# compile check) but does NOT sign-build, notarize, or cut a release — no [skip ci] needed (§4.3).
- name: release-decision — did semantic-release compute a version?
id: release-decision
if: github.event_name == 'push'
run: |
if [ -n "$(tr -d '[:space:]' < "$VERSION_FILE" 2>/dev/null)" ]; then
echo "will-release=true" >> "$GITHUB_OUTPUT"
echo "Release-worthy: semantic-release will cut v$(cat "$VERSION_FILE")."
else
echo "will-release=false" >> "$GITHUB_OUTPUT"
echo "::notice::No release-worthy commit — build/test only; notarize+release tail skipped."
fi
# Inject the release version only when releasing; an empty CURRENT_PROJECT_VERSION would crash
# App.version (see config/local.xcconfig). Non-release builds use the committed 0.0.0 default.
- run: scripts/replace_environment_variables_in_app.sh
if: github.event_name == 'push' && steps.release-decision.outputs.will-release == 'true'
# codesign needs APPLE_P12_CERTIFICATE — gated on signing-ready so a not-yet-provisioned fork
# does not RED on the missing-cert import (PLAN §3.3/§4.3).
- run: scripts/codesign/setup_ci_master.sh
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
# Guard A — the anti-relock unit test (appended to LicenseManagerTests.swift). Runs on both
# push and PR (no secrets needed); on the push path it sits before the sign/tag steps below
# so a relock fails BEFORE any irreversible side-effect (PLAN §4.4). This is what keeps push
# CI GREEN today on the signing-unprovisioned fork.
- run: scripts/run_tests.sh
- run: scripts/build_app.sh
# alt-tab-free [depaywall]: build the Release product to prove the tree compiles. The fork
# inherits upstream's Developer ID via config/release.xcconfig (CODE_SIGN_IDENTITY), which is
# absent on CI until the owner provisions the Apple cert — so when the release gate is NOT
# signing-ready we build AD-HOC (CODE_SIGN_IDENTITY=-, signing not required, no timestamp) to
# prove the tree compiles without a cert. When the owner adds the secrets AND sets the fork's
# Developer ID in config/local.xcconfig, this builds signed for the release tail (PLAN §3.3/§4.3).
- name: build app (signed — owner cert provisioned)
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
run: scripts/build_app.sh
- name: build app (ad-hoc — until signing-provisioned)
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready != 'true'
run: scripts/build_app.sh CODE_SIGN_IDENTITY=- CODE_SIGNING_REQUIRED=NO OTHER_CODE_SIGN_FLAGS=--timestamp=none
# --- Release tail: requires the owner's Apple Developer ID + Sparkle secrets. Skipped cleanly
# (NOT failed) when they are absent, so push CI stays GREEN until the owner provisions them. ---
- run: scripts/package_and_notarize_release.sh
- run: scripts/upload_symbols_to_appcenter.sh
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
# alt-tab-free [depaywall]: upload_symbols_to_appcenter.sh REMOVED — telemetry is off (PLAN §3.4).
- run: scripts/update_appcast.sh
- run: scripts/update_readme_and_website.sh
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
# alt-tab-free [depaywall]: update_readme_and_website.sh REMOVED — it queried the UPSTREAM
# lwouis/alt-tab-macos GitHub API for stars/downloads and rewrote docs/contributors.md from the
# UPSTREAM contributor graph (semantic mismatch for the fork) and dispatched the lwouis website.
# Cosmetic only; dropped per PLAN §4.0/§4.3 (alongside update_website.sh, already removed).
- run: npx semantic-release
- id: set_tag_name
run: echo "tag_name=v"$(cat $VERSION_FILE)"" >> "$GITHUB_OUTPUT"
- uses: softprops/action-gh-release@v1
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
- id: set_release_info
run: scripts/extract_latest_changelog.sh
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
# alt-tab-free [depaywall]: belt-and-suspenders copy of Guard B + Guard C immediately before the
# release is created. The load-bearing copy is at the top of the job (pre-tag-push); this second
# copy guards the gh-release object itself (PLAN §4.4).
- name: anti-relock + anti-conflict re-check (belt-and-suspenders)
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
run: |
grep -q 'depaywall' src/pro/license/LicenseManager.swift \
|| { echo "PAYWALL RELOCKED: depaywall marker missing from computeState()"; exit 1; }
grep -Eq 'guard[[:space:]]+false[[:space:]]+else' src/pro/license/LicenseManager.swift \
|| { echo "PAYWALL RELOCKED: 'guard false else' (forced .pro) missing from computeState()"; exit 1; }
if git -c grep.lineNumber=false grep -nE '^(<<<<<<<|=======|>>>>>>>)' -- . ':(exclude)docs/'; then
echo "UNRESOLVED CONFLICT MARKERS present — resolve before release"; exit 1
fi
# alt-tab-free [depaywall]: point the release at THIS fork's repo via the ambient GITHUB_TOKEN
# (release.config.js has no @semantic-release/github plugin, so softprops is the sole release
# creator — PLAN §4.3). repository defaults to ${{ github.repository }} = the fork.
- uses: softprops/action-gh-release@v3
if: github.event_name == 'push' && steps.release-gate.outputs.signing-ready == 'true' && steps.release-decision.outputs.will-release == 'true'
with:
tag_name: ${{ steps.set_tag_name.outputs.tag_name }}
repository: ${{ github.repository }}
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ steps.set_release_info.outputs.tag_name }}
body: ${{ steps.set_release_info.outputs.body }}
files: ${{ env.XCODE_BUILD_PATH }}/*.zip
- run: scripts/update_website.sh
# alt-tab-free [depaywall]: the release tail intentionally does NOT advance .fork-sync-state.
# That file is the UPSTREAM-sync cursor — the last-synced UPSTREAM tag (e.g. v11.3.0), read by
# upstream_sync.yml to pick "the oldest upstream tag strictly newer than it." The fork versions
# independently (semantic-release cuts v100.x), so a prior revision's step that wrote the FORK
# release tag here set the cursor to v100.x — after which no upstream tag is ever "newer" and
# upstream-sync would silently never fire. The cursor must instead be advanced by the
# upstream-sync merge flow, recording the UPSTREAM tag it synced (to be wired with
# upstream_sync.yml — PLAN §4.2). Until then .fork-sync-state stays at the last real upstream tag.
# alt-tab-free [depaywall]: update_website.sh (lwouis website dispatch) REMOVED (PLAN §3.4/§4.2).
+94
View File
@@ -0,0 +1,94 @@
# alt-tab-free — anti-relock guard workflow (docs/PLAN-maintained-fork.md §4.4)
#
# A SEPARATE, fork-owned workflow that runs the anti-relock guards on every PR,
# INDEPENDENTLY of ci_cd.yml. Rationale (§4.4): ci_cd.yml is the file most likely to take an
# upstream conflict, and a careless "keep ours/theirs" resolution could silently strip its
# pull_request: trigger or its release-step gating — at which point the in-ci_cd.yml guards
# would stop gating PRs with NO error. A guard workflow that does NOT inherit ci_cd.yml's
# trigger survives that. This is the reviewer's primary green/red signal on a sync PR.
#
# Three guards, each fails the job LOUDLY:
# A — the Test scheme (the mock-injected anti-relock unit tests in LicenseManagerTests.swift)
# B — a target-independent grep that the de-paywall flip is still present in computeState()
# C — a tree-wide grep that no unresolved git conflict markers survive into a merge/release
#
# Defense-in-depth note: Guards B + C are ALSO wired into ci_cd.yml as the FIRST push-job
# steps (CI agent owns that) so a relock/conflict-laden tree aborts the release BEFORE the tag
# is pushed or the binary signed, even if this PR gate is ever missing/misconfigured (§4.4).
name: guard
on:
pull_request:
branches: [master]
permissions:
contents: read
jobs:
# Guards B + C are near-instant greps; run them on cheap ubuntu so a relock or a still-
# conflicted tree fails FAST, before the expensive macOS Guard-A job even starts (§4.5).
grep-guards:
name: anti-relock greps (B + C)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
# GUARD B — verify the de-paywall flip is still present at the single state producer.
# §4.4 pitfall: a bare `return .pro` grep MATCHES THE UNPATCHED FILE (computeState() already
# contains `return .pro` in the keychain-valid branch on a fully relocked tree), so it is NOT
# load-bearing. The load-bearing signals are (1) the `depaywall` marker comment, which exists
# ONLY because the fork added it, AND (2) the `if false { … }` wrap that the patch introduces
# around the original (now dead) body. Both are absent on an unpatched/relocked upstream file.
- name: Guard B — de-paywall marker + if-false wrap present in computeState()
run: |
set -euo pipefail
F=src/pro/license/LicenseManager.swift
if [ ! -f "$F" ]; then
echo "::error::Guard B: $F not found — chokepoint moved? Refresh the de-paywall patch (§6.2)."
exit 1
fi
grep -q 'depaywall' "$F" || {
echo "::error::PAYWALL RELOCKED: 'depaywall' marker missing from $F — the de-paywall flip was lost in a merge. Refresh the patch (§6.2)."
exit 1
}
grep -Eq 'guard[[:space:]]+false[[:space:]]+else' "$F" || {
echo "::error::PAYWALL RELOCKED: 'if false { … }' wrap missing from $F — the de-paywall body-suppress was lost. Refresh the patch (§6.2)."
exit 1
}
echo "Guard B OK: de-paywall marker + if-false wrap present in $F."
# GUARD C — no unresolved git conflict markers anywhere in the tree. The §4.2 sync cron
# deliberately commits a conflicted tree (markers + --no-verify) for a human to resolve;
# nothing else guarantees the human removed EVERY marker before merge. A markers-laden
# commit merged to master becomes a permanent ancestor of the published tag (un-compilable
# source), contradicting §5(1). Exclude docs/ so this plan's own literal marker examples
# don't trip the grep.
- name: Guard C — no unresolved merge conflict markers
run: |
set -euo pipefail
if git -c grep.lineNumber=false grep -nE '^(<<<<<<<|=======|>>>>>>>)' -- . ':(exclude)docs/'; then
echo "::error::UNRESOLVED CONFLICT MARKERS present — resolve before merge/release (§4.4 Guard C)."
exit 1
fi
echo "Guard C OK: no unresolved conflict markers."
# GUARD A — the behavioral anti-relock unit tests (mock-injected LicenseManager) via the Test
# scheme. §4.4: this MUST run on macos-15 with the pinned Xcode — run_tests.sh is `xcodebuild
# test`, which cannot run on ubuntu. If left on ubuntu, Guard A silently degrades to greps-only
# and the behavioral relock test never executes (the exact silent-disarming class this plan
# guards against). Bootstrap assertion (§4.4): on the deliberately-relocked acceptance PR,
# confirm THIS job produced a real test result that is RED on the relock — not just the greps.
unit-tests:
name: anti-relock unit tests (A)
runs-on: macos-15 # MUST match ci_cd.yml — `xcodebuild test` needs the pinned Xcode
steps:
- uses: actions/checkout@v6
# Pin the same Xcode as ci_cd.yml (§4.5 bootstrap invariant — re-pin on every upstream bump).
- run: sudo xcode-select -s /Applications/Xcode_26.0.1.app/Contents/Developer
# run_tests.sh runs the `Test` scheme (-configuration Release), which includes the
# appended anti-relock tests in src/pro/license/LicenseManagerTests.swift:
# testDepaywallProNeverLocked — load-bearing `state == .pro` assert
# testDepaywallStillProAfterTrialExpiry — discriminating (expired-trial) assert
# A relock makes computeState() fall back to computeTrialState() and these go RED.
- name: Guard A — run the Test scheme (anti-relock unit tests)
run: scripts/run_tests.sh
+226
View File
@@ -0,0 +1,226 @@
# alt-tab-free — upstream sync workflow (docs/PLAN-maintained-fork.md §4.2)
#
# Polls lwouis/alt-tab-macos for new release tags and opens a reviewable sync PR.
# Selects the OLDEST upstream tag strictly newer than the last-merged tag recorded in
# `.fork-sync-state` (NOT "newest tag minus --is-ancestor"). This is the §4.2
# never-drop-commits invariant: `.fork-sync-state` advances ONLY when a sync PR merges to
# master (a ci_cd.yml push-job step — owned by the CI agent), so a sync PR that is
# closed-without-merge or abandoned can never silently skip its tag — that tag stays "next"
# until it is actually merged. This subsumes the old `merge-base --is-ancestor` guard.
#
# A release is cut only when a human merges the PR to master (ci_cd.yml on: push). This
# workflow never releases; it only opens the PR for review.
name: upstream-sync
on:
# §4.2 cron-durability note: the in-repo `schedule:` SILENTLY auto-disables after 60 days
# of repo inactivity (no error, no notification). It is kept here as belt-and-suspenders.
# The RECOMMENDED PRIMARY trigger is an EXTERNAL scheduler hitting `repository_dispatch`
# carrying the SYNC_BOT_TOKEN (immune to the 60-day rule, and composes with the
# workflow-re-trigger token). See ownerActions / §4.2.
schedule:
- cron: '0 7 * * *' # daily; cheap, idempotent
workflow_dispatch: {}
repository_dispatch:
types: [upstream-sync] # external-scheduler entry point (§4.2 primary durability path)
# GITHUB_TOKEN is read-only by default; opening a PR + pushing a branch need these.
permissions:
contents: write
pull-requests: write
jobs:
sync:
runs-on: ubuntu-latest # pure git, no Xcode
env:
# CRITICAL (§4.2 BLOCKING) — do NOT use ${{ github.token }} here. By GitHub's documented
# recursion-prevention rule, a branch push / PR authored with the default GITHUB_TOKEN
# does NOT trigger other workflows — so guard.yml and ci_cd.yml's pull_request: checks
# would NEVER fire on the sync PR and the entire pre-merge gate would silently never run.
# SYNC_BOT_TOKEN MUST be a fork-owned credential that re-triggers workflows: a GitHub App
# installation token (preferred — least-privilege, short-lived) or a fork-owned PAT.
GH_TOKEN: ${{ secrets.SYNC_BOT_TOKEN }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
# Persist the fork-owned credential (NOT the default GITHUB_TOKEN) as the push
# credential, so the branch push below re-triggers guard.yml / ci_cd.yml PR checks.
token: ${{ secrets.SYNC_BOT_TOKEN }}
- name: Fail closed if SYNC_BOT_TOKEN is missing
run: |
# §4.2: without the workflow-re-triggering token the pre-merge gate is silently
# disarmed. Fail loudly here rather than open a check-less PR.
if [ -z "${SYNC_BOT_TOKEN:-}" ]; then
echo "::error::SYNC_BOT_TOKEN is not set. Refusing to open a check-less sync PR (§4.2)."
echo "Provision a GitHub App installation token (preferred) or fork-owned PAT as SYNC_BOT_TOKEN."
exit 1
fi
env:
SYNC_BOT_TOKEN: ${{ secrets.SYNC_BOT_TOKEN }}
- name: Add upstream + fetch tags
run: |
set -euo pipefail
git remote add upstream https://github.com/lwouis/alt-tab-macos.git || true
git fetch upstream --tags --force
- name: Verify sync labels exist (§4.2 — fail closed, never treat empty as "no open sync")
run: |
set -euo pipefail
# Guard 2 below and the §0.1 trip-wire query `sync` / `conflict` / `chokepoint-refresh`.
# `gh pr list --label <missing>` returns an EMPTY LIST, not an error, for a label that
# was never created — so on a fresh repo Guard 2 would silently no-op. Fail closed if a
# required label is absent; the bootstrap (§6.1) creates them with `gh label create`.
missing=0
for L in sync conflict chokepoint-refresh; do
if ! gh label list --json name --jq '.[].name' | grep -qxF "$L"; then
echo "::error::Required label '$L' is missing. Create it at bootstrap (§6.1): gh label create $L"
missing=1
fi
done
[ "$missing" -eq 0 ] || exit 1
- name: Select oldest upstream tag strictly newer than .fork-sync-state
id: tag
run: |
set -euo pipefail
# State-file-driven selection (§4.2): NOT "newest tag minus --is-ancestor".
last_synced="$(tr -d '[:space:]' < .fork-sync-state)"
if [ -z "$last_synced" ]; then
echo "::error::.fork-sync-state is empty; seed it with the last-merged upstream tag (e.g. v11.3.0)."
exit 1
fi
echo "Last synced (from .fork-sync-state): $last_synced"
# UPSTREAM-ONLY enumeration: `git tag -l 'v*'` would also match the FORK's OWN
# semantic-release tags (the fork cuts vX.Y.Z every sync — §4.3), so list tags from
# the upstream remote explicitly. Sort by version; keep only tags strictly newer than
# the recorded one; take the OLDEST of those (resolve-in-order — §4.2).
all_newer="$(git ls-remote --tags --refs upstream 'v*' \
| awk -F/ '{print $NF}' \
| sort -V \
| awk -v last="$last_synced" '
$0 == last { seen = 1; next }
seen { print }
')"
# Fallback for the case where last_synced is not itself present upstream: take every
# tag that sorts strictly after it.
if [ -z "$all_newer" ]; then
all_newer="$(git ls-remote --tags --refs upstream 'v*' \
| awk -F/ '{print $NF}' \
| sort -V \
| awk -v last="$last_synced" '{ if ($0 != last) print $0 }' \
| while read -r t; do
# keep only tags that sort AFTER last_synced
if [ "$(printf '%s\n%s\n' "$last" "$t" | sort -V | tail -1)" = "$t" ] && [ "$t" != "$last" ]; then
echo "$t"
fi
done)"
fi
next="$(printf '%s\n' "$all_newer" | sed '/^$/d' | head -1)"
if [ -z "$next" ]; then
echo "Up to date: no upstream tag newer than $last_synced."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Next tag to sync (oldest strictly newer): $next"
# Guard — a prior sync is still OPEN (resolve-in-order, §4.2): do NOT open a new PR
# while any sync/* PR is unmerged. A backlog pauses syncing until the human merges it;
# this is the never-drop-commits behavior. The liveness alert keys off the stalled flag.
# `gh pr list --label sync` fails closed because the label existence was verified above.
open_sync="$(gh pr list --state open --label sync --json number,headRefName,createdAt \
--jq 'sort_by(.createdAt) | .[0] // empty')"
if [ -n "$open_sync" ]; then
echo "A prior sync PR is still open (resolve-in-order): $open_sync"
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "stalled=true" >> "$GITHUB_OUTPUT" # liveness alert keys off this (§4.2)
exit 0
fi
echo "latest=$next" >> "$GITHUB_OUTPUT"
- name: Merge onto a sync branch (real merge commit, conventional message)
if: steps.tag.outputs.skip != 'true'
id: merge
run: |
set -euo pipefail
TAG='${{ steps.tag.outputs.latest }}'
git config user.name "fork-sync-bot"
git config user.email "fork-sync-bot@users.noreply.github.com"
git switch -c "sync/${TAG}"
# NO --no-commit: let git author a REAL merge commit with a CONVENTIONAL message so
# commitlint / @semantic-release/commit-analyzer stay happy (§4.3). On conflict, commit
# the conflicted tree (markers included, --no-verify) so the PR shows the markers for a
# human to resolve; Guard C (guard.yml + ci_cd.yml) then blocks it from ever shipping.
if git merge --no-ff -m "chore(sync): merge upstream ${TAG}" "${TAG}"; then
conflicts=false
else
git add -A
git commit --no-verify \
-m "chore(sync): merge upstream ${TAG} (CONFLICTS — resolve before merge)"
conflicts=true
fi
echo "conflicts=${conflicts}" >> "$GITHUB_OUTPUT"
# §0.1 trip-wire A — surface chokepoint churn as a per-sync signal. A nonzero count
# means an upstream change touched a de-paywall chokepoint file in this merge range
# (last-synced tag .. new tag); the PR is labeled `chokepoint-refresh` (below) so the
# trip-wire is a single query, not a memory exercise.
CHOKEPOINTS="src/pro/license/LicenseManager.swift src/pro/ProFeature.swift src/preferences/PreferenceDefinition.swift src/pro/scheduling/ProTransitionManager.swift src/pro/license/LicenseCookie.swift src/vendors/AppCenterCrashes.swift"
LAST_SYNCED="$(tr -d '[:space:]' < .fork-sync-state)"
churn="$(git rev-list --count "${LAST_SYNCED}..${TAG}" -- $CHOKEPOINTS 2>/dev/null || echo 0)"
# Also flag if the merge left a conflict in any chokepoint file (the conflicted commit
# is HEAD; compare against its first parent HEAD~1 = the pre-merge master tip).
chokepoint_conflict=0
if git diff --name-only HEAD~1 HEAD 2>/dev/null | grep -qE 'LicenseManager\.swift|ProFeature\.swift|PreferenceDefinition\.swift|ProTransitionManager\.swift|LicenseCookie\.swift|AppCenterCrashes\.swift'; then
if [ "${conflicts:-false}" = "true" ]; then
chokepoint_conflict=1
fi
fi
echo "churn=${churn}" >> "$GITHUB_OUTPUT"
echo "chokepoint_conflict=${chokepoint_conflict}" >> "$GITHUB_OUTPUT"
git push origin "HEAD:sync/${TAG}"
- name: Open PR
if: steps.tag.outputs.skip != 'true'
run: |
set -euo pipefail
TAG='${{ steps.tag.outputs.latest }}'
CHURN='${{ steps.merge.outputs.churn }}'
CONFLICTS='${{ steps.merge.outputs.conflicts }}'
CHOKEPOINT_CONFLICT='${{ steps.merge.outputs.chokepoint_conflict }}'
# Label fail-closed (§4.2): conflict -> `sync,conflict`, else `sync`.
if [ "$CONFLICTS" = "true" ]; then
LABELS="sync,conflict"
else
LABELS="sync"
fi
BODY="Automated upstream sync to \`${TAG}\`.
Selected as the OLDEST upstream tag strictly newer than \`.fork-sync-state\` (§4.2).
Verify the guard.yml + ci_cd.yml PR checks are GREEN (anti-relock test + marker/conflict greps) before merge.
If checks did not appear, SYNC_BOT_TOKEN is mis-set to the default GITHUB_TOKEN — the gate is disarmed (§4.2).
Chokepoint-churn count for this merge range: ${CHURN} (nonzero => de-paywall chokepoint touched, see §0.1 trip-wire A).
NEVER close this PR to defer it — \`.fork-sync-state\` only advances on MERGE, so leaving it OPEN keeps this tag 'next'; closing it would silently skip the tag (§4.2 / §6.2)."
gh pr create \
--head "sync/${TAG}" \
--base master \
--title "sync: merge upstream ${TAG}" \
--body "$BODY" \
--label "$LABELS"
# §0.1 trip-wire A — auto-apply `chokepoint-refresh` from CI when a chokepoint file
# changed or conflicted, so the trip-wire tally never depends on a human remembering.
if [ "${CHURN:-0}" -gt 0 ] || [ "${CHOKEPOINT_CONFLICT:-0}" = "1" ]; then
gh pr edit "sync/${TAG}" --add-label chokepoint-refresh || true
fi
+11 -2
View File
@@ -7,10 +7,19 @@ IDEWorkspaceChecks.plist
/node_modules/
/DerivedData/
/build/
/vendor/*/.build/
/vendor/*/build/
/vendor/*/.swiftpm/
/vendor/*/Package.resolved
.DS_Store
/docs/_site/
/docs/vendor/
codesign.conf
codesign.crt
codesign.key
codesign.p12
/.claude/*
!/.claude/skills/
/scripts/l10n/missing-translations.json
/ai/output/
# alt-tab-free [depaywall]: the Sparkle feed is published OUT OF TREE to the gh-pages branch by
# scripts/update_appcast.sh; the in-tree appcast.xml is removed (PLAN §3.3).
/appcast.xml
+8
View File
@@ -0,0 +1,8 @@
# Approved historical findings (exact fingerprints only, no patterns): readOnlyToken values in contributor/l10n scripts and an AppCenter
# encryption key size constant, all introduced upstream before this fork. Any new or different finding is still reported.
9147a4a864689ab94531c75b1b04d7c4f3581def:vendor/AppCenter/Sources/AppCenter/Internals/Util/MSACEncrypterPrivate.h:generic-api-key:20
44007195b77d6809048c134c78a6d68d1895704f:scripts/update_readme_and_website.sh:generic-api-key:6
528028d41bbbe57ea90b89a04a96a114872c405f:scripts/export_l10n_strings_to_poeditor.sh:generic-api-key:5
d544ff3b7a6d4023ccd25783008836f50ec5b79d:scripts/import_l10n_strings_from_poeditor.sh:generic-api-key:5
9a04c275cb9fba763c2272acc09055bf6476755d:scripts/update_contributors.sh:generic-api-key:5
13c1cb0d000401df11a1c496b5273338db1886d7:scripts/import_l10n_strings_from_poeditor.sh:generic-api-key:6
+5 -7
View File
@@ -1,8 +1,6 @@
retain_objc_accessible: true
project: alt-tab-macos.xcodeproj
schemes:
- Release
targets:
- alt-tab-macos
workspace: alt-tab-macos.xcworkspace
report_exclude:
- src/api-wrappers/PrivateApis.swift
- Release
index_exclude:
- vendor/**
- src/api-wrappers/private-apis/**
-1
View File
@@ -2,7 +2,6 @@
# src/**/*.swift: Matches all .swift files in the src directory and all its subdirectories.
# !node_modules/**: Excludes all files in the node_modules directory and all its subdirectories.
Pods/**
Generated/**
**/PrivateApis.swift
+14
View File
@@ -0,0 +1,14 @@
# macOS development
- Don't use xcode directly to develop
- Use pure swift 5.8 code to make the app. No interface builder. No SwiftUI.
- Aim for compact code. Within methods, don't have groups of statements separated with newlines. No inline comments for simple code. Instead, split statements into sub-methods.
- Use guard closes as much as possible to separate the happy-path under them
- Organize source files into folders. Folders should group files that change together, at the same pace (e.g. one feature)
- Favor low latency and responsiveness. Reuse objects, avoid wasting memory or I/O.
# Workflow
- Copy commands from ai/build.sh and run them, to confirm compilation works after you're done with implementing a change
# License / Keychain invariant
- The app's Developer ID, TeamID, and bundle ID must remain stable across builds. Keychain items are tied to the code signature; changing any of these orphans every user's stored license key and forces mass re-activation. If a rotation is unavoidable, plan a migration first (e.g., a backup-restore handler, or `kSecAttrAccessGroup` with a stable group identifier).
- Do not introduce legacy `SecKeychain*` API or `kSecAccessControl` (biometric/PIN gating) into license code — both can trigger Keychain password prompts, which is bad UX for license activation.
+1
View File
@@ -0,0 +1 @@
@include ./AGENTS.md
+57 -29
View File
@@ -2,55 +2,83 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ATSApplicationFontsPath</key>
<string></string>
<key>AppCenterApplicationForwarderEnabled</key>
<string>0</string>
<key>AppCenterSecret</key>
<string>#APPCENTER_SECRET#</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string>app.icns</string>
<!-- ===== Bundle identity (required by macOS / App Store) ===== -->
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>#VERSION#</string>
<key>CFBundleVersion</key>
<string>#VERSION#</string>
<key>FeedbackToken</key>
<string>#FEEDBACK_TOKEN#</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleIconFile</key>
<string>app.icns</string>
<key>NSHumanReadableCopyright</key>
<string>GPL-3.0 licence</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<!-- ===== Versioning (substituted from xcconfig; CI overrides via config/local.xcconfig) ===== -->
<key>CFBundleShortVersionString</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<!-- ===== Launch behavior (read by LaunchServices before app starts) ===== -->
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>LSUIElement</key>
<string>true</string>
<key>NSHumanReadableCopyright</key>
<string>GPL-3.0 licence</string>
<key>NSPrincipalClass</key>
<string>AppCenterApplication</string>
<key>NSSupportsAutomaticTermination</key>
<string>false</string>
<key>NSSupportsSuddenTermination</key>
<string>false</string>
<key>SUEnableAutomaticChecks</key>
<string>true</string>
<key>SUEnableJavaScript</key>
<string>true</string>
<key>SUFeedURL</key>
<string>https://raw.githubusercontent.com/lwouis/alt-tab-macos/master/appcast.xml</string>
<key>ATSApplicationFontsPath</key>
<string></string>
<!-- ===== URL scheme registration (LaunchServices dispatches $(PRODUCT_BUNDLE_IDENTIFIER):// to us) ===== -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleURLSchemes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
</array>
<!-- ===== Sparkle (auto-update framework — reads these directly from the bundle) ===== -->
<key>SUPublicEDKey</key>
<string>2e9SQOBoaKElchSa/4QDli/nvYkyuDNfynfzBF6vJK4=</string>
<!-- Fork EdDSA public key for Sparkle update verification. The matching private key
is held as CI secret SPARKLE_ED_PRIVATE_KEY (see docs/EXECUTION-STATUS.md §3.3).
Auto-checks stay off (below) until DOMAIN serves a real appcast host. -->
<string>1YfoCJDk/T8GQx1Gpf3O4ApFgDkBiN6oe/z/Kfnxs/M=</string>
<key>SUEnableAutomaticChecks</key>
<!-- alt-tab-free: enabled 2026-06-16 — DOMAIN serves the appcast on GitHub Pages (gh-pages). -->
<string>true</string>
<key>SUScheduledCheckInterval</key>
<string>604800</string>
<!-- ===== AppCenter (crash reporter — read by AppCenterApplication superclass at init) ===== -->
<key>AppCenterApplicationForwarderEnabled</key>
<string>0</string>
<!-- ===== Build-time secrets (substituted from xcconfig; override per-dev via config/local.xcconfig) ===== -->
<key>AppCenterSecret</key>
<string>$(APPCENTER_SECRET)</string>
<key>Domain</key>
<string>$(DOMAIN)</string>
<key>ApiDomain</key>
<string>$(API_DOMAIN)</string>
</dict>
</plist>
+34
View File
@@ -0,0 +1,34 @@
# NOTICE — Statement of Changes (GPL-3.0 §5(a))
This file carries the prominent notice, required by GNU GPL v3.0 §5(a), that this work
has been modified, and gives the relevant date. It is a **living document**: whenever a
sync from upstream changes this fork's modification surface, update the change list and
the date below (see `docs/PLAN-maintained-fork.md` §6.2).
**Forked from:** [lwouis/alt-tab-macos](https://github.com/lwouis/alt-tab-macos) v11.3.0,
© Louis Pontoise, licensed GPL-3.0.
**Modified by:** the CommandTabFree fork. This fork neutralizes the AltTab Pro paywall so that
all features are free.
**Date of modification:** 2026-06-10.
**License:** CommandTabFree is released under the **GNU General Public License v3.0**, the same
license as upstream. The full license text is in [`LICENCE.md`](LICENCE.md), which is kept
byte-for-byte identical to upstream and is never edited.
## Changes made in this fork
- **`LicenseManager.computeState`** (`src/pro/license/LicenseManager.swift`) — forced to
return `.pro`, opening every Pro feature gate. This is the single live license-state
producer, so this one change unlocks all paywalled features.
- **`LicenseCookie.syncLicenseCookie`** (`src/pro/license/LicenseCookie.swift`) — made a
no-op, so no license cookie is written to the upstream domain.
- **`AppCenterCrash.init`** (`src/vendors/AppCenterCrashes.swift`) — telemetry disabled;
AppCenter is never started.
- **`App.handleCustomUrl`** (`src/App.swift`) — the `activate` deep-link handler is
disabled, so a crafted `…://activate?license_key=…` URL can no longer POST the machine
hardware fingerprint to a license backend.
The upstream copyright, contributor credits (`docs/contributors.md`), and third-party
acknowledgments (`docs/acknowledgments.md`) are retained unchanged.
-45
View File
@@ -1,45 +0,0 @@
# disable warnings coming from pods, which are always noise from our perspective
inhibit_all_warnings!
def deployment_target_from_xcconfig()
xcconfig_path = 'config/base.xcconfig'
File.foreach(xcconfig_path) do |line|
if line.start_with?('MACOSX_DEPLOYMENT_TARGET')
target = line.split("=").last.strip
puts "MACOSX_DEPLOYMENT_TARGET: #{target}"
return target
end
end
puts "\e[31mCouldn't read MACOSX_DEPLOYMENT_TARGET from #{xcconfig_path}\e[0m"
exit 1
end
deployment_target = deployment_target_from_xcconfig()
platform :osx, deployment_target
target 'alt-tab-macos' do
use_frameworks!
pod 'LetsMove', :git => 'https://github.com/lwouis/LetsMove.git', :commit => '7abf4daed1a25218f2b52f2dfd190aee5a50071c'
pod 'Sparkle', :podspec => 'https://raw.githubusercontent.com/lwouis/Sparkle/fix-iframe-popup-1.24/Sparkle.podspec'
pod 'ShortcutRecorder', :git => 'https://github.com/lwouis/ShortcutRecorder.git', :branch => 'alt-tab-current'
pod 'AppCenter/Crashes', '4.3.0'
pod 'SwiftyBeaver', '1.9.0'
end
target 'unit-tests' do
use_frameworks!
pod 'ShortcutRecorder', :git => 'https://github.com/lwouis/ShortcutRecorder.git', :branch => 'alt-tab-current'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
# disable code signing which is unnecessary for pods
config.build_settings['CODE_SIGNING_REQUIRED'] = 'NO'
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
# set deployment_target for all pods, to avoid libarclite compiler error
config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = deployment_target
end
end
end
-49
View File
@@ -1,49 +0,0 @@
PODS:
- AppCenter/Core (4.3.0)
- AppCenter/Crashes (4.3.0):
- AppCenter/Core
- LetsMove (1.24)
- ShortcutRecorder (3.1)
- Sparkle (1.24.0)
- SwiftyBeaver (1.9.0)
DEPENDENCIES:
- AppCenter/Crashes (= 4.3.0)
- LetsMove (from `https://github.com/lwouis/LetsMove.git`, commit `7abf4daed1a25218f2b52f2dfd190aee5a50071c`)
- ShortcutRecorder (from `https://github.com/lwouis/ShortcutRecorder.git`, branch `alt-tab-current`)
- Sparkle (from `https://raw.githubusercontent.com/lwouis/Sparkle/fix-iframe-popup-1.24/Sparkle.podspec`)
- SwiftyBeaver (= 1.9.0)
SPEC REPOS:
trunk:
- AppCenter
- SwiftyBeaver
EXTERNAL SOURCES:
LetsMove:
:commit: 7abf4daed1a25218f2b52f2dfd190aee5a50071c
:git: https://github.com/lwouis/LetsMove.git
ShortcutRecorder:
:branch: alt-tab-current
:git: https://github.com/lwouis/ShortcutRecorder.git
Sparkle:
:podspec: https://raw.githubusercontent.com/lwouis/Sparkle/fix-iframe-popup-1.24/Sparkle.podspec
CHECKOUT OPTIONS:
LetsMove:
:commit: 7abf4daed1a25218f2b52f2dfd190aee5a50071c
:git: https://github.com/lwouis/LetsMove.git
ShortcutRecorder:
:commit: 594b360e07a8a368ffec2567f77e465477b9994f
:git: https://github.com/lwouis/ShortcutRecorder.git
SPEC CHECKSUMS:
AppCenter: 883369ab78427b0561c688158d689dfe1f993ea9
LetsMove: fefe56bc7bc7fb7d37049e28a14f297961229fc5
ShortcutRecorder: fdf620aca34101b0cba3b10fca815e0459254189
Sparkle: 1fa490bb4ab2a9b37cfb9ea4feec19dd33b81cd2
SwiftyBeaver: d39e7c376bf15e9fffca8263b8fd1f42ea56aa2d
PODFILE CHECKSUM: c20cb0e8753361ba1c1daea73624f879862271ed
COCOAPODS: 1.16.2
BIN
View File
Binary file not shown.
@@ -1,99 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AvailableLibraries</key>
<array>
<dict>
<key>LibraryIdentifier</key>
<string>tvos-arm64</string>
<key>LibraryPath</key>
<string>AppCenter.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>tvos</string>
</dict>
<dict>
<key>LibraryIdentifier</key>
<string>ios-arm64_x86_64-maccatalyst</string>
<key>LibraryPath</key>
<string>AppCenter.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>maccatalyst</string>
</dict>
<dict>
<key>LibraryIdentifier</key>
<string>ios-arm64_i386_x86_64-simulator</string>
<key>LibraryPath</key>
<string>AppCenter.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>i386</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
<dict>
<key>LibraryIdentifier</key>
<string>ios-arm64_arm64e_armv7_armv7s</string>
<key>LibraryPath</key>
<string>AppCenter.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>arm64e</string>
<string>armv7</string>
<string>armv7s</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
</dict>
<dict>
<key>LibraryIdentifier</key>
<string>tvos-arm64_x86_64-simulator</string>
<key>LibraryPath</key>
<string>AppCenter.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>tvos</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
<dict>
<key>LibraryIdentifier</key>
<string>macos-arm64_x86_64</string>
<key>LibraryPath</key>
<string>AppCenter.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>macos</string>
</dict>
</array>
<key>CFBundlePackageType</key>
<string>XFWK</string>
<key>XCFrameworkFormatVersion</key>
<string>1.0</string>
</dict>
</plist>
@@ -1,13 +0,0 @@
framework module AppCenter {
umbrella header "AppCenter.h"
export *
module * { export * }
link framework "Foundation"
link framework "CoreTelephony"
link framework "SystemConfiguration"
link framework "UIKit"
link "sqlite3"
link "z"
}
@@ -1,44 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACAppCenter.h>)
#import <AppCenter/MSACAbstractLog.h>
#import <AppCenter/MSACAppCenter.h>
#import <AppCenter/MSACAppCenterErrors.h>
#import <AppCenter/MSACChannelGroupProtocol.h>
#import <AppCenter/MSACChannelProtocol.h>
#import <AppCenter/MSACConstants+Flags.h>
#import <AppCenter/MSACConstants.h>
#import <AppCenter/MSACCustomProperties.h>
#import <AppCenter/MSACDevice.h>
#import <AppCenter/MSACEnable.h>
#import <AppCenter/MSACLog.h>
#import <AppCenter/MSACLogWithProperties.h>
#import <AppCenter/MSACLogger.h>
#import <AppCenter/MSACSerializableObject.h>
#import <AppCenter/MSACService.h>
#import <AppCenter/MSACServiceAbstract.h>
#import <AppCenter/MSACWrapperLogger.h>
#import <AppCenter/MSACWrapperSdk.h>
#else
#import "MSACAbstractLog.h"
#import "MSACAppCenter.h"
#import "MSACAppCenterErrors.h"
#import "MSACChannelGroupProtocol.h"
#import "MSACChannelProtocol.h"
#import "MSACConstants+Flags.h"
#import "MSACConstants.h"
#import "MSACCustomProperties.h"
#import "MSACDevice.h"
#import "MSACEnable.h"
#import "MSACLog.h"
#import "MSACLogWithProperties.h"
#import "MSACLogger.h"
#import "MSACSerializableObject.h"
#import "MSACService.h"
#import "MSACServiceAbstract.h"
#import "MSACWrapperLogger.h"
#import "MSACWrapperSdk.h"
#endif
@@ -1,203 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#ifndef MSAC_APP_CENTER
#define MSAC_APP_CENTER
#if __has_include(<AppCenter/MSACConstants.h>)
#import <AppCenter/MSACConstants.h>
#else
#import "MSACConstants.h"
#endif
@class MSACWrapperSdk;
#if !TARGET_OS_TV
@class MSACCustomProperties;
#endif
NS_SWIFT_NAME(AppCenter)
@interface MSACAppCenter : NSObject
/**
* Returns the singleton instance of MSACAppCenter.
*/
+ (instancetype)sharedInstance;
/**
* Configure the SDK with an application secret.
*
* @param appSecret A unique and secret key used to identify the application.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)configureWithAppSecret:(NSString *)appSecret NS_SWIFT_NAME(configure(withAppSecret:));
/**
* Configure the SDK.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)configure;
/**
* Configure the SDK with an application secret and an array of services to start.
*
* @param appSecret A unique and secret key used to identify the application.
* @param services Array of services to start.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)start:(NSString *)appSecret withServices:(NSArray<Class> *)services NS_SWIFT_NAME(start(withAppSecret:services:));
/**
* Start the SDK with an array of services.
*
* @param services Array of services to start.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)startWithServices:(NSArray<Class> *)services NS_SWIFT_NAME(start(services:));
/**
* Start a service.
*
* @param service A service to start.
*
* @discussion This may be called only once per service per application process lifetime.
*/
+ (void)startService:(Class)service;
/**
* Configure the SDK with an array of services to start from a library. This will not start the service at application level, it will enable
* the service only for the library.
*
* @param services Array of services to start.
*/
+ (void)startFromLibraryWithServices:(NSArray<Class> *)services NS_SWIFT_NAME(startFromLibrary(services:));
/**
* The flag indicates whether the SDK has already been configured or not.
*/
@property(class, atomic, readonly, getter=isConfigured) BOOL configured;
/**
* The flag indicates whether app is running in App Center Test Cloud.
*/
@property(class, atomic, readonly, getter=isRunningInAppCenterTestCloud) BOOL runningInAppCenterTestCloud;
/**
* The flag indicates whether or not the SDK was enabled as a whole
*
* The state is persisted in the device's storage across application launches.
*/
@property(class, nonatomic, getter=isEnabled, setter=setEnabled:) BOOL enabled NS_SWIFT_NAME(enabled);
/**
* Flag indicating whether SDK can send network requests.
*
* The state is persisted in the device's storage across application launches.
*/
@property(class, nonatomic, getter=isNetworkRequestsAllowed, setter=setNetworkRequestsAllowed:)
BOOL networkRequestsAllowed NS_SWIFT_NAME(networkRequestsAllowed);
/**
* The SDK's log level.
*/
@property(class, nonatomic) MSACLogLevel logLevel;
/**
* Base URL to use for backend communication.
*/
@property(class, nonatomic, strong) NSString *logUrl;
/**
* Set log handler.
*/
@property(class, nonatomic) MSACLogHandler logHandler;
/**
* Set wrapper SDK information to use when building device properties. This is intended in case you are building a SDK that uses the App
* Center SDK under the hood, e.g. our Xamarin SDK or ReactNative SDk.
*/
@property(class, nonatomic, strong) MSACWrapperSdk *wrapperSdk;
#if !TARGET_OS_TV
/**
* Set the custom properties.
*
* @param customProperties Custom properties object.
*/
+ (void)setCustomProperties:(MSACCustomProperties *)customProperties;
#endif
/**
* Check whether the application delegate forwarder is enabled or not.
*
* @discussion The application delegate forwarder forwards messages that target your application delegate methods via swizzling to the SDK.
* It simplifies the SDK integration but may not be suitable to any situations. For
* instance it should be disabled if you or one of your third party SDK is doing message forwarding on the application delegate. Message
* forwarding usually implies the implementation of @see NSObject#forwardingTargetForSelector: or @see NSObject#forwardInvocation: methods.
* To disable the application delegate forwarder just add the `AppCenterAppDelegateForwarderEnabled` tag to your Info .plist file and set it
* to `0`. Then you will have to forward any application delegate needed by the SDK manually.
*/
@property(class, readonly, nonatomic, getter=isAppDelegateForwarderEnabled) BOOL appDelegateForwarderEnabled;
/**
* Unique installation identifier.
*
*/
@property(class, readonly, nonatomic) NSUUID *installId;
/**
* Detect if a debugger is attached to the app process. This is only invoked once on app startup and can not detect
* if the debugger is being attached during runtime!
*
*/
@property(class, readonly, nonatomic, getter=isDebuggerAttached) BOOL debuggerAttached;
/**
* Current version of AppCenter SDK.
*
*/
@property(class, readonly, nonatomic) NSString *sdkVersion;
/**
* Set the maximum size of the internal storage. This method must be called before App Center is started. This method is only intended for
* applications.
*
* @param sizeInBytes Maximum size of the internal storage in bytes. This will be rounded up to the nearest multiple of a SQLite page size
* (default is 4096 bytes). Values below 20,480 bytes (20 KiB) will be ignored.
*
* @param completionHandler Callback that is invoked when the database size has been set. The `BOOL` parameter is `YES` if changing the size
* is successful, and `NO` otherwise. This parameter can be null.
*
* @discussion This only sets the maximum size of the database, but App Center modules might store additional data.
* The value passed to this method is not persisted on disk. The default maximum database size is 10485760 bytes (10 MiB).
*/
+ (void)setMaxStorageSize:(long)sizeInBytes completionHandler:(void (^)(BOOL))completionHandler;
/**
* Set the user identifier.
*
* @discussion Set the user identifier for logs sent for the default target token when the secret passed in @c
* MSACAppCenter:start:withServices: contains "target={targetToken}".
*
* For App Center backend the user identifier maximum length is 256 characters.
*
* AppCenter must be configured or started before this API can be used.
*/
@property(class, nonatomic, strong) NSString *userId;
/**
* Set country code to use when building device properties.
*
* @see https://www.iso.org/obp/ui/#search for more information.
*/
@property(class, nonatomic, strong) NSString *countryCode;
@end
#endif
@@ -1,41 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_APP_CENTER_ERRORS_H
#define MSAC_APP_CENTER_ERRORS_H
#import <Foundation/Foundation.h>
#define MSAC_APP_CENTER_BASE_DOMAIN @"com.Microsoft.AppCenter."
NS_ASSUME_NONNULL_BEGIN
#pragma mark - Domain
static NSString *const kMSACACErrorDomain = MSAC_APP_CENTER_BASE_DOMAIN @"ErrorDomain";
#pragma mark - General
// Error codes.
NS_ENUM(NSInteger){MSACACLogInvalidContainerErrorCode = 1, MSACACCanceledErrorCode = 2, MSACACDisabledErrorCode = 3};
// Error descriptions.
static NSString const *kMSACACLogInvalidContainerErrorDesc = @"Invalid log container.";
static NSString const *kMSACACCanceledErrorDesc = @"The operation was canceled.";
static NSString const *kMSACACDisabledErrorDesc = @"The service is disabled.";
#pragma mark - Connection
// Error codes.
NS_ENUM(NSInteger){MSACACConnectionPausedErrorCode = 100, MSACACConnectionHttpErrorCode = 101};
// Error descriptions.
static NSString const *kMSACACConnectionHttpErrorDesc = @"An HTTP error occured.";
static NSString const *kMSACACConnectionPausedErrorDesc = @"Canceled, connection paused with log deletion.";
// Error user info keys.
static NSString const *kMSACACConnectionHttpCodeErrorKey = @"MSConnectionHttpCode";
NS_ASSUME_NONNULL_END
#endif
@@ -1,87 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CHANNEL_GROUP_PROTOCOL_H
#define MSAC_CHANNEL_GROUP_PROTOCOL_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACChannelProtocol.h>)
#import <AppCenter/MSACChannelProtocol.h>
#else
#import "MSACChannelProtocol.h"
#endif
NS_ASSUME_NONNULL_BEGIN
@class MSACChannelUnitConfiguration;
@protocol MSACIngestionProtocol;
@protocol MSACChannelUnitProtocol;
/**
* `MSACChannelGroupProtocol` represents a kind of channel that contains constituent MSACChannelUnit objects. When an operation from the
* `MSACChannelProtocol` is performed on the group, that operation should be propagated to its constituent MSACChannelUnit objects.
*/
NS_SWIFT_NAME(ChannelGroupProtocol)
@protocol MSACChannelGroupProtocol <MSACChannelProtocol>
/**
* Initialize a channel unit with the given configuration.
*
* @param configuration channel configuration.
*
* @return The added `MSACChannelUnitProtocol`. Use this object to enqueue logs.
*/
- (id<MSACChannelUnitProtocol>)addChannelUnitWithConfiguration:(MSACChannelUnitConfiguration *)configuration
NS_SWIFT_NAME(addChannelUnit(withConfiguration:));
/**
* Initialize a channel unit with the given configuration.
*
* @param configuration channel configuration.
* @param ingestion The alternative ingestion object
*
* @return The added `MSACChannelUnitProtocol`. Use this object to enqueue logs.
*/
- (id<MSACChannelUnitProtocol>)addChannelUnitWithConfiguration:(MSACChannelUnitConfiguration *)configuration
withIngestion:(nullable id<MSACIngestionProtocol>)ingestion
NS_SWIFT_NAME(addChannelUnit(_:ingestion:));
/**
* Change the base URL (schema + authority + port only) used to communicate with the backend.
*/
@property(nonatomic, strong) NSString *_Nullable logUrl;
/**
* Set the app secret.
*/
@property(nonatomic, strong) NSString *_Nullable appSecret;
/**
* Set the maximum size of the internal storage. This method must be called before App Center is started.
*
* @discussion The default maximum database size is 10485760 bytes (10 MiB).
*
* @param sizeInBytes Maximum size of the internal storage in bytes. This will be rounded up to the nearest multiple of a SQLite page size
* (default is 4096 bytes). Values below 24576 bytes (24 KiB) will be ignored.
* @param completionHandler Callback that is invoked when the database size has been set. The `BOOL` parameter is `YES` if changing the size
* is successful, and `NO` otherwise.
*/
- (void)setMaxStorageSize:(long)sizeInBytes
completionHandler:(nullable void (^)(BOOL))completionHandler NS_SWIFT_NAME(setMaxStorageSize(_:completionHandler:));
/**
* Return a channel unit instance for the given groupId.
*
* @param groupId The group ID for a channel unit.
*
* @return A channel unit instance or `nil`.
*/
- (nullable id<MSACChannelUnitProtocol>)channelUnitForGroupId:(NSString *)groupId;
@end
NS_ASSUME_NONNULL_END
#endif
@@ -1,68 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CHANNEL_PROTOCOL_H
#define MSAC_CHANNEL_PROTOCOL_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACEnable.h>)
#import <AppCenter/MSACEnable.h>
#else
#import "MSACEnable.h"
#endif
NS_ASSUME_NONNULL_BEGIN
@protocol MSACChannelDelegate;
/**
* `MSACChannelProtocol` contains the essential operations of a channel. Channels are broadly responsible for enqueuing logs to be sent to
* the backend and/or stored on disk.
*/
NS_SWIFT_NAME(ChannelProtocol)
@protocol MSACChannelProtocol <NSObject, MSACEnable>
/**
* Add delegate.
*
* @param delegate delegate.
*/
- (void)addDelegate:(id<MSACChannelDelegate>)delegate;
/**
* Remove delegate.
*
* @param delegate delegate.
*/
- (void)removeDelegate:(id<MSACChannelDelegate>)delegate;
/**
* Pause operations, logs will be stored but not sent.
*
* @param identifyingObject Object used to identify the pause request.
*
* @discussion A paused channel doesn't forward logs to the ingestion. The identifying object used to pause the channel can be any unique
* object. The same identifying object must be used to call resume. For simplicity if the caller is the one owning the channel then @c self
* can be used as identifying object.
*
* @see resumeWithIdentifyingObject:
*/
- (void)pauseWithIdentifyingObject:(id<NSObject>)identifyingObject;
/**
* Resume operations, logs can be sent again.
*
* @param identifyingObject Object used to passed to the pause method.
*
* @discussion The channel only resume when all the outstanding identifying objects have been resumed.
*
* @see pauseWithIdentifyingObject:
*/
- (void)resumeWithIdentifyingObject:(id<NSObject>)identifyingObject;
@end
NS_ASSUME_NONNULL_END
#endif
@@ -1,18 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CONSTANTS_FLAGS_H
#define MSAC_CONSTANTS_FLAGS_H
#import <Foundation/Foundation.h>
typedef NS_OPTIONS(NSUInteger, MSACFlags) {
MSACFlagsNone = (0 << 0), // => 00000000
MSACFlagsNormal = (1 << 0), // => 00000001
MSACFlagsCritical = (1 << 1), // => 00000010
MSACFlagsPersistenceNormal DEPRECATED_MSG_ATTRIBUTE("please use MSACFlagsNormal") = MSACFlagsNormal,
MSACFlagsPersistenceCritical DEPRECATED_MSG_ATTRIBUTE("please use MSACFlagsCritical") = MSACFlagsCritical,
MSACFlagsDefault = MSACFlagsNormal
} NS_SWIFT_NAME(Flags);
#endif
@@ -1,170 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
/**
* Log Levels
*/
typedef NS_ENUM(NSUInteger, MSACLogLevel) {
/**
* Logging will be very chatty
*/
MSACLogLevelVerbose = 2,
/**
* Debug information will be logged
*/
MSACLogLevelDebug = 3,
/**
* Information will be logged
*/
MSACLogLevelInfo = 4,
/**
* Errors and warnings will be logged
*/
MSACLogLevelWarning = 5,
/**
* Errors will be logged
*/
MSACLogLevelError = 6,
/**
* Only critical errors will be logged
*/
MSACLogLevelAssert = 7,
/**
* Logging is disabled
*/
MSACLogLevelNone = 99
} NS_SWIFT_NAME(LogLevel);
typedef NSString * (^MSACLogMessageProvider)(void)NS_SWIFT_NAME(LogMessageProvider);
typedef void (^MSACLogHandler)(MSACLogMessageProvider messageProvider, MSACLogLevel logLevel, NSString *tag, const char *file,
const char *function, uint line) NS_SWIFT_NAME(LogHandler);
/**
* Channel priorities, check the kMSACPriorityCount if you add a new value.
* The order matters here! Values NEED to range from low priority to high priority.
*/
typedef NS_ENUM(NSInteger, MSACPriority) { MSACPriorityBackground, MSACPriorityDefault, MSACPriorityHigh } NS_SWIFT_NAME(Priority);
static short const kMSACPriorityCount = MSACPriorityHigh + 1;
/**
* The priority by which the modules are initialized.
* MSACPriorityMax is reserved for only 1 module and this needs to be Crashes.
* Crashes needs to be initialized first to catch crashes in our other SDK Modules (which will hopefully never happen) and to avoid losing
* any log at crash time.
*/
typedef NS_ENUM(NSInteger, MSACInitializationPriority) {
MSACInitializationPriorityDefault = 500,
MSACInitializationPriorityHigh = 750,
MSACInitializationPriorityMax = 999
} NS_SWIFT_NAME(InitializationPriority);
/**
* Enum with the different HTTP status codes.
*/
typedef NS_ENUM(NSInteger, MSACHTTPCodesNo) {
// Invalid
MSACHTTPCodesNo0XXInvalidUnknown = 0,
// Informational
MSACHTTPCodesNo1XXInformationalUnknown = 1,
MSACHTTPCodesNo100Continue = 100,
MSACHTTPCodesNo101SwitchingProtocols = 101,
MSACHTTPCodesNo102Processing = 102,
// Success
MSACHTTPCodesNo2XXSuccessUnknown = 2,
MSACHTTPCodesNo200OK = 200,
MSACHTTPCodesNo201Created = 201,
MSACHTTPCodesNo202Accepted = 202,
MSACHTTPCodesNo203NonAuthoritativeInformation = 203,
MSACHTTPCodesNo204NoContent = 204,
MSACHTTPCodesNo205ResetContent = 205,
MSACHTTPCodesNo206PartialContent = 206,
MSACHTTPCodesNo207MultiStatus = 207,
MSACHTTPCodesNo208AlreadyReported = 208,
MSACHTTPCodesNo209IMUsed = 209,
// Redirection
MSACHTTPCodesNo3XXSuccessUnknown = 3,
MSACHTTPCodesNo300MultipleChoices = 300,
MSACHTTPCodesNo301MovedPermanently = 301,
MSACHTTPCodesNo302Found = 302,
MSACHTTPCodesNo303SeeOther = 303,
MSACHTTPCodesNo304NotModified = 304,
MSACHTTPCodesNo305UseProxy = 305,
MSACHTTPCodesNo306SwitchProxy = 306,
MSACHTTPCodesNo307TemporaryRedirect = 307,
MSACHTTPCodesNo308PermanentRedirect = 308,
// Client error
MSACHTTPCodesNo4XXSuccessUnknown = 4,
MSACHTTPCodesNo400BadRequest = 400,
MSACHTTPCodesNo401Unauthorised = 401,
MSACHTTPCodesNo402PaymentRequired = 402,
MSACHTTPCodesNo403Forbidden = 403,
MSACHTTPCodesNo404NotFound = 404,
MSACHTTPCodesNo405MethodNotAllowed = 405,
MSACHTTPCodesNo406NotAcceptable = 406,
MSACHTTPCodesNo407ProxyAuthenticationRequired = 407,
MSACHTTPCodesNo408RequestTimeout = 408,
MSACHTTPCodesNo409Conflict = 409,
MSACHTTPCodesNo410Gone = 410,
MSACHTTPCodesNo411LengthRequired = 411,
MSACHTTPCodesNo412PreconditionFailed = 412,
MSACHTTPCodesNo413RequestEntityTooLarge = 413,
MSACHTTPCodesNo414RequestURITooLong = 414,
MSACHTTPCodesNo415UnsupportedMediaType = 415,
MSACHTTPCodesNo416RequestedRangeNotSatisfiable = 416,
MSACHTTPCodesNo417ExpectationFailed = 417,
MSACHTTPCodesNo418IamATeapot = 418,
MSACHTTPCodesNo419AuthenticationTimeout = 419,
MSACHTTPCodesNo420MethodFailureSpringFramework = 420,
MSACHTTPCodesNo420EnhanceYourCalmTwitter = 4200,
MSACHTTPCodesNo422UnprocessableEntity = 422,
MSACHTTPCodesNo423Locked = 423,
MSACHTTPCodesNo424FailedDependency = 424,
MSACHTTPCodesNo424MethodFailureWebDaw = 4240,
MSACHTTPCodesNo425UnorderedCollection = 425,
MSACHTTPCodesNo426UpgradeRequired = 426,
MSACHTTPCodesNo428PreconditionRequired = 428,
MSACHTTPCodesNo429TooManyRequests = 429,
MSACHTTPCodesNo431RequestHeaderFieldsTooLarge = 431,
MSACHTTPCodesNo444NoResponseNginx = 444,
MSACHTTPCodesNo449RetryWithMicrosoft = 449,
MSACHTTPCodesNo450BlockedByWindowsParentalControls = 450,
MSACHTTPCodesNo451RedirectMicrosoft = 451,
MSACHTTPCodesNo451UnavailableForLegalReasons = 4510,
MSACHTTPCodesNo494RequestHeaderTooLargeNginx = 494,
MSACHTTPCodesNo495CertErrorNginx = 495,
MSACHTTPCodesNo496NoCertNginx = 496,
MSACHTTPCodesNo497HTTPToHTTPSNginx = 497,
MSACHTTPCodesNo499ClientClosedRequestNginx = 499,
// Server error
MSACHTTPCodesNo5XXSuccessUnknown = 5,
MSACHTTPCodesNo500InternalServerError = 500,
MSACHTTPCodesNo501NotImplemented = 501,
MSACHTTPCodesNo502BadGateway = 502,
MSACHTTPCodesNo503ServiceUnavailable = 503,
MSACHTTPCodesNo504GatewayTimeout = 504,
MSACHTTPCodesNo505HTTPVersionNotSupported = 505,
MSACHTTPCodesNo506VariantAlsoNegotiates = 506,
MSACHTTPCodesNo507InsufficientStorage = 507,
MSACHTTPCodesNo508LoopDetected = 508,
MSACHTTPCodesNo509BandwidthLimitExceeded = 509,
MSACHTTPCodesNo510NotExtended = 510,
MSACHTTPCodesNo511NetworkAuthenticationRequired = 511,
MSACHTTPCodesNo522ConnectionTimedOut = 522,
MSACHTTPCodesNo598NetworkReadTimeoutErrorUnknown = 598,
MSACHTTPCodesNo599NetworkConnectTimeoutErrorUnknown = 599
} NS_SWIFT_NAME(HTTPCodesNo);
@@ -1,71 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CUSTOM_PROPERTIES_H
#define MSAC_CUSTOM_PROPERTIES_H
#import <Foundation/Foundation.h>
/**
* Custom properties builder.
* Collects multiple properties to send in one log.
*/
NS_SWIFT_NAME(CustomProperties)
@interface MSACCustomProperties : NSObject
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setString:(NSString *)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setNumber:(NSNumber *)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setBool:(BOOL)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setDate:(NSDate *)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Clear the property for the specified key.
*
* @param key Key whose mapping is to be cleared.
*
* @return This instance.
*/
- (instancetype)clearPropertyForKey:(NSString *)key NS_SWIFT_NAME(clearProperty(forKey:));
@end
#endif
@@ -1,101 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_DEVICE_H
#define MSAC_DEVICE_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACWrapperSdk.h>)
#import <AppCenter/MSACWrapperSdk.h>
#else
#import "MSACWrapperSdk.h"
#endif
NS_SWIFT_NAME(Device)
@interface MSACDevice : MSACWrapperSdk
/*
* Name of the SDK. Consists of the name of the SDK and the platform, e.g. "appcenter.ios", "appcenter.android"
*/
@property(nonatomic, copy, readonly) NSString *sdkName;
/*
* Version of the SDK in semver format, e.g. "1.2.0" or "0.12.3-alpha.1".
*/
@property(nonatomic, copy, readonly) NSString *sdkVersion;
/*
* Device model (example: iPad2,3).
*/
@property(nonatomic, copy, readonly) NSString *model;
/*
* Device manufacturer (example: HTC).
*/
@property(nonatomic, copy, readonly) NSString *oemName;
/*
* OS name (example: iOS).
*/
@property(nonatomic, copy, readonly) NSString *osName;
/*
* OS version (example: 9.3.0).
*/
@property(nonatomic, copy, readonly) NSString *osVersion;
/*
* OS build code (example: LMY47X). [optional]
*/
@property(nonatomic, copy, readonly) NSString *osBuild;
/*
* API level when applicable like in Android (example: 15). [optional]
*/
@property(nonatomic, copy, readonly) NSNumber *osApiLevel;
/*
* Language code (example: en_US).
*/
@property(nonatomic, copy, readonly) NSString *locale;
/*
* The offset in minutes from UTC for the device time zone, including daylight savings time.
*/
@property(nonatomic, readonly, strong) NSNumber *timeZoneOffset;
/*
* Screen size of the device in pixels (example: 640x480).
*/
@property(nonatomic, copy, readonly) NSString *screenSize;
/*
* Application version name, e.g. 1.1.0
*/
@property(nonatomic, copy, readonly) NSString *appVersion;
/*
* Carrier name (for mobile devices). [optional]
*/
@property(nonatomic, copy, readonly) NSString *carrierName;
/*
* Carrier country code (for mobile devices). [optional]
*/
@property(nonatomic, copy, readonly) NSString *carrierCountry;
/*
* The app's build number, e.g. 42.
*/
@property(nonatomic, copy, readonly) NSString *appBuild;
/*
* The bundle identifier, package identifier, or namespace, depending on what the individual plattforms use, .e.g com.microsoft.example.
* [optional]
*/
@property(nonatomic, copy, readonly) NSString *appNamespace;
@end
#endif
@@ -1,27 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_ENABLE_H
#define MSAC_ENABLE_H
#import <Foundation/Foundation.h>
/**
* Protocol to define an instance that can be enabled/disabled.
*/
NS_SWIFT_NAME(Enable)
@protocol MSACEnable <NSObject>
@required
/**
* Enable/disable this instance and delete data on disabled state.
*
* @param isEnabled A boolean value set to YES to enable the instance or NO to disable it.
* @param deleteData A boolean value set to YES to delete data or NO to keep it.
*/
- (void)setEnabled:(BOOL)isEnabled andDeleteDataOnDisabled:(BOOL)deleteData NS_SWIFT_NAME(setEnabled(_:deleteDataOnDisabled:));
@end
#endif
@@ -1,74 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_LOG_H
#define MSAC_LOG_H
#import <Foundation/Foundation.h>
@class MSACDevice;
NS_SWIFT_NAME(Log)
@protocol MSACLog <NSObject>
/**
* Log type.
*/
@property(nonatomic, copy) NSString *type;
/**
* Log timestamp.
*/
@property(nonatomic, strong) NSDate *timestamp;
/**
* A session identifier is used to correlate logs together. A session is an abstract concept in the API and is not necessarily an analytics
* session, it can be used to only track crashes.
*/
@property(nonatomic, copy) NSString *sid;
/**
* Optional distribution group ID value.
*/
@property(nonatomic, copy) NSString *distributionGroupId;
/**
* Optional user identifier.
*/
@property(nonatomic, copy) NSString *userId;
/**
* Device properties associated to this log.
*/
@property(nonatomic, strong) MSACDevice *device;
/**
* Transient object tag. For example, a log can be tagged with a transmission target. We do this currently to prevent properties being
* applied retroactively to previous logs by comparing their tags.
*/
@property(nonatomic, strong) NSObject *tag;
/**
* Checks if the object's values are valid.
*
* @return YES, if the object is valid.
*/
- (BOOL)isValid;
/**
* Adds a transmission target token that this log should be sent to.
*
* @param token The transmission target token.
*/
- (void)addTransmissionTargetToken:(NSString *)token;
/**
* Gets all transmission target tokens that this log should be sent to.
*
* @returns Collection of transmission target tokens that this log should be sent to.
*/
- (NSSet *)transmissionTargetTokens;
@end
#endif
@@ -1,25 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_LOG_WITH_PROPERTIES_H
#define MSAC_LOG_WITH_PROPERTIES_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACAbstractLog.h>)
#import <AppCenter/MSACAbstractLog.h>
#else
#import "MSACAbstractLog.h"
#endif
NS_SWIFT_NAME(LogWithProperties)
@interface MSACLogWithProperties : MSACAbstractLog
/**
* Additional key/value pair parameters. [optional]
*/
@property(nonatomic, strong) NSDictionary<NSString *, NSString *> *properties;
@end
#endif
@@ -1,54 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#ifndef MSAC_LOGGER
#define MSAC_LOGGER
#if __has_include(<AppCenter/MSACConstants.h>)
#import <AppCenter/MSACConstants.h>
#else
#import "MSACConstants.h"
#endif
#define MSACLog(_level, _tag, _message) \
[MSACLogger logMessage:_message level:_level tag:_tag file:__FILE__ function:__PRETTY_FUNCTION__ line:__LINE__]
#define MSACLogAssert(tag, format, ...) \
MSACLog(MSACLogLevelAssert, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogError(tag, format, ...) \
MSACLog(MSACLogLevelError, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogWarning(tag, format, ...) \
MSACLog(MSACLogLevelWarning, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogInfo(tag, format, ...) \
MSACLog(MSACLogLevelInfo, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogDebug(tag, format, ...) \
MSACLog(MSACLogLevelDebug, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogVerbose(tag, format, ...) \
MSACLog(MSACLogLevelVerbose, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
NS_SWIFT_NAME(Logger)
@interface MSACLogger : NSObject
+ (void)logMessage:(MSACLogMessageProvider)messageProvider
level:(MSACLogLevel)loglevel
tag:(NSString *)tag
file:(const char *)file
function:(const char *)function
line:(uint)line;
@end
#endif
@@ -1,19 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#ifndef SERIALIZABLE_OBJECT_H
#define SERIALIZABLE_OBJECT_H
@protocol MSACSerializableObject <NSCoding>
/**
* Serialize this object to a dictionary.
*
* @return A dictionary representing this object.
*/
- (NSMutableDictionary *)serializeToDictionary;
@end
#endif
@@ -1,23 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_SERVICE_H
#define MSAC_SERVICE_H
#import <Foundation/Foundation.h>
/**
* Protocol declaring service logic.
*/
NS_SWIFT_NAME(Service)
@protocol MSACService <NSObject>
/**
* Indicates whether this service is enabled.
* The state is persisted in the device's storage across application launches.
*/
@property(class, nonatomic, getter=isEnabled, setter=setEnabled:) BOOL enabled NS_SWIFT_NAME(enabled);
@end
#endif
@@ -1,58 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_SERVICE_ABSTRACT_H
#define MSAC_SERVICE_ABSTRACT_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACService.h>)
#import <AppCenter/MSACService.h>
#else
#import "MSACService.h"
#endif
@protocol MSACChannelGroupProtocol;
/**
* Abstraction of services common logic.
* This class is intended to be subclassed only not instantiated directly.
*/
NS_SWIFT_NAME(ServiceAbstract)
@interface MSACServiceAbstract : NSObject <MSACService>
/**
* The flag indicates whether the service is started from application or not.
*/
@property(nonatomic, assign) BOOL startedFromApplication;
/**
* Start this service with a channel group. Also sets the flag that indicates that a service has been started.
*
* @param channelGroup channel group used to persist and send logs.
* @param appSecret app secret for the SDK.
* @param token default transmission target token for this service.
* @param fromApplication indicates whether the service started from an application or not.
*/
- (void)startWithChannelGroup:(id<MSACChannelGroupProtocol>)channelGroup
appSecret:(NSString *)appSecret
transmissionTargetToken:(NSString *)token
fromApplication:(BOOL)fromApplication;
/**
* Update configuration when the service requires to start again. This method should only be called if the service is started from libraries
* and then is being started from an application.
*
* @param appSecret app secret for the SDK.
* @param token default transmission target token for this service.
*/
- (void)updateConfigurationWithAppSecret:(NSString *)appSecret transmissionTargetToken:(NSString *)token;
/**
* The flag indicate whether the service needs the application secret or not.
*/
@property(atomic, readonly) BOOL isAppSecretRequired;
@end
#endif
@@ -1,21 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACConstants.h>)
#import <AppCenter/MSACConstants.h>
#else
#import "MSACConstants.h"
#endif
/**
* This is a utility for producing App Center style log messages. It is only intended for use by App Center services and wrapper SDKs of App
* Center.
*/
NS_SWIFT_NAME(WrapperLogger)
@interface MSACWrapperLogger : NSObject
+ (void)MSACWrapperLog:(MSACLogMessageProvider)message tag:(NSString *)tag level:(MSACLogLevel)level;
@end
@@ -1,60 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_WRAPPER_SDK_H
#define MSAC_WRAPPER_SDK_H
#import <Foundation/Foundation.h>
NS_SWIFT_NAME(WrapperSdk)
@interface MSACWrapperSdk : NSObject
/*
* Version of the wrapper SDK. When the SDK is embedding another base SDK (for example Xamarin.Android wraps Android), the Xamarin specific
* version is populated into this field while sdkVersion refers to the original Android SDK. [optional]
*/
@property(nonatomic, copy, readonly) NSString *wrapperSdkVersion;
/*
* Name of the wrapper SDK (examples: Xamarin, Cordova). [optional]
*/
@property(nonatomic, copy, readonly) NSString *wrapperSdkName;
/*
* Version of the wrapper technology framework (Xamarin runtime version or ReactNative or Cordova etc...). [optional]
*/
@property(nonatomic, copy, readonly) NSString *wrapperRuntimeVersion;
/*
* Label that is used to identify application code 'version' released via Live Update beacon running on device.
*/
@property(nonatomic, copy, readonly) NSString *liveUpdateReleaseLabel;
/*
* Identifier of environment that current application release belongs to, deployment key then maps to environment like Production, Staging.
*/
@property(nonatomic, copy, readonly) NSString *liveUpdateDeploymentKey;
/*
* Hash of all files (ReactNative or Cordova) deployed to device via LiveUpdate beacon. Helps identify the Release version on device or need
* to download updates in future
*/
@property(nonatomic, copy, readonly) NSString *liveUpdatePackageHash;
- (instancetype)initWithWrapperSdkVersion:(NSString *)wrapperSdkVersion
wrapperSdkName:(NSString *)wrapperSdkName
wrapperRuntimeVersion:(NSString *)wrapperRuntimeVersion
liveUpdateReleaseLabel:(NSString *)liveUpdateReleaseLabel
liveUpdateDeploymentKey:(NSString *)liveUpdateDeploymentKey
liveUpdatePackageHash:(NSString *)liveUpdatePackageHash;
/**
* Checks if the object's values are valid.
*
* @return YES, if the object is valid.
*/
- (BOOL)isValid;
@end
#endif
@@ -1,13 +0,0 @@
framework module AppCenter {
umbrella header "AppCenter.h"
export *
module * { export * }
link framework "Foundation"
link framework "CoreTelephony"
link framework "SystemConfiguration"
link framework "UIKit"
link "sqlite3"
link "z"
}
@@ -1,114 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#import "MSACConstants+Flags.h"
@protocol MSACChannelUnitProtocol;
@protocol MSACChannelGroupProtocol;
@protocol MSACChannelProtocol;
@protocol MSACLog;
NS_ASSUME_NONNULL_BEGIN
@protocol MSACChannelDelegate <NSObject>
@optional
/**
* A callback that is called when a channel unit is added to the channel group.
*
* @param channelGroup The channel group.
* @param channel The newly added channel.
*/
- (void)channelGroup:(id<MSACChannelGroupProtocol>)channelGroup didAddChannelUnit:(id<MSACChannelUnitProtocol>)channel;
/**
* A callback that is called when a log is just enqueued. Delegates may want to prepare the log a little more before further processing.
*
* @param log The log to prepare.
*/
- (void)channel:(id<MSACChannelProtocol>)channel prepareLog:(id<MSACLog>)log;
/**
* A callback that is called after a log is definitely prepared.
*
* @param log The log.
* @param internalId An internal Id to keep track of logs.
* @param flags Options for the log.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didPrepareLog:(id<MSACLog>)log internalId:(NSString *)internalId flags:(MSACFlags)flags;
/**
* A callback that is called after a log completed the enqueueing process whether it was successful or not.
*
* @param log The log.
* @param internalId An internal Id to keep track of logs.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didCompleteEnqueueingLog:(id<MSACLog>)log internalId:(NSString *)internalId;
/**
* Callback method that will be called before each log will be send to the server.
*
* @param channel The channel object.
* @param log The log to be sent.
*/
- (void)channel:(id<MSACChannelProtocol>)channel willSendLog:(id<MSACLog>)log;
/**
* Callback method that will be called in case the SDK was able to send a log.
*
* @param channel The channel object.
* @param log The log to be sent.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didSucceedSendingLog:(id<MSACLog>)log;
/**
* Callback method that will be called in case the SDK was unable to send a log.
*
* @param channel The channel object.
* @param log The log to be sent.
* @param error The error that occured.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didFailSendingLog:(id<MSACLog>)log withError:(nullable NSError *)error;
/**
* A callback that is called when setEnabled has been invoked.
*
* @param channel The channel.
* @param isEnabled The boolean that indicates enabled.
* @param deletedData The boolean that indicates deleting data on disabled.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didSetEnabled:(BOOL)isEnabled andDeleteDataOnDisabled:(BOOL)deletedData;
/**
* A callback that is called when pause has been invoked.
*
* @param channel The channel.
* @param identifyingObject The identifying object used to pause the channel.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didPauseWithIdentifyingObject:(id<NSObject>)identifyingObject;
/**
* A callback that is called when resume has been invoked.
*
* @param channel The channel.
* @param identifyingObject The identifying object used to resume the channel.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didResumeWithIdentifyingObject:(id<NSObject>)identifyingObject;
/**
* Callback method that will determine if a log should be filtered out from the usual processing pipeline. If any delegate returns true, the
* log is filtered.
*
* @param channelUnit The channel unit that is going to send the log.
* @param log The log to be filtered or not.
*
* @return `true` if the log should be filtered out.
*/
- (BOOL)channelUnit:(id<MSACChannelUnitProtocol>)channelUnit shouldFilterLog:(id<MSACLog>)log;
@end
NS_ASSUME_NONNULL_END
@@ -1,417 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>files</key>
<dict>
<key>Headers/AppCenter.h</key>
<data>
w9sW6K7DVhGfORLCjGXijaR25m0=
</data>
<key>Headers/MSACAbstractLog.h</key>
<data>
+Ikfy/fTOpqwPZM3Fpii3cpsx8Y=
</data>
<key>Headers/MSACAppCenter.h</key>
<data>
2cUgfgx3odOGivdk+n6FXq94KgU=
</data>
<key>Headers/MSACAppCenterErrors.h</key>
<data>
x7h4qpHD4GI3jrJ3F7n4UXAANsk=
</data>
<key>Headers/MSACChannelGroupProtocol.h</key>
<data>
jyWCHN4PSygLVy0IM5565DvDQAc=
</data>
<key>Headers/MSACChannelProtocol.h</key>
<data>
Y1rKi/TsirTR0MGBf1rIO/TTG0A=
</data>
<key>Headers/MSACConstants+Flags.h</key>
<data>
GK1gUSyIjWdv7KBP68wNxjxaH+E=
</data>
<key>Headers/MSACConstants.h</key>
<data>
d9HwKA0/VH3+pLRj1Pd49mqn2gI=
</data>
<key>Headers/MSACCustomProperties.h</key>
<data>
m7A9hEgL3d0gV4SyKmXJYRtwqoQ=
</data>
<key>Headers/MSACDevice.h</key>
<data>
suv4Wkt36Nkscy7jX2SSYzrkLRs=
</data>
<key>Headers/MSACEnable.h</key>
<data>
3DnplEFkD1LImYNk+84TqcQvBho=
</data>
<key>Headers/MSACLog.h</key>
<data>
1/7NIwYuYLGHIVMZps8b6/zOpJg=
</data>
<key>Headers/MSACLogWithProperties.h</key>
<data>
I4y13KVE36pyXv85mc5OWlCjplE=
</data>
<key>Headers/MSACLogger.h</key>
<data>
CaYHmB3+psy5/txfMvd2+bWGJkc=
</data>
<key>Headers/MSACSerializableObject.h</key>
<data>
or5nqKvOQVn2ZieUCmYK6fIZkWY=
</data>
<key>Headers/MSACService.h</key>
<data>
lz5atiMe+oTdu9e6g74KPC0CjOs=
</data>
<key>Headers/MSACServiceAbstract.h</key>
<data>
rBHatSAJK78PLgsMIpFqkby4tgA=
</data>
<key>Headers/MSACWrapperLogger.h</key>
<data>
qBVuNkF12BZYytRhCKwZ7zkiKhc=
</data>
<key>Headers/MSACWrapperSdk.h</key>
<data>
W9sdhEGnIGk/aFHS3gWwQ6FxUfI=
</data>
<key>Info.plist</key>
<data>
vQsDzcm1lLcpUNIaE5cw31rdoVk=
</data>
<key>Modules/module.modulemap</key>
<data>
go9b9XYQJIVcGlS/K5PS+8A+0dI=
</data>
<key>PrivateHeaders/MSACChannelDelegate.h</key>
<data>
Msff4BZ/b1IjaYeKTDBHtNtT7wI=
</data>
</dict>
<key>files2</key>
<dict>
<key>Headers/AppCenter.h</key>
<dict>
<key>hash</key>
<data>
w9sW6K7DVhGfORLCjGXijaR25m0=
</data>
<key>hash2</key>
<data>
e9qe35Ew1pz0RMBfwa2Jv+3188p8iTwwktkIgCa/ztg=
</data>
</dict>
<key>Headers/MSACAbstractLog.h</key>
<dict>
<key>hash</key>
<data>
+Ikfy/fTOpqwPZM3Fpii3cpsx8Y=
</data>
<key>hash2</key>
<data>
7hsXFv3UkGsJLcc3eh2pMUrGbGYP2hCUC854z05SzNQ=
</data>
</dict>
<key>Headers/MSACAppCenter.h</key>
<dict>
<key>hash</key>
<data>
2cUgfgx3odOGivdk+n6FXq94KgU=
</data>
<key>hash2</key>
<data>
C10z0NrhN4J4qdWbypOdjlQ8QLlq4tvPMP21geOS4vI=
</data>
</dict>
<key>Headers/MSACAppCenterErrors.h</key>
<dict>
<key>hash</key>
<data>
x7h4qpHD4GI3jrJ3F7n4UXAANsk=
</data>
<key>hash2</key>
<data>
OcNwIIu4yFxG62mZtiABP3/9DoN9tj1fL/7nSvF8u8s=
</data>
</dict>
<key>Headers/MSACChannelGroupProtocol.h</key>
<dict>
<key>hash</key>
<data>
jyWCHN4PSygLVy0IM5565DvDQAc=
</data>
<key>hash2</key>
<data>
d36rCjxsURqDkFv+g5BwWNybz5Zksc9B91gqArFcJbk=
</data>
</dict>
<key>Headers/MSACChannelProtocol.h</key>
<dict>
<key>hash</key>
<data>
Y1rKi/TsirTR0MGBf1rIO/TTG0A=
</data>
<key>hash2</key>
<data>
fI1fLkJvo9SXh2bAUWKIYlretRCOoGWJwlyvqMfQZNc=
</data>
</dict>
<key>Headers/MSACConstants+Flags.h</key>
<dict>
<key>hash</key>
<data>
GK1gUSyIjWdv7KBP68wNxjxaH+E=
</data>
<key>hash2</key>
<data>
UDnw7GyNXzip13MvAvNKQQsWIUgU296uJHjPEkReCY8=
</data>
</dict>
<key>Headers/MSACConstants.h</key>
<dict>
<key>hash</key>
<data>
d9HwKA0/VH3+pLRj1Pd49mqn2gI=
</data>
<key>hash2</key>
<data>
xx69UfYa0qw6aSDuVsUAqd/1+t90QCPkQUae+elZwZ0=
</data>
</dict>
<key>Headers/MSACCustomProperties.h</key>
<dict>
<key>hash</key>
<data>
m7A9hEgL3d0gV4SyKmXJYRtwqoQ=
</data>
<key>hash2</key>
<data>
FveTXq+kqUdHHlSdLAoQisgT+95bzAuXTrTOQG/b/P8=
</data>
</dict>
<key>Headers/MSACDevice.h</key>
<dict>
<key>hash</key>
<data>
suv4Wkt36Nkscy7jX2SSYzrkLRs=
</data>
<key>hash2</key>
<data>
i3TVX2C+DfcRKn2HTBaydWBYHjryX2Cy/eJJxjTFiT8=
</data>
</dict>
<key>Headers/MSACEnable.h</key>
<dict>
<key>hash</key>
<data>
3DnplEFkD1LImYNk+84TqcQvBho=
</data>
<key>hash2</key>
<data>
XrDKc7bXZaW8JW4NMItSBrHLR6a+LRG1JSLXZ0U0NsI=
</data>
</dict>
<key>Headers/MSACLog.h</key>
<dict>
<key>hash</key>
<data>
1/7NIwYuYLGHIVMZps8b6/zOpJg=
</data>
<key>hash2</key>
<data>
3GF6xCTfpLDmOqKnacEOEDr5mkM/llKm0IoIEyISZKA=
</data>
</dict>
<key>Headers/MSACLogWithProperties.h</key>
<dict>
<key>hash</key>
<data>
I4y13KVE36pyXv85mc5OWlCjplE=
</data>
<key>hash2</key>
<data>
WIrz7Xsi04AboAmZ5dA3d3t8D/8PomKLwsp7oorznVM=
</data>
</dict>
<key>Headers/MSACLogger.h</key>
<dict>
<key>hash</key>
<data>
CaYHmB3+psy5/txfMvd2+bWGJkc=
</data>
<key>hash2</key>
<data>
GipSaz+D+Z5eWauQP+10U8xvbAnxPeIRD4HTvn0F5DQ=
</data>
</dict>
<key>Headers/MSACSerializableObject.h</key>
<dict>
<key>hash</key>
<data>
or5nqKvOQVn2ZieUCmYK6fIZkWY=
</data>
<key>hash2</key>
<data>
TdCeoNla8kUqc5HPES6WNwi7ycy+4vRr3HGDipEXNVE=
</data>
</dict>
<key>Headers/MSACService.h</key>
<dict>
<key>hash</key>
<data>
lz5atiMe+oTdu9e6g74KPC0CjOs=
</data>
<key>hash2</key>
<data>
aiO/PWAQDwhbPW1HDGqNM0kn4xYSwqPmdpmcTgpW/CE=
</data>
</dict>
<key>Headers/MSACServiceAbstract.h</key>
<dict>
<key>hash</key>
<data>
rBHatSAJK78PLgsMIpFqkby4tgA=
</data>
<key>hash2</key>
<data>
vi9/mVDQylipTtHNfUe9r4GXjlc2bEnKFV8wmN/IXaE=
</data>
</dict>
<key>Headers/MSACWrapperLogger.h</key>
<dict>
<key>hash</key>
<data>
qBVuNkF12BZYytRhCKwZ7zkiKhc=
</data>
<key>hash2</key>
<data>
h2VHxvALAogCMocFQMUjmOkhCm+qkJwpGTzxwdxTdwo=
</data>
</dict>
<key>Headers/MSACWrapperSdk.h</key>
<dict>
<key>hash</key>
<data>
W9sdhEGnIGk/aFHS3gWwQ6FxUfI=
</data>
<key>hash2</key>
<data>
5x+0epJnQN2wZKY2xjvsjAYrr6H1QGYIGz0ptux72dU=
</data>
</dict>
<key>Modules/module.modulemap</key>
<dict>
<key>hash</key>
<data>
go9b9XYQJIVcGlS/K5PS+8A+0dI=
</data>
<key>hash2</key>
<data>
o0lkqm4+xeVosltUC3U+jCZnS35Tg8gUiUaKXbo0ZbQ=
</data>
</dict>
<key>PrivateHeaders/MSACChannelDelegate.h</key>
<dict>
<key>hash</key>
<data>
Msff4BZ/b1IjaYeKTDBHtNtT7wI=
</data>
<key>hash2</key>
<data>
d1uS+ptvOX/o3CCB23FEJAtvcf7KIf/8ozlruAf1f0g=
</data>
</dict>
</dict>
<key>rules</key>
<dict>
<key>^.*</key>
<true/>
<key>^.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^Base\.lproj/</key>
<dict>
<key>weight</key>
<real>1010</real>
</dict>
<key>^version.plist$</key>
<true/>
</dict>
<key>rules2</key>
<dict>
<key>.*\.dSYM($|/)</key>
<dict>
<key>weight</key>
<real>11</real>
</dict>
<key>^(.*/)?\.DS_Store$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>2000</real>
</dict>
<key>^.*</key>
<true/>
<key>^.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^Base\.lproj/</key>
<dict>
<key>weight</key>
<real>1010</real>
</dict>
<key>^Info\.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^PkgInfo$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^embedded\.provisionprofile$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
<key>^version\.plist$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
</dict>
</dict>
</plist>
@@ -1 +0,0 @@
Versions/Current/AppCenter
@@ -1 +0,0 @@
Versions/Current/PrivateHeaders
@@ -1,44 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACAppCenter.h>)
#import <AppCenter/MSACAbstractLog.h>
#import <AppCenter/MSACAppCenter.h>
#import <AppCenter/MSACAppCenterErrors.h>
#import <AppCenter/MSACChannelGroupProtocol.h>
#import <AppCenter/MSACChannelProtocol.h>
#import <AppCenter/MSACConstants+Flags.h>
#import <AppCenter/MSACConstants.h>
#import <AppCenter/MSACCustomProperties.h>
#import <AppCenter/MSACDevice.h>
#import <AppCenter/MSACEnable.h>
#import <AppCenter/MSACLog.h>
#import <AppCenter/MSACLogWithProperties.h>
#import <AppCenter/MSACLogger.h>
#import <AppCenter/MSACSerializableObject.h>
#import <AppCenter/MSACService.h>
#import <AppCenter/MSACServiceAbstract.h>
#import <AppCenter/MSACWrapperLogger.h>
#import <AppCenter/MSACWrapperSdk.h>
#else
#import "MSACAbstractLog.h"
#import "MSACAppCenter.h"
#import "MSACAppCenterErrors.h"
#import "MSACChannelGroupProtocol.h"
#import "MSACChannelProtocol.h"
#import "MSACConstants+Flags.h"
#import "MSACConstants.h"
#import "MSACCustomProperties.h"
#import "MSACDevice.h"
#import "MSACEnable.h"
#import "MSACLog.h"
#import "MSACLogWithProperties.h"
#import "MSACLogger.h"
#import "MSACSerializableObject.h"
#import "MSACService.h"
#import "MSACServiceAbstract.h"
#import "MSACWrapperLogger.h"
#import "MSACWrapperSdk.h"
#endif
@@ -1,14 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_ABSTRACT_LOG_H
#define MSAC_ABSTRACT_LOG_H
#import <Foundation/Foundation.h>
NS_SWIFT_NAME(AbstractLog)
@interface MSACAbstractLog : NSObject
@end
#endif
@@ -1,203 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#ifndef MSAC_APP_CENTER
#define MSAC_APP_CENTER
#if __has_include(<AppCenter/MSACConstants.h>)
#import <AppCenter/MSACConstants.h>
#else
#import "MSACConstants.h"
#endif
@class MSACWrapperSdk;
#if !TARGET_OS_TV
@class MSACCustomProperties;
#endif
NS_SWIFT_NAME(AppCenter)
@interface MSACAppCenter : NSObject
/**
* Returns the singleton instance of MSACAppCenter.
*/
+ (instancetype)sharedInstance;
/**
* Configure the SDK with an application secret.
*
* @param appSecret A unique and secret key used to identify the application.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)configureWithAppSecret:(NSString *)appSecret NS_SWIFT_NAME(configure(withAppSecret:));
/**
* Configure the SDK.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)configure;
/**
* Configure the SDK with an application secret and an array of services to start.
*
* @param appSecret A unique and secret key used to identify the application.
* @param services Array of services to start.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)start:(NSString *)appSecret withServices:(NSArray<Class> *)services NS_SWIFT_NAME(start(withAppSecret:services:));
/**
* Start the SDK with an array of services.
*
* @param services Array of services to start.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)startWithServices:(NSArray<Class> *)services NS_SWIFT_NAME(start(services:));
/**
* Start a service.
*
* @param service A service to start.
*
* @discussion This may be called only once per service per application process lifetime.
*/
+ (void)startService:(Class)service;
/**
* Configure the SDK with an array of services to start from a library. This will not start the service at application level, it will enable
* the service only for the library.
*
* @param services Array of services to start.
*/
+ (void)startFromLibraryWithServices:(NSArray<Class> *)services NS_SWIFT_NAME(startFromLibrary(services:));
/**
* The flag indicates whether the SDK has already been configured or not.
*/
@property(class, atomic, readonly, getter=isConfigured) BOOL configured;
/**
* The flag indicates whether app is running in App Center Test Cloud.
*/
@property(class, atomic, readonly, getter=isRunningInAppCenterTestCloud) BOOL runningInAppCenterTestCloud;
/**
* The flag indicates whether or not the SDK was enabled as a whole
*
* The state is persisted in the device's storage across application launches.
*/
@property(class, nonatomic, getter=isEnabled, setter=setEnabled:) BOOL enabled NS_SWIFT_NAME(enabled);
/**
* Flag indicating whether SDK can send network requests.
*
* The state is persisted in the device's storage across application launches.
*/
@property(class, nonatomic, getter=isNetworkRequestsAllowed, setter=setNetworkRequestsAllowed:)
BOOL networkRequestsAllowed NS_SWIFT_NAME(networkRequestsAllowed);
/**
* The SDK's log level.
*/
@property(class, nonatomic) MSACLogLevel logLevel;
/**
* Base URL to use for backend communication.
*/
@property(class, nonatomic, strong) NSString *logUrl;
/**
* Set log handler.
*/
@property(class, nonatomic) MSACLogHandler logHandler;
/**
* Set wrapper SDK information to use when building device properties. This is intended in case you are building a SDK that uses the App
* Center SDK under the hood, e.g. our Xamarin SDK or ReactNative SDk.
*/
@property(class, nonatomic, strong) MSACWrapperSdk *wrapperSdk;
#if !TARGET_OS_TV
/**
* Set the custom properties.
*
* @param customProperties Custom properties object.
*/
+ (void)setCustomProperties:(MSACCustomProperties *)customProperties;
#endif
/**
* Check whether the application delegate forwarder is enabled or not.
*
* @discussion The application delegate forwarder forwards messages that target your application delegate methods via swizzling to the SDK.
* It simplifies the SDK integration but may not be suitable to any situations. For
* instance it should be disabled if you or one of your third party SDK is doing message forwarding on the application delegate. Message
* forwarding usually implies the implementation of @see NSObject#forwardingTargetForSelector: or @see NSObject#forwardInvocation: methods.
* To disable the application delegate forwarder just add the `AppCenterAppDelegateForwarderEnabled` tag to your Info .plist file and set it
* to `0`. Then you will have to forward any application delegate needed by the SDK manually.
*/
@property(class, readonly, nonatomic, getter=isAppDelegateForwarderEnabled) BOOL appDelegateForwarderEnabled;
/**
* Unique installation identifier.
*
*/
@property(class, readonly, nonatomic) NSUUID *installId;
/**
* Detect if a debugger is attached to the app process. This is only invoked once on app startup and can not detect
* if the debugger is being attached during runtime!
*
*/
@property(class, readonly, nonatomic, getter=isDebuggerAttached) BOOL debuggerAttached;
/**
* Current version of AppCenter SDK.
*
*/
@property(class, readonly, nonatomic) NSString *sdkVersion;
/**
* Set the maximum size of the internal storage. This method must be called before App Center is started. This method is only intended for
* applications.
*
* @param sizeInBytes Maximum size of the internal storage in bytes. This will be rounded up to the nearest multiple of a SQLite page size
* (default is 4096 bytes). Values below 20,480 bytes (20 KiB) will be ignored.
*
* @param completionHandler Callback that is invoked when the database size has been set. The `BOOL` parameter is `YES` if changing the size
* is successful, and `NO` otherwise. This parameter can be null.
*
* @discussion This only sets the maximum size of the database, but App Center modules might store additional data.
* The value passed to this method is not persisted on disk. The default maximum database size is 10485760 bytes (10 MiB).
*/
+ (void)setMaxStorageSize:(long)sizeInBytes completionHandler:(void (^)(BOOL))completionHandler;
/**
* Set the user identifier.
*
* @discussion Set the user identifier for logs sent for the default target token when the secret passed in @c
* MSACAppCenter:start:withServices: contains "target={targetToken}".
*
* For App Center backend the user identifier maximum length is 256 characters.
*
* AppCenter must be configured or started before this API can be used.
*/
@property(class, nonatomic, strong) NSString *userId;
/**
* Set country code to use when building device properties.
*
* @see https://www.iso.org/obp/ui/#search for more information.
*/
@property(class, nonatomic, strong) NSString *countryCode;
@end
#endif
@@ -1,41 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_APP_CENTER_ERRORS_H
#define MSAC_APP_CENTER_ERRORS_H
#import <Foundation/Foundation.h>
#define MSAC_APP_CENTER_BASE_DOMAIN @"com.Microsoft.AppCenter."
NS_ASSUME_NONNULL_BEGIN
#pragma mark - Domain
static NSString *const kMSACACErrorDomain = MSAC_APP_CENTER_BASE_DOMAIN @"ErrorDomain";
#pragma mark - General
// Error codes.
NS_ENUM(NSInteger){MSACACLogInvalidContainerErrorCode = 1, MSACACCanceledErrorCode = 2, MSACACDisabledErrorCode = 3};
// Error descriptions.
static NSString const *kMSACACLogInvalidContainerErrorDesc = @"Invalid log container.";
static NSString const *kMSACACCanceledErrorDesc = @"The operation was canceled.";
static NSString const *kMSACACDisabledErrorDesc = @"The service is disabled.";
#pragma mark - Connection
// Error codes.
NS_ENUM(NSInteger){MSACACConnectionPausedErrorCode = 100, MSACACConnectionHttpErrorCode = 101};
// Error descriptions.
static NSString const *kMSACACConnectionHttpErrorDesc = @"An HTTP error occured.";
static NSString const *kMSACACConnectionPausedErrorDesc = @"Canceled, connection paused with log deletion.";
// Error user info keys.
static NSString const *kMSACACConnectionHttpCodeErrorKey = @"MSConnectionHttpCode";
NS_ASSUME_NONNULL_END
#endif
@@ -1,87 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CHANNEL_GROUP_PROTOCOL_H
#define MSAC_CHANNEL_GROUP_PROTOCOL_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACChannelProtocol.h>)
#import <AppCenter/MSACChannelProtocol.h>
#else
#import "MSACChannelProtocol.h"
#endif
NS_ASSUME_NONNULL_BEGIN
@class MSACChannelUnitConfiguration;
@protocol MSACIngestionProtocol;
@protocol MSACChannelUnitProtocol;
/**
* `MSACChannelGroupProtocol` represents a kind of channel that contains constituent MSACChannelUnit objects. When an operation from the
* `MSACChannelProtocol` is performed on the group, that operation should be propagated to its constituent MSACChannelUnit objects.
*/
NS_SWIFT_NAME(ChannelGroupProtocol)
@protocol MSACChannelGroupProtocol <MSACChannelProtocol>
/**
* Initialize a channel unit with the given configuration.
*
* @param configuration channel configuration.
*
* @return The added `MSACChannelUnitProtocol`. Use this object to enqueue logs.
*/
- (id<MSACChannelUnitProtocol>)addChannelUnitWithConfiguration:(MSACChannelUnitConfiguration *)configuration
NS_SWIFT_NAME(addChannelUnit(withConfiguration:));
/**
* Initialize a channel unit with the given configuration.
*
* @param configuration channel configuration.
* @param ingestion The alternative ingestion object
*
* @return The added `MSACChannelUnitProtocol`. Use this object to enqueue logs.
*/
- (id<MSACChannelUnitProtocol>)addChannelUnitWithConfiguration:(MSACChannelUnitConfiguration *)configuration
withIngestion:(nullable id<MSACIngestionProtocol>)ingestion
NS_SWIFT_NAME(addChannelUnit(_:ingestion:));
/**
* Change the base URL (schema + authority + port only) used to communicate with the backend.
*/
@property(nonatomic, strong) NSString *_Nullable logUrl;
/**
* Set the app secret.
*/
@property(nonatomic, strong) NSString *_Nullable appSecret;
/**
* Set the maximum size of the internal storage. This method must be called before App Center is started.
*
* @discussion The default maximum database size is 10485760 bytes (10 MiB).
*
* @param sizeInBytes Maximum size of the internal storage in bytes. This will be rounded up to the nearest multiple of a SQLite page size
* (default is 4096 bytes). Values below 24576 bytes (24 KiB) will be ignored.
* @param completionHandler Callback that is invoked when the database size has been set. The `BOOL` parameter is `YES` if changing the size
* is successful, and `NO` otherwise.
*/
- (void)setMaxStorageSize:(long)sizeInBytes
completionHandler:(nullable void (^)(BOOL))completionHandler NS_SWIFT_NAME(setMaxStorageSize(_:completionHandler:));
/**
* Return a channel unit instance for the given groupId.
*
* @param groupId The group ID for a channel unit.
*
* @return A channel unit instance or `nil`.
*/
- (nullable id<MSACChannelUnitProtocol>)channelUnitForGroupId:(NSString *)groupId;
@end
NS_ASSUME_NONNULL_END
#endif
@@ -1,68 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CHANNEL_PROTOCOL_H
#define MSAC_CHANNEL_PROTOCOL_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACEnable.h>)
#import <AppCenter/MSACEnable.h>
#else
#import "MSACEnable.h"
#endif
NS_ASSUME_NONNULL_BEGIN
@protocol MSACChannelDelegate;
/**
* `MSACChannelProtocol` contains the essential operations of a channel. Channels are broadly responsible for enqueuing logs to be sent to
* the backend and/or stored on disk.
*/
NS_SWIFT_NAME(ChannelProtocol)
@protocol MSACChannelProtocol <NSObject, MSACEnable>
/**
* Add delegate.
*
* @param delegate delegate.
*/
- (void)addDelegate:(id<MSACChannelDelegate>)delegate;
/**
* Remove delegate.
*
* @param delegate delegate.
*/
- (void)removeDelegate:(id<MSACChannelDelegate>)delegate;
/**
* Pause operations, logs will be stored but not sent.
*
* @param identifyingObject Object used to identify the pause request.
*
* @discussion A paused channel doesn't forward logs to the ingestion. The identifying object used to pause the channel can be any unique
* object. The same identifying object must be used to call resume. For simplicity if the caller is the one owning the channel then @c self
* can be used as identifying object.
*
* @see resumeWithIdentifyingObject:
*/
- (void)pauseWithIdentifyingObject:(id<NSObject>)identifyingObject;
/**
* Resume operations, logs can be sent again.
*
* @param identifyingObject Object used to passed to the pause method.
*
* @discussion The channel only resume when all the outstanding identifying objects have been resumed.
*
* @see pauseWithIdentifyingObject:
*/
- (void)resumeWithIdentifyingObject:(id<NSObject>)identifyingObject;
@end
NS_ASSUME_NONNULL_END
#endif
@@ -1,18 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CONSTANTS_FLAGS_H
#define MSAC_CONSTANTS_FLAGS_H
#import <Foundation/Foundation.h>
typedef NS_OPTIONS(NSUInteger, MSACFlags) {
MSACFlagsNone = (0 << 0), // => 00000000
MSACFlagsNormal = (1 << 0), // => 00000001
MSACFlagsCritical = (1 << 1), // => 00000010
MSACFlagsPersistenceNormal DEPRECATED_MSG_ATTRIBUTE("please use MSACFlagsNormal") = MSACFlagsNormal,
MSACFlagsPersistenceCritical DEPRECATED_MSG_ATTRIBUTE("please use MSACFlagsCritical") = MSACFlagsCritical,
MSACFlagsDefault = MSACFlagsNormal
} NS_SWIFT_NAME(Flags);
#endif
@@ -1,170 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
/**
* Log Levels
*/
typedef NS_ENUM(NSUInteger, MSACLogLevel) {
/**
* Logging will be very chatty
*/
MSACLogLevelVerbose = 2,
/**
* Debug information will be logged
*/
MSACLogLevelDebug = 3,
/**
* Information will be logged
*/
MSACLogLevelInfo = 4,
/**
* Errors and warnings will be logged
*/
MSACLogLevelWarning = 5,
/**
* Errors will be logged
*/
MSACLogLevelError = 6,
/**
* Only critical errors will be logged
*/
MSACLogLevelAssert = 7,
/**
* Logging is disabled
*/
MSACLogLevelNone = 99
} NS_SWIFT_NAME(LogLevel);
typedef NSString * (^MSACLogMessageProvider)(void)NS_SWIFT_NAME(LogMessageProvider);
typedef void (^MSACLogHandler)(MSACLogMessageProvider messageProvider, MSACLogLevel logLevel, NSString *tag, const char *file,
const char *function, uint line) NS_SWIFT_NAME(LogHandler);
/**
* Channel priorities, check the kMSACPriorityCount if you add a new value.
* The order matters here! Values NEED to range from low priority to high priority.
*/
typedef NS_ENUM(NSInteger, MSACPriority) { MSACPriorityBackground, MSACPriorityDefault, MSACPriorityHigh } NS_SWIFT_NAME(Priority);
static short const kMSACPriorityCount = MSACPriorityHigh + 1;
/**
* The priority by which the modules are initialized.
* MSACPriorityMax is reserved for only 1 module and this needs to be Crashes.
* Crashes needs to be initialized first to catch crashes in our other SDK Modules (which will hopefully never happen) and to avoid losing
* any log at crash time.
*/
typedef NS_ENUM(NSInteger, MSACInitializationPriority) {
MSACInitializationPriorityDefault = 500,
MSACInitializationPriorityHigh = 750,
MSACInitializationPriorityMax = 999
} NS_SWIFT_NAME(InitializationPriority);
/**
* Enum with the different HTTP status codes.
*/
typedef NS_ENUM(NSInteger, MSACHTTPCodesNo) {
// Invalid
MSACHTTPCodesNo0XXInvalidUnknown = 0,
// Informational
MSACHTTPCodesNo1XXInformationalUnknown = 1,
MSACHTTPCodesNo100Continue = 100,
MSACHTTPCodesNo101SwitchingProtocols = 101,
MSACHTTPCodesNo102Processing = 102,
// Success
MSACHTTPCodesNo2XXSuccessUnknown = 2,
MSACHTTPCodesNo200OK = 200,
MSACHTTPCodesNo201Created = 201,
MSACHTTPCodesNo202Accepted = 202,
MSACHTTPCodesNo203NonAuthoritativeInformation = 203,
MSACHTTPCodesNo204NoContent = 204,
MSACHTTPCodesNo205ResetContent = 205,
MSACHTTPCodesNo206PartialContent = 206,
MSACHTTPCodesNo207MultiStatus = 207,
MSACHTTPCodesNo208AlreadyReported = 208,
MSACHTTPCodesNo209IMUsed = 209,
// Redirection
MSACHTTPCodesNo3XXSuccessUnknown = 3,
MSACHTTPCodesNo300MultipleChoices = 300,
MSACHTTPCodesNo301MovedPermanently = 301,
MSACHTTPCodesNo302Found = 302,
MSACHTTPCodesNo303SeeOther = 303,
MSACHTTPCodesNo304NotModified = 304,
MSACHTTPCodesNo305UseProxy = 305,
MSACHTTPCodesNo306SwitchProxy = 306,
MSACHTTPCodesNo307TemporaryRedirect = 307,
MSACHTTPCodesNo308PermanentRedirect = 308,
// Client error
MSACHTTPCodesNo4XXSuccessUnknown = 4,
MSACHTTPCodesNo400BadRequest = 400,
MSACHTTPCodesNo401Unauthorised = 401,
MSACHTTPCodesNo402PaymentRequired = 402,
MSACHTTPCodesNo403Forbidden = 403,
MSACHTTPCodesNo404NotFound = 404,
MSACHTTPCodesNo405MethodNotAllowed = 405,
MSACHTTPCodesNo406NotAcceptable = 406,
MSACHTTPCodesNo407ProxyAuthenticationRequired = 407,
MSACHTTPCodesNo408RequestTimeout = 408,
MSACHTTPCodesNo409Conflict = 409,
MSACHTTPCodesNo410Gone = 410,
MSACHTTPCodesNo411LengthRequired = 411,
MSACHTTPCodesNo412PreconditionFailed = 412,
MSACHTTPCodesNo413RequestEntityTooLarge = 413,
MSACHTTPCodesNo414RequestURITooLong = 414,
MSACHTTPCodesNo415UnsupportedMediaType = 415,
MSACHTTPCodesNo416RequestedRangeNotSatisfiable = 416,
MSACHTTPCodesNo417ExpectationFailed = 417,
MSACHTTPCodesNo418IamATeapot = 418,
MSACHTTPCodesNo419AuthenticationTimeout = 419,
MSACHTTPCodesNo420MethodFailureSpringFramework = 420,
MSACHTTPCodesNo420EnhanceYourCalmTwitter = 4200,
MSACHTTPCodesNo422UnprocessableEntity = 422,
MSACHTTPCodesNo423Locked = 423,
MSACHTTPCodesNo424FailedDependency = 424,
MSACHTTPCodesNo424MethodFailureWebDaw = 4240,
MSACHTTPCodesNo425UnorderedCollection = 425,
MSACHTTPCodesNo426UpgradeRequired = 426,
MSACHTTPCodesNo428PreconditionRequired = 428,
MSACHTTPCodesNo429TooManyRequests = 429,
MSACHTTPCodesNo431RequestHeaderFieldsTooLarge = 431,
MSACHTTPCodesNo444NoResponseNginx = 444,
MSACHTTPCodesNo449RetryWithMicrosoft = 449,
MSACHTTPCodesNo450BlockedByWindowsParentalControls = 450,
MSACHTTPCodesNo451RedirectMicrosoft = 451,
MSACHTTPCodesNo451UnavailableForLegalReasons = 4510,
MSACHTTPCodesNo494RequestHeaderTooLargeNginx = 494,
MSACHTTPCodesNo495CertErrorNginx = 495,
MSACHTTPCodesNo496NoCertNginx = 496,
MSACHTTPCodesNo497HTTPToHTTPSNginx = 497,
MSACHTTPCodesNo499ClientClosedRequestNginx = 499,
// Server error
MSACHTTPCodesNo5XXSuccessUnknown = 5,
MSACHTTPCodesNo500InternalServerError = 500,
MSACHTTPCodesNo501NotImplemented = 501,
MSACHTTPCodesNo502BadGateway = 502,
MSACHTTPCodesNo503ServiceUnavailable = 503,
MSACHTTPCodesNo504GatewayTimeout = 504,
MSACHTTPCodesNo505HTTPVersionNotSupported = 505,
MSACHTTPCodesNo506VariantAlsoNegotiates = 506,
MSACHTTPCodesNo507InsufficientStorage = 507,
MSACHTTPCodesNo508LoopDetected = 508,
MSACHTTPCodesNo509BandwidthLimitExceeded = 509,
MSACHTTPCodesNo510NotExtended = 510,
MSACHTTPCodesNo511NetworkAuthenticationRequired = 511,
MSACHTTPCodesNo522ConnectionTimedOut = 522,
MSACHTTPCodesNo598NetworkReadTimeoutErrorUnknown = 598,
MSACHTTPCodesNo599NetworkConnectTimeoutErrorUnknown = 599
} NS_SWIFT_NAME(HTTPCodesNo);
@@ -1,71 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CUSTOM_PROPERTIES_H
#define MSAC_CUSTOM_PROPERTIES_H
#import <Foundation/Foundation.h>
/**
* Custom properties builder.
* Collects multiple properties to send in one log.
*/
NS_SWIFT_NAME(CustomProperties)
@interface MSACCustomProperties : NSObject
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setString:(NSString *)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setNumber:(NSNumber *)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setBool:(BOOL)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setDate:(NSDate *)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Clear the property for the specified key.
*
* @param key Key whose mapping is to be cleared.
*
* @return This instance.
*/
- (instancetype)clearPropertyForKey:(NSString *)key NS_SWIFT_NAME(clearProperty(forKey:));
@end
#endif
@@ -1,101 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_DEVICE_H
#define MSAC_DEVICE_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACWrapperSdk.h>)
#import <AppCenter/MSACWrapperSdk.h>
#else
#import "MSACWrapperSdk.h"
#endif
NS_SWIFT_NAME(Device)
@interface MSACDevice : MSACWrapperSdk
/*
* Name of the SDK. Consists of the name of the SDK and the platform, e.g. "appcenter.ios", "appcenter.android"
*/
@property(nonatomic, copy, readonly) NSString *sdkName;
/*
* Version of the SDK in semver format, e.g. "1.2.0" or "0.12.3-alpha.1".
*/
@property(nonatomic, copy, readonly) NSString *sdkVersion;
/*
* Device model (example: iPad2,3).
*/
@property(nonatomic, copy, readonly) NSString *model;
/*
* Device manufacturer (example: HTC).
*/
@property(nonatomic, copy, readonly) NSString *oemName;
/*
* OS name (example: iOS).
*/
@property(nonatomic, copy, readonly) NSString *osName;
/*
* OS version (example: 9.3.0).
*/
@property(nonatomic, copy, readonly) NSString *osVersion;
/*
* OS build code (example: LMY47X). [optional]
*/
@property(nonatomic, copy, readonly) NSString *osBuild;
/*
* API level when applicable like in Android (example: 15). [optional]
*/
@property(nonatomic, copy, readonly) NSNumber *osApiLevel;
/*
* Language code (example: en_US).
*/
@property(nonatomic, copy, readonly) NSString *locale;
/*
* The offset in minutes from UTC for the device time zone, including daylight savings time.
*/
@property(nonatomic, readonly, strong) NSNumber *timeZoneOffset;
/*
* Screen size of the device in pixels (example: 640x480).
*/
@property(nonatomic, copy, readonly) NSString *screenSize;
/*
* Application version name, e.g. 1.1.0
*/
@property(nonatomic, copy, readonly) NSString *appVersion;
/*
* Carrier name (for mobile devices). [optional]
*/
@property(nonatomic, copy, readonly) NSString *carrierName;
/*
* Carrier country code (for mobile devices). [optional]
*/
@property(nonatomic, copy, readonly) NSString *carrierCountry;
/*
* The app's build number, e.g. 42.
*/
@property(nonatomic, copy, readonly) NSString *appBuild;
/*
* The bundle identifier, package identifier, or namespace, depending on what the individual plattforms use, .e.g com.microsoft.example.
* [optional]
*/
@property(nonatomic, copy, readonly) NSString *appNamespace;
@end
#endif
@@ -1,27 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_ENABLE_H
#define MSAC_ENABLE_H
#import <Foundation/Foundation.h>
/**
* Protocol to define an instance that can be enabled/disabled.
*/
NS_SWIFT_NAME(Enable)
@protocol MSACEnable <NSObject>
@required
/**
* Enable/disable this instance and delete data on disabled state.
*
* @param isEnabled A boolean value set to YES to enable the instance or NO to disable it.
* @param deleteData A boolean value set to YES to delete data or NO to keep it.
*/
- (void)setEnabled:(BOOL)isEnabled andDeleteDataOnDisabled:(BOOL)deleteData NS_SWIFT_NAME(setEnabled(_:deleteDataOnDisabled:));
@end
#endif
@@ -1,74 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_LOG_H
#define MSAC_LOG_H
#import <Foundation/Foundation.h>
@class MSACDevice;
NS_SWIFT_NAME(Log)
@protocol MSACLog <NSObject>
/**
* Log type.
*/
@property(nonatomic, copy) NSString *type;
/**
* Log timestamp.
*/
@property(nonatomic, strong) NSDate *timestamp;
/**
* A session identifier is used to correlate logs together. A session is an abstract concept in the API and is not necessarily an analytics
* session, it can be used to only track crashes.
*/
@property(nonatomic, copy) NSString *sid;
/**
* Optional distribution group ID value.
*/
@property(nonatomic, copy) NSString *distributionGroupId;
/**
* Optional user identifier.
*/
@property(nonatomic, copy) NSString *userId;
/**
* Device properties associated to this log.
*/
@property(nonatomic, strong) MSACDevice *device;
/**
* Transient object tag. For example, a log can be tagged with a transmission target. We do this currently to prevent properties being
* applied retroactively to previous logs by comparing their tags.
*/
@property(nonatomic, strong) NSObject *tag;
/**
* Checks if the object's values are valid.
*
* @return YES, if the object is valid.
*/
- (BOOL)isValid;
/**
* Adds a transmission target token that this log should be sent to.
*
* @param token The transmission target token.
*/
- (void)addTransmissionTargetToken:(NSString *)token;
/**
* Gets all transmission target tokens that this log should be sent to.
*
* @returns Collection of transmission target tokens that this log should be sent to.
*/
- (NSSet *)transmissionTargetTokens;
@end
#endif
@@ -1,25 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_LOG_WITH_PROPERTIES_H
#define MSAC_LOG_WITH_PROPERTIES_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACAbstractLog.h>)
#import <AppCenter/MSACAbstractLog.h>
#else
#import "MSACAbstractLog.h"
#endif
NS_SWIFT_NAME(LogWithProperties)
@interface MSACLogWithProperties : MSACAbstractLog
/**
* Additional key/value pair parameters. [optional]
*/
@property(nonatomic, strong) NSDictionary<NSString *, NSString *> *properties;
@end
#endif
@@ -1,54 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#ifndef MSAC_LOGGER
#define MSAC_LOGGER
#if __has_include(<AppCenter/MSACConstants.h>)
#import <AppCenter/MSACConstants.h>
#else
#import "MSACConstants.h"
#endif
#define MSACLog(_level, _tag, _message) \
[MSACLogger logMessage:_message level:_level tag:_tag file:__FILE__ function:__PRETTY_FUNCTION__ line:__LINE__]
#define MSACLogAssert(tag, format, ...) \
MSACLog(MSACLogLevelAssert, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogError(tag, format, ...) \
MSACLog(MSACLogLevelError, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogWarning(tag, format, ...) \
MSACLog(MSACLogLevelWarning, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogInfo(tag, format, ...) \
MSACLog(MSACLogLevelInfo, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogDebug(tag, format, ...) \
MSACLog(MSACLogLevelDebug, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogVerbose(tag, format, ...) \
MSACLog(MSACLogLevelVerbose, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
NS_SWIFT_NAME(Logger)
@interface MSACLogger : NSObject
+ (void)logMessage:(MSACLogMessageProvider)messageProvider
level:(MSACLogLevel)loglevel
tag:(NSString *)tag
file:(const char *)file
function:(const char *)function
line:(uint)line;
@end
#endif
@@ -1,19 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#ifndef SERIALIZABLE_OBJECT_H
#define SERIALIZABLE_OBJECT_H
@protocol MSACSerializableObject <NSCoding>
/**
* Serialize this object to a dictionary.
*
* @return A dictionary representing this object.
*/
- (NSMutableDictionary *)serializeToDictionary;
@end
#endif
@@ -1,23 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_SERVICE_H
#define MSAC_SERVICE_H
#import <Foundation/Foundation.h>
/**
* Protocol declaring service logic.
*/
NS_SWIFT_NAME(Service)
@protocol MSACService <NSObject>
/**
* Indicates whether this service is enabled.
* The state is persisted in the device's storage across application launches.
*/
@property(class, nonatomic, getter=isEnabled, setter=setEnabled:) BOOL enabled NS_SWIFT_NAME(enabled);
@end
#endif
@@ -1,58 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_SERVICE_ABSTRACT_H
#define MSAC_SERVICE_ABSTRACT_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACService.h>)
#import <AppCenter/MSACService.h>
#else
#import "MSACService.h"
#endif
@protocol MSACChannelGroupProtocol;
/**
* Abstraction of services common logic.
* This class is intended to be subclassed only not instantiated directly.
*/
NS_SWIFT_NAME(ServiceAbstract)
@interface MSACServiceAbstract : NSObject <MSACService>
/**
* The flag indicates whether the service is started from application or not.
*/
@property(nonatomic, assign) BOOL startedFromApplication;
/**
* Start this service with a channel group. Also sets the flag that indicates that a service has been started.
*
* @param channelGroup channel group used to persist and send logs.
* @param appSecret app secret for the SDK.
* @param token default transmission target token for this service.
* @param fromApplication indicates whether the service started from an application or not.
*/
- (void)startWithChannelGroup:(id<MSACChannelGroupProtocol>)channelGroup
appSecret:(NSString *)appSecret
transmissionTargetToken:(NSString *)token
fromApplication:(BOOL)fromApplication;
/**
* Update configuration when the service requires to start again. This method should only be called if the service is started from libraries
* and then is being started from an application.
*
* @param appSecret app secret for the SDK.
* @param token default transmission target token for this service.
*/
- (void)updateConfigurationWithAppSecret:(NSString *)appSecret transmissionTargetToken:(NSString *)token;
/**
* The flag indicate whether the service needs the application secret or not.
*/
@property(atomic, readonly) BOOL isAppSecretRequired;
@end
#endif
@@ -1,21 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACConstants.h>)
#import <AppCenter/MSACConstants.h>
#else
#import "MSACConstants.h"
#endif
/**
* This is a utility for producing App Center style log messages. It is only intended for use by App Center services and wrapper SDKs of App
* Center.
*/
NS_SWIFT_NAME(WrapperLogger)
@interface MSACWrapperLogger : NSObject
+ (void)MSACWrapperLog:(MSACLogMessageProvider)message tag:(NSString *)tag level:(MSACLogLevel)level;
@end
@@ -1,60 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_WRAPPER_SDK_H
#define MSAC_WRAPPER_SDK_H
#import <Foundation/Foundation.h>
NS_SWIFT_NAME(WrapperSdk)
@interface MSACWrapperSdk : NSObject
/*
* Version of the wrapper SDK. When the SDK is embedding another base SDK (for example Xamarin.Android wraps Android), the Xamarin specific
* version is populated into this field while sdkVersion refers to the original Android SDK. [optional]
*/
@property(nonatomic, copy, readonly) NSString *wrapperSdkVersion;
/*
* Name of the wrapper SDK (examples: Xamarin, Cordova). [optional]
*/
@property(nonatomic, copy, readonly) NSString *wrapperSdkName;
/*
* Version of the wrapper technology framework (Xamarin runtime version or ReactNative or Cordova etc...). [optional]
*/
@property(nonatomic, copy, readonly) NSString *wrapperRuntimeVersion;
/*
* Label that is used to identify application code 'version' released via Live Update beacon running on device.
*/
@property(nonatomic, copy, readonly) NSString *liveUpdateReleaseLabel;
/*
* Identifier of environment that current application release belongs to, deployment key then maps to environment like Production, Staging.
*/
@property(nonatomic, copy, readonly) NSString *liveUpdateDeploymentKey;
/*
* Hash of all files (ReactNative or Cordova) deployed to device via LiveUpdate beacon. Helps identify the Release version on device or need
* to download updates in future
*/
@property(nonatomic, copy, readonly) NSString *liveUpdatePackageHash;
- (instancetype)initWithWrapperSdkVersion:(NSString *)wrapperSdkVersion
wrapperSdkName:(NSString *)wrapperSdkName
wrapperRuntimeVersion:(NSString *)wrapperRuntimeVersion
liveUpdateReleaseLabel:(NSString *)liveUpdateReleaseLabel
liveUpdateDeploymentKey:(NSString *)liveUpdateDeploymentKey
liveUpdatePackageHash:(NSString *)liveUpdatePackageHash;
/**
* Checks if the object's values are valid.
*
* @return YES, if the object is valid.
*/
- (BOOL)isValid;
@end
#endif
@@ -1,13 +0,0 @@
framework module AppCenter {
umbrella header "AppCenter.h"
export *
module * { export * }
link framework "Foundation"
link framework "CoreTelephony"
link framework "SystemConfiguration"
link framework "UIKit"
link "sqlite3"
link "z"
}
@@ -1,114 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#import "MSACConstants+Flags.h"
@protocol MSACChannelUnitProtocol;
@protocol MSACChannelGroupProtocol;
@protocol MSACChannelProtocol;
@protocol MSACLog;
NS_ASSUME_NONNULL_BEGIN
@protocol MSACChannelDelegate <NSObject>
@optional
/**
* A callback that is called when a channel unit is added to the channel group.
*
* @param channelGroup The channel group.
* @param channel The newly added channel.
*/
- (void)channelGroup:(id<MSACChannelGroupProtocol>)channelGroup didAddChannelUnit:(id<MSACChannelUnitProtocol>)channel;
/**
* A callback that is called when a log is just enqueued. Delegates may want to prepare the log a little more before further processing.
*
* @param log The log to prepare.
*/
- (void)channel:(id<MSACChannelProtocol>)channel prepareLog:(id<MSACLog>)log;
/**
* A callback that is called after a log is definitely prepared.
*
* @param log The log.
* @param internalId An internal Id to keep track of logs.
* @param flags Options for the log.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didPrepareLog:(id<MSACLog>)log internalId:(NSString *)internalId flags:(MSACFlags)flags;
/**
* A callback that is called after a log completed the enqueueing process whether it was successful or not.
*
* @param log The log.
* @param internalId An internal Id to keep track of logs.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didCompleteEnqueueingLog:(id<MSACLog>)log internalId:(NSString *)internalId;
/**
* Callback method that will be called before each log will be send to the server.
*
* @param channel The channel object.
* @param log The log to be sent.
*/
- (void)channel:(id<MSACChannelProtocol>)channel willSendLog:(id<MSACLog>)log;
/**
* Callback method that will be called in case the SDK was able to send a log.
*
* @param channel The channel object.
* @param log The log to be sent.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didSucceedSendingLog:(id<MSACLog>)log;
/**
* Callback method that will be called in case the SDK was unable to send a log.
*
* @param channel The channel object.
* @param log The log to be sent.
* @param error The error that occured.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didFailSendingLog:(id<MSACLog>)log withError:(nullable NSError *)error;
/**
* A callback that is called when setEnabled has been invoked.
*
* @param channel The channel.
* @param isEnabled The boolean that indicates enabled.
* @param deletedData The boolean that indicates deleting data on disabled.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didSetEnabled:(BOOL)isEnabled andDeleteDataOnDisabled:(BOOL)deletedData;
/**
* A callback that is called when pause has been invoked.
*
* @param channel The channel.
* @param identifyingObject The identifying object used to pause the channel.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didPauseWithIdentifyingObject:(id<NSObject>)identifyingObject;
/**
* A callback that is called when resume has been invoked.
*
* @param channel The channel.
* @param identifyingObject The identifying object used to resume the channel.
*/
- (void)channel:(id<MSACChannelProtocol>)channel didResumeWithIdentifyingObject:(id<NSObject>)identifyingObject;
/**
* Callback method that will determine if a log should be filtered out from the usual processing pipeline. If any delegate returns true, the
* log is filtered.
*
* @param channelUnit The channel unit that is going to send the log.
* @param log The log to be filtered or not.
*
* @return `true` if the log should be filtered out.
*/
- (BOOL)channelUnit:(id<MSACChannelUnitProtocol>)channelUnit shouldFilterLog:(id<MSACLog>)log;
@end
NS_ASSUME_NONNULL_END
@@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>19H1323</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>AppCenter</string>
<key>CFBundleIdentifier</key>
<string>com.microsoft.appcenter</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>AppCenter</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>11C505</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string>19B90</string>
<key>DTSDKName</key>
<string>macosx10.15</string>
<key>DTXcode</key>
<string>1130</string>
<key>DTXcodeBuild</key>
<string>11C505</string>
<key>LSMinimumSystemVersion</key>
<string>10.15</string>
<key>UIDeviceFamily</key>
<array>
<integer>2</integer>
</array>
</dict>
</plist>
@@ -1 +0,0 @@
Versions/Current/AppCenter
@@ -1 +0,0 @@
Versions/Current/Headers
@@ -1 +0,0 @@
Versions/Current/Modules
@@ -1 +0,0 @@
Versions/Current/PrivateHeaders
@@ -1 +0,0 @@
Versions/Current/Resources
@@ -1,44 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACAppCenter.h>)
#import <AppCenter/MSACAbstractLog.h>
#import <AppCenter/MSACAppCenter.h>
#import <AppCenter/MSACAppCenterErrors.h>
#import <AppCenter/MSACChannelGroupProtocol.h>
#import <AppCenter/MSACChannelProtocol.h>
#import <AppCenter/MSACConstants+Flags.h>
#import <AppCenter/MSACConstants.h>
#import <AppCenter/MSACCustomProperties.h>
#import <AppCenter/MSACDevice.h>
#import <AppCenter/MSACEnable.h>
#import <AppCenter/MSACLog.h>
#import <AppCenter/MSACLogWithProperties.h>
#import <AppCenter/MSACLogger.h>
#import <AppCenter/MSACSerializableObject.h>
#import <AppCenter/MSACService.h>
#import <AppCenter/MSACServiceAbstract.h>
#import <AppCenter/MSACWrapperLogger.h>
#import <AppCenter/MSACWrapperSdk.h>
#else
#import "MSACAbstractLog.h"
#import "MSACAppCenter.h"
#import "MSACAppCenterErrors.h"
#import "MSACChannelGroupProtocol.h"
#import "MSACChannelProtocol.h"
#import "MSACConstants+Flags.h"
#import "MSACConstants.h"
#import "MSACCustomProperties.h"
#import "MSACDevice.h"
#import "MSACEnable.h"
#import "MSACLog.h"
#import "MSACLogWithProperties.h"
#import "MSACLogger.h"
#import "MSACSerializableObject.h"
#import "MSACService.h"
#import "MSACServiceAbstract.h"
#import "MSACWrapperLogger.h"
#import "MSACWrapperSdk.h"
#endif
@@ -1,203 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#ifndef MSAC_APP_CENTER
#define MSAC_APP_CENTER
#if __has_include(<AppCenter/MSACConstants.h>)
#import <AppCenter/MSACConstants.h>
#else
#import "MSACConstants.h"
#endif
@class MSACWrapperSdk;
#if !TARGET_OS_TV
@class MSACCustomProperties;
#endif
NS_SWIFT_NAME(AppCenter)
@interface MSACAppCenter : NSObject
/**
* Returns the singleton instance of MSACAppCenter.
*/
+ (instancetype)sharedInstance;
/**
* Configure the SDK with an application secret.
*
* @param appSecret A unique and secret key used to identify the application.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)configureWithAppSecret:(NSString *)appSecret NS_SWIFT_NAME(configure(withAppSecret:));
/**
* Configure the SDK.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)configure;
/**
* Configure the SDK with an application secret and an array of services to start.
*
* @param appSecret A unique and secret key used to identify the application.
* @param services Array of services to start.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)start:(NSString *)appSecret withServices:(NSArray<Class> *)services NS_SWIFT_NAME(start(withAppSecret:services:));
/**
* Start the SDK with an array of services.
*
* @param services Array of services to start.
*
* @discussion This may be called only once per application process lifetime.
*/
+ (void)startWithServices:(NSArray<Class> *)services NS_SWIFT_NAME(start(services:));
/**
* Start a service.
*
* @param service A service to start.
*
* @discussion This may be called only once per service per application process lifetime.
*/
+ (void)startService:(Class)service;
/**
* Configure the SDK with an array of services to start from a library. This will not start the service at application level, it will enable
* the service only for the library.
*
* @param services Array of services to start.
*/
+ (void)startFromLibraryWithServices:(NSArray<Class> *)services NS_SWIFT_NAME(startFromLibrary(services:));
/**
* The flag indicates whether the SDK has already been configured or not.
*/
@property(class, atomic, readonly, getter=isConfigured) BOOL configured;
/**
* The flag indicates whether app is running in App Center Test Cloud.
*/
@property(class, atomic, readonly, getter=isRunningInAppCenterTestCloud) BOOL runningInAppCenterTestCloud;
/**
* The flag indicates whether or not the SDK was enabled as a whole
*
* The state is persisted in the device's storage across application launches.
*/
@property(class, nonatomic, getter=isEnabled, setter=setEnabled:) BOOL enabled NS_SWIFT_NAME(enabled);
/**
* Flag indicating whether SDK can send network requests.
*
* The state is persisted in the device's storage across application launches.
*/
@property(class, nonatomic, getter=isNetworkRequestsAllowed, setter=setNetworkRequestsAllowed:)
BOOL networkRequestsAllowed NS_SWIFT_NAME(networkRequestsAllowed);
/**
* The SDK's log level.
*/
@property(class, nonatomic) MSACLogLevel logLevel;
/**
* Base URL to use for backend communication.
*/
@property(class, nonatomic, strong) NSString *logUrl;
/**
* Set log handler.
*/
@property(class, nonatomic) MSACLogHandler logHandler;
/**
* Set wrapper SDK information to use when building device properties. This is intended in case you are building a SDK that uses the App
* Center SDK under the hood, e.g. our Xamarin SDK or ReactNative SDk.
*/
@property(class, nonatomic, strong) MSACWrapperSdk *wrapperSdk;
#if !TARGET_OS_TV
/**
* Set the custom properties.
*
* @param customProperties Custom properties object.
*/
+ (void)setCustomProperties:(MSACCustomProperties *)customProperties;
#endif
/**
* Check whether the application delegate forwarder is enabled or not.
*
* @discussion The application delegate forwarder forwards messages that target your application delegate methods via swizzling to the SDK.
* It simplifies the SDK integration but may not be suitable to any situations. For
* instance it should be disabled if you or one of your third party SDK is doing message forwarding on the application delegate. Message
* forwarding usually implies the implementation of @see NSObject#forwardingTargetForSelector: or @see NSObject#forwardInvocation: methods.
* To disable the application delegate forwarder just add the `AppCenterAppDelegateForwarderEnabled` tag to your Info .plist file and set it
* to `0`. Then you will have to forward any application delegate needed by the SDK manually.
*/
@property(class, readonly, nonatomic, getter=isAppDelegateForwarderEnabled) BOOL appDelegateForwarderEnabled;
/**
* Unique installation identifier.
*
*/
@property(class, readonly, nonatomic) NSUUID *installId;
/**
* Detect if a debugger is attached to the app process. This is only invoked once on app startup and can not detect
* if the debugger is being attached during runtime!
*
*/
@property(class, readonly, nonatomic, getter=isDebuggerAttached) BOOL debuggerAttached;
/**
* Current version of AppCenter SDK.
*
*/
@property(class, readonly, nonatomic) NSString *sdkVersion;
/**
* Set the maximum size of the internal storage. This method must be called before App Center is started. This method is only intended for
* applications.
*
* @param sizeInBytes Maximum size of the internal storage in bytes. This will be rounded up to the nearest multiple of a SQLite page size
* (default is 4096 bytes). Values below 20,480 bytes (20 KiB) will be ignored.
*
* @param completionHandler Callback that is invoked when the database size has been set. The `BOOL` parameter is `YES` if changing the size
* is successful, and `NO` otherwise. This parameter can be null.
*
* @discussion This only sets the maximum size of the database, but App Center modules might store additional data.
* The value passed to this method is not persisted on disk. The default maximum database size is 10485760 bytes (10 MiB).
*/
+ (void)setMaxStorageSize:(long)sizeInBytes completionHandler:(void (^)(BOOL))completionHandler;
/**
* Set the user identifier.
*
* @discussion Set the user identifier for logs sent for the default target token when the secret passed in @c
* MSACAppCenter:start:withServices: contains "target={targetToken}".
*
* For App Center backend the user identifier maximum length is 256 characters.
*
* AppCenter must be configured or started before this API can be used.
*/
@property(class, nonatomic, strong) NSString *userId;
/**
* Set country code to use when building device properties.
*
* @see https://www.iso.org/obp/ui/#search for more information.
*/
@property(class, nonatomic, strong) NSString *countryCode;
@end
#endif
@@ -1,41 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_APP_CENTER_ERRORS_H
#define MSAC_APP_CENTER_ERRORS_H
#import <Foundation/Foundation.h>
#define MSAC_APP_CENTER_BASE_DOMAIN @"com.Microsoft.AppCenter."
NS_ASSUME_NONNULL_BEGIN
#pragma mark - Domain
static NSString *const kMSACACErrorDomain = MSAC_APP_CENTER_BASE_DOMAIN @"ErrorDomain";
#pragma mark - General
// Error codes.
NS_ENUM(NSInteger){MSACACLogInvalidContainerErrorCode = 1, MSACACCanceledErrorCode = 2, MSACACDisabledErrorCode = 3};
// Error descriptions.
static NSString const *kMSACACLogInvalidContainerErrorDesc = @"Invalid log container.";
static NSString const *kMSACACCanceledErrorDesc = @"The operation was canceled.";
static NSString const *kMSACACDisabledErrorDesc = @"The service is disabled.";
#pragma mark - Connection
// Error codes.
NS_ENUM(NSInteger){MSACACConnectionPausedErrorCode = 100, MSACACConnectionHttpErrorCode = 101};
// Error descriptions.
static NSString const *kMSACACConnectionHttpErrorDesc = @"An HTTP error occured.";
static NSString const *kMSACACConnectionPausedErrorDesc = @"Canceled, connection paused with log deletion.";
// Error user info keys.
static NSString const *kMSACACConnectionHttpCodeErrorKey = @"MSConnectionHttpCode";
NS_ASSUME_NONNULL_END
#endif
@@ -1,87 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CHANNEL_GROUP_PROTOCOL_H
#define MSAC_CHANNEL_GROUP_PROTOCOL_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACChannelProtocol.h>)
#import <AppCenter/MSACChannelProtocol.h>
#else
#import "MSACChannelProtocol.h"
#endif
NS_ASSUME_NONNULL_BEGIN
@class MSACChannelUnitConfiguration;
@protocol MSACIngestionProtocol;
@protocol MSACChannelUnitProtocol;
/**
* `MSACChannelGroupProtocol` represents a kind of channel that contains constituent MSACChannelUnit objects. When an operation from the
* `MSACChannelProtocol` is performed on the group, that operation should be propagated to its constituent MSACChannelUnit objects.
*/
NS_SWIFT_NAME(ChannelGroupProtocol)
@protocol MSACChannelGroupProtocol <MSACChannelProtocol>
/**
* Initialize a channel unit with the given configuration.
*
* @param configuration channel configuration.
*
* @return The added `MSACChannelUnitProtocol`. Use this object to enqueue logs.
*/
- (id<MSACChannelUnitProtocol>)addChannelUnitWithConfiguration:(MSACChannelUnitConfiguration *)configuration
NS_SWIFT_NAME(addChannelUnit(withConfiguration:));
/**
* Initialize a channel unit with the given configuration.
*
* @param configuration channel configuration.
* @param ingestion The alternative ingestion object
*
* @return The added `MSACChannelUnitProtocol`. Use this object to enqueue logs.
*/
- (id<MSACChannelUnitProtocol>)addChannelUnitWithConfiguration:(MSACChannelUnitConfiguration *)configuration
withIngestion:(nullable id<MSACIngestionProtocol>)ingestion
NS_SWIFT_NAME(addChannelUnit(_:ingestion:));
/**
* Change the base URL (schema + authority + port only) used to communicate with the backend.
*/
@property(nonatomic, strong) NSString *_Nullable logUrl;
/**
* Set the app secret.
*/
@property(nonatomic, strong) NSString *_Nullable appSecret;
/**
* Set the maximum size of the internal storage. This method must be called before App Center is started.
*
* @discussion The default maximum database size is 10485760 bytes (10 MiB).
*
* @param sizeInBytes Maximum size of the internal storage in bytes. This will be rounded up to the nearest multiple of a SQLite page size
* (default is 4096 bytes). Values below 24576 bytes (24 KiB) will be ignored.
* @param completionHandler Callback that is invoked when the database size has been set. The `BOOL` parameter is `YES` if changing the size
* is successful, and `NO` otherwise.
*/
- (void)setMaxStorageSize:(long)sizeInBytes
completionHandler:(nullable void (^)(BOOL))completionHandler NS_SWIFT_NAME(setMaxStorageSize(_:completionHandler:));
/**
* Return a channel unit instance for the given groupId.
*
* @param groupId The group ID for a channel unit.
*
* @return A channel unit instance or `nil`.
*/
- (nullable id<MSACChannelUnitProtocol>)channelUnitForGroupId:(NSString *)groupId;
@end
NS_ASSUME_NONNULL_END
#endif
@@ -1,68 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CHANNEL_PROTOCOL_H
#define MSAC_CHANNEL_PROTOCOL_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACEnable.h>)
#import <AppCenter/MSACEnable.h>
#else
#import "MSACEnable.h"
#endif
NS_ASSUME_NONNULL_BEGIN
@protocol MSACChannelDelegate;
/**
* `MSACChannelProtocol` contains the essential operations of a channel. Channels are broadly responsible for enqueuing logs to be sent to
* the backend and/or stored on disk.
*/
NS_SWIFT_NAME(ChannelProtocol)
@protocol MSACChannelProtocol <NSObject, MSACEnable>
/**
* Add delegate.
*
* @param delegate delegate.
*/
- (void)addDelegate:(id<MSACChannelDelegate>)delegate;
/**
* Remove delegate.
*
* @param delegate delegate.
*/
- (void)removeDelegate:(id<MSACChannelDelegate>)delegate;
/**
* Pause operations, logs will be stored but not sent.
*
* @param identifyingObject Object used to identify the pause request.
*
* @discussion A paused channel doesn't forward logs to the ingestion. The identifying object used to pause the channel can be any unique
* object. The same identifying object must be used to call resume. For simplicity if the caller is the one owning the channel then @c self
* can be used as identifying object.
*
* @see resumeWithIdentifyingObject:
*/
- (void)pauseWithIdentifyingObject:(id<NSObject>)identifyingObject;
/**
* Resume operations, logs can be sent again.
*
* @param identifyingObject Object used to passed to the pause method.
*
* @discussion The channel only resume when all the outstanding identifying objects have been resumed.
*
* @see pauseWithIdentifyingObject:
*/
- (void)resumeWithIdentifyingObject:(id<NSObject>)identifyingObject;
@end
NS_ASSUME_NONNULL_END
#endif
@@ -1,18 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CONSTANTS_FLAGS_H
#define MSAC_CONSTANTS_FLAGS_H
#import <Foundation/Foundation.h>
typedef NS_OPTIONS(NSUInteger, MSACFlags) {
MSACFlagsNone = (0 << 0), // => 00000000
MSACFlagsNormal = (1 << 0), // => 00000001
MSACFlagsCritical = (1 << 1), // => 00000010
MSACFlagsPersistenceNormal DEPRECATED_MSG_ATTRIBUTE("please use MSACFlagsNormal") = MSACFlagsNormal,
MSACFlagsPersistenceCritical DEPRECATED_MSG_ATTRIBUTE("please use MSACFlagsCritical") = MSACFlagsCritical,
MSACFlagsDefault = MSACFlagsNormal
} NS_SWIFT_NAME(Flags);
#endif
@@ -1,170 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
/**
* Log Levels
*/
typedef NS_ENUM(NSUInteger, MSACLogLevel) {
/**
* Logging will be very chatty
*/
MSACLogLevelVerbose = 2,
/**
* Debug information will be logged
*/
MSACLogLevelDebug = 3,
/**
* Information will be logged
*/
MSACLogLevelInfo = 4,
/**
* Errors and warnings will be logged
*/
MSACLogLevelWarning = 5,
/**
* Errors will be logged
*/
MSACLogLevelError = 6,
/**
* Only critical errors will be logged
*/
MSACLogLevelAssert = 7,
/**
* Logging is disabled
*/
MSACLogLevelNone = 99
} NS_SWIFT_NAME(LogLevel);
typedef NSString * (^MSACLogMessageProvider)(void)NS_SWIFT_NAME(LogMessageProvider);
typedef void (^MSACLogHandler)(MSACLogMessageProvider messageProvider, MSACLogLevel logLevel, NSString *tag, const char *file,
const char *function, uint line) NS_SWIFT_NAME(LogHandler);
/**
* Channel priorities, check the kMSACPriorityCount if you add a new value.
* The order matters here! Values NEED to range from low priority to high priority.
*/
typedef NS_ENUM(NSInteger, MSACPriority) { MSACPriorityBackground, MSACPriorityDefault, MSACPriorityHigh } NS_SWIFT_NAME(Priority);
static short const kMSACPriorityCount = MSACPriorityHigh + 1;
/**
* The priority by which the modules are initialized.
* MSACPriorityMax is reserved for only 1 module and this needs to be Crashes.
* Crashes needs to be initialized first to catch crashes in our other SDK Modules (which will hopefully never happen) and to avoid losing
* any log at crash time.
*/
typedef NS_ENUM(NSInteger, MSACInitializationPriority) {
MSACInitializationPriorityDefault = 500,
MSACInitializationPriorityHigh = 750,
MSACInitializationPriorityMax = 999
} NS_SWIFT_NAME(InitializationPriority);
/**
* Enum with the different HTTP status codes.
*/
typedef NS_ENUM(NSInteger, MSACHTTPCodesNo) {
// Invalid
MSACHTTPCodesNo0XXInvalidUnknown = 0,
// Informational
MSACHTTPCodesNo1XXInformationalUnknown = 1,
MSACHTTPCodesNo100Continue = 100,
MSACHTTPCodesNo101SwitchingProtocols = 101,
MSACHTTPCodesNo102Processing = 102,
// Success
MSACHTTPCodesNo2XXSuccessUnknown = 2,
MSACHTTPCodesNo200OK = 200,
MSACHTTPCodesNo201Created = 201,
MSACHTTPCodesNo202Accepted = 202,
MSACHTTPCodesNo203NonAuthoritativeInformation = 203,
MSACHTTPCodesNo204NoContent = 204,
MSACHTTPCodesNo205ResetContent = 205,
MSACHTTPCodesNo206PartialContent = 206,
MSACHTTPCodesNo207MultiStatus = 207,
MSACHTTPCodesNo208AlreadyReported = 208,
MSACHTTPCodesNo209IMUsed = 209,
// Redirection
MSACHTTPCodesNo3XXSuccessUnknown = 3,
MSACHTTPCodesNo300MultipleChoices = 300,
MSACHTTPCodesNo301MovedPermanently = 301,
MSACHTTPCodesNo302Found = 302,
MSACHTTPCodesNo303SeeOther = 303,
MSACHTTPCodesNo304NotModified = 304,
MSACHTTPCodesNo305UseProxy = 305,
MSACHTTPCodesNo306SwitchProxy = 306,
MSACHTTPCodesNo307TemporaryRedirect = 307,
MSACHTTPCodesNo308PermanentRedirect = 308,
// Client error
MSACHTTPCodesNo4XXSuccessUnknown = 4,
MSACHTTPCodesNo400BadRequest = 400,
MSACHTTPCodesNo401Unauthorised = 401,
MSACHTTPCodesNo402PaymentRequired = 402,
MSACHTTPCodesNo403Forbidden = 403,
MSACHTTPCodesNo404NotFound = 404,
MSACHTTPCodesNo405MethodNotAllowed = 405,
MSACHTTPCodesNo406NotAcceptable = 406,
MSACHTTPCodesNo407ProxyAuthenticationRequired = 407,
MSACHTTPCodesNo408RequestTimeout = 408,
MSACHTTPCodesNo409Conflict = 409,
MSACHTTPCodesNo410Gone = 410,
MSACHTTPCodesNo411LengthRequired = 411,
MSACHTTPCodesNo412PreconditionFailed = 412,
MSACHTTPCodesNo413RequestEntityTooLarge = 413,
MSACHTTPCodesNo414RequestURITooLong = 414,
MSACHTTPCodesNo415UnsupportedMediaType = 415,
MSACHTTPCodesNo416RequestedRangeNotSatisfiable = 416,
MSACHTTPCodesNo417ExpectationFailed = 417,
MSACHTTPCodesNo418IamATeapot = 418,
MSACHTTPCodesNo419AuthenticationTimeout = 419,
MSACHTTPCodesNo420MethodFailureSpringFramework = 420,
MSACHTTPCodesNo420EnhanceYourCalmTwitter = 4200,
MSACHTTPCodesNo422UnprocessableEntity = 422,
MSACHTTPCodesNo423Locked = 423,
MSACHTTPCodesNo424FailedDependency = 424,
MSACHTTPCodesNo424MethodFailureWebDaw = 4240,
MSACHTTPCodesNo425UnorderedCollection = 425,
MSACHTTPCodesNo426UpgradeRequired = 426,
MSACHTTPCodesNo428PreconditionRequired = 428,
MSACHTTPCodesNo429TooManyRequests = 429,
MSACHTTPCodesNo431RequestHeaderFieldsTooLarge = 431,
MSACHTTPCodesNo444NoResponseNginx = 444,
MSACHTTPCodesNo449RetryWithMicrosoft = 449,
MSACHTTPCodesNo450BlockedByWindowsParentalControls = 450,
MSACHTTPCodesNo451RedirectMicrosoft = 451,
MSACHTTPCodesNo451UnavailableForLegalReasons = 4510,
MSACHTTPCodesNo494RequestHeaderTooLargeNginx = 494,
MSACHTTPCodesNo495CertErrorNginx = 495,
MSACHTTPCodesNo496NoCertNginx = 496,
MSACHTTPCodesNo497HTTPToHTTPSNginx = 497,
MSACHTTPCodesNo499ClientClosedRequestNginx = 499,
// Server error
MSACHTTPCodesNo5XXSuccessUnknown = 5,
MSACHTTPCodesNo500InternalServerError = 500,
MSACHTTPCodesNo501NotImplemented = 501,
MSACHTTPCodesNo502BadGateway = 502,
MSACHTTPCodesNo503ServiceUnavailable = 503,
MSACHTTPCodesNo504GatewayTimeout = 504,
MSACHTTPCodesNo505HTTPVersionNotSupported = 505,
MSACHTTPCodesNo506VariantAlsoNegotiates = 506,
MSACHTTPCodesNo507InsufficientStorage = 507,
MSACHTTPCodesNo508LoopDetected = 508,
MSACHTTPCodesNo509BandwidthLimitExceeded = 509,
MSACHTTPCodesNo510NotExtended = 510,
MSACHTTPCodesNo511NetworkAuthenticationRequired = 511,
MSACHTTPCodesNo522ConnectionTimedOut = 522,
MSACHTTPCodesNo598NetworkReadTimeoutErrorUnknown = 598,
MSACHTTPCodesNo599NetworkConnectTimeoutErrorUnknown = 599
} NS_SWIFT_NAME(HTTPCodesNo);
@@ -1,71 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_CUSTOM_PROPERTIES_H
#define MSAC_CUSTOM_PROPERTIES_H
#import <Foundation/Foundation.h>
/**
* Custom properties builder.
* Collects multiple properties to send in one log.
*/
NS_SWIFT_NAME(CustomProperties)
@interface MSACCustomProperties : NSObject
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setString:(NSString *)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setNumber:(NSNumber *)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setBool:(BOOL)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Set the specified property value with the specified key.
* If the properties previously contained a property for the key, the old value is replaced.
*
* @param key Key with which the specified value is to be set.
* @param value Value to be set with the specified key.
*
* @return This instance.
*/
- (instancetype)setDate:(NSDate *)value forKey:(NSString *)key NS_SWIFT_NAME(set(_:forKey:));
/**
* Clear the property for the specified key.
*
* @param key Key whose mapping is to be cleared.
*
* @return This instance.
*/
- (instancetype)clearPropertyForKey:(NSString *)key NS_SWIFT_NAME(clearProperty(forKey:));
@end
#endif
@@ -1,101 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_DEVICE_H
#define MSAC_DEVICE_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACWrapperSdk.h>)
#import <AppCenter/MSACWrapperSdk.h>
#else
#import "MSACWrapperSdk.h"
#endif
NS_SWIFT_NAME(Device)
@interface MSACDevice : MSACWrapperSdk
/*
* Name of the SDK. Consists of the name of the SDK and the platform, e.g. "appcenter.ios", "appcenter.android"
*/
@property(nonatomic, copy, readonly) NSString *sdkName;
/*
* Version of the SDK in semver format, e.g. "1.2.0" or "0.12.3-alpha.1".
*/
@property(nonatomic, copy, readonly) NSString *sdkVersion;
/*
* Device model (example: iPad2,3).
*/
@property(nonatomic, copy, readonly) NSString *model;
/*
* Device manufacturer (example: HTC).
*/
@property(nonatomic, copy, readonly) NSString *oemName;
/*
* OS name (example: iOS).
*/
@property(nonatomic, copy, readonly) NSString *osName;
/*
* OS version (example: 9.3.0).
*/
@property(nonatomic, copy, readonly) NSString *osVersion;
/*
* OS build code (example: LMY47X). [optional]
*/
@property(nonatomic, copy, readonly) NSString *osBuild;
/*
* API level when applicable like in Android (example: 15). [optional]
*/
@property(nonatomic, copy, readonly) NSNumber *osApiLevel;
/*
* Language code (example: en_US).
*/
@property(nonatomic, copy, readonly) NSString *locale;
/*
* The offset in minutes from UTC for the device time zone, including daylight savings time.
*/
@property(nonatomic, readonly, strong) NSNumber *timeZoneOffset;
/*
* Screen size of the device in pixels (example: 640x480).
*/
@property(nonatomic, copy, readonly) NSString *screenSize;
/*
* Application version name, e.g. 1.1.0
*/
@property(nonatomic, copy, readonly) NSString *appVersion;
/*
* Carrier name (for mobile devices). [optional]
*/
@property(nonatomic, copy, readonly) NSString *carrierName;
/*
* Carrier country code (for mobile devices). [optional]
*/
@property(nonatomic, copy, readonly) NSString *carrierCountry;
/*
* The app's build number, e.g. 42.
*/
@property(nonatomic, copy, readonly) NSString *appBuild;
/*
* The bundle identifier, package identifier, or namespace, depending on what the individual plattforms use, .e.g com.microsoft.example.
* [optional]
*/
@property(nonatomic, copy, readonly) NSString *appNamespace;
@end
#endif
@@ -1,27 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_ENABLE_H
#define MSAC_ENABLE_H
#import <Foundation/Foundation.h>
/**
* Protocol to define an instance that can be enabled/disabled.
*/
NS_SWIFT_NAME(Enable)
@protocol MSACEnable <NSObject>
@required
/**
* Enable/disable this instance and delete data on disabled state.
*
* @param isEnabled A boolean value set to YES to enable the instance or NO to disable it.
* @param deleteData A boolean value set to YES to delete data or NO to keep it.
*/
- (void)setEnabled:(BOOL)isEnabled andDeleteDataOnDisabled:(BOOL)deleteData NS_SWIFT_NAME(setEnabled(_:deleteDataOnDisabled:));
@end
#endif
@@ -1,74 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_LOG_H
#define MSAC_LOG_H
#import <Foundation/Foundation.h>
@class MSACDevice;
NS_SWIFT_NAME(Log)
@protocol MSACLog <NSObject>
/**
* Log type.
*/
@property(nonatomic, copy) NSString *type;
/**
* Log timestamp.
*/
@property(nonatomic, strong) NSDate *timestamp;
/**
* A session identifier is used to correlate logs together. A session is an abstract concept in the API and is not necessarily an analytics
* session, it can be used to only track crashes.
*/
@property(nonatomic, copy) NSString *sid;
/**
* Optional distribution group ID value.
*/
@property(nonatomic, copy) NSString *distributionGroupId;
/**
* Optional user identifier.
*/
@property(nonatomic, copy) NSString *userId;
/**
* Device properties associated to this log.
*/
@property(nonatomic, strong) MSACDevice *device;
/**
* Transient object tag. For example, a log can be tagged with a transmission target. We do this currently to prevent properties being
* applied retroactively to previous logs by comparing their tags.
*/
@property(nonatomic, strong) NSObject *tag;
/**
* Checks if the object's values are valid.
*
* @return YES, if the object is valid.
*/
- (BOOL)isValid;
/**
* Adds a transmission target token that this log should be sent to.
*
* @param token The transmission target token.
*/
- (void)addTransmissionTargetToken:(NSString *)token;
/**
* Gets all transmission target tokens that this log should be sent to.
*
* @returns Collection of transmission target tokens that this log should be sent to.
*/
- (NSSet *)transmissionTargetTokens;
@end
#endif
@@ -1,25 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_LOG_WITH_PROPERTIES_H
#define MSAC_LOG_WITH_PROPERTIES_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACAbstractLog.h>)
#import <AppCenter/MSACAbstractLog.h>
#else
#import "MSACAbstractLog.h"
#endif
NS_SWIFT_NAME(LogWithProperties)
@interface MSACLogWithProperties : MSACAbstractLog
/**
* Additional key/value pair parameters. [optional]
*/
@property(nonatomic, strong) NSDictionary<NSString *, NSString *> *properties;
@end
#endif
@@ -1,54 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#ifndef MSAC_LOGGER
#define MSAC_LOGGER
#if __has_include(<AppCenter/MSACConstants.h>)
#import <AppCenter/MSACConstants.h>
#else
#import "MSACConstants.h"
#endif
#define MSACLog(_level, _tag, _message) \
[MSACLogger logMessage:_message level:_level tag:_tag file:__FILE__ function:__PRETTY_FUNCTION__ line:__LINE__]
#define MSACLogAssert(tag, format, ...) \
MSACLog(MSACLogLevelAssert, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogError(tag, format, ...) \
MSACLog(MSACLogLevelError, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogWarning(tag, format, ...) \
MSACLog(MSACLogLevelWarning, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogInfo(tag, format, ...) \
MSACLog(MSACLogLevelInfo, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogDebug(tag, format, ...) \
MSACLog(MSACLogLevelDebug, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
#define MSACLogVerbose(tag, format, ...) \
MSACLog(MSACLogLevelVerbose, tag, (^{ \
return [NSString stringWithFormat:(format), ##__VA_ARGS__]; \
}))
NS_SWIFT_NAME(Logger)
@interface MSACLogger : NSObject
+ (void)logMessage:(MSACLogMessageProvider)messageProvider
level:(MSACLogLevel)loglevel
tag:(NSString *)tag
file:(const char *)file
function:(const char *)function
line:(uint)line;
@end
#endif
@@ -1,19 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#ifndef SERIALIZABLE_OBJECT_H
#define SERIALIZABLE_OBJECT_H
@protocol MSACSerializableObject <NSCoding>
/**
* Serialize this object to a dictionary.
*
* @return A dictionary representing this object.
*/
- (NSMutableDictionary *)serializeToDictionary;
@end
#endif
@@ -1,23 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_SERVICE_H
#define MSAC_SERVICE_H
#import <Foundation/Foundation.h>
/**
* Protocol declaring service logic.
*/
NS_SWIFT_NAME(Service)
@protocol MSACService <NSObject>
/**
* Indicates whether this service is enabled.
* The state is persisted in the device's storage across application launches.
*/
@property(class, nonatomic, getter=isEnabled, setter=setEnabled:) BOOL enabled NS_SWIFT_NAME(enabled);
@end
#endif
@@ -1,58 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_SERVICE_ABSTRACT_H
#define MSAC_SERVICE_ABSTRACT_H
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACService.h>)
#import <AppCenter/MSACService.h>
#else
#import "MSACService.h"
#endif
@protocol MSACChannelGroupProtocol;
/**
* Abstraction of services common logic.
* This class is intended to be subclassed only not instantiated directly.
*/
NS_SWIFT_NAME(ServiceAbstract)
@interface MSACServiceAbstract : NSObject <MSACService>
/**
* The flag indicates whether the service is started from application or not.
*/
@property(nonatomic, assign) BOOL startedFromApplication;
/**
* Start this service with a channel group. Also sets the flag that indicates that a service has been started.
*
* @param channelGroup channel group used to persist and send logs.
* @param appSecret app secret for the SDK.
* @param token default transmission target token for this service.
* @param fromApplication indicates whether the service started from an application or not.
*/
- (void)startWithChannelGroup:(id<MSACChannelGroupProtocol>)channelGroup
appSecret:(NSString *)appSecret
transmissionTargetToken:(NSString *)token
fromApplication:(BOOL)fromApplication;
/**
* Update configuration when the service requires to start again. This method should only be called if the service is started from libraries
* and then is being started from an application.
*
* @param appSecret app secret for the SDK.
* @param token default transmission target token for this service.
*/
- (void)updateConfigurationWithAppSecret:(NSString *)appSecret transmissionTargetToken:(NSString *)token;
/**
* The flag indicate whether the service needs the application secret or not.
*/
@property(atomic, readonly) BOOL isAppSecretRequired;
@end
#endif
@@ -1,21 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#if __has_include(<AppCenter/MSACConstants.h>)
#import <AppCenter/MSACConstants.h>
#else
#import "MSACConstants.h"
#endif
/**
* This is a utility for producing App Center style log messages. It is only intended for use by App Center services and wrapper SDKs of App
* Center.
*/
NS_SWIFT_NAME(WrapperLogger)
@interface MSACWrapperLogger : NSObject
+ (void)MSACWrapperLog:(MSACLogMessageProvider)message tag:(NSString *)tag level:(MSACLogLevel)level;
@end
@@ -1,60 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef MSAC_WRAPPER_SDK_H
#define MSAC_WRAPPER_SDK_H
#import <Foundation/Foundation.h>
NS_SWIFT_NAME(WrapperSdk)
@interface MSACWrapperSdk : NSObject
/*
* Version of the wrapper SDK. When the SDK is embedding another base SDK (for example Xamarin.Android wraps Android), the Xamarin specific
* version is populated into this field while sdkVersion refers to the original Android SDK. [optional]
*/
@property(nonatomic, copy, readonly) NSString *wrapperSdkVersion;
/*
* Name of the wrapper SDK (examples: Xamarin, Cordova). [optional]
*/
@property(nonatomic, copy, readonly) NSString *wrapperSdkName;
/*
* Version of the wrapper technology framework (Xamarin runtime version or ReactNative or Cordova etc...). [optional]
*/
@property(nonatomic, copy, readonly) NSString *wrapperRuntimeVersion;
/*
* Label that is used to identify application code 'version' released via Live Update beacon running on device.
*/
@property(nonatomic, copy, readonly) NSString *liveUpdateReleaseLabel;
/*
* Identifier of environment that current application release belongs to, deployment key then maps to environment like Production, Staging.
*/
@property(nonatomic, copy, readonly) NSString *liveUpdateDeploymentKey;
/*
* Hash of all files (ReactNative or Cordova) deployed to device via LiveUpdate beacon. Helps identify the Release version on device or need
* to download updates in future
*/
@property(nonatomic, copy, readonly) NSString *liveUpdatePackageHash;
- (instancetype)initWithWrapperSdkVersion:(NSString *)wrapperSdkVersion
wrapperSdkName:(NSString *)wrapperSdkName
wrapperRuntimeVersion:(NSString *)wrapperRuntimeVersion
liveUpdateReleaseLabel:(NSString *)liveUpdateReleaseLabel
liveUpdateDeploymentKey:(NSString *)liveUpdateDeploymentKey
liveUpdatePackageHash:(NSString *)liveUpdatePackageHash;
/**
* Checks if the object's values are valid.
*
* @return YES, if the object is valid.
*/
- (BOOL)isValid;
@end
#endif
Loaded 100 of 1981 files, more files were not shown because too many files have changed in this diff. Show more