@mcamdali/sdkbump 0.0.0-stage → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.de.md +251 -0
  3. package/README.es.md +252 -0
  4. package/README.fr.md +252 -0
  5. package/README.ja.md +250 -0
  6. package/README.ko.md +250 -0
  7. package/README.md +322 -2
  8. package/README.pt-BR.md +252 -0
  9. package/README.ru.md +252 -0
  10. package/README.tr.md +338 -0
  11. package/README.zh-CN.md +250 -0
  12. package/dist/cli/main.d.ts +2 -0
  13. package/dist/cli/main.js +11 -0
  14. package/dist/cli/run.d.ts +29 -0
  15. package/dist/cli/run.js +111 -0
  16. package/dist/collect/app.d.ts +48 -0
  17. package/dist/collect/app.js +117 -0
  18. package/dist/collect/blank.d.ts +6 -0
  19. package/dist/collect/blank.js +75 -0
  20. package/dist/collect/pbxproj.d.ts +45 -0
  21. package/dist/collect/pbxproj.js +260 -0
  22. package/dist/collect/plist-binary.d.ts +2 -0
  23. package/dist/collect/plist-binary.js +123 -0
  24. package/dist/collect/plist-value.d.ts +15 -0
  25. package/dist/collect/plist-value.js +14 -0
  26. package/dist/collect/plist-xml.d.ts +2 -0
  27. package/dist/collect/plist-xml.js +195 -0
  28. package/dist/collect/plist.d.ts +6 -0
  29. package/dist/collect/plist.js +19 -0
  30. package/dist/collect/regions.d.ts +9 -0
  31. package/dist/collect/regions.js +108 -0
  32. package/dist/collect/sources.d.ts +45 -0
  33. package/dist/collect/sources.js +99 -0
  34. package/dist/core/files.d.ts +22 -0
  35. package/dist/core/files.js +47 -0
  36. package/dist/core/lines.d.ts +2 -0
  37. package/dist/core/lines.js +21 -0
  38. package/dist/core/versions.d.ts +18 -0
  39. package/dist/core/versions.js +63 -0
  40. package/dist/detect/project.d.ts +46 -0
  41. package/dist/detect/project.js +220 -0
  42. package/dist/index.d.ts +26 -0
  43. package/dist/index.js +27 -0
  44. package/dist/model.d.ts +93 -0
  45. package/dist/model.js +2 -0
  46. package/dist/report/index.d.ts +12 -0
  47. package/dist/report/index.js +22 -0
  48. package/dist/report/markdown.d.ts +2 -0
  49. package/dist/report/markdown.js +113 -0
  50. package/dist/report/text.d.ts +27 -0
  51. package/dist/report/text.js +63 -0
  52. package/dist/report/tty.d.ts +7 -0
  53. package/dist/report/tty.js +112 -0
  54. package/dist/rules/check.d.ts +11 -0
  55. package/dist/rules/check.js +253 -0
  56. package/dist/rules/data.d.ts +217 -0
  57. package/dist/rules/data.js +141 -0
  58. package/dist/rules/fixes.d.ts +28 -0
  59. package/dist/rules/fixes.js +161 -0
  60. package/dist/rules/patterns.d.ts +29 -0
  61. package/dist/rules/patterns.js +109 -0
  62. package/dist/rules/query.d.ts +16 -0
  63. package/dist/rules/query.js +50 -0
  64. package/dist/scan.d.ts +10 -0
  65. package/dist/scan.js +115 -0
  66. package/dist/version.d.ts +2 -0
  67. package/dist/version.js +7 -0
  68. package/package.json +69 -4
  69. package/rules/ios27.json +613 -0
  70. package/rules/schema.json +449 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Muhittin Camdali
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.de.md ADDED
@@ -0,0 +1,251 @@
1
+ <!-- i18n-source: README.md@49073c524eb2b7aad433b6794961ec40869c1170 status=reviewed -->
2
+ <!-- brand:start -->
3
+
4
+ <p align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-light.svg" alt="sdkbump: Checks native iOS, Flutter and React Native apps for the iOS 27 SDK changes and names the fix for each."></picture></p>
5
+
6
+ <!-- lang-selector:start -->
7
+ <p align="center"><a href="README.md">English</a> · <a href="README.tr.md">Türkçe</a> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ja.md">日本語</a> · <a href="README.ko.md">한국어</a> · <a href="README.es.md">Español</a> · <a href="README.de.md">Deutsch</a> · <a href="README.fr.md">Français</a> · <a href="README.pt-BR.md">Português (Brasil)</a> · <a href="README.ru.md">Русский</a></p>
8
+ <!-- lang-selector:end -->
9
+
10
+ <p align="center">
11
+ <a href="https://github.com/muhittincamdali/sdkbump/actions/workflows/ci.yml"><img src="https://github.com/muhittincamdali/sdkbump/actions/workflows/ci.yml/badge.svg" alt="CI-Status"></a>
12
+ <a href="https://github.com/muhittincamdali/sdkbump/releases"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-light.svg" alt="Aktuelle Version: v0.1.2"></picture></a>
13
+ <a href="https://github.com/muhittincamdali/sdkbump/blob/main/package.json"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-light.svg" alt="Sprachversion: Node.js 22.12+"></picture></a>
14
+ <a href="https://github.com/muhittincamdali/sdkbump/blob/main/LICENSE"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-light.svg" alt="Lizenz: MIT"></picture></a>
15
+ </p>
16
+
17
+ <p align="center">
18
+ <a href="#schnellstart"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-de-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-de-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-de-light.svg" alt="Loslegen"></picture></a>
19
+ <a href="https://muhittincamdali.github.io/sdkbump/"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-de-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-de-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-de-light.svg" alt="Dokumentation"></picture></a>
20
+ <a href="https://github.com/muhittincamdali/sdkbump/tree/main/docs/guides"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-de-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-de-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-de-light.svg" alt="Anleitungen"></picture></a>
21
+ <a href="https://github.com/muhittincamdali/sdkbump/tree/main/examples"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-de-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-de-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-de-light.svg" alt="Beispiele"></picture></a>
22
+ </p>
23
+
24
+ > Dies ist eine Übersetzung der englischen README. Bei Abweichungen gilt die englische Fassung.
25
+
26
+ <!-- brand:end -->
27
+
28
+ Bevor du einen mit Xcode 27 gebauten Release auslieferst: sdkbump prüft ein natives iOS-, Flutter- oder React-Native/Expo-Projekt auf das, was das iOS-27-SDK ändert, allen voran den UIScene-Lebenszyklus, und sagt dir, welche Lösung zu welchem Fund passt. Es liest die Dateien deines Projekts; es baut, startet oder ändert nichts.
29
+
30
+ <picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-rn-087-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-rn-087-light.svg"><img src="docs/media/demo-rn-087-light.svg" alt="sdkbump auf einer React-Native-0.87-App: startet nicht, wenn sie mit dem iOS-27-SDK gebaut wird; SCN001 keine Scene-Konfiguration und SCN002 Fenster im App Delegate erzeugt, mit drei Möglichkeiten zur Behebung"></picture>
31
+
32
+ <sub>Mit der echten CLI aufgezeichnet, auf dem <a href="fixtures/rn-087">rn-087-Fixture</a>, einer React-Native-0.87.1-App aus <code>@react-native-community/cli init</code> (<code>npm run demo</code>).</sub>
33
+
34
+ ## Highlights
35
+
36
+ - **Beantwortet „Startet die App?“** Eine App, die keine Scene deklariert, lässt sich mit Xcode 27 bauen und bleibt dann beim Start stehen. sdkbump sagt dir das, bevor du es auf einem Testgerät merkst, und nennt die Dateien, die du ändern musst.
37
+ - **Nativ, Flutter, React Native und Expo** in einem Bericht mit denselben Regel-IDs, als Text, Markdown oder JSON und mit einem Exit-Code für CI.
38
+ - **Die Lösung, die zu deinem Projekt passt**: React Native 0.88 oder ein selbst geschriebener Scene Delegate, das Opt-in von Expo SDK 57 oder SDK 58, die automatische Migration von Flutter oder die manuellen Schritte (sdkbump prüft dieselben Bedingungen wie der Migrator von Flutter) oder die SwiftUI-API für eine SwiftUI-App.
39
+ - **Auch stille Fehler**: App-Delegate-Methoden und Startoptionen, die UIKit nicht mehr verwendet, sobald die App eine Scene hat (Links, Handoff, Quick Actions, Wechsel in den Vorder- und Hintergrund), und Fenstersuchen, die das richtige Fenster nicht mehr finden.
40
+ - **Jede Aussage hat eine Quelle.** Die Regeln sind Daten ([rules/ios27.json](rules/ios27.json)) und jede verweist auf die Seiten von Apple, Flutter, React Native oder Expo; die Tests schlagen fehl, wenn eine Regel das nicht tut.
41
+ - **Im iOS-27-Simulator geprüft**: Der Startfehler und der schwarze Bildschirm hinter SCN001 und SCN002 wurden mit Xcode 27.0 nachgestellt; die Aufnahmen liegen im Repository.
42
+
43
+ ## Schnellstart
44
+
45
+ Du brauchst [Node.js](https://nodejs.org/) 22.12 oder neuer (`node --version` zeigt die Version an; auf einem Mac installiert `brew install node` es). Mehr nicht.
46
+
47
+ **1. Öffne ein Terminal im Ordner deiner App**, also dem mit der `.xcodeproj`, der `pubspec.yaml` oder der `package.json`:
48
+
49
+ ```sh
50
+ cd path/to/YourApp
51
+ ```
52
+
53
+ **2. Starte sdkbump:**
54
+
55
+ ```sh
56
+ npx @mcamdali/sdkbump
57
+ ```
58
+
59
+ Das npm-Paket heißt `@mcamdali/sdkbump`; der Befehl, den es installiert, heißt `sdkbump`. Ein `npx sdkbump` ohne Scope führt es nicht aus.
60
+
61
+ **3. Lies die erste Zeile unter dem Namen deines Projekts.** „Fails to launch when built with the iOS 27 SDK“ (startet nicht, wenn mit dem iOS-27-SDK gebaut) bedeutet, dass die App beim Start stehen bleibt, bis du die **ERROR**-Funde behoben hast; jeder Fund nennt, welche Lösung aus der Liste „How to fix“ zutrifft. **WARNING**-Funde verhindern den Start nicht, funktionieren aber nicht mehr, sobald die App eine Scene hat. „Launch not determined“ (Start nicht bestimmbar) bedeutet, dass sdkbump eine Info.plist nicht lesen konnte; die Hinweise am Ende des Berichts sagen, welche und warum (siehe Grenzen weiter unten).
62
+
63
+ ## Was sich ändert, wenn du mit dem iOS-27-SDK baust
64
+
65
+ Aus Apples
66
+ [Transitioning to the UIKit scene-based life cycle](https://developer.apple.com/documentation/uikit/transitioning-to-the-uikit-scene-based-life-cycle) (Übersetzung):
67
+
68
+ > Ab iOS 27, iPadOS 27, Mac Catalyst 27, tvOS 27 und visionOS 27 müssen Apps, die mit dem neuesten SDK gebaut werden, den Scene-basierten Lebenszyklus übernehmen, sonst starten sie nicht.
69
+
70
+ 1. **Die App bleibt beim Start stehen, wenn sie keine Scene deklariert.** Es gibt kein `UIApplicationSceneManifest` mit einer Konfiguration in der Info.plist und kein `application(_:configurationForConnecting:options:)`: UIKit beendet den Prozess mit der Meldung „UIScene life cycle is required for apps built with this SDK“. Der Compiler warnt nicht, weil die Prüfung beim Start der App läuft. React Native 0.87 und früher, Expo SDK 57 ohne Opt-in und Expo SDK 56 und früher erzeugen solche Apps; ebenso Flutter-Apps, die das Flutter-Tool nicht migrieren kann.
71
+ 2. **Mit einer Scene empfängt der App Delegate keine UI-Ereignisse mehr.** Links, User Activities, Quick Actions und die Wechsel zwischen aktiv und Hintergrund gehen an den Scene Delegate, und ein Fenster, das der App Delegate erzeugt, wird nie angezeigt.
72
+
73
+ [Warum es kompiliert und trotzdem abstürzt](docs/guides/why-it-crashes.md) zeigt die [Start-Matrix](examples/launch-matrix/README.md), die wir im iOS-27.0-Simulator ausgeführt haben.
74
+
75
+ ## Was sdkbump prüft
76
+
77
+ | Regel | Schweregrad | Fund | Im iOS-27.0-Simulator beobachtet |
78
+ | ------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
79
+ | SCN001 | error | Keine Scene-Konfiguration: kein konfiguriertes `UIApplicationSceneManifest`, kein `configurationForConnecting`, keine SwiftUI-`App`; bei Expo ohne `ios/` die SDK-Version und `enableSceneSupport` | bleibt beim Start stehen |
80
+ | SCN002 | error | Der App Delegate erzeugt das Fenster mit `UIWindow(frame:)` | schwarzer Bildschirm, sobald die App eine Scene hat |
81
+ | SCN003 | warning | App-Delegate-Methoden und Startoptions-Schlüssel, die UIKit mit Scenes nicht mehr verwendet (13 davon), es sei denn, der Scene Delegate behandelt sie bereits | `applicationDidEnterBackground(_:)` wird in einer SwiftUI-App nicht aufgerufen |
82
+ | SCN004 | warning | Fenstersuchen über `UIApplication.shared.keyWindow`, `.windows` oder das `window` des App Delegate | nur Deprecation-Warnungen des Compilers |
83
+
84
+ Regeldaten `ios27@2026.10.15`, geprüft gegen Xcode 27.0 (27A266a). Wenn in React Native oder Expo `react-native-uiscene-bridge` oder `react-native-xcode27` installiert ist, werden die Funde, die es zur Laufzeit behandelt, als behandelt angezeigt, mit den Einschränkungen aus dessen README, und lassen den Lauf nicht fehlschlagen.
85
+
86
+ ## Installation
87
+
88
+ Installiere den Befehl `sdkbump` von npm (Paket `@mcamdali/sdkbump`):
89
+
90
+ ```sh
91
+ npm i -g @mcamdali/sdkbump
92
+ sdkbump
93
+ ```
94
+
95
+ In einem Projekt pinnt `npm install --save-dev @mcamdali/sdkbump` eine Version, und `npx sdkbump` führt dann diese Kopie aus. Jedes [GitHub-Release](https://github.com/muhittincamdali/sdkbump/releases) enthält dasselbe Paket auch als `sdkbump-<version>.tgz` mit einer Datei `SHA256SUMS`; `npx` führt es ohne npm über seine URL aus. Eine Homebrew-Formula für `muhittincamdali/tap` bereitet der Release-Workflow vor (geplant mit dem ersten Release des Taps).
96
+
97
+ ## Verwendung
98
+
99
+ ```text
100
+ sdkbump [path] [options]
101
+ ```
102
+
103
+ | Option | Was sie tut |
104
+ | ----------------------- | --------------------------------------------------------------------------- |
105
+ | `path` | Projektordner oder `.xcodeproj`; Standard ist der aktuelle Ordner |
106
+ | `-f, --format <format>` | `tty` (Standard), `markdown` oder `json` |
107
+ | `-o, --output <file>` | Schreibt den Bericht in eine Datei statt ins Terminal |
108
+ | `--fail-on <severity>` | `error` (Standard), `warning`, `info` oder `none`: wann der Exit-Code 1 ist |
109
+ | `--no-color` | Reiner Text auch im Terminal (`NO_COLOR` und `FORCE_COLOR` werden beachtet) |
110
+
111
+ Exit-Codes: `0` kein unbehandelter Fund auf der Stufe von `--fail-on` oder darüber, `1` Funde auf dieser Stufe oder darüber, `2` ungültige Argumente, kein iOS-Projekt gefunden oder ein unerwarteter Fehler.
112
+
113
+ sdkbump findet die iOS-App selbst: eine `.xcodeproj` im Stammordner oder einen Ordner darunter bei nativen Apps, `ios/` bei Flutter-, React-Native- und Expo-Apps (`example/ios/` bei einem Flutter-Plugin). Es liest jedes iOS-App-Target in der Projektdatei, die Info.plist, die jedes davon nennt (XML oder binär), und die Swift- und Objective-C-Dateien der App; Pods, `node_modules`, Build-Ausgaben und Tests lässt es aus. Expo-Apps ohne `ios/` werden anhand von package.json und app.json geprüft.
114
+
115
+ ### Einen Markdown-Bericht beim Code aufbewahren
116
+
117
+ ```sh
118
+ npx @mcamdali/sdkbump --format markdown --output sdkbump.md
119
+ ```
120
+
121
+ ### Den JSON-Bericht in Skripten verwenden
122
+
123
+ ```sh
124
+ npx @mcamdali/sdkbump --format json > sdkbump.json
125
+ ```
126
+
127
+ Jeder Fund hat `rule`, `severity`, `file`, `line`, `message`, den `fix` mit seinen Schritten und seiner Anleitung, `alternatives`, `mitigation` (gesetzt, wenn ein Workaround-Paket den Fund behandelt) und `sources`. Das Layout ist `schemaVersion` 0 und kann sich vor 1.0 ändern. [examples/shell/launch-blockers.sh](examples/shell/launch-blockers.sh) filtert ihn mit `jq`.
128
+
129
+ ### In CI ausführen
130
+
131
+ [examples/github-actions/sdkbump.yml](examples/github-actions/sdkbump.yml) fügt den Bericht der Job-Zusammenfassung jedes Pull Requests hinzu, der die iOS-App berührt, und lässt den Job bei Fehlern fehlschlagen.
132
+
133
+ ### Aus JavaScript
134
+
135
+ ```js
136
+ import { render, scan } from 'sdkbump';
137
+
138
+ const report = await scan('path/to/app');
139
+ console.log(report.verdict.text);
140
+ console.log(render(report, 'markdown'));
141
+ ```
142
+
143
+ Eine lauffähige Version ist [examples/api/verdicts.mjs](examples/api/verdicts.mjs).
144
+
145
+ ## Demo
146
+
147
+ Die Terminal-Aufnahmen stammen von der CLI auf den [Fixtures](fixtures/README.md), echten Projekten, die mit der jeweiligen Toolchain erstellt wurden:
148
+
149
+ | Projekt | Aufnahme |
150
+ | ------------------------------------------------------ | -------------------------------------------------------------------------------------- |
151
+ | React-Native-0.87.1-App | oben auf dieser Seite |
152
+ | Flutter-App mit angepasstem AppDelegate (Flutter 3.24) | [hell](docs/media/demo-flutter-light.svg) · [dunkel](docs/media/demo-flutter-dark.svg) |
153
+ | SwiftUI-App mit einem Adaptor-App-Delegate | [hell](docs/media/demo-swiftui-light.svg) · [dunkel](docs/media/demo-swiftui-dark.svg) |
154
+
155
+ Im iOS-27.0-Simulator (iPhone 17, mit Xcode 27.0 gebaut) bleibt das native UIKit-Fixture beim Start stehen, und dieselbe App, auf einen Scene Delegate umgestellt, startet:
156
+
157
+ <picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-simulator-native-uikit-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-simulator-native-uikit-light.svg"><img src="docs/media/demo-simulator-native-uikit-light.svg" alt="scripts/simulator-check.sh native-uikit im iOS-27.0-Simulator: 4 Sekunden nach dem Start läuft die App nicht, mit der Zeile von UIKit: Application failed to launch: UIScene life cycle is required for apps built with this SDK"></picture>
158
+
159
+ <p align="center"><img src="docs/media/simulator/launched.png" width="480" alt="Die Fixtures native-uikit-scenes und native-swiftui laufen in einem iPhone-17-Simulator mit iOS 27.0, gebaut mit Xcode 27.0"></p>
160
+
161
+ Gemessen am 15. Oktober 2026 auf einem Mac (Apple Silicon, M5 Max) mit Node.js 26.11, während andere Jobs darauf liefen: drei Serien mit je 100 Läufen von `node dist/cli/main.js` auf den zehn Fixtures, Node.js-Start eingerechnet. Die Mediane der drei Serien lagen bei 0,11, 0,12 und 0,19 Sekunden; der langsamste Lauf dauerte 0,33 Sekunden. Auf einem stärker ausgelasteten Rechner dauert es länger.
162
+
163
+ ## Status
164
+
165
+ | Funktion | Status |
166
+ | ----------------------------------------------------------------------------------------------------- | ------------- |
167
+ | Erkennung von nativen, Flutter- (App und Plugin-Beispiel), React-Native- und Expo-Projekten | funktioniert |
168
+ | SCN001 bis SCN004 auf der Info.plist und den Swift-/Objective-C-Quellen der App selbst | funktioniert |
169
+ | Auswahl der Lösung nach Ökosystem und Version; Prüfung der Flutter-Automigration; Workaround-Pakete | funktioniert |
170
+ | Berichte für Terminal, Markdown und JSON; Exit-Codes von `--fail-on` | funktioniert |
171
+ | Abhängigkeiten: Pods, `node_modules` und Flutter-Plugin-Quellen, mit Nennung des Pakets | geplant (0.2) |
172
+ | SCN005-Workaround-Hinweis als eigene Regel; DPT001 für Deployment Targets unter 15.0 | geplant (0.2) |
173
+ | `--verify`: Bauen und Starten im iOS-27-Simulator über die CLI | geplant (0.3) |
174
+ | Swift-/Objective-C-Syntaxbäume statt Mustern; Prüfungen gebauter `.app`-Dateien; SiriKit-Deprecations | geplant (0.5) |
175
+ | `fix --dry-run` für native Apps, SARIF-Ausgabe, GitHub Action | geplant (0.8) |
176
+ | Stabiles Regelschema und JSON-Layout | geplant (1.0) |
177
+
178
+ ## Grenzen
179
+
180
+ - **Muster, kein Compiler.** Die Regeln sind reguläre Ausdrücke über Swift- und Objective-C-Text, in dem Kommentare und Strings ausgeblendet sind. Generierter Code, Code hinter Makros oder ungewöhnlich geschriebener Code kann übersehen oder fälschlich erkannt werden. Syntaxbäume sind geplant (0.5).
181
+ - **Nur die eigenen Quellen der App.** Pods, `node_modules`, Flutter-Plugins und andere Abhängigkeiten werden nicht gelesen; ein Plugin, das sich auf App-Delegate-Methoden verlässt, die UIKit nicht mehr aufruft, wird also nicht gemeldet. Prüfungen der Abhängigkeiten sind geplant (0.2).
182
+ - **Build-Einstellungen nur aus project.pbxproj.** sdkbump liest `INFOPLIST_FILE` und `GENERATE_INFOPLIST_FILE` aus der Projektdatei und setzt `$(SRCROOT)`, `$(PROJECT_DIR)`, `$(TARGET_NAME)` und `$(PRODUCT_NAME)` ein. Es liest keine `.xcconfig`-Dateien, setzt keine anderen Build-Einstellungen ein und liest keine Info.plist außerhalb des Projektordners. Kann es die Info.plist eines Targets nicht lesen, ist SCN001 ein Info-Fund und das Ergebnis lautet „Launch not determined“, statt zu raten.
183
+ - **Keine Datei zum Unterdrücken.** Ein Fund lässt sich nicht als geprüft markieren; `--fail-on` legt fest, welche Schweregrade den Lauf fehlschlagen lassen.
184
+ - **Nur Dateien.** sdkbump baut und startet die App nicht; `--verify` ist geplant (0.3).
185
+
186
+ ## Dokumentation
187
+
188
+ API-Referenz und Anleitungen: [muhittincamdali.github.io/sdkbump](https://muhittincamdali.github.io/sdkbump/).
189
+
190
+ ## Anleitungen
191
+
192
+ - [Warum es kompiliert und trotzdem abstürzt](docs/guides/why-it-crashes.md)
193
+ - [Native UIKit- und SwiftUI-Apps](docs/guides/native-ios.md)
194
+ - [Flutter: ein angepasster AppDelegate und Plugins](docs/guides/flutter.md)
195
+ - [React Native vor 0.88 und Expo vor SDK 58](docs/guides/react-native-expo.md)
196
+ - [Autoren nativer Module: Links und Benachrichtigungen beim Kaltstart](docs/guides/native-module-authors.md)
197
+
198
+ ## Verwandte Tools
199
+
200
+ Andere Projekte arbeiten an derselben Änderung; welches passt, hängt davon ab, was du brauchst:
201
+
202
+ - [react-native-uiscene-bridge](https://github.com/Atomics-hub/react-native-uiscene-bridge) und [react-native-xcode27](https://github.com/Atomics-hub/react-native-xcode27) lassen eine React-Native- oder Expo-App zur Laufzeit ohne Codeänderungen starten. Sie passen, wenn du noch nicht aktualisieren kannst; sdkbump erkennt sie.
203
+ - [auditor-uiscene](https://github.com/Anzell/auditor-uiscene) prüft Flutter-Apps und ihre Plugins mit einem Shell-Skript.
204
+ - Der Migrator von Flutter selbst (`flutter build ios` ab 3.41) migriert eine unveränderte Flutter-App.
205
+ - [flutter_spm_doctor](https://pub.dev/packages/flutter_spm_doctor) prüft Flutter-Plugins.
206
+
207
+ ## Voraussetzungen
208
+
209
+ | Toolchain | Mindestversion |
210
+ | --------- | -------------- |
211
+ | Node.js | 22.12 |
212
+
213
+ sdkbump braucht kein Xcode: Es liest Dateien und läuft deshalb auch unter Linux. CI führt die Tests mit Node.js 22 und 24 (Linux) aus; lokal bestehen alle 280 mit Node.js 22.23, 24.22 und 26.11 auf einem Mac (Apple Silicon). Die Simulator-Aufnahmen brauchen einen Mac mit Xcode 27 und sind nicht Teil von CI.
214
+
215
+ ## Architektur
216
+
217
+ ```text
218
+ path ─► detectProject native | flutter | react-native | expo; iOS folder; versions
219
+ ─► collectApp iOS app targets from project.pbxproj, their Info.plist (XML or binary),
220
+ Swift and Objective-C sources with comments and strings blanked
221
+ ─► checkApp SCN001…SCN004, fix per ecosystem and version, workaround packages
222
+ rules/ios27.json what each rule says, fixes, sources (validated with zod)
223
+ ─► render tty | markdown | json
224
+ ```
225
+
226
+ - Die Erkennungsmuster sind reguläre Ausdrücke über Quelltext, dessen Kommentare und Strings geleert wurden, und zählen, wo es darauf ankommt, nur innerhalb eines App Delegate oder Scene Delegate.
227
+ - Die Regeldaten sind vom Code getrennt und versioniert (`ios27@2026.10.15`); ein Test schlägt fehl, wenn eine Regel, eine Lösung oder ein Workaround keine Quelle hat.
228
+ - Die CLI (`src/cli/`) parst nur Argumente, wählt Farben und Breiten und setzt den Exit-Code.
229
+
230
+ ## Roadmap
231
+
232
+ Siehe die Tabelle [Status](#status): 0.2 ergänzt Abhängigkeiten und Deployment Targets, 0.3 das Starten im Simulator über die CLI, 0.5 Syntaxbäume und Prüfungen gebauter Apps, 0.8 Korrekturen und SARIF, 1.0 ein stabiles Schema. [CHANGELOG.md](CHANGELOG.md) listet auf, was sich mit jedem Release geändert hat.
233
+
234
+ ## FAQ
235
+
236
+ **Meine App läuft heute unter iOS 27. Ist sie betroffen?** Wenn sie mit Xcode 26 oder früher gebaut wurde, gilt die Prüfung für diesen Build nicht: In unserem Lauf startete derselbe Code, gelinkt gegen das iOS-26-SDK, im iOS-27-Simulator. Sie gilt für deinen nächsten Build mit Xcode 27.
237
+
238
+ **Ersetzt sdkbump Tests auf einem Gerät?** Nein. Es liest Dateien. Die Simulator-Aufnahmen in diesem Repository stammen aus dem iOS-27.0-Simulator; nichts davon wurde auf einem Gerät ausgeführt.
239
+
240
+ **Warum gilt ein Fund als „behandelt“?** Ein Workaround-Paket in der package.json (react-native-uiscene-bridge oder react-native-xcode27) deklariert zur Laufzeit eine Scene. Die App startet, hat aber weiterhin keine eigene Scene-Unterstützung; der Bericht listet die Einschränkungen des Pakets und die eigentliche Lösung auf.
241
+
242
+ **Ändert sdkbump mein Projekt?** Nein. Es liest es und schreibt nur den Bericht, den du anforderst.
243
+
244
+
245
+ ## Mitwirken
246
+
247
+ Beiträge sind willkommen. Lies vor einem Pull Request den [Leitfaden für Beiträge](CONTRIBUTING.md) und den [Verhaltenskodex](https://github.com/muhittincamdali/.github/blob/main/CODE_OF_CONDUCT.md). Sicherheitsprobleme meldest du vertraulich, wie in der [Sicherheitsrichtlinie](SECURITY.md) beschrieben.
248
+
249
+ ## Lizenz
250
+
251
+ Veröffentlicht unter der MIT-Lizenz. Siehe [LICENSE](LICENSE).
package/README.es.md ADDED
@@ -0,0 +1,252 @@
1
+ <!-- i18n-source: README.md@49073c524eb2b7aad433b6794961ec40869c1170 status=reviewed -->
2
+ <!-- brand:start -->
3
+
4
+ <p align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/banner-light.svg" alt="sdkbump: Checks native iOS, Flutter and React Native apps for the iOS 27 SDK changes and names the fix for each."></picture></p>
5
+
6
+ <!-- lang-selector:start -->
7
+ <p align="center"><a href="README.md">English</a> · <a href="README.tr.md">Türkçe</a> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ja.md">日本語</a> · <a href="README.ko.md">한국어</a> · <a href="README.es.md">Español</a> · <a href="README.de.md">Deutsch</a> · <a href="README.fr.md">Français</a> · <a href="README.pt-BR.md">Português (Brasil)</a> · <a href="README.ru.md">Русский</a></p>
8
+ <!-- lang-selector:end -->
9
+
10
+ <p align="center">
11
+ <a href="https://github.com/muhittincamdali/sdkbump/actions/workflows/ci.yml"><img src="https://github.com/muhittincamdali/sdkbump/actions/workflows/ci.yml/badge.svg" alt="Estado de CI"></a>
12
+ <a href="https://github.com/muhittincamdali/sdkbump/releases"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-version-light.svg" alt="Última versión: v0.1.2"></picture></a>
13
+ <a href="https://github.com/muhittincamdali/sdkbump/blob/main/package.json"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-language-light.svg" alt="Versión del lenguaje: Node.js 22.12+"></picture></a>
14
+ <a href="https://github.com/muhittincamdali/sdkbump/blob/main/LICENSE"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/badge-license-light.svg" alt="Licencia: MIT"></picture></a>
15
+ </p>
16
+
17
+ <p align="center">
18
+ <a href="#inicio-rápido"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-es-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-es-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-start-es-light.svg" alt="Empezar"></picture></a>
19
+ <a href="https://muhittincamdali.github.io/sdkbump/"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-es-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-es-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-docs-es-light.svg" alt="Documentación"></picture></a>
20
+ <a href="https://github.com/muhittincamdali/sdkbump/tree/main/docs/guides"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-es-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-es-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-guides-es-light.svg" alt="Guías"></picture></a>
21
+ <a href="https://github.com/muhittincamdali/sdkbump/tree/main/examples"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-es-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-es-light.svg"><img src="https://raw.githubusercontent.com/muhittincamdali/sdkbump/main/.github/brand/button-examples-es-light.svg" alt="Ejemplos"></picture></a>
22
+ </p>
23
+
24
+ > Esta es una traducción del README en inglés. Si hay diferencias, la versión en inglés es la vigente.
25
+
26
+ <!-- brand:end -->
27
+
28
+ Antes de publicar una versión compilada con Xcode 27: sdkbump revisa un proyecto iOS nativo, Flutter o React Native/Expo para detectar lo que cambia el SDK de iOS 27, empezando por el ciclo de vida de UIScene, y te dice qué solución corresponde a cada hallazgo. Lee los archivos de tu proyecto; no compila, no ejecuta ni modifica nada.
29
+
30
+ <picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-rn-087-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-rn-087-light.svg"><img src="docs/media/demo-rn-087-light.svg" alt="sdkbump ejecutado sobre una app de React Native 0.87: no se inicia al compilarla con el SDK de iOS 27; SCN001 sin configuración de escena y SCN002 ventana creada en el app delegate, con tres formas de solucionarlo"></picture>
31
+
32
+ <sub>Grabado con la CLI real sobre el <a href="fixtures/rn-087">fixture rn-087</a>, una app de React
33
+ Native 0.87.1 creada con <code>@react-native-community/cli init</code> (<code>npm run demo</code>).</sub>
34
+
35
+ ## Lo más destacado
36
+
37
+ - **Responde a «¿se iniciará?».** Una app que no declara ninguna escena se compila con Xcode 27 y luego se detiene al iniciarse. sdkbump te lo dice antes de que lo descubras en un dispositivo de pruebas y señala los archivos que hay que cambiar.
38
+ - **Nativo, Flutter, React Native y Expo** en un solo informe con los mismos ID de regla, en texto, Markdown o JSON, y con un código de salida para CI.
39
+ - **La solución que corresponde a tu proyecto**: React Native 0.88 o un scene delegate escrito a mano, la activación opcional de Expo SDK 57 o SDK 58, la migración automática de Flutter o los pasos manuales (sdkbump comprueba las mismas condiciones que el migrador de Flutter), o la API de SwiftUI para una app SwiftUI.
40
+ - **También los fallos silenciosos**: métodos del app delegate y opciones de lanzamiento que UIKit deja de usar cuando la app tiene una escena (enlaces, Handoff, acciones rápidas, paso a primer y segundo plano) y búsquedas de ventana que ya no encuentran la ventana correcta.
41
+ - **Cada afirmación tiene una fuente.** Las reglas son datos ([rules/ios27.json](rules/ios27.json)) y cada una cita las páginas de Apple, Flutter, React Native o Expo; las pruebas fallan si alguna no lo hace.
42
+ - **Comprobado en el simulador de iOS 27**: el fallo de inicio y la pantalla negra detrás de SCN001 y SCN002 se reprodujeron con Xcode 27.0, y las grabaciones están en el repositorio.
43
+
44
+ ## Inicio rápido
45
+
46
+ Necesitas [Node.js](https://nodejs.org/) 22.12 o posterior (`node --version` muestra la versión; en un Mac, `brew install node` lo instala). Nada más.
47
+
48
+ **1. Abre una terminal en la carpeta de tu app**, la que contiene el `.xcodeproj`, el `pubspec.yaml` o el `package.json`:
49
+
50
+ ```sh
51
+ cd path/to/YourApp
52
+ ```
53
+
54
+ **2. Ejecuta sdkbump:**
55
+
56
+ ```sh
57
+ npx @mcamdali/sdkbump
58
+ ```
59
+
60
+ El paquete de npm es `@mcamdali/sdkbump`; el comando que instala es `sdkbump`. Un `npx sdkbump` sin scope no lo ejecuta.
61
+
62
+ **3. Lee la primera línea bajo el nombre de tu proyecto.** «Fails to launch when built with the iOS 27 SDK» (no se inicia al compilarla con el SDK de iOS 27) significa que la app se detiene al iniciarse hasta que corrijas los hallazgos **ERROR**; cada uno indica qué solución de la lista «How to fix» corresponde. Los hallazgos **WARNING** no impiden el inicio, pero dejan de funcionar cuando la app tiene una escena. «Launch not determined» (no se puede determinar el inicio) significa que sdkbump no pudo leer un Info.plist; las notas al final del informe dicen cuál y por qué (consulta Límites más abajo).
63
+
64
+ ## Qué cambia al compilar con el SDK de iOS 27
65
+
66
+ De la página de Apple
67
+ [Transitioning to the UIKit scene-based life cycle](https://developer.apple.com/documentation/uikit/transitioning-to-the-uikit-scene-based-life-cycle) (traducción):
68
+
69
+ > A partir de iOS 27, iPadOS 27, Mac Catalyst 27, tvOS 27 y visionOS 27, las apps compiladas con el último SDK deben adoptar el ciclo de vida basado en escenas o no se iniciarán.
70
+
71
+ 1. **La app se detiene al iniciarse si no declara ninguna escena.** Sin un `UIApplicationSceneManifest` con una configuración en Info.plist y sin `application(_:configurationForConnecting:options:)`, UIKit termina el proceso con el mensaje «UIScene life cycle is required for apps built with this SDK». El compilador no avisa, porque la comprobación se hace cuando la app arranca. React Native 0.87 y anteriores, Expo SDK 57 sin su activación opcional y Expo SDK 56 y anteriores crean apps así; también las apps Flutter que la herramienta de Flutter no puede migrar.
72
+ 2. **Con una escena, el app delegate deja de recibir eventos de la interfaz.** Los enlaces, las user activities, las acciones rápidas y las transiciones activa/segundo plano pasan al scene delegate, y una ventana que cree el app delegate nunca se muestra.
73
+
74
+ [Por qué compila y aun así se bloquea](docs/guides/why-it-crashes.md) muestra la [matriz de inicio](examples/launch-matrix/README.md) que ejecutamos en el simulador de iOS 27.0.
75
+
76
+ ## Qué revisa sdkbump
77
+
78
+ | Regla | Gravedad | Hallazgo | Observado en el simulador de iOS 27.0 |
79
+ | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
80
+ | SCN001 | error | Sin configuración de escena: ningún `UIApplicationSceneManifest` configurado, ningún `configurationForConnecting`, y no es una `App` de SwiftUI; en Expo sin `ios/`, la versión del SDK y `enableSceneSupport` | se detiene al iniciarse |
81
+ | SCN002 | error | El app delegate crea la ventana con `UIWindow(frame:)` | pantalla negra cuando la app tiene una escena |
82
+ | SCN003 | warning | Métodos del app delegate y claves de opciones de lanzamiento que UIKit ya no usa con escenas (13 en total), salvo que el scene delegate ya los gestione | `applicationDidEnterBackground(_:)` no se llama en una app SwiftUI |
83
+ | SCN004 | warning | Búsquedas de ventana mediante `UIApplication.shared.keyWindow`, `.windows` o el `window` del app delegate | solo avisos de obsolescencia del compilador |
84
+
85
+ Datos de reglas `ios27@2026.10.15`, comprobados con Xcode 27.0 (27A266a). Cuando React Native o Expo tienen instalado `react-native-uiscene-bridge` o `react-native-xcode27`, los hallazgos que estos gestionan en tiempo de ejecución se muestran como gestionados, con los límites indicados en su README, y no hacen fallar la ejecución.
86
+
87
+ ## Instalación
88
+
89
+ Instala el comando `sdkbump` desde npm (paquete `@mcamdali/sdkbump`):
90
+
91
+ ```sh
92
+ npm i -g @mcamdali/sdkbump
93
+ sdkbump
94
+ ```
95
+
96
+ En un proyecto, `npm install --save-dev @mcamdali/sdkbump` fija una versión y luego `npx sdkbump` ejecuta esa copia. Cada [versión en GitHub](https://github.com/muhittincamdali/sdkbump/releases) incluye también el mismo paquete como `sdkbump-<versión>.tgz` con un archivo `SHA256SUMS`; `npx` lo ejecuta desde su URL sin npm. El workflow de publicación prepara una fórmula de Homebrew para `muhittincamdali/tap` (planificada con la primera versión del tap).
97
+
98
+ ## Uso
99
+
100
+ ```text
101
+ sdkbump [path] [options]
102
+ ```
103
+
104
+ | Opción | Qué hace |
105
+ | ----------------------- | ---------------------------------------------------------------------------------- |
106
+ | `path` | Carpeta del proyecto o `.xcodeproj`; por defecto, la carpeta actual |
107
+ | `-f, --format <format>` | `tty` (por defecto), `markdown` o `json` |
108
+ | `-o, --output <file>` | Escribe el informe en un archivo en lugar de en la terminal |
109
+ | `--fail-on <severity>` | `error` (por defecto), `warning`, `info` o `none`: cuándo el código de salida es 1 |
110
+ | `--no-color` | Texto sin formato incluso en una terminal (se respetan `NO_COLOR` y `FORCE_COLOR`) |
111
+
112
+ Códigos de salida: `0` ningún hallazgo sin gestionar en `--fail-on` o por encima, `1` hallazgos en ese nivel o por encima, `2` argumentos incorrectos, no se encontró ningún proyecto iOS o un error inesperado.
113
+
114
+ sdkbump encuentra la app iOS por sí mismo: un `.xcodeproj` en la raíz o una carpeta más abajo para las apps nativas, `ios/` para las apps Flutter, React Native y Expo (`example/ios/` para un plugin de Flutter). Lee todos los targets de app iOS del archivo de proyecto, el Info.plist que nombra cada uno (XML o binario) y los archivos Swift y Objective-C de la app, y omite Pods, `node_modules`, la salida de compilación y las pruebas. Las apps Expo sin `ios/` se comprueban a partir de package.json y app.json.
115
+
116
+ ### Guardar un informe en Markdown junto al código
117
+
118
+ ```sh
119
+ npx @mcamdali/sdkbump --format markdown --output sdkbump.md
120
+ ```
121
+
122
+ ### Usar el informe JSON en scripts
123
+
124
+ ```sh
125
+ npx @mcamdali/sdkbump --format json > sdkbump.json
126
+ ```
127
+
128
+ Cada hallazgo tiene `rule`, `severity`, `file`, `line`, `message`, el `fix` con sus pasos y su guía, `alternatives`, `mitigation` (se establece cuando lo resuelve un paquete de solución provisional) y `sources`. El formato es `schemaVersion` 0 y puede cambiar antes de la 1.0. [examples/shell/launch-blockers.sh](examples/shell/launch-blockers.sh) lo filtra con `jq`.
129
+
130
+ ### Ejecutarlo en CI
131
+
132
+ [examples/github-actions/sdkbump.yml](examples/github-actions/sdkbump.yml) añade el informe al resumen del job de cada pull request que toque la app iOS y hace fallar el job si hay errores.
133
+
134
+ ### Desde JavaScript
135
+
136
+ ```js
137
+ import { render, scan } from 'sdkbump';
138
+
139
+ const report = await scan('path/to/app');
140
+ console.log(report.verdict.text);
141
+ console.log(render(report, 'markdown'));
142
+ ```
143
+
144
+ Una versión ejecutable es [examples/api/verdicts.mjs](examples/api/verdicts.mjs).
145
+
146
+ ## Demo
147
+
148
+ Las grabaciones de terminal proceden de la CLI ejecutada sobre los [fixtures](fixtures/README.md), proyectos reales creados con cada toolchain:
149
+
150
+ | Proyecto | Grabación |
151
+ | -------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
152
+ | App de React Native 0.87.1 | al principio de esta página |
153
+ | App de Flutter con un AppDelegate personalizado (Flutter 3.24) | [claro](docs/media/demo-flutter-light.svg) · [oscuro](docs/media/demo-flutter-dark.svg) |
154
+ | App de SwiftUI con un app delegate mediante adaptador | [claro](docs/media/demo-swiftui-light.svg) · [oscuro](docs/media/demo-swiftui-dark.svg) |
155
+
156
+ En el simulador de iOS 27.0 (iPhone 17, compilado con Xcode 27.0), el fixture nativo de UIKit se detiene al iniciarse, y la misma app migrada a un scene delegate se inicia:
157
+
158
+ <picture><source media="(prefers-color-scheme: dark)" srcset="docs/media/demo-simulator-native-uikit-dark.svg"><source media="(prefers-color-scheme: light)" srcset="docs/media/demo-simulator-native-uikit-light.svg"><img src="docs/media/demo-simulator-native-uikit-light.svg" alt="scripts/simulator-check.sh native-uikit en el simulador de iOS 27.0: no se está ejecutando 4 segundos después del inicio, con la línea de UIKit: Application failed to launch: UIScene life cycle is required for apps built with this SDK"></picture>
159
+
160
+ <p align="center"><img src="docs/media/simulator/launched.png" width="480" alt="Los fixtures native-uikit-scenes y native-swiftui ejecutándose en un simulador de iPhone 17 con iOS 27.0, compilados con Xcode 27.0"></p>
161
+
162
+ Medido el 15 de octubre de 2026 en un Mac (Apple silicon, M5 Max) con Node.js 26.11 mientras ejecutaba otros trabajos: tres series de 100 ejecuciones de `node dist/cli/main.js` sobre los diez fixtures, incluido el arranque de Node.js. Las medianas de las tres series fueron 0,11, 0,12 y 0,19 segundos; la ejecución más lenta tardó 0,33 segundos. Con más carga en la máquina, los tiempos son mayores.
163
+
164
+ ## Estado
165
+
166
+ | Función | Estado |
167
+ | --------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
168
+ | Detección de proyectos nativos, Flutter (app y ejemplo de plugin), React Native y Expo | funciona |
169
+ | SCN001 a SCN004 sobre el Info.plist y los fuentes Swift/Objective-C de la propia app | funciona |
170
+ | Selección de la solución por ecosistema y versión; comprobación de la migración automática de Flutter; paquetes de solución provisional | funciona |
171
+ | Informes en terminal, Markdown y JSON; códigos de salida de `--fail-on` | funciona |
172
+ | Dependencias: Pods, `node_modules` y fuentes de plugins de Flutter, con el nombre del paquete | planificado (0.2) |
173
+ | Aviso de solución provisional SCN005 como regla propia; DPT001 para deployment targets inferiores a 15.0 | planificado (0.2) |
174
+ | `--verify`: compilar e iniciar en el simulador de iOS 27 desde la CLI | planificado (0.3) |
175
+ | Árboles de sintaxis de Swift/Objective-C en lugar de patrones; comprobaciones de `.app` compiladas; obsolescencias de SiriKit | planificado (0.5) |
176
+ | `fix --dry-run` para apps nativas, salida SARIF, GitHub Action | planificado (0.8) |
177
+ | Esquema de reglas y formato JSON estables | planificado (1.0) |
178
+
179
+ ## Límites
180
+
181
+ - **Patrones, no un compilador.** Las reglas son expresiones regulares sobre texto Swift y Objective-C con los comentarios y las cadenas en blanco. El código generado, oculto tras macros o escrito de una forma poco habitual puede pasarse por alto o detectarse por error. Los árboles de sintaxis están planificados (0.5).
182
+ - **Solo las fuentes propias de la app.** No se leen Pods, `node_modules`, plugins de Flutter ni otras dependencias, así que no se informa de un plugin que dependa de métodos del app delegate que UIKit ya no llama. La revisión de dependencias está planificada (0.2).
183
+ - **Ajustes de compilación solo de project.pbxproj.** sdkbump lee `INFOPLIST_FILE` y `GENERATE_INFOPLIST_FILE` del archivo del proyecto y expande `$(SRCROOT)`, `$(PROJECT_DIR)`, `$(TARGET_NAME)` y `$(PRODUCT_NAME)`. No lee archivos `.xcconfig`, no expande otros ajustes de compilación y no lee un Info.plist fuera de la carpeta del proyecto. Cuando no puede leer el Info.plist de un target, SCN001 es un hallazgo de tipo info y el veredicto es «Launch not determined» en lugar de una suposición.
184
+ - **Sin archivo de supresión.** Un hallazgo no se puede marcar como revisado; `--fail-on` decide qué severidades hacen fallar la ejecución.
185
+ - **Solo archivos.** sdkbump no compila ni inicia la app; `--verify` está planificado (0.3).
186
+
187
+ ## Documentación
188
+
189
+ Referencia de la API y guías: [muhittincamdali.github.io/sdkbump](https://muhittincamdali.github.io/sdkbump/).
190
+
191
+ ## Guías
192
+
193
+ - [Por qué compila y aun así se bloquea](docs/guides/why-it-crashes.md)
194
+ - [Apps nativas con UIKit y SwiftUI](docs/guides/native-ios.md)
195
+ - [Flutter: un AppDelegate personalizado y plugins](docs/guides/flutter.md)
196
+ - [React Native anterior a 0.88 y Expo anterior a SDK 58](docs/guides/react-native-expo.md)
197
+ - [Autores de módulos nativos: enlaces y notificaciones en el arranque en frío](docs/guides/native-module-authors.md)
198
+
199
+ ## Herramientas relacionadas
200
+
201
+ Otros proyectos trabajan en el mismo cambio; cuál te conviene depende de lo que necesites:
202
+
203
+ - [react-native-uiscene-bridge](https://github.com/Atomics-hub/react-native-uiscene-bridge) y [react-native-xcode27](https://github.com/Atomics-hub/react-native-xcode27) hacen que una app de React Native o Expo se inicie sin cambios de código, en tiempo de ejecución. Sirven cuando todavía no puedes actualizar; sdkbump los reconoce.
204
+ - [auditor-uiscene](https://github.com/Anzell/auditor-uiscene) audita apps Flutter y sus plugins con un script de shell.
205
+ - El propio migrador de Flutter (`flutter build ios` desde la 3.41) migra una app Flutter sin modificar.
206
+ - [flutter_spm_doctor](https://pub.dev/packages/flutter_spm_doctor) revisa los plugins de Flutter.
207
+
208
+ ## Requisitos
209
+
210
+ | Toolchain | Versión mínima |
211
+ | --------- | -------------- |
212
+ | Node.js | 22.12 |
213
+
214
+ sdkbump no necesita Xcode: lee archivos, así que también funciona en Linux. CI ejecuta las pruebas en Node.js 22 y 24 (Linux); en local, las 280 pasan en Node.js 22.23, 24.22 y 26.11 en un Mac (Apple silicon). Las grabaciones del simulador requieren un Mac con Xcode 27 y no forman parte de CI.
215
+
216
+ ## Arquitectura
217
+
218
+ ```text
219
+ path ─► detectProject native | flutter | react-native | expo; iOS folder; versions
220
+ ─► collectApp iOS app targets from project.pbxproj, their Info.plist (XML or binary),
221
+ Swift and Objective-C sources with comments and strings blanked
222
+ ─► checkApp SCN001…SCN004, fix per ecosystem and version, workaround packages
223
+ rules/ios27.json what each rule says, fixes, sources (validated with zod)
224
+ ─► render tty | markdown | json
225
+ ```
226
+
227
+ - Los patrones de detección son expresiones regulares sobre el texto fuente con los comentarios y las cadenas en blanco, y, cuando importa, solo cuentan dentro de un app delegate o un scene delegate.
228
+ - Los datos de las reglas están separados del código y tienen versión (`ios27@2026.10.15`); una prueba falla cuando una regla, una solución o una solución provisional no tiene fuente.
229
+ - La CLI (`src/cli/`) solo interpreta los argumentos, elige los colores y los anchos, y establece el código de salida.
230
+
231
+ ## Hoja de ruta
232
+
233
+ Consulta la tabla de [Estado](#estado): la 0.2 añade dependencias y deployment targets, la 0.3 el inicio en el simulador desde la CLI, la 0.5 árboles de sintaxis y comprobaciones de la app compilada, la 0.8 correcciones y SARIF, y la 1.0 un esquema estable. [CHANGELOG.md](CHANGELOG.md) enumera lo que cambió en cada versión.
234
+
235
+ ## Preguntas frecuentes
236
+
237
+ **Mi app funciona hoy en iOS 27. ¿Le afecta?** Si se compiló con Xcode 26 o anterior, la comprobación no se aplica a esa compilación: en nuestra prueba, el mismo código enlazado con el SDK de iOS 26 se inició en el simulador de iOS 27. Se aplica a tu próxima compilación con Xcode 27.
238
+
239
+ **¿Sustituye sdkbump las pruebas en un dispositivo?** No. Lee archivos. Las grabaciones del simulador de este repositorio son del simulador de iOS 27.0; nada de lo que hay aquí se ejecutó en un dispositivo.
240
+
241
+ **¿Por qué un hallazgo aparece como «gestionado»?** Un paquete de solución provisional en package.json (react-native-uiscene-bridge o react-native-xcode27) declara una escena en tiempo de ejecución. La app se inicia, pero sigue sin tener soporte de escenas propio; el informe enumera los límites del paquete y la solución real.
242
+
243
+ **¿Modifica sdkbump mi proyecto?** No. Lo lee y solo escribe el informe que le pidas.
244
+
245
+
246
+ ## Contribuir
247
+
248
+ Las contribuciones son bienvenidas. Lee la [guía de contribución](CONTRIBUTING.md) y el [código de conducta](https://github.com/muhittincamdali/.github/blob/main/CODE_OF_CONDUCT.md) antes de abrir una pull request. Informa de los problemas de seguridad de forma privada, como se describe en la [política de seguridad](SECURITY.md).
249
+
250
+ ## Licencia
251
+
252
+ Publicado bajo la licencia MIT. Consulta [LICENSE](LICENSE).